fix: allow access to app even if first sync fails#29
Conversation
📝 WalkthroughWalkthroughThis PR refactors the codebase to externalize core utilities into workspace packages ( Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
Deploying bahar with
|
| Latest commit: |
f087007
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://d436d7bf.bahar-5xu.pages.dev |
| Branch Preview URL: | https://feat-improve-scheduling-opti.bahar-5xu.pages.dev |
26cd618 to
1342caf
Compare
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
bahar-marketing | f087007 | Commit Preview URL | Dec 27 2025, 07:01 AM |
67faeb6 to
39ec453
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (6)
apps/web/src/lib/search/index.ts (2)
33-33: Consider using the exportedBATCH_SIZEconstant.The
BATCH_SIZEis hardcoded as100in bothhydrateOramaDbandrehydrateOramaDb. However,@bahar/db-operationsexports aBATCH_SIZEconstant set to500. Consider importing and using this constant for consistency across the codebase, or document why a different batch size is needed for Orama operations.🔎 Proposed fix
+import { safeJsonParse, BATCH_SIZE } from "@bahar/db-operations"; -import { safeJsonParse } from "@bahar/db-operations"; export const hydrateOramaDb = async () => { if (isOramaHydrated) return ok({ skippedCount: 0 }); - const BATCH_SIZE = 100; const db = await ensureDb();And similarly for
rehydrateOramaDb:export const rehydrateOramaDb = async () => { - const BATCH_SIZE = 100; const db = await ensureDb();Also applies to: 179-179
139-143: Remove unnecessary type casts.The type casts
oramaDb as DictionaryOramaandnewOramaDb as DictionaryOramaare unnecessary. SincecreateDictionaryDatabase()returnsDictionaryOrama, TypeScript should correctly infer the type. If the cast is needed due to a type mismatch, consider adding an explicit type annotation to the variable declaration instead.🔎 Proposed fix
For
hydrateOramaDb:if (dictionaryEntries.length > 0) { await insertDocuments( - oramaDb as DictionaryOrama, + oramaDb, dictionaryEntries, BATCH_SIZE, );For
rehydrateOramaDb:if (dictionaryEntries.length > 0) { await insertDocuments( - newOramaDb as DictionaryOrama, + newOramaDb, dictionaryEntries, BATCH_SIZE, );If type errors occur, add explicit type annotations:
-let oramaDb = createDictionaryDatabase(); +let oramaDb: DictionaryOrama = createDictionaryDatabase();Also applies to: 218-222
apps/web/src/components/errors/ErrorMessage.tsx (1)
117-124: Good defensive rendering improvement.Adding the
error.causeguard prevents displaying an empty "Cause:" field when no cause exists. The fragment wrapper on lines 118-123 is unnecessary for a single child but doesn't impact functionality.🔎 Optional: Remove unnecessary fragment
{isDisplayError && error.cause && ( - <> - <ErrorDetailField - fieldName={<Trans>Cause:</Trans>} - detail={error.cause} - /> - </> + <ErrorDetailField + fieldName={<Trans>Cause:</Trans>} + detail={error.cause} + /> )}apps/web/src/lib/date/index.ts (1)
142-146: Side-effect assignment inside condition reduces readability.The assignment
value = differenceInCalendarDays(laterDate, earlierDate)inside the condition is a code smell that makes the logic harder to follow.🔎 Suggested refactor
- } else if ( - Math.abs(diffInSeconds) < SECONDS_IN_WEEK && - (value = differenceInCalendarDays(laterDate, earlierDate)) && - Math.abs(value) < 7 - ) { - unit = "day"; + } else if (Math.abs(diffInSeconds) < SECONDS_IN_WEEK) { + value = differenceInCalendarDays(laterDate, earlierDate); + if (Math.abs(value) < 7) { + unit = "day"; + } else { + value = differenceInCalendarWeeks(laterDate, earlierDate); + unit = "week"; + }apps/web/src/components/features/flashcards/FlashcardDrawer/utils.ts (1)
60-66: Consider explicit initialization instead of type assertion.The empty object with
as Record<...>could lead to runtime issues ifgradesarray is ever modified. A safer approach:🔎 Suggested refactor
- const results: Record< - ReviewRating, - { label: string; unit: IntlFormatDistanceUnit } - > = {} as Record< - ReviewRating, - { label: string; unit: IntlFormatDistanceUnit } - >; + const results = new Map<ReviewRating, { label: string; unit: IntlFormatDistanceUnit }>(); for (const grade of grades) { - results[grade] = formatInterval({ due: dates[grade], now, locale }); + results.set(grade, formatInterval({ due: dates[grade], now, locale })); }Or initialize with all keys upfront if preferring object syntax.
apps/web/src/lib/date/constants.ts (1)
112-127: Minor inconsistency in MINUTES_IN_ constants.*
MINUTES_IN_YEAR(525600) assumes exactly 365 days, andMINUTES_IN_MONTH(43200) assumes exactly 30 days. This differs fromSECONDS_IN_YEARandSECONDS_IN_MONTHwhich useDAYS_IN_YEAR = 365.2425for precision.This is likely intentional for simplicity, but worth documenting if these constants are used interchangeably with the more precise SECONDS_IN_* variants.
🔎 Optional: derive from DAYS_IN_YEAR for consistency
-export const MINUTES_IN_YEAR = 525600; +export const MINUTES_IN_YEAR = DAYS_IN_YEAR * 24 * 60; // ~525949.8 -export const MINUTES_IN_MONTH = 43200; +export const MINUTES_IN_MONTH = MINUTES_IN_YEAR / 12; // ~43829.15
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (21)
apps/web/package.jsonapps/web/src/components/errors/ErrorMessage.tsxapps/web/src/components/features/flashcards/FlashcardDrawer/FlashcardDrawer.tsxapps/web/src/components/features/flashcards/FlashcardDrawer/GradeOption.tsxapps/web/src/components/features/flashcards/FlashcardDrawer/utils.tsapps/web/src/components/search/Highlight.tsxapps/web/src/lib/date/constants.tsapps/web/src/lib/date/index.tsapps/web/src/lib/db/export/index.tsapps/web/src/lib/db/index.tsapps/web/src/lib/db/operations/dictionary-entries.tsapps/web/src/lib/db/operations/flashcards.tsapps/web/src/lib/db/utils.tsapps/web/src/lib/fetch.tsapps/web/src/lib/result.tsapps/web/src/lib/search/index.tsapps/web/src/lib/search/orama-tokenizer.tsapps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsxapps/web/src/routes/_authorized-layout/route.tsxpackages/db-operations/package.jsonpackages/db-operations/src/utils.ts
💤 Files with no reviewable changes (5)
- apps/web/src/lib/fetch.ts
- packages/db-operations/src/utils.ts
- apps/web/src/lib/result.ts
- apps/web/src/lib/search/orama-tokenizer.ts
- apps/web/src/lib/db/utils.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Use TypeScript with strict typing across entire codebase; do not useanytype unless absolutely necessary
UseDisplayErrorclass for user-friendly error messages andResult<T, E>type for explicit error handling with Rust-like pattern
Use Drizzle ORM for database operations across all database interactions
Files:
apps/web/src/components/search/Highlight.tsxapps/web/src/components/features/flashcards/FlashcardDrawer/GradeOption.tsxapps/web/src/lib/date/index.tsapps/web/src/lib/db/index.tsapps/web/src/components/errors/ErrorMessage.tsxapps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsxapps/web/src/lib/db/export/index.tsapps/web/src/lib/date/constants.tsapps/web/src/lib/db/operations/dictionary-entries.tsapps/web/src/components/features/flashcards/FlashcardDrawer/FlashcardDrawer.tsxapps/web/src/lib/db/operations/flashcards.tsapps/web/src/components/features/flashcards/FlashcardDrawer/utils.tsapps/web/src/routes/_authorized-layout/route.tsxapps/web/src/lib/search/index.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx,js,jsx}: Write self-documenting code and avoid overuse of comments
Error handling with try/catch blocks and structured error types
Component naming: use PascalCase for components, camelCase for functions/variables
Files:
apps/web/src/components/search/Highlight.tsxapps/web/src/components/features/flashcards/FlashcardDrawer/GradeOption.tsxapps/web/src/lib/date/index.tsapps/web/src/lib/db/index.tsapps/web/src/components/errors/ErrorMessage.tsxapps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsxapps/web/src/lib/db/export/index.tsapps/web/src/lib/date/constants.tsapps/web/src/lib/db/operations/dictionary-entries.tsapps/web/src/components/features/flashcards/FlashcardDrawer/FlashcardDrawer.tsxapps/web/src/lib/db/operations/flashcards.tsapps/web/src/components/features/flashcards/FlashcardDrawer/utils.tsapps/web/src/routes/_authorized-layout/route.tsxapps/web/src/lib/search/index.ts
**/*.{tsx,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{tsx,jsx}: React components use functional style with hooks
Prefer using Jotai atoms over React Context
State management: use Tanstack Query for async state and Jotai for atomic state
Files:
apps/web/src/components/search/Highlight.tsxapps/web/src/components/features/flashcards/FlashcardDrawer/GradeOption.tsxapps/web/src/components/errors/ErrorMessage.tsxapps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsxapps/web/src/components/features/flashcards/FlashcardDrawer/FlashcardDrawer.tsxapps/web/src/routes/_authorized-layout/route.tsx
apps/web/**/*.{tsx,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/web/**/*.{tsx,jsx}: Web app uses Shadcn/UI components and Tailwind CSS v4 for styling; use thecn()utility function for combining and conditionally applying Tailwind classes
Web app uses Tanstack Router for client-side routing
Files:
apps/web/src/components/search/Highlight.tsxapps/web/src/components/features/flashcards/FlashcardDrawer/GradeOption.tsxapps/web/src/components/errors/ErrorMessage.tsxapps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsxapps/web/src/components/features/flashcards/FlashcardDrawer/FlashcardDrawer.tsxapps/web/src/routes/_authorized-layout/route.tsx
🧠 Learnings (16)
📚 Learning: 2025-11-27T23:01:26.752Z
Learnt from: Shunseii
Repo: Shunseii/bahar PR: 24
File: packages/drizzle-user-db-schemas/package.json:1-20
Timestamp: 2025-11-27T23:01:26.752Z
Learning: drizzle-zod0.5.1 has peer dependencies of "zod": "*" (accepts any version) and "drizzle-orm": ">=0.23.13". The zod wildcard peer dependency means any zod version is compatible with drizzle-zod0.5.1.
Applied to files:
packages/db-operations/package.json
📚 Learning: 2025-12-27T05:56:33.043Z
Learnt from: CR
Repo: Shunseii/bahar PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-27T05:56:33.043Z
Learning: Applies to **/*.{tsx,jsx} : Prefer using Jotai atoms over React Context
Applied to files:
apps/web/src/components/search/Highlight.tsx
📚 Learning: 2025-12-27T05:56:33.043Z
Learnt from: CR
Repo: Shunseii/bahar PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-27T05:56:33.043Z
Learning: Applies to **/*.{tsx,jsx} : State management: use Tanstack Query for async state and Jotai for atomic state
Applied to files:
apps/web/src/components/search/Highlight.tsx
📚 Learning: 2025-11-27T06:02:25.941Z
Learnt from: Shunseii
Repo: Shunseii/bahar PR: 24
File: apps/web/src/components/features/decks/DeckDialogContent.tsx:195-201
Timestamp: 2025-11-27T06:02:25.941Z
Learning: In apps/web/src/components/features/decks/DeckDialogContent.tsx, the backend API calls (trpc.decks.create and trpc.decks.update) are temporary and planned to be removed after migration is complete.
Applied to files:
apps/web/src/components/features/flashcards/FlashcardDrawer/GradeOption.tsxapps/web/src/components/features/flashcards/FlashcardDrawer/FlashcardDrawer.tsxapps/web/src/lib/db/operations/flashcards.tsapps/web/src/routes/_authorized-layout/route.tsx
📚 Learning: 2025-12-27T05:56:33.043Z
Learnt from: CR
Repo: Shunseii/bahar PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-27T05:56:33.043Z
Learning: Applies to **/*.{tsx,jsx} : React components use functional style with hooks
Applied to files:
apps/web/src/components/features/flashcards/FlashcardDrawer/GradeOption.tsxapps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsxapps/web/src/components/features/flashcards/FlashcardDrawer/FlashcardDrawer.tsx
📚 Learning: 2025-12-25T22:07:07.504Z
Learnt from: Shunseii
Repo: Shunseii/bahar PR: 27
File: apps/api/src/db/schema/auth.ts:34-36
Timestamp: 2025-12-25T22:07:07.504Z
Learning: Files in apps/api/src/db/schema/auth.ts are auto-generated by better-auth and should not be manually modified as changes will be overwritten. Any schema issues should be tested and reported upstream to better-auth.
Applied to files:
apps/web/src/lib/db/index.tsapps/web/src/routes/_authorized-layout/route.tsx
📚 Learning: 2025-12-27T05:56:33.044Z
Learnt from: CR
Repo: Shunseii/bahar PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-27T05:56:33.044Z
Learning: Applies to **/*.{ts,tsx} : Use Drizzle ORM for database operations across all database interactions
Applied to files:
apps/web/src/lib/db/index.tsapps/web/src/lib/search/index.ts
📚 Learning: 2025-12-27T05:56:33.044Z
Learnt from: CR
Repo: Shunseii/bahar PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-27T05:56:33.044Z
Learning: Applies to **/*.{ts,tsx} : Use `DisplayError` class for user-friendly error messages and `Result<T, E>` type for explicit error handling with Rust-like pattern
Applied to files:
apps/web/src/components/errors/ErrorMessage.tsx
📚 Learning: 2025-12-27T05:56:33.044Z
Learnt from: CR
Repo: Shunseii/bahar PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-27T05:56:33.044Z
Learning: Applies to apps/web/**/*.{tsx,jsx} : Web app uses Tanstack Router for client-side routing
Applied to files:
apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsxapps/web/src/routes/_authorized-layout/route.tsx
📚 Learning: 2025-12-27T05:56:33.043Z
Learnt from: CR
Repo: Shunseii/bahar PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-27T05:56:33.043Z
Learning: Applies to apps/web/**/*.{tsx,jsx} : Web app uses Shadcn/UI components and Tailwind CSS v4 for styling; use the `cn()` utility function for combining and conditionally applying Tailwind classes
Applied to files:
apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx
📚 Learning: 2025-12-27T05:56:33.043Z
Learnt from: CR
Repo: Shunseii/bahar PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-27T05:56:33.043Z
Learning: Applies to apps/mobile/**/*.{tsx,jsx} : Mobile app uses UniWind (Tailwind for React Native) with Tailwind CSS v4
Applied to files:
apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx
📚 Learning: 2025-12-27T05:56:33.043Z
Learnt from: CR
Repo: Shunseii/bahar PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-27T05:56:33.043Z
Learning: Applies to apps/mobile/**/*.{tsx,jsx} : Mobile app uses Expo with file-based routing (Expo Router)
Applied to files:
apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx
📚 Learning: 2025-12-27T05:56:33.044Z
Learnt from: CR
Repo: Shunseii/bahar PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-27T05:56:33.044Z
Learning: Orama search engine is client-side WASM with multi-language support (Arabic and English), indexed from local database on app initialization, featuring stemming, stopwords, and quantized positional search (QPS)
Applied to files:
apps/web/src/lib/search/index.ts
📚 Learning: 2025-11-27T06:51:53.688Z
Learnt from: Shunseii
Repo: Shunseii/bahar PR: 24
File: apps/web/src/lib/search/orama-tokenizer.ts:31-31
Timestamp: 2025-11-27T06:51:53.688Z
Learning: In Orama (search library), custom tokenizers must include a `normalizationCache: Map<string, string>` property as part of the required tokenizer interface, even if not explicitly used in the tokenize method implementation. This is part of Orama's documented API contract for custom tokenizers.
Applied to files:
apps/web/src/lib/search/index.ts
📚 Learning: 2025-11-27T06:48:31.996Z
Learnt from: Shunseii
Repo: Shunseii/bahar PR: 24
File: apps/web/src/hooks/db/index.ts:59-60
Timestamp: 2025-11-27T06:48:31.996Z
Learning: In the Bahar project, Orama methods (insert, update, remove, search) are synchronous by default since no async plugins are being used. Orama v3.0.0+ core methods are sync; they only become async when specific plugins like plugin-embeddings are added. Do not suggest awaiting Orama operations unless async plugins are confirmed to be in use.
Applied to files:
apps/web/src/lib/search/index.ts
📚 Learning: 2025-11-27T06:48:57.365Z
Learnt from: Shunseii
Repo: Shunseii/bahar PR: 24
File: apps/web/src/hooks/db/index.ts:84-85
Timestamp: 2025-11-27T06:48:57.365Z
Learning: In the Orama search library, core operations like insert(), remove(), and update() are synchronous by default. They only become asynchronous when specific plugins (e.g., embedding generators) or Orama Cloud features are used. Don't suggest awaiting these operations unless async plugins are confirmed to be in use.
Applied to files:
apps/web/src/lib/search/index.ts
🧬 Code graph analysis (5)
apps/web/src/lib/date/index.ts (1)
apps/web/src/lib/date/constants.ts (7)
SECONDS_IN_MINUTE(168-168)SECONDS_IN_HOUR(161-161)SECONDS_IN_DAY(175-175)SECONDS_IN_WEEK(182-182)SECONDS_IN_MONTH(196-196)SECONDS_IN_QUARTER(203-203)SECONDS_IN_YEAR(189-189)
apps/web/src/components/errors/ErrorMessage.tsx (1)
apps/web/src/lib/error.ts (1)
error(42-44)
apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx (2)
apps/web/src/lib/db/import/index.ts (3)
batchArray(69-73)createImportStatements(11-11)createImportStatements(37-46)apps/web/src/lib/db/import/v1/index.ts (1)
createImportStatements(14-77)
apps/web/src/lib/db/operations/dictionary-entries.ts (2)
packages/db-operations/src/index.ts (1)
convertRawDictionaryEntryToSelect(29-29)packages/db-operations/src/converters.ts (1)
convertRawDictionaryEntryToSelect(55-124)
apps/web/src/lib/search/index.ts (5)
packages/search/src/database.ts (2)
createDictionaryDatabase(41-50)insertDocuments(55-61)packages/search/src/index.ts (3)
createDictionaryDatabase(33-33)insertDocuments(34-34)DictionaryOrama(29-29)packages/db-operations/src/constants.ts (1)
BATCH_SIZE(36-36)apps/mobile/src/lib/search/index.ts (1)
rehydrateOramaDb(57-112)apps/web/src/lib/db/index.ts (1)
ensureDb(33-39)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Cloudflare Pages
- GitHub Check: Workers Builds: bahar-marketing
🔇 Additional comments (16)
apps/web/src/lib/db/operations/flashcards.ts (2)
14-16: LGTM: Import refactoring aligns with workspace package consolidation.The migration from local
../utilsto the workspace package@bahar/db-operationsimproves code organization and reusability. KeepingDICTIONARY_ENTRY_COLUMNSand the conversion function together ensures consistency.
133-159: LGTM: Function call updated correctly.The call to
convertRawDictionaryEntryToSelectmaintains the same usage pattern and error handling logic. TypeScript type checking ensures signature compatibility, and the Result-based error handling with Sentry logging remains intact.apps/web/src/components/search/Highlight.tsx (1)
1-16: LGTM!The import path update to
@bahar/searchaligns with the workspace package externalization. The component correctly uses Jotai for atomic state, memoization for performance, and DOMPurify for XSS protection.apps/web/src/lib/db/index.ts (2)
4-4: LGTM on import update.Import path correctly migrated to the workspace package
@bahar/result.
154-166: The review comment is incorrect. The PR objective is already met by the current code.The
turso_remote_sync_failederror is explicitly handled in the route's beforeLoad (lines 287-289 in_authorized-layout/route.tsx), where it breaks without throwing, allowing the app to continue. The Route does not returnok(null)from_initDbInternalbecause the current design is better: it returns the Result with error details, and callers decide how to handle it. This allows different call sites to handle sync failures differently, while in this case the route handler specifically allows continuation for sync failures to permit offline-first usage with the local database.apps/web/src/lib/db/export/index.ts (1)
6-10: LGTM!Import paths correctly updated to workspace packages, and the function call renamed to match the new
@bahar/db-operationsAPI. Error handling logic remains intact.Also applies to: 25-25
apps/web/src/lib/db/operations/dictionary-entries.ts (2)
8-11: LGTM!Import correctly updated to
@bahar/db-operations.
37-41: LGTM!All four usages of
convertRawDictionaryEntryToSelectare consistently updated to use the new function name from@bahar/db-operations. Error handling pattern remains correct throughout.Also applies to: 132-136, 246-250, 281-285
apps/web/package.json (1)
14-17: LGTM!New workspace dependencies correctly added to support the externalized utilities. The
workspace:*protocol is appropriate for internal packages.apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx (2)
271-273: LGTM!Formatting change only. The spread of the generator into an array is correct for batch processing.
284-285: LGTM!Cosmetic formatting changes that improve readability. No functional impact.
Also applies to: 387-397
packages/db-operations/package.json (1)
19-21: LGTM!The cleanup of dependencies looks appropriate.
nanoidis actively used insrc/utils.tsand keeping it as the only runtime dependency aligns with the package's purpose.apps/web/src/routes/_authorized-layout/route.tsx (1)
296-299: LGTM! Graceful degradation for remote sync failures.The change correctly allows users to continue using the app with the local database when the initial remote sync fails. The error is still captured in Sentry (lines 233-240), ensuring visibility for debugging while not blocking the user experience.
apps/web/src/components/features/flashcards/FlashcardDrawer/GradeOption.tsx (1)
17-28: LGTM! Clean simplification of props interface.Moving the interval formatting logic out of this component improves separation of concerns. The component is now a pure presentation component that receives a pre-computed label string.
apps/web/src/components/features/flashcards/FlashcardDrawer/FlashcardDrawer.tsx (1)
146-162: LGTM! Well-structured interval label computation.The memoization correctly depends on
schedulingCards,now, andlocale. The guard at line 436 ensures grade options only render when labels are available.One consideration: the locale derivation (line 147) is limited to Arabic (
ar-u-nu-arab) for RTL and English (en) otherwise. If additional RTL languages (e.g., Hebrew, Persian) are added in the future, this logic may need to be revisited.apps/web/src/lib/date/constants.ts (1)
1-16: Well-documented constants module.The JSDoc documentation is thorough and follows date-fns conventions. Good use of derived constants (e.g.,
SECONDS_IN_DAY = SECONDS_IN_HOUR * 24) to avoid magic numbers and ensure consistency.
Summary by CodeRabbit
New Features
Bug Fixes
Refactor
✏️ Tip: You can customize this high-level summary in your review settings.