Conversation
|
Caution Review failedThe pull request is closed. WalkthroughAdds snippet-sharing via URL, Toaster notifications (sonner), a tryCatch utility, snippet id in snippet types, server-side snippet-by-ID fetching and TRPC procedure, and client flows to activate a language using a snippet from the URL or a shared link. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related PRs
Pre-merge checks❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (5)
src/features/snippets/infrastructure/repositories/snippet.repository.server.ts (2)
3-19: Consider keeping an explicit return type forfindRandomSnippetsRight now the return type is inferred from the Prisma call. For a core repository method, an explicit return type (e.g. a small
RandomSnippettype with{id, content}) can help prevent accidental contract changes if the Prisma query is modified later.
21-47:findSnippetByIdshape looks good; ensure relations are requiredThe query and returned shape (
{id, content, languageId}) look correct and nicely flattened. Just make sure your Prisma schema guarantees thatfileVersionandfileare always present for any existing snippet; otherwisesnippet.fileVersion.file.languageIdwould throw at runtime if those relations are nullable or missing. If they’re not strictly required, consider a defensive null-check or tightening the schema.src/utils.ts (1)
1-20:tryCatchworks; could be simplified to tuple typesThe helper behaves as intended and is a nice fit for
const [data, error] = await tryCatch(...). If you want to simplify the types, you could model the result as literal tuples instead of array interfaces, e.g.:type Result<T, E = Error> = [T, null] | [null, E]; export async function tryCatch<T, E = Error>(promise: Promise<T>): Promise<Result<T, E>> { try { const data = await promise; return [data, null]; } catch (error) { return [null, error as E]; } }The current version is still perfectly valid, so this is purely a style/clarity tweak.
src/features/game/hooks/useGameSnippets.ts (1)
30-32: First assumption verified; second concern remains valid for robustnessThe TRPC
snippet.byIdrouter explicitly throwsTRPCErrorwhen the snippet doesn't exist, so your first assumption is confirmed—mutateAsyncwill correctly reject andtryCatchhandles it properly.However, the second assumption still warrants attention:
const language = availableLanguages![snippet.languageId];(line 65)
The hook uses a non-null assertion without checking thatavailableLanguagesis loaded. While the current caller (page.tsx) guards this before invokingactivateLanguageWithSnippet, the hook doesn't protect itself. If reused elsewhere without that guard in the future, it could crash. A simple check likeif (!availableLanguages || !availableLanguages[snippet.languageId])would make it self-contained.Error messaging (lines 57–62) treats all mutation errors the same. A network timeout or server error will show "Snippet not found", which may confuse users. Consider distinguishing between retrieval failures and missing snippets if feasible.
src/server/trpc/routers/snippet.ts (1)
34-34: Consider simplifying the variable assignment.The intermediate variable assignment is redundant and could be simplified for better readability.
Apply this diff:
- const snippetId = input.snippetId; - const snippet = await getSnippetById(snippetId); + const snippet = await getSnippetById(input.snippetId);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (10)
package.json(1 hunks)src/app/game/layout.tsx(1 hunks)src/app/game/page.tsx(5 hunks)src/features/game/components/game-view.tsx(2 hunks)src/features/game/hooks/useGameSnippets.ts(4 hunks)src/features/shared/types/snippet.ts(1 hunks)src/features/snippets/infrastructure/repositories/snippet.repository.server.ts(2 hunks)src/features/snippets/services/get-snippets.server.ts(3 hunks)src/server/trpc/routers/snippet.ts(2 hunks)src/utils.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
src/app/game/page.tsx (3)
src/features/game/hooks/useGameSnippets.ts (1)
useGameSnippets(14-112)src/features/shared/types/language.ts (1)
ILanguage(1-6)src/features/game/state/game-store.ts (1)
language(55-70)
src/features/snippets/services/get-snippets.server.ts (2)
src/features/shared/types/snippet.ts (1)
IRawSnippet(5-9)src/features/snippets/infrastructure/repositories/snippet.repository.server.ts (1)
findSnippetById(21-48)
src/features/game/hooks/useGameSnippets.ts (4)
src/features/shared/types/language.ts (1)
ILanguage(1-6)src/utils.ts (1)
tryCatch(13-20)src/features/snippets/services/build-client-snippets.client.ts (1)
buildClientSnippets(4-15)src/features/game/state/game-store.ts (3)
snippets(71-77)newSnippet(102-113)language(55-70)
🔇 Additional comments (7)
package.json (1)
43-43: Sonner dependency addition matches usageAdding
"sonner": "^2.0.7"here is consistent with the newToaster/toastimports in the game layout and hooks; no issues from the package.json side.src/features/shared/types/snippet.ts (1)
5-9: ExtendingIRawSnippetwithidis consistent with new flowsAdding
id: stringtoIRawSnippetmatches the new snippet-by-id and sharing logic. Just ensure all places constructingIRawSnippet(not only the updated services in this PR) now populateidso type checks stay green.src/features/snippets/services/get-snippets.server.ts (1)
3-3: Server snippet getters correctly align with newIRawSnippetshapeIncluding
idingetRandomSnippets’ return objects and introducinggetSnippetById(withlanguageIdand computeddisabledRanges) cleanly align the server layer with the updatedIRawSnippetcontract and the new snippet-by-id flow. Both functions look correct and consistent.Also applies to: 20-23, 38-51
src/app/game/page.tsx (1)
28-30: URL-based snippet activation wiring looks correctUsing
useSearchParamsto readsnippetIdFromUrland the newactivateLanguageWithSnippetEventin the init effect gives you a clean “if snippet param → start from that snippet, else → normal init” flow. The dependency array[availableLanguages, snippetIdFromUrl]also means that if the query param is added or removed client-side, the game re-initializes accordingly. No issues from a correctness standpoint.Also applies to: 44-45, 83-105
src/features/game/components/game-view.tsx (2)
10-10: LGTM!The new imports support the share functionality and toast notifications appropriately.
Also applies to: 12-12
72-95: LGTM!The UI layout restructuring to accommodate both share and settings buttons is well-implemented. The grid layout approach properly centers content while allowing for the button cluster, and the disabled states are appropriately synchronized with game status.
src/server/trpc/routers/snippet.ts (1)
4-4: LGTM!The addition of
getSnippetByIdto the imports appropriately supports the new endpoint.
Summary by CodeRabbit
New Features
Dependencies
✏️ Tip: You can customize this high-level summary in your review settings.