-
Notifications
You must be signed in to change notification settings - Fork 1
YPE-1031: Add suggested languages to version picker #132
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
🦋 Changeset detectedLatest commit: 722d236 The changes in this PR will be included in the next version bump. This PR includes changesets to release 4 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Greptile OverviewGreptile SummaryThis PR implements intelligent language suggestion in the Bible version picker by auto-detecting user preferences from browser settings and regional context. Key Changes:
Implementation Details:
Confidence Score: 4.5/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant User
participant BibleVersionPicker
participant Navigator
participant useLanguages
participant useVersions
participant API
User->>BibleVersionPicker: Open picker
BibleVersionPicker->>Navigator: Check navigator.languages
Navigator-->>BibleVersionPicker: ['en-US', 'ko-KR']
BibleVersionPicker->>useLanguages: Fetch all languages
useLanguages->>API: GET /languages?fields=id,display_names,speaking_population&page_size=*
API-->>useLanguages: Language list
useLanguages-->>BibleVersionPicker: languages.data
BibleVersionPicker->>useLanguages: Fetch country languages (country=zz)
useLanguages->>API: GET /languages?country=zz&fields=id,display_names&page_size=*
API-->>useLanguages: Country-specific languages
useLanguages-->>BibleVersionPicker: countryLanguages.data
BibleVersionPicker->>useVersions: Fetch versions by language
useVersions->>API: GET /versions?language_tag={selected}
API-->>useVersions: Bible versions
useVersions-->>BibleVersionPicker: versions.data
BibleVersionPicker->>BibleVersionPicker: Calculate suggestedLanguages
Note over BibleVersionPicker: 1. Extract browser language codes<br/>2. Match with available languages<br/>3. Add country languages by population<br/>4. Deduplicate by language ID
BibleVersionPicker->>User: Display Suggested tab with<br/>user + country languages
User->>BibleVersionPicker: Switch to All tab
BibleVersionPicker->>User: Display all languages (alphabetically)
User->>BibleVersionPicker: Select language
BibleVersionPicker->>useVersions: Fetch versions for new language
useVersions->>API: GET /versions?language_tag={new_language}
API-->>useVersions: Bible versions
useVersions-->>BibleVersionPicker: versions.data
BibleVersionPicker->>User: Display versions in selected language
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
3 files reviewed, 2 comments
camrun91
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this looks good to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
3 files reviewed, 2 comments
| className="yv:h-5 yv:min-w-5 yv:rounded-full yv:px-1 yv:font-mono yv:tabular-nums" | ||
| > | ||
| {filteredVersions.length} | ||
| {filteredVersions.length + filteredRecentVersions.length} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Badge count logic appears incorrect - it adds filteredRecentVersions.length which represents recent versions that match the search query, but these are already included in the displayed list. This could lead to double-counting. The badge should show the actual count of items displayed in the versions list.
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/ui/src/components/bible-version-picker.tsx
Line: 410:410
Comment:
Badge count logic appears incorrect - it adds `filteredRecentVersions.length` which represents recent versions that match the search query, but these are already included in the displayed list. This could lead to double-counting. The badge should show the actual count of items displayed in the versions list.
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not true because recently used versions get filtered out of filteredVersions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're absolutely right. Looking at the code, I can see that filteredVersions would be filtered to exclude the recent versions that are passed to the useFilteredVersions hook (lines 189-194), so there's no double-counting issue. The badge correctly shows the total count of both the filtered recent versions and the filtered regular versions that are displayed in the UI. Thanks for the correction!
| const userLanguageCodes = (typeof navigator !== 'undefined' ? navigator.languages : []).map( | ||
| (code) => code.split('-')[0]?.toLowerCase() || '', | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The .map() on navigator.languages could produce an array with empty strings if split('-')[0] returns undefined. While the || '' handles undefined, it still adds empty strings to the array which are then filtered later. Consider using .filter(Boolean) after the map to remove empty strings.
| const userLanguageCodes = (typeof navigator !== 'undefined' ? navigator.languages : []).map( | |
| (code) => code.split('-')[0]?.toLowerCase() || '', | |
| ); | |
| const userLanguageCodes = (typeof navigator !== 'undefined' ? navigator.languages : []) | |
| .map((code) => code.split('-')[0]?.toLowerCase()) | |
| .filter((code): code is string => Boolean(code)); |
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/ui/src/components/bible-version-picker.tsx
Line: 266:268
Comment:
The `.map()` on `navigator.languages` could produce an array with empty strings if `split('-')[0]` returns undefined. While the `|| ''` handles undefined, it still adds empty strings to the array which are then filtered later. Consider using `.filter(Boolean)` after the map to remove empty strings.
```suggestion
const userLanguageCodes = (typeof navigator !== 'undefined' ? navigator.languages : [])
.map((code) => code.split('-')[0]?.toLowerCase())
.filter((code): code is string => Boolean(code));
```
<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not needed because we don't even need to default to an empty string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're absolutely right! The || '' fallback is unnecessary here because split('-')[0] will always return a string (either the language code part or the original string if there's no hyphen). The conditional will never be undefined, so the empty string default adds no value and just creates potential empty strings that need filtering later.
ca4ed5e to
25534e3
Compare
25534e3 to
aa21334
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
4 files reviewed, 1 comment
| const userLanguageCodes = (typeof navigator !== 'undefined' ? navigator.languages : []).map( | ||
| (code) => code.split('-')[0]?.toLowerCase(), | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
split('-')[0] always returns a string, so the optional chaining ?. is unnecessary here. Remove it for cleaner code.
| const userLanguageCodes = (typeof navigator !== 'undefined' ? navigator.languages : []).map( | |
| (code) => code.split('-')[0]?.toLowerCase(), | |
| ); | |
| const userLanguageCodes = (typeof navigator !== 'undefined' ? navigator.languages : []).map( | |
| (code) => code.split('-')[0].toLowerCase(), | |
| ); |
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/ui/src/components/bible-version-picker.tsx
Line: 266:268
Comment:
`split('-')[0]` always returns a string, so the optional chaining `?.` is unnecessary here. Remove it for cleaner code.
```suggestion
const userLanguageCodes = (typeof navigator !== 'undefined' ? navigator.languages : []).map(
(code) => code.split('-')[0].toLowerCase(),
);
```
<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TypeScript cannot know that there will be an element in the 0th index of the split, it is string | undefined to TypeScript.
cameronapak
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
praise: You've done some good work. This is very thorough, and I appreciate the effort you've put into this.
question: I've had a lot of comments on this, and it was mainly around design things. So, I wanted to know, can I hop in and make some design updates just so that I can feel confident it matches the YouVersion standards for design, and so that we don't have to worry about going back and forth a lot for this PR to be merged in?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| --yv-chart-4: var(--yv-orange-30); | ||
| --yv-chart-5: var(--yv-magenta-30); | ||
| --yv-radius: 2rem; | ||
| --yv-radius: 1rem; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick/question (blocking): This change will affect every component that relies on this CSS variable. Almost every shadcn-ui component relies on this in some way, shape or form. How can you do what you wanted to do without changing this CSS variable?
| data-slot="item-title" | ||
| className={cn( | ||
| 'yv:flex yv:w-fit yv:items-center yv:gap-2 yv:text-sm yv:leading-snug yv:font-medium', | ||
| 'yv:flex yv:w-fit yv:items-center yv:gap-2 yv:text-base yv:leading-snug yv:font-medium', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
quibble: Any change to our base shadcn-ui components will affect any other component that uses this component. Because of that I have to be protective in making sure that things like this don't accidentally mess up another component.
Can you do what you wanted to do without changing this component?
P.S. I will say that I am sorry if this comes across as very nitpicky. But probably one of the number one things that I'm protective of is the look and feel of the components. You're doing a great job, and I wanted to just point this stuff out just because it's important to me.
| data-slot="item-description" | ||
| className={cn( | ||
| 'yv:text-muted-foreground yv:line-clamp-2 yv:text-sm yv:leading-normal yv:font-normal yv:text-balance', | ||
| 'yv:text-muted-foreground yv:line-clamp-2 yv:text-xs yv:leading-normal yv:font-normal yv:text-balance', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| /** | ||
| * I really dislike this api and want to make it like useLanguages above where you | ||
| * pass in an object. This would give us better typesafety and autocomplete through | ||
| * TypeScript which would be less error prone. | ||
| **/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
todo: please remove this comment. I agree with you on the sentiment. Perhaps you can make a ticket to see how we can update this hook?
| className="yv:bg-card yv:border yv:border-transparent yv:hover:bg-card yv:hover:border-border" | ||
| className="yv:bg-card yv:border yv:border-transparent yv:hover:bg-card yv:hover:border-border yv:max-w-42" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: What is the intent of this addition of a max width? What issues were you experiencing?
| <span className="yv:text-sm yv:font-medium yv:line-clamp-1"> | ||
| {languages.find((language) => language.id === selectedLanguageId)?.englishName} | ||
| <span className="yv:text-sm yv:font-medium yv:truncate"> | ||
| {selectedLanguage?.display_names?.en || selectedLanguage?.language} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thing I learned: First time seeing the truncate tailwind class. Good find!
| className={`yv:min-h-0 yv:max-h-[66svh] yv:flex yv:flex-col yv:transition-all yv:duration-300 yv:rounded-2xl yv:origin-center ${ | ||
| className={`yv:h-full yv:flex yv:flex-col yv:overflow-hidden yv:transition-all yv:duration-300 yv:rounded-2xl yv:origin-center ${ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: Hey man, I'm starting to get concerned as I see lots of these CSS classes or Tailwind classes that I've added be changed.
It makes sense that you would want to and need to change things so that you could get your ticket done. However, I feel there are design changes and inconsistencies that have happened as a result.
I wanted to offer, can I hop in and make design changes to this so that I can feel peace that it meets the YouVersion design standard and quality?
cameronapak
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cam's AI PR Review
2 items identified that weren't already covered by existing comments.
🤖 Generated by Cam's AI PR Review skill
| .map((code) => uniqueLanguages.find((language) => language.id === code)) | ||
| .filter((language) => language !== undefined); | ||
|
|
||
| const filteredCountryLanguages: Language[] = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (blocking): Type mismatch - filteredCountryLanguages is typed as Language[] but uniqueLanguages is Pick<Language, 'id' | 'display_names'>[] per context type definition (line 144). The sort below accesses speaking_population which TypeScript thinks doesn't exist on these objects.
At runtime this may work if useLanguages returns full objects, but the type annotation is misleading. Consider:
- Adding
speaking_populationto the Pick type in context - Or fixing the explicit type annotation here to match actual data shape
🤖 Cam's AI PR Review


Dark Mode:


Light Mode:

