Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@ahmedriad1
Copy link
Collaborator

@ahmedriad1 ahmedriad1 commented Dec 9, 2025

Auto-generated from by github action

Summary by CodeRabbit

  • New Features

    • Added "Expand all" / "Collapse all" labels across supported languages.
    • Homepage "Collections" replaced by more granular sections: Featured Genres, Special Collections, Individual Collections.
  • Chores

    • Upgraded Next.js to v16.0.7.
    • Improved UI hydration stability to reduce rendering mismatches.

✏️ Tip: You can customize this high-level summary in your review settings.

AnasMations and others added 8 commits December 3, 2025 15:58
- Render primaryName and secondaryName
Updated dependencies to fix Next.js CVE vulnerabilities.

The fix-react2shell-next tool automatically updated the following packages to their secure versions:
- next
- react-server-dom-webpack
- react-server-dom-parcel  
- react-server-dom-turbopack

All package.json files have been scanned and vulnerable versions have been patched to the correct fixed versions based on the official React advisory.

Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
…ce-ad-viud10

Fix React Server Components RCE vulnerability
@vercel
Copy link
Contributor

vercel bot commented Dec 9, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Updated (UTC)
usul Ready Ready Preview Dec 9, 2025 2:33pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 9, 2025

Note

.coderabbit.yaml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized key(s) in object: 'path_filters'
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Walkthrough

Consolidates genre handling to use advanced genres across pages and API, adds new GenreNode type and updates genre components, appends expand/collapse localization keys in many locales, removes the fromHomepage route/nav parameter, adds suppressHydrationWarning to several UI components, and bumps Next.js version.

Changes

Cohort / File(s) Summary
Localization: Common (expand/collapse)
locales/ar/common.json, locales/bn/common.json, locales/es/common.json, locales/fa/common.json, locales/fr/common.json, locales/ha/common.json, locales/hi/common.json, locales/ms/common.json, locales/ps/common.json, locales/ru/common.json, locales/so/common.json, locales/tr/common.json, locales/ur/common.json
Added top-level keys expand-all and collapse-all with translations.
Localization: Home sections
locales/*/home.json (ar, bn, en, es, fa, fr, ha, hi, ms, ps, ru, so, tr, ur)
Replaced sections.collections with sections.genres, sections.special-collections, and sections.individual-collections.
Genre API & homepage genres
src/lib/api/genres.ts, src/app/[locale]/page.tsx
Added getHomepageAdvancedGenres; switched homepage to fetch advanced genres and updated UI/navigation to use genres links.
URLs / Navigation
src/lib/urls.ts
Removed fromHomepage parameter from navigation.genres.bySlug(); URL now always /genre/{slug}.
Genre page & OG route
src/app/[locale]/(entityPages)/genre/[genreSlug]/page.tsx, src/app/[locale]/(entityPages)/genre/[genreSlug]/routeType.ts, src/app/api/og/genre/[slug]/route.tsx
Consolidated genre retrieval to always use getAdvancedGenre; removed fromHomepage route param and related fallback logic.
Author page & search filters
src/app/[locale]/(entityPages)/author/[authorSlug]/page.tsx, src/hooks/use-global-chat.ts
Switched filter field from genres to advancedGenres (renamed local variable genreIdsadvancedGenreIds in hook).
Genre components & types
src/types/genre.ts, src/components/genres-filter/client.tsx, src/components/genres-tree-chart/client.tsx
Added exported GenreNode type (id, slug, primaryName, secondaryName, numberOfBooks, children[]); components updated to use GenreNode, display primaryName/secondaryName, and adjusted tree-chart layout, wrapping, and sizing.
UI hydration fixes
src/components/cloudflare-image.tsx, src/components/navbar/locale-switcher.tsx, src/components/navbar/profile-dropdown.tsx, src/components/ui/command/index.tsx, src/components/ui/dropdown-menu/index.tsx, src/components/ui/navigation-menu.tsx, src/components/ui/select/index.tsx
Added suppressHydrationWarning to various UI components and wrappers to suppress hydration warnings.
Other adjustments
src/components/genres-filter/client.tsx
Replaced local GenreNode interface with imported GenreNode; render labels use primaryName.
Deps
package.json
Bumped Next.js version from 16.0.1 to 16.0.7.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Areas requiring extra attention:

  • src/components/genres-tree-chart/client.tsx — text-wrapping, sizing, and layout changes (high-density visual logic).
  • src/app/(entityPages)/genre/* and src/app/api/og/genre/* — ensure getAdvancedGenre covers prior fallback cases.
  • src/lib/urls.ts and navigation call sites — verify removal of fromHomepage didn't leave stale callers.
  • Localization files — confirm new keys present and syntactically valid in all locale JSON files.
  • UI hydration changes — ensure suppressHydrationWarning usage is intentional and doesn't mask real hydration mismatches.

Poem

🐰 I hopped through locales, one by one,
Primary names shining bright as sun.
FromHomepage gone — the path is neat,
Tree nodes stretch on nimble feet.
Hydration eased, the UI hums — a cozy bun.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title uses an emoji and generic phrasing ('Sync Crowdin Translations') that lacks specificity about the actual changes in the pull request. Consider a more descriptive title that specifies the key changes, such as 'Update locale files with genre-based navigation restructuring' or 'Refactor genre navigation and add expand/collapse translations'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch l10n_crowdin_translations

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3818c0d and 9b445e5.

📒 Files selected for processing (1)
  • locales/ar/home.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • locales/ar/home.json

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/genres-filter/client.tsx (1)

163-168: Fuse search index references non-existent name field.

The GenreNode type (from src/types/genre.ts) has primaryName and secondaryName fields, but the Fuse index is configured to search on ["id", "name"]. The name key won't match any field, causing genre name searches to fail silently.

   const index = useMemo(() => {
     return new Fuse(allGenres, {
-      keys: ["id", "name"],
+      keys: ["id", "primaryName", "secondaryName"],
       threshold: 0.3,
     });
   }, [allGenres]);
🧹 Nitpick comments (2)
src/components/genres-tree-chart/client.tsx (1)

7-7: Prefer type-only import for GenreNode.

Since GenreNode is only used as a type annotation, use a type-only import for better tree-shaking and clearer intent.

-import { GenreNode } from "@/types/genre";
+import type { GenreNode } from "@/types/genre";
src/app/[locale]/(entityPages)/genre/[genreSlug]/page.tsx (1)

9-9: Remove duplicate getAdvancedGenre function from advanced-genres.ts.

Identical implementations of getAdvancedGenre exist in both src/lib/api/genres.ts and src/lib/api/advanced-genres.ts. Only the version in genres.ts is imported and used throughout the codebase; the version in advanced-genres.ts is dead code. Remove the duplicate from advanced-genres.ts to eliminate confusion and maintenance burden.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 531ce41 and 3818c0d.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (46)
  • locales/ar/common.json (1 hunks)
  • locales/ar/home.json (1 hunks)
  • locales/bn/common.json (1 hunks)
  • locales/bn/home.json (1 hunks)
  • locales/en/home.json (1 hunks)
  • locales/es/common.json (1 hunks)
  • locales/es/home.json (1 hunks)
  • locales/fa/common.json (1 hunks)
  • locales/fa/home.json (1 hunks)
  • locales/fr/common.json (1 hunks)
  • locales/fr/home.json (1 hunks)
  • locales/ha/common.json (1 hunks)
  • locales/ha/home.json (1 hunks)
  • locales/hi/common.json (1 hunks)
  • locales/hi/home.json (1 hunks)
  • locales/ms/common.json (1 hunks)
  • locales/ms/home.json (1 hunks)
  • locales/ps/common.json (1 hunks)
  • locales/ps/home.json (1 hunks)
  • locales/ru/common.json (1 hunks)
  • locales/ru/home.json (1 hunks)
  • locales/so/common.json (1 hunks)
  • locales/so/home.json (1 hunks)
  • locales/tr/common.json (1 hunks)
  • locales/tr/home.json (1 hunks)
  • locales/ur/common.json (1 hunks)
  • locales/ur/home.json (1 hunks)
  • package.json (1 hunks)
  • src/app/[locale]/(entityPages)/author/[authorSlug]/page.tsx (1 hunks)
  • src/app/[locale]/(entityPages)/genre/[genreSlug]/page.tsx (4 hunks)
  • src/app/[locale]/(entityPages)/genre/[genreSlug]/routeType.ts (0 hunks)
  • src/app/[locale]/page.tsx (3 hunks)
  • src/app/api/og/genre/[slug]/route.tsx (3 hunks)
  • src/components/cloudflare-image.tsx (1 hunks)
  • src/components/genres-filter/client.tsx (2 hunks)
  • src/components/genres-tree-chart/client.tsx (8 hunks)
  • src/components/navbar/locale-switcher.tsx (1 hunks)
  • src/components/navbar/profile-dropdown.tsx (1 hunks)
  • src/components/ui/command/index.tsx (3 hunks)
  • src/components/ui/dropdown-menu/index.tsx (2 hunks)
  • src/components/ui/navigation-menu.tsx (2 hunks)
  • src/components/ui/select/index.tsx (4 hunks)
  • src/hooks/use-global-chat.ts (1 hunks)
  • src/lib/api/genres.ts (1 hunks)
  • src/lib/urls.ts (1 hunks)
  • src/types/genre.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • src/app/[locale]/(entityPages)/genre/[genreSlug]/routeType.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/localization.mdc)

If you're using a translation key in the codebase, use the useTranslations hook from next-intl as shown: import { useTranslations } from "next-intl"; const t = useTranslations(); t("common.delete");

Files:

  • src/components/navbar/profile-dropdown.tsx
  • src/components/ui/command/index.tsx
  • src/components/ui/navigation-menu.tsx
  • src/components/genres-filter/client.tsx
  • src/app/api/og/genre/[slug]/route.tsx
  • src/app/[locale]/(entityPages)/author/[authorSlug]/page.tsx
  • src/app/[locale]/(entityPages)/genre/[genreSlug]/page.tsx
  • src/components/genres-tree-chart/client.tsx
  • src/components/cloudflare-image.tsx
  • src/components/navbar/locale-switcher.tsx
  • src/components/ui/dropdown-menu/index.tsx
  • src/components/ui/select/index.tsx
  • src/app/[locale]/page.tsx
locales/en/**/*

📄 CodeRabbit inference engine (.cursor/rules/localization.mdc)

Whenever you're adding a new string to the codebase, make sure to add it to a translation file in locales/en.

Files:

  • locales/en/home.json
🧠 Learnings (1)
📚 Learning: 2025-08-06T11:58:32.752Z
Learnt from: CR
Repo: seemorg/usul PR: 0
File: .cursor/rules/localization.mdc:0-0
Timestamp: 2025-08-06T11:58:32.752Z
Learning: Applies to **/*.tsx : If you're using a translation key in the codebase, use the `useTranslations` hook from `next-intl` as shown: `import { useTranslations } from "next-intl"; const t = useTranslations(); t("common.delete");`

Applied to files:

  • src/components/genres-tree-chart/client.tsx
🧬 Code graph analysis (6)
src/lib/api/genres.ts (3)
src/lib/locale/utils.ts (1)
  • PathLocale (13-13)
src/lib/api/utils.ts (1)
  • apiFetch (37-69)
src/types/api/genre.ts (1)
  • ApiGenreCollection (11-14)
src/hooks/use-global-chat.ts (1)
src/stores/chat-filters.ts (1)
  • useChatFilters (26-79)
src/app/api/og/genre/[slug]/route.tsx (2)
src/lib/api/genres.ts (1)
  • getAdvancedGenre (7-14)
src/lib/api/advanced-genres.ts (1)
  • getAdvancedGenre (7-14)
src/app/[locale]/(entityPages)/genre/[genreSlug]/page.tsx (2)
src/lib/api/genres.ts (1)
  • getAdvancedGenre (7-14)
src/lib/api/advanced-genres.ts (1)
  • getAdvancedGenre (7-14)
src/components/genres-tree-chart/client.tsx (1)
src/types/genre.ts (1)
  • GenreNode (13-20)
src/app/[locale]/page.tsx (2)
src/lib/api/genres.ts (1)
  • getHomepageAdvancedGenres (16-23)
src/lib/urls.ts (1)
  • navigation (4-61)
🔇 Additional comments (44)
locales/ha/home.json (1)

6-8: Valid JSON structure with consistent key naming across all language files.

The additions follow the established kebab-case convention and maintain proper JSON syntax. The structural change from a single collections key to three granular collection types (genres, special-collections, individual-collections) has been consistently applied across all 14 language files.

Verification confirms that all 14 language translations (ar, bn, en, es, fa, fr, ha, hi, ms, ps, ru, so, tr, ur) include the same three new keys with appropriate semantic alignment. Note: the PR summary mentions 12 languages, but the repository actually contains 14 language files, all of which have been updated consistently.

src/components/cloudflare-image.tsx (1)

22-24: LGTM! Hydration warning suppression applied.

The addition of suppressHydrationWarning is consistent with the broader pattern in this PR to address SSR/hydration mismatches. This is a valid React 19 feature for cases where hydration differences are expected and acceptable (e.g., timestamps, client-specific content).

locales/ms/common.json (1)

245-247: LGTM! Localization keys added correctly.

The new expand-all and collapse-all keys are properly structured and translated for the Malay locale, consistent with the pattern across other locale files in this PR.

src/components/navbar/profile-dropdown.tsx (1)

74-79: LGTM! Hydration warning suppression applied to dropdown trigger.

The addition of suppressHydrationWarning to the dropdown trigger Button is consistent with the broader pattern in this PR for addressing SSR/hydration mismatches in interactive UI components.

locales/bn/common.json (1)

245-247: LGTM! Localization keys added correctly.

The new expand-all and collapse-all keys are properly structured and translated for the Bengali locale, consistent with the pattern across other locale files in this PR.

locales/so/home.json (1)

6-8: LGTM! Sections refactored to support new genre structure.

The replacement of the collections key with three more specific keys (genres, special-collections, individual-collections) aligns with the broader genre-centric refactoring described in the PR summary. The Somali translations are properly structured.

locales/ur/common.json (1)

245-247: LGTM! Localization keys added correctly.

The new expand-all and collapse-all keys are properly structured and translated for the Urdu locale, consistent with the pattern across other locale files in this PR.

src/hooks/use-global-chat.ts (2)

99-101: Variable renamed to align with advanced genres refactoring.

The renaming from genreIds to advancedGenreIds is consistent with the broader genre refactoring mentioned in the PR summary.


102-109: Ensure backend API endpoint has been updated to accept advancedGenreIds.

The frontend correctly sends advancedGenreIds in the request body to /chat/multi. However, backend compatibility cannot be verified from this frontend-only repository. Coordinate with the backend team to confirm the external API service accepts this field name.

locales/ps/common.json (1)

246-247: Locale addition looks good.

The new "expand-all" and "collapse-all" keys follow the consistent pattern across other locales and are properly formatted with valid JSON syntax.

locales/ha/common.json (1)

246-247: Locale addition looks good.

The new "expand-all" and "collapse-all" keys are properly formatted with correct Hausa translations and valid JSON syntax.

locales/ps/home.json (1)

6-8: Verify UI components have been updated for section restructuring.

The "collections" key has been split into three granular keys ("genres", "special-collections", "individual-collections"), which represents a structural change. Please verify that all components referencing the old "collections" key in the home section have been updated to use the appropriate new keys.

locales/fa/common.json (1)

246-247: Locale addition looks good, but verify existing control characters.

The new "expand-all" and "collapse-all" keys are properly formatted. However, the file contains suspicious escape sequences at lines 88 and 130 (\u0006 and \f), which appear to be unintended control characters. These should be verified and corrected before merge.

locales/hi/common.json (1)

246-247: Locale addition looks good.

The new "expand-all" and "collapse-all" keys are properly formatted with correct Hindi translations and valid JSON syntax.

locales/fr/common.json (1)

246-247: Locale addition looks good.

The new "expand-all" and "collapse-all" keys are properly formatted with correct French translations and valid JSON syntax.

locales/so/common.json (1)

246-247: Locale addition looks good.

The new "expand-all" and "collapse-all" keys are properly formatted with correct Somali translations and valid JSON syntax.

locales/es/common.json (1)

246-247: Locale addition looks good.

The new "expand-all" and "collapse-all" keys are properly formatted with correct Spanish translations and valid JSON syntax.

locales/bn/home.json (1)

5-8: Bengali sections now aligned with new genres/collections structure

Keys genres, special-collections, and individual-collections look consistent with the English source and maintain the existing JSON structure. No issues from an i18n/structure perspective.

locales/tr/common.json (1)

245-247: Turkish expand/collapse strings look good; ensure base English keys exist

"expand-all": "Tümünü genişlet" and "collapse-all": "Tümünü daralt" are clear and placed correctly. Just double‑check that the same keys exist in locales/en/common.json so English remains the canonical source, per the i18n guideline for new strings.

locales/ru/common.json (1)

245-247: Russian expand/collapse translations are clear and well‑placed

"Развернуть все" / "Свернуть все" match the intended UI behavior and the JSON object remains valid. No further changes needed here.

locales/en/home.json (1)

5-8: Base English home sections updated correctly for genres

Replacing the old sections.collections with sections.genres: "Featured Genres" keeps the structure consistent with other locales and with the new genre‑focused UI. No structural or wording issues from this change.

src/components/ui/select/index.tsx (1)

10-11: Targeted hydration warnings suppression for Radix Select looks reasonable

Adding suppressHydrationWarning to SelectPrimitive.Trigger and SelectPrimitive.Content should help mask known SSR/client mismatches around the Radix portal without changing Select behavior, and the icon fallback refactor is a no‑op logically. Assuming this was driven by concrete hydration warnings, the changes look good.

Also applies to: 33-41, 44-51, 93-120

locales/tr/home.json (1)

5-8: Turkish home sections updated to new genres/collections split

The new genres, special-collections, and individual-collections keys mirror the English structure and the wording is appropriate for the UI. No issues spotted.

locales/hi/home.json (1)

5-8: Hindi home sections follow the new genres/collections pattern

The added genres, special-collections, and individual-collections entries match the new homepage sections schema and keep the JSON well‑formed. Looks good.

locales/es/home.json (1)

5-8: Spanish home sections correctly split into genres and collections

"Géneros Destacados", "Colecciones especiales", and "Colecciones individuales" align with the updated sections model and fit naturally in the existing copy. No changes requested.

locales/ur/home.json (1)

6-8: LGTM! Translation keys are well-structured.

The expansion from a single "collections" key to three distinct section keys (genres, special-collections, individual-collections) aligns with the broader refactoring visible across all locale files in this PR.

src/lib/api/genres.ts (1)

16-23: LGTM! New API function follows established patterns.

The getHomepageAdvancedGenres function correctly mirrors the existing getHomepageGenres implementation, uses the cache wrapper, and has proper typing.

src/components/ui/command/index.tsx (1)

20-20: Verify hydration warnings before suppressing them.

Three suppressHydrationWarning props have been added to Command components. This is part of a broader pattern across the PR affecting multiple UI components. Ensure these address actual, documented hydration mismatches rather than masking underlying problems.

Consider documenting why these components experience hydration mismatches in a comment or ADR.

Also applies to: 61-61, 73-73

src/components/ui/navigation-menu.tsx (2)

21-21: Verify hydration warnings before suppressing them.

Similar to other UI components in this PR, suppressHydrationWarning has been added to navigation menu primitives. Ensure these address actual, documented hydration mismatches.

Also applies to: 62-62


12-12: LGTM! Active state management looks good.

The active state tracking and conditional viewport translation based on menu position is well-implemented.

Also applies to: 25-31

src/components/navbar/locale-switcher.tsx (1)

28-32: Remove suppressHydrationWarning unless a confirmed hydration mismatch has been verified.

The locale name displayed by getLocaleFullName(selectedLocale) should be deterministic based on useLocale(), which returns the same value on server and client (derived from the URL segment [locale]). Other components in the codebase use useLocale() without suppressing hydration warnings—for example, src/components/footer/index.tsx and src/app/[locale]/t/[bookId]/_components/coming-soon-alert.tsx apply useLocale() values to attributes like dir without the suppression flag.

If there is a genuine hydration mismatch, add a comment explaining why and what the actual mismatch is. If no mismatch exists, remove the suppression.

src/app/[locale]/(entityPages)/author/[authorSlug]/page.tsx (1)

86-97: Advanced genres filter wiring looks consistent; just confirm backend expects advancedGenres

Mapping genres from searchParams into filters.advancedGenres aligns with the rest of the advanced genres refactor and keeps GenresFilter in sync via currentGenres={genres}. Please just confirm that searchBooks and the underlying search API now read advancedGenres rather than the old genres field so filters are actually applied.

locales/ms/home.json (1)

5-8: New section keys align with the updated homepage structure

The added genres, special-collections, and individual-collections keys match the new homepage sections used in code and keep the JSON structure consistent. No issues from an i18n/structure standpoint.

locales/ar/common.json (1)

245-247: Expand/collapse labels are correctly added and named

The new expand-all / collapse-all keys match the expected UI control names and integrate cleanly at the root of common.json without affecting existing structure.

locales/ar/home.json (1)

5-8: Sections JSON matches the new genres-based homepage layout

Switching from a single collections label to genres, special-collections, and individual-collections mirrors the new UI structure and keeps Arabic home translations in sync with code and other locales.

src/app/[locale]/page.tsx (1)

133-147: Homepage genres now correctly use the advanced genres API and genres navigation

Using getHomepageAdvancedGenres({ locale: pathLocale }) and wiring the section through title={t("home.sections.genres")}, href={navigation.genres.all()}, and href={navigation.genres.bySlug(genre.slug)} keeps the homepage fully aligned with the new advanced genres flow and URL contract. The (genres || []).map(...) pattern safely handles missing data as well.

Also applies to: 185-203

src/lib/urls.ts (1)

28-34: Simplified genres.bySlug is verified—all call sites use the new signature

The updated navigation.genres.bySlug(genreSlug) implementation returning /genre/${genreSlug} is correct. All 10 call sites across the codebase (global-search.ts, genre-search-result.tsx, book-search-result/info-dialog.tsx, genres-tree-chart/client.tsx, sitemap route, homepage, book-info, search results, and genre page) correctly pass only the slug parameter with no options object or fromHomepage parameter. The simplification is complete and consistent.

src/app/[locale]/(entityPages)/genre/[genreSlug]/page.tsx (1)

30-34: LGTM! Clean simplification to single API call.

The refactor consolidates genre fetching to use getAdvancedGenre consistently, removing the previous conditional logic and fallback patterns. The filters now correctly use advancedGenres: [genre.id].

Also applies to: 55-59, 71-71

src/components/genres-filter/client.tsx (2)

361-370: LGTM! Display logic correctly uses primaryName.

The rendering now properly accesses genre.primaryName which aligns with the imported GenreNode type definition.


3-3: Type import and interface update look correct.

The GenreNode type import and its usage in GenresFilterProps.hierarchy properly centralizes the type definition.

Also applies to: 16-19

src/components/genres-tree-chart/client.tsx (3)

15-17: LGTM! Strong typing improvement.

Replacing any[] with GenreNode[] improves type safety. The root node structure correctly uses primaryName to match the GenreNode type.

Also applies to: 82-86


353-368: LGTM! Multi-line label rendering correctly implemented.

The data-label uses double newlines (\n\n) for visual separation in the wrapped output, while the initial text uses single newlines. The wrapText function properly handles both cases.


159-161: Box dimensions and font sizing adjustments look reasonable.

The increased boxHeight (100) and adjusted padding accommodate the new multi-line primary/secondary name display. The minimum font size of 6px is small but acceptable as a fallback for long names.

Also applies to: 376-378

src/app/api/og/genre/[slug]/route.tsx (1)

5-5: LGTM! Simplified to single API call.

The refactor cleanly removes conditional logic, using getAdvancedGenre as the single source. The unused _request parameter is correctly prefixed with underscore. The genre.name property at line 50 is valid—ApiGenre is explicitly typed with a name: string field.

"lucide-react": "^0.503.0",
"nanoid": "^5.0.9",
"next": "16.0.1",
"next": "16.0.7",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

npm view [email protected] version 2>&1 || npm view next versions --json | jq '.[] | select(startswith("16.0"))'

Repository: seemorg/usul

Length of output: 62


🌐 Web query:

Next.js 16.0.7 release stable version

💡 Result:

Yes — Next.js 16.0.7 is a stable security patch released on December 3, 2025 (it fixes CVE-2025-66478). Upgrade to [email protected] as recommended. [1][2][3]

Sources:
[1] Next.js security advisory (CVE-2025-66478) — nextjs.org/blog/CVE-2025-66478.
[2] Next.js GitHub security issue/discussion confirming patched versions.
[3] Release/patch listings (endoflife.date / third‑party advisories noting 16.0.7).


🌐 Web query:

Next.js version 16 release date breaking changes

💡 Result:

Release date

  • Next.js 16 was released October 21, 2025. [1]

Key breaking changes (most important)

  • Async Request APIs: synchronous access removed — cookies(), headers(), draftMode(), params and searchParams are now async (must be awaited / used in async components). [2][1]
  • Node / TypeScript minimums: Node.js >= 20.9.0 and TypeScript >= 5.x required. [1][2]
  • middleware.ts → proxy.ts: edge middleware renamed to clarify network boundary. [1][2]
  • Cache/Rendering model changes: new Cache Components / "use cache" and default dynamic-at-request-time behavior that changes caching semantics (may require opt-in / migration). [1][3]
  • Removed/deprecated features: AMP support removed; some legacy imports/APIs (legacy image import, publicRuntimeConfig/serverRuntimeConfig, etc.) removed. [1][5]
  • CLI/config changes: next lint removed as a built-in command; flat config defaults and other config/CLI changes. [6][1]
  • API changes: revalidateTag() signature updated (now requires cacheLife profile for SWR behavior) and other stabilized APIs removed "unstable_" prefixes. [2][1]

Migration help

  • Official upgrade guide and automated codemod: npx @next/codemod@canary upgrade latest; see the Next.js upgrade docs for step-by-step changes and typegen helpers. [2][1]

Sources

  1. Next.js blog — “Next.js 16” (Oct 21, 2025). [1]
  2. Next.js docs — “Upgrading: Version 16” (upgrade guide / breaking changes). [2]
  3. InfoQ summary of Next.js 16 release. [3]

Update Next.js to 16.0.7 requires addressing breaking changes.

Next.js 16.0.7 is a stable security patch (released December 3, 2025, fixing CVE-2025-66478). However, the upgrade from Next.js 15.x introduces major breaking changes that require code migration:

  • Request APIs (cookies(), headers(), draftMode(), params, searchParams) are now async and must be awaited
  • Requires Node.js >= 20.9.0 and TypeScript >= 5.x
  • middleware.ts renamed to proxy.ts
  • Cache/rendering model changes with "use cache" directive
  • Various legacy APIs removed (AMP support, publicRuntimeConfig/serverRuntimeConfig, etc.)
  • revalidateTag() signature updated

Verify the codebase handles these changes. Use npx @next/codemod@canary upgrade latest to assist with migration, and review the official Next.js upgrade guide for step-by-step migration details.

🤖 Prompt for AI Agents
In package.json around line 55 (the Next.js version bump to "next": "16.0.7"),
update the repo to be compatible with Next.js 16 by: bumping engines to Node
>=20.9.0 and TypeScript >=5.x in package.json; running npx @next/codemod@canary
upgrade latest to auto-apply migration transforms; search and update all uses of
request APIs (cookies(), headers(), draftMode(), params, searchParams) to await
the async versions; rename any middleware.ts to proxy.ts and adjust
imports/exports; audit rendering/cache directives and add "use cache" or other
new directives where needed; update calls to revalidateTag() to the new
signature; remove or replace deprecated legacy APIs (AMP,
publicRuntimeConfig/serverRuntimeConfig, etc.); then reinstall deps, run
typechecks and full test suite, and fix any remaining type or runtime errors
reported.

Comment on lines +9 to +13
const DropdownMenuTrigger = ({
...props
}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) => (
<DropdownMenuPrimitive.Trigger suppressHydrationWarning {...props} />
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n src/components/ui/dropdown-menu/index.tsx

Repository: seemorg/usul

Length of output: 7473


🏁 Script executed:

rg "DropdownMenuTrigger" -A 3 -B 1 --type tsx --type ts

Repository: seemorg/usul

Length of output: 83


🏁 Script executed:

rg "DropdownMenuTrigger" -A 3 -B 1 --type typescript

Repository: seemorg/usul

Length of output: 90


🏁 Script executed:

rg "DropdownMenuTrigger" -A 3 -B 1

Repository: seemorg/usul

Length of output: 10045


🏁 Script executed:

cd src/components/ui/dropdown-menu && git log --oneline -20 index.tsx

Repository: seemorg/usul

Length of output: 105


🏁 Script executed:

git log --all --oneline -- src/components/ui/dropdown-menu/index.tsx | head -20

Repository: seemorg/usul

Length of output: 583


🏁 Script executed:

git show 5c7ce64:src/components/ui/dropdown-menu/index.tsx | head -50

Repository: seemorg/usul

Length of output: 1835


🏁 Script executed:

git show 5c7ce64:src/components/ui/dropdown-menu/index.tsx | grep -A 15 "DropdownMenuContent"

Repository: seemorg/usul

Length of output: 1173


Wrap DropdownMenuTrigger and DropdownMenuContent with forwardRef to preserve ref forwarding

The change from a direct alias (const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;) to a plain function component breaks ref forwarding. While current usages in the codebase use asChild (which bypasses this), converting to a plain function component removes the ability for consumers to pass refs directly to these components, which is a breaking API change.

To maintain backward compatibility and preserve the public API:

-const DropdownMenuTrigger = ({
-  ...props
-}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) => (
-  <DropdownMenuPrimitive.Trigger suppressHydrationWarning {...props} />
-);
+const DropdownMenuTrigger = React.forwardRef<
+  React.ElementRef<typeof DropdownMenuPrimitive.Trigger>,
+  React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Trigger>
+>((props, ref) => (
+  <DropdownMenuPrimitive.Trigger
+    ref={ref}
+    suppressHydrationWarning
+    {...props}
+  />
+));
+
+DropdownMenuTrigger.displayName =
+  DropdownMenuPrimitive.Trigger.displayName ?? "DropdownMenuTrigger";

Apply the same pattern to DropdownMenuContent (lines 57–74) to ensure consistent ref forwarding behavior across all exported components.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const DropdownMenuTrigger = ({
...props
}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) => (
<DropdownMenuPrimitive.Trigger suppressHydrationWarning {...props} />
);
const DropdownMenuTrigger = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Trigger>
>((props, ref) => (
<DropdownMenuPrimitive.Trigger
ref={ref}
suppressHydrationWarning
{...props}
/>
));
DropdownMenuTrigger.displayName =
DropdownMenuPrimitive.Trigger.displayName ?? "DropdownMenuTrigger";

"relative z-10 flex max-w-max flex-1 items-center justify-center",
className,
)}
onValueChange={(value) => (value ? setActive(Number(value)) : null)}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix the onValueChange handler logic.

The callback returns null instead of calling setActive(null) when the value is falsy. This means the active state won't be cleared when the menu closes.

Apply this diff:

-      onValueChange={(value) => (value ? setActive(Number(value)) : null)}
+      onValueChange={(value) => setActive(value ? Number(value) : null)}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onValueChange={(value) => (value ? setActive(Number(value)) : null)}
onValueChange={(value) => setActive(value ? Number(value) : null)}
🤖 Prompt for AI Agents
In src/components/ui/navigation-menu.tsx around line 20, the onValueChange
handler currently returns null when value is falsy, so it never clears the
active state; change the handler to call setActive(null) when value is falsy and
call setActive(Number(value)) when truthy (or parse accordingly) so the active
state is cleared when the menu closes.

Comment on lines +13 to +20
export type GenreNode = {
id: string;
slug: string;
primaryName: string;
secondaryName: string;
numberOfBooks: number;
children?: GenreNode[];
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Relax secondaryName and consider aligning count field naming

GenreNode.secondaryName is required here, whereas GenreDocument.secondaryName is optional. Unless the advanced genres API truly guarantees a secondary name for every node, this will either force callers to manufacture placeholder strings or fight the existing data model.

Also, GenreDocument uses booksCount while GenreNode uses numberOfBooks. The semantic difference may be intentional (e.g., total vs. direct children), but if they refer to the same concept it’s worth unifying to avoid confusion when mapping between the two.

Suggested minimal change:

-export type GenreNode = {
-  id: string;
-  slug: string;
-  primaryName: string;
-  secondaryName: string;
-  numberOfBooks: number;
-  children?: GenreNode[];
-};
+export type GenreNode = {
+  id: string;
+  slug: string;
+  primaryName: string;
+  secondaryName?: string;
+  numberOfBooks: number;
+  children?: GenreNode[];
+};
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export type GenreNode = {
id: string;
slug: string;
primaryName: string;
secondaryName: string;
numberOfBooks: number;
children?: GenreNode[];
};
export type GenreNode = {
id: string;
slug: string;
primaryName: string;
secondaryName?: string;
numberOfBooks: number;
children?: GenreNode[];
};
🤖 Prompt for AI Agents
In src/types/genre.ts around lines 13 to 20, make GenreNode.secondaryName
optional to match GenreDocument and rename numberOfBooks to booksCount (and keep
its type) so the two types align; update the children type accordingly
(children?: GenreNode[]) and ensure any call sites mapping between GenreDocument
and GenreNode use booksCount consistently.

@AnasMations AnasMations merged commit 9b445e5 into dev Dec 9, 2025
10 of 11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants