feat: add next-intl RTL Arabic support (#104) - #123
Conversation
|
@Ayinkx1 is attempting to deploy a commit to the Deen Bridge Team on Vercel. A member of the Team first needs to authorize it. |
ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (62)
💤 Files with no reviewable changes (1)
WalkthroughThe PR adds next-intl English/Arabic routing, RTL support, localized landing and dashboard navigation, new public pages, protected account layouts, and dashboard features for chat, learning content, spaces, search, wallet management, and donations. ChangesInternationalization and RTL support
Public and landing page experiences
Account and dashboard experiences
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant Visitor
participant LocaleSwitcher
participant Middleware
participant LocaleLayout
participant TranslationCatalog
Visitor->>LocaleSwitcher: choose English or Arabic
LocaleSwitcher->>Middleware: navigate to current route with locale
Middleware->>LocaleLayout: resolve locale
LocaleLayout->>TranslationCatalog: load locale messages
TranslationCatalog-->>LocaleLayout: return translated messages
LocaleLayout-->>Visitor: render localized RTL or LTR page
Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 3❌ Failed checks (3 warnings)
✅ Passed checks (2 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 Checkov (3.3.8)messages/ar.jsonTraceback (most recent call last): messages/en.jsonTraceback (most recent call last): package.jsonTraceback (most recent call last): 🔧 ESLint
ESLint install timed out. The project may have too many dependencies for the sandbox. Comment |
There was a problem hiding this comment.
Actionable comments posted: 16
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
🟡 Minor comments (24)
app/[locale]/not-found.js-1-3 (1)
1-3: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winPreserve the active locale in 404 fallback navigation.
NotFoundCompcurrently falls back to/dashboard/classesor/loginwithout the[locale]prefix. From an Arabic route, this can send users to the default locale instead of preserving/ar. Update the shared component to derive or receive the active locale and prefix both fallback paths.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/not-found.js around lines 1 - 3, Update NotFoundComp to derive or receive the active locale and include it in both fallback navigation paths, `/dashboard/classes` and `/login`, so 404 navigation preserves locale prefixes such as `/ar`; keep the existing fallback destinations otherwise unchanged.app/[locale]/account/security/page.jsx-151-151 (1)
151-151: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winTypo in the CSS value: extra
)infill.
fill="var(--color-accent))"has an unbalanced parenthesis, so this resolves to an invalid CSS value and the label likely won't take the intended color. Compare with the sibling<Label>just above (line 145) which correctly usesvar(--color-accent).🐛 Suggested fix
- fill="var(--color-accent))" + fill="var(--color-accent)"🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/account/security/page.jsx at line 151, Correct the fill value in the affected Label element to use a balanced var(--color-accent) expression, matching the sibling Label above.app/[locale]/account/support/page.jsx-83-85 (1)
83-85: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winLooks like a leftover debug placeholder — the "hi"
<div>should go.This empty grid column just renders the text "hi", which is almost certainly scaffolding that slipped in. Removing it avoids shipping stray text to users:
🧹 Suggested cleanup
- <div> - hi -</div> - </div>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/account/support/page.jsx around lines 83 - 85, Remove the placeholder “hi” div from the support page’s rendered markup, leaving the surrounding layout structure unchanged.app/[locale]/account/profile/[profileid]/page.jsx-24-24 (1)
24-24: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick winPlease drop the user-object
console.log— it leaks PII.
console.log("Fetched user:", res?.user)prints the full user record (likely name, email, etc.) into the browser console on every profile load. Beyond being noisy, logging user identifiers is a privacy/compliance concern (GDPR/CCPA), so it's best removed before release.🔒 Suggested change
- setUser(res?.user || null); - console.log("Fetched user:", res?.user); - setLoading(false); + setUser(res?.user || null); + setLoading(false);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/account/profile/[profileid]/page.jsx at line 24, Remove the user-object console.log from the profile-loading flow so profile loads no longer emit personal user data; leave the surrounding fetch and response handling unchanged.app/[locale]/account/notifications/page.jsx-601-608 (1)
601-608: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winPagination controls aren't keyboard- or screen-reader-accessible.
The two arrows are bare
lucide-reacticons with only ahover:style — there's no<button>, noonClick, and no accessible label, so keyboard users can't focus or activate them and assistive tech won't announce them. The footer also says "Showing 1-10 of 32" while the table renders more than 10 rows, so the text is out of sync with the data too. Wrapping the icons in buttons fixes both focusability and labeling:♿ Suggested fix
- <div className="flex text-xs text-muted-foreground gap-4"> - <ArrowLeftToLine className="hover:text-accent" size={17}/> - <ArrowRightToLine className="hover:text-accent" size={17}/> - </div> + <div className="flex text-xs text-muted-foreground gap-4"> + <Button variant="ghost" size="icon" aria-label="Previous page" disabled={/* isFirstPage */ false}> + <ArrowLeftToLine size={17} /> + </Button> + <Button variant="ghost" size="icon" aria-label="Next page" disabled={/* isLastPage */ false}> + <ArrowRightToLine size={17} /> + </Button> + </div>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/account/notifications/page.jsx around lines 601 - 608, Update the pagination controls in the CardFooter to use accessible buttons around the ArrowLeftToLine and ArrowRightToLine icons, with keyboard activation and descriptive aria-labels (and click behavior if pagination is supported). Replace the hard-coded “Showing 1-10 of 32” text with values derived from the rendered notification data so the displayed range and total remain accurate.app/[locale]/account/profile/[profileid]/page.jsx-18-52 (1)
18-52: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winDistinguish request failures from missing profiles here.
getUserById(profileid)returnsnullon caught API/request errors, so this component falls through toNotFoundCompand never showsNetworkErrorComp/Retry for transient failures. Treatnullas the error path (or letgetUserByIdthrow) so users can retry instead of seeing a permanent 404-style state.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/account/profile/[profileid]/page.jsx around lines 18 - 52, Update fetchUser to distinguish request failure from a genuinely missing profile: when getUserById(profileid) returns null, set the error state and avoid treating it as a missing user, so the existing NetworkErrorComp retry path renders. Preserve NotFoundComp for successful responses where the user is actually absent.components/molecules/ladingpage/Navbar.jsx-34-34 (1)
34-34: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winLocalize the mobile logo alternative text too.
The desktop image now uses
t("logo"), but the mobile image still hasalt="Logo"at Line 60. Arabic screen readers therefore receive English text, leaving the landing navbar partially untranslated. Reuse the same message key for both images.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@components/molecules/ladingpage/Navbar.jsx` at line 34, Update the mobile logo image’s alt attribute in the Navbar component to use the existing t("logo") translation key, matching the desktop logo image and removing the hardcoded English "Logo" text.components/organisms/dashboard/sidebar-left.jsx-23-23 (1)
23-23: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winKeep the sidebar border override physical.
components/ui/sidebar.jsxadds a physicalborder-rfor the left sidebar, soborder-e-0only clears the inline-end side in RTL and leaves the divider visible. Useborder-r-0here, or move the border logic into the shared sidebar component so both stay aligned.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@components/organisms/dashboard/sidebar-left.jsx` at line 23, Update the Sidebar invocation in the dashboard sidebar component to use the physical right-border override that clears the shared component’s border-r styling, replacing the current border-e-0 class with border-r-0 while preserving the existing props.components/stellar/WalletConnectButton.jsx-101-107 (1)
101-107: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winFormat Stellar balances without binary floating point.
The
dir="ltr"wrappers are fine, butparseFloat(...).toFixed(...)can round USDC/XLM balances incorrectly. Use the raw decimal string or a decimal-safe formatter so the displayed amount stays exact.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@components/stellar/WalletConnectButton.jsx` around lines 101 - 107, Update the balance rendering near the USDC and XLM display spans to avoid parseFloat and binary floating-point rounding. Use the existing raw decimal values or a decimal-safe formatter while preserving the two-decimal display format and dir="ltr" wrappers.Source: Path instructions
app/[locale]/dashboard/ai/page.jsx-117-121 (1)
117-121: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winMinor: guard against an undefined
data.response. If the upstream ever returns a body withoutresponse, the assistant bubble renders empty (undefined). A small fallback keeps the UI sensible.🛡️ Suggested guard
- const aiResponse = data.response; + const aiResponse = data.response ?? "Sorry, I couldn't generate a response.";🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/dashboard/ai/page.jsx around lines 117 - 121, Update the response handling in the AI message flow to guard against an undefined data.response before appending the assistant message. Use a sensible fallback content value so the assistant bubble never receives undefined, while preserving the existing response content when it is present.app/[locale]/dashboard/messages/page.jsx-7-14 (1)
7-14: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winMinor (a11y):
alt="shadow"is misleading. This is the "choose a chat" empty-state illustration, soalt="shadow"gives screen-reader users nothing useful. If it's purely decorative, use an emptyalt=""so it's skipped; otherwise describe its purpose.♿ Suggested change
- alt="shadow" + alt="Select a conversation to start chatting"🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/dashboard/messages/page.jsx around lines 7 - 14, Update the Image element rendering choose-chat.svg to replace the misleading alt text with an empty alt value if the illustration is decorative, ensuring screen readers skip it; otherwise provide a concise description of the choose-chat empty state.app/[locale]/dashboard/messages/[room]/page.jsx-220-222 (1)
220-222: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winMinor: the list key always falls back to the array index.
listenToMessagesreturns docs shaped as{ id: doc.id, ... }(noteid, not_id), somsg._idis alwaysundefinedandkey={msg._id || i}degrades to the index. Using the real doc id keeps keys stable as messages stream in.🔧 Suggested change
- key={msg._id || i} + key={msg.id || msg._id || i}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/dashboard/messages/[room]/page.jsx around lines 220 - 222, Update the message list key in the render loop to use msg.id, matching the document shape returned by listenToMessages, instead of msg._id. Preserve the index only as a fallback when no document id is available.app/[locale]/dashboard/ai/page.jsx-127-140 (1)
127-140: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winMinor: the error-message extraction assumes an Axios error, but this path uses
fetch. Because a failed request throwsnew Error(\HTTP error! status: ...`),error.responseis alwaysundefined, so theerror.response?.data?.message/.detailsbranches never fire and users only ever see the rawerror.message. The route handler (app/api/ai/chat/route.js) actually returns a JSON body withmessage/details`, so reading the response body would surface a much more helpful toast.🛠️ Suggested direction
- if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - - const data = await response.json(); + const data = await response.json().catch(() => ({})); + if (!response.ok) { + throw new Error(data.details || data.message || `HTTP error! status: ${response.status}`); + }Then in
catch,error.messagealready carries the server-provided detail.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/dashboard/ai/page.jsx around lines 127 - 140, Update the catch block in the AI response flow to stop relying on Axios-only error.response fields, since the request uses fetch. Use the existing error.message, which already contains the server-provided detail from the route handler, when constructing errorMessage, while retaining the generic fallback.app/[locale]/dashboard/messages/[room]/page.jsx-130-133 (1)
130-133: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winMinor: prefer a toast over
alert()for send failures. The rest of the app usessonner(toast.error), and a nativealert()is jarring, blocks the thread, and looks out of place. Consistency here also helps screen-reader users get a uniform experience.💡 Suggested change
- console.log("Failed to send message:", error); - alert("Failed to send message. Please try again."); + console.error("Failed to send message:", error); + toast.error("Failed to send message. Please try again.");(add
import { toast } from "sonner";)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/dashboard/messages/[room]/page.jsx around lines 130 - 133, Replace the native alert in the message-send error handler with the app’s sonner notification pattern: import toast from sonner and call toast.error with the existing failure message, while preserving the console logging and catch flow.app/[locale]/(pages)/(auth)/login/page.jsx-28-28 (1)
28-28: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winMake the side-panel image alternative text intentional.
alt="Image"is not meaningful accessible text. These panels appear decorative, so usealt=""; otherwise provide a description of the image’s purpose.
app/[locale]/(pages)/(auth)/login/page.jsx#L28-L28: replace the generic alt text.app/[locale]/(pages)/(auth)/signup/page.jsx#L26-L26: replace the generic alt text.app/[locale]/profile-setup/page.jsx#L42-L42: replace the generic alt text.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/(pages)/(auth)/login/page.jsx at line 28, Replace the generic alt text with an empty alt value for the decorative side-panel images in app/[locale]/(pages)/(auth)/login/page.jsx lines 28-28, app/[locale]/(pages)/(auth)/signup/page.jsx lines 26-26, and app/[locale]/profile-setup/page.jsx lines 42-42. No descriptions are needed because these images are decorative.app/[locale]/dashboard/library/[bookid]/BookDetailPageClient.jsx-128-136 (1)
128-136: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick winAdd
rel="noopener noreferrer"to thetarget="_blank"download links. Opening an untrustedbook.fileUrlin a new tab withoutrelexposes the opener to reverse tabnabbing (the opened page can manipulatewindow.opener). Modern browsers default tonoopener, but setting it explicitly is the robust, lint-clean fix.
app/[locale]/dashboard/library/[bookid]/BookDetailPageClient.jsx#L128-L136: addrel="noopener noreferrer"to the DownloadButton(it spreads...propsto the underlying link).app/[locale]/dashboard/library/read/[bookid]/BookReaderClient.jsx#L294-L306: addrel="noopener noreferrer"to the DownloadButton.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/dashboard/library/[bookid]/BookDetailPageClient.jsx around lines 128 - 136, Add rel="noopener noreferrer" to the target="_blank" Download Button in BookDetailPageClient.jsx (lines 128-136) and the corresponding Download Button in BookReaderClient.jsx (lines 294-306), preserving the existing book.fileUrl/download behavior.Source: Linters/SAST tools
app/[locale]/dashboard/search/[searchparam]/page.jsx-71-73 (1)
71-73: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winUse locale-aware date formatting with an explicit locale/timezone.
new Date(date).toLocaleString()relies on the ambient locale/timezone. This PR's goal is active-locale-aware formatting, and React Doctor also flags it as a hydration-mismatch risk on SSR paths. Passing an explicit locale (e.g., fromnext-intl) andtimeZonemakes server/client output deterministic and honors the selected locale.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/dashboard/search/[searchparam]/page.jsx around lines 71 - 73, The formatDate function currently depends on the environment’s locale and timezone. Update formatDate to accept and use the active locale plus an explicit deterministic timeZone when calling toLocaleString, sourcing the locale from the existing next-intl context or page locale, while preserving the null result for missing dates.Source: Linters/SAST tools
app/[locale]/dashboard/courses/[courseId]/CourseDetailPageClient.jsx-169-171 (1)
169-171: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winPlaceholder copy mismatch: this is a course, not a book.
The review textarea on the course page still says "What did you think about the book?", which will confuse learners leaving a course review. A quick copy fix keeps the UX consistent.
✏️ Suggested copy fix
- placeholder="What did you think about the book?" + placeholder="What did you think about the course?"🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/dashboard/courses/[courseId]/CourseDetailPageClient.jsx around lines 169 - 171, Update the review Textarea placeholder in CourseDetailPageClient to refer to the course instead of the book, preserving the existing styling and review flow.app/[locale]/layout.js-52-67 (1)
52-67: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winGenerate locale-aware metadata for Arabic routes.
app/[locale]/layout.jsstill exports a static Englishmetadataobject, so/arwill keep English title, description, Open Graph, and Twitter text. Switch this togenerateMetadata({ params })(or otherwise branch onlocale) so Arabic pages get localized metadata too.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/layout.js around lines 52 - 67, Replace the static metadata export in RootLayout with locale-aware generateMetadata({ params }). Resolve the locale from params, select the localized title, description, Open Graph, and Twitter values for Arabic versus English, and preserve the existing metadata structure for other locales.app/[locale]/(pages)/(landingPage)/Partners.jsx-26-27 (1)
26-27: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winMirror the marquee edge fades in RTL.
Lines 26-27 remain physically anchored and retain LTR gradient directions, so the fade effect does not mirror on
/ar. Use logical start/end placement and direction-aware gradients.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/(pages)/(landingPage)/Partners.jsx around lines 26 - 27, Update the marquee edge-fade elements in the Partners component to use logical start/end positioning instead of left/right anchors, and make each gradient direction respond to the document direction so the fades mirror correctly in RTL while preserving the existing sizing and styling.Source: Path instructions
app/[locale]/(pages)/(landingPage)/CTA.jsx-15-18 (1)
15-18: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winAvoid nesting the CTA button inside a link.
Line 15 wraps
Button’s native<button>inLink, creating invalid nested interactive elements. Render one styledLink, or update the shared button API to render a single link element for navigation.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/(pages)/(landingPage)/CTA.jsx around lines 15 - 18, Update the CTA navigation around the Link and Button elements to render a single interactive element instead of nesting Button’s native button inside Link. Preserve the existing signup destination, translated label, styling, and hover behavior by either styling Link directly or using the shared Button API’s link-rendering support.app/[locale]/(pages)/blog/page.jsx-124-146 (1)
124-146: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winUse logical positioning and a direction-aware arrow.
left-4anchors the date badge physically on the left, while→always points right. In Arabic, usestart-4and a mirrored/direction-aware icon or RTL transform.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/(pages)/blog/page.jsx around lines 124 - 146, Update the blog card date badge positioning to use logical `start-4` instead of `left-4`, and replace the hardcoded right arrow in the “Read more” link with a direction-aware or RTL-mirrored icon so it points correctly for Arabic and other RTL locales.app/[locale]/(pages)/blog/layout.jsx-33-33 (1)
33-33: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winUse
openGraph.siteNamehere.site_nameis not a supported Metadata API key, so Next won’t emit the intendedog:site_nametag.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/(pages)/blog/layout.jsx at line 33, Update the metadata configuration in the blog layout to use the supported openGraph.siteName key instead of site_name, preserving the existing “Deen Bridge Blog” value so Next.js emits the intended Open Graph site name.Source: MCP tools
app/[locale]/(pages)/blog/page.jsx-125-142 (1)
125-142: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winUse the page locale when formatting blog dates.
toLocaleDateString("en-US")hardcodes English, and withouttimeZone: "UTC"an ISO date can land on a different day across environments. Format once with the active locale and reuse that value instead of rendering the rawpost.date.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/(pages)/blog/page.jsx around lines 125 - 142, Update the blog date rendering in the page component to format each post date once using the active page locale and timeZone "UTC", then reuse that formatted value in both the displayed date locations instead of rendering raw post.date.Source: Linters/SAST tools
🧹 Nitpick comments (13)
app/[locale]/account/security/page.jsx (1)
298-298: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueSmall grammar nit in the user-facing copy.
"You're average more steps a day this year than last year." reads awkwardly — likely intended as "You're averaging more steps a day this year than last year."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/account/security/page.jsx at line 298, Correct the user-facing sentence in the security page copy from “You're average more steps...” to “You're averaging more steps a day this year than last year.”app/[locale]/account/layout.jsx (1)
12-13: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueTiny cleanup:
pathis computed but never used (and.split("")looks unintended).
usePathname().split("")splits the pathname into an array of individual characters, and the resultingpathis never referenced anywhere in the component. It's harmless at runtime, but it's a little confusing for the next reader and can trip up lint rules. Safe to drop entirely:♻️ Suggested cleanup
-export default function Layout({ children }) { - const path = usePathname().split(""); - return ( +export default function Layout({ children }) { + return (You can then also drop the
usePathnameimport if nothing else uses it.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/account/layout.jsx around lines 12 - 13, Remove the unused path declaration from Layout, including the unintended usePathname().split("") computation, and remove the usePathname import if it is no longer referenced elsewhere in the component.app/[locale]/account/settings/page.jsx (1)
475-505: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winHeads-up for when this gets wired to a real API:
confirmPasswordis collected but never validated.Right now
handleAccountSaveis a mock (setTimeout), so nothing breaks — but the "Confirm New Password" field is never compared againstnewPassword, so once you connect this to a real endpoint a mismatch would sail straight through. Worth adding a guard now while the form is fresh in mind:♻️ Suggested guard
const handleAccountSave = async (e) => { e.preventDefault(); + if (account.newPassword && account.newPassword !== account.confirmPassword) { + showMessage("error", "New password and confirmation do not match."); + return; + } setIsLoading(true);(For context: the
setstate-same-varand missing-keywarnings from static analysis on this file are false positives — thesetTimeoutcalls are fine andCheckCircleis a conditional child of the already-keyedButton.)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/account/settings/page.jsx around lines 475 - 505, Add a validation guard in handleAccountSave that compares account.confirmPassword with account.newPassword before the mock save proceeds, and return early with the form’s existing error feedback when they differ. Keep the current setTimeout success flow unchanged for matching passwords.Source: Linters/SAST tools
app/[locale]/account/support/page.jsx (1)
20-23: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win
handleSubmitis a no-op, so the ticket form doesn't do anything yet.
handleSubmitonly callse.preventDefault()—subject,description,image, andloadingare all captured in state but never sent anywhere, andloading/setLoading(andmodalHandler) are declared but unused. That means clicking "Create a ticket" silently does nothing. If this is intentionally staged for a follow-up, a// TODOcomment would signal that clearly.I'm happy to draft the submission logic (e.g., building the FormData with the image and posting to your tickets endpoint) — want me to open an issue to track it?
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/account/support/page.jsx around lines 20 - 23, Implement the ticket submission flow in handleSubmit instead of leaving it as a no-op: build a FormData payload from subject, description, and image, manage loading with setLoading, and submit it to the tickets endpoint using the existing request conventions. Handle success and failure through modalHandler, reset or preserve form state appropriately, and ensure loading is cleared on every path.app/[locale]/account/notifications/page.jsx (1)
63-597: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winThis looks like unadapted boilerplate: 16 hand-copied rows of product/sales data on a "Notifications" page.
Two things worth addressing here:
- Content mismatch — the columns are
Name / Price / Total Sales / Created atwith rows like "Laser Lemonade Machine" and "$499.99". That's e-commerce product data, not notifications, so this reads as a template that wasn't tailored to the feature yet.- Duplication — the same
<TableRow>markup is copy-pasted ~16 times. Driving it from a data array keeps it DRY and makes it trivial to swap in real notification data later.♻️ Sketch of a data-driven approach
const notifications = [/* { id, title, image, createdAt, ... } */]; <TableBody> {notifications.map((n) => ( <TableRow key={n.id}> {/* one row template referencing n.* */} </TableRow> ))} </TableBody>Want me to open an issue to track wiring this up to a real notifications source?
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/account/notifications/page.jsx around lines 63 - 597, Replace the repeated hand-copied product rows in the TableBody with a notifications data array and a single mapped TableRow template, keyed by each notification’s unique id. Adapt the displayed columns, labels, image/metadata, and actions to notification content rather than e-commerce fields such as price and total sales, while preserving the existing table and dropdown structure.components/molecules/dashboard/nav-main.jsx (1)
23-23: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse explicit translation keys in both dashboard navigation lists.
Both components derive
next-intlmessage IDs from English display text, making catalog keys brittle when labels change or contain multiple words.
components/molecules/dashboard/nav-main.jsx#L23-L23: add a stabletranslationKeyto eachdata.navMainitem and callt(item.translationKey).components/molecules/dashboard/nav-routers.jsx#L97-L97: add a stable translation key to each route record and translate that key instead ofitem.name.toLowerCase().🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@components/molecules/dashboard/nav-main.jsx` at line 23, Replace label-derived translation IDs with explicit stable translation keys in both navigation lists: update each data.navMain item and route record in components/molecules/dashboard/nav-main.jsx (line 23) and components/molecules/dashboard/nav-routers.jsx (line 97) to define a translationKey, then have the corresponding renderers call t(item.translationKey) instead of deriving keys from display text.app/[locale]/dashboard/sadaqah/page.jsx (1)
508-540: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winKeep monetary amounts LTR in the Arabic layout.
This page lives under
app/[locale]and is reachable at/ar, where the document is RTL. A PR objective is to keep monetary values LTR within RTL layouts, but${formatAmount(donation.amount)}USDC (and the balance/pool figures above) inherit RTL, which can flip the$/USDCordering around the number. Wrapping the numeric+currency runs indir="ltr"(or a<bdi>) keeps them rendering correctly under Arabic. Please confirm whether this page is in the current translation/RTL-audit scope; if it's intentionally deferred as an untranslated fallback area, this can wait.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/dashboard/sadaqah/page.jsx around lines 508 - 540, The monetary amount and currency displays in the dashboard, including the recent donation value rendered in the recent.map block and the balance/pool figures above, must remain LTR under Arabic RTL layouts. Wrap each complete numeric-and-currency run with dir="ltr" or an equivalent bdi element, and apply the same treatment to all affected figures on this page; confirm this page is within the current RTL-audit scope rather than deferring it as an untranslated fallback.app/[locale]/dashboard/page.jsx (1)
1-1: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueNit: stale
// pages/dashboard.jsxcomment. This is an App Router route (app/[locale]/dashboard/page.jsx), so the leading comment points at the wrong location/paradigm and can confuse contributors. Safe to remove.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/dashboard/page.jsx at line 1, Remove the stale leading “pages/dashboard.jsx” comment from the dashboard route file; no other code changes are needed.app/[locale]/dashboard/messages/[room]/page.jsx (1)
277-293: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winRecommended: debounce the typing signal.
setTyping(room, user._id, true)fires on every keystroke, and each call is a FirestoresetDocwrite (lib/actions/messages/typing.js). On a longer message that's dozens of writes per message — real cost and quota churn. Debouncing the "true" write and flipping tofalseafter a short idle timeout (in addition toonBlur) gives the same UX far more cheaply.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/dashboard/messages/[room]/page.jsx around lines 277 - 293, The message Textarea’s onChange currently writes the typing state on every keystroke. Update the typing flow around setTyping, setNewMessage, and the Textarea handlers to debounce the true signal and schedule a short idle-timeout false signal, while retaining the immediate onBlur reset; clear or replace pending timers as needed so stale callbacks cannot overwrite newer typing activity.app/[locale]/dashboard/ai/layout.js (1)
4-9: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueNit:
pathnameis computed but never used.usePathname()here just adds an unused subscription/import — safe to drop until it's actually needed, which keeps the component lean and avoids confusing future readers.♻️ Suggested cleanup
-import { usePathname } from "next/navigation";const [chatData, setChatData] = useState({ messages: [], chatId: null }); - const pathname = usePathname();🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/dashboard/ai/layout.js around lines 4 - 9, Remove the unused usePathname import and delete the pathname declaration from Layout, while leaving the currentChatId and chatData state setup unchanged.app/[locale]/dashboard/courses/[courseId]/CourseDetailPageClient.jsx (1)
108-112: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low valueConsider
next/imagefor the preview thumbnail.A raw
<img>skips Next.js optimization (automatic sizing, lazy-loading, format negotiation) that the rest of this PR already relies on vianext/image. Not blocking, but worth aligning for performance and to avoid the@next/next/no-img-elementlint warning in CI.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/dashboard/courses/[courseId]/CourseDetailPageClient.jsx around lines 108 - 112, Replace the raw img element in CourseDetailPageClient with Next.js’s Image component, preserving the existing thumbnail source, alt text, styling, and preview appearance while supplying the sizing or fill configuration required by next/image.app/[locale]/(pages)/(landingPage)/WhyDeenBridge.jsx (1)
1-5: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winRemove the unnecessary client boundaries.
Neither component uses browser-only APIs, state, or event handlers, so keeping them as client components only widens the client bundle.
useTranslationscan stay here, and importingButtonfrom a server component is fine.
app/[locale]/(pages)/(landingPage)/WhyDeenBridge.jsx#L1-L5: drop"use client".app/[locale]/(pages)/(landingPage)/Partners.jsx#L1-L3: drop"use client"; it only maps static data.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/(pages)/(landingPage)/WhyDeenBridge.jsx around lines 1 - 5, Remove the "use client" directive from WhyDeenBridge.jsx and Partners.jsx; both components can remain server components while retaining useTranslations, Button imports, and static data mapping unchanged.Source: Path instructions
app/[locale]/(pages)/blog/page.jsx (1)
1-1: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winRemove the unnecessary client boundary.
This page only renders static data and links; it has no state, effects, or browser-only APIs. Removing
"use client"keeps the listing server-rendered and avoids shipping the entire post catalog and card tree as client code.As per path instructions,
app/**is a Next.js 15 App Router project; client components that could be server components should be flagged.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/(pages)/blog/page.jsx at line 1, Remove the unnecessary "use client" directive from the blog page module so it remains a server component. Preserve the existing static post catalog and link-rendering behavior without adding client-only state, effects, or browser APIs.Source: Path instructions
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 275d3c8b-0ec4-45e6-b62e-b34ca20c48d1
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (62)
app/(pages)/(landingPage)/WhyDeenBridge.jsxapp/[locale]/(pages)/(auth)/login/page.jsxapp/[locale]/(pages)/(auth)/signup/page.jsxapp/[locale]/(pages)/(landingPage)/About.jsxapp/[locale]/(pages)/(landingPage)/CTA.jsxapp/[locale]/(pages)/(landingPage)/Footer.jsxapp/[locale]/(pages)/(landingPage)/Hero.jsxapp/[locale]/(pages)/(landingPage)/HowItWorks.jsxapp/[locale]/(pages)/(landingPage)/Partners.jsxapp/[locale]/(pages)/(landingPage)/Stats.jsxapp/[locale]/(pages)/(landingPage)/Testimonials.jsxapp/[locale]/(pages)/(landingPage)/WhyDeenBridge.jsxapp/[locale]/(pages)/blog/layout.jsxapp/[locale]/(pages)/blog/page.jsxapp/[locale]/account/layout.jsxapp/[locale]/account/notifications/page.jsxapp/[locale]/account/profile/[profileid]/page.jsxapp/[locale]/account/security/page.jsxapp/[locale]/account/settings/page.jsxapp/[locale]/account/support/page.jsxapp/[locale]/account/wallet/page.jsxapp/[locale]/dashboard/ai/layout.jsapp/[locale]/dashboard/ai/page.jsxapp/[locale]/dashboard/courses/[courseId]/CourseDetailPageClient.jsxapp/[locale]/dashboard/courses/[courseId]/page.jsxapp/[locale]/dashboard/courses/page.jsxapp/[locale]/dashboard/layout.jsxapp/[locale]/dashboard/library/[bookid]/BookDetailPageClient.jsxapp/[locale]/dashboard/library/[bookid]/page.jsxapp/[locale]/dashboard/library/page.jsxapp/[locale]/dashboard/library/read/[bookid]/BookReaderClient.jsxapp/[locale]/dashboard/library/read/[bookid]/page.jsxapp/[locale]/dashboard/messages/[room]/page.jsxapp/[locale]/dashboard/messages/layout.jsapp/[locale]/dashboard/messages/page.jsxapp/[locale]/dashboard/page.jsxapp/[locale]/dashboard/reels/page.jsxapp/[locale]/dashboard/sadaqah/page.jsxapp/[locale]/dashboard/search/[searchparam]/page.jsxapp/[locale]/dashboard/spaces/[spacesid]/page.jsxapp/[locale]/dashboard/spaces/page.jsxapp/[locale]/layout.jsapp/[locale]/loading.jsxapp/[locale]/not-found.jsapp/[locale]/page.jsxapp/[locale]/profile-setup/page.jsxcomponents/i18n/LocaleSwitcher.jsxcomponents/molecules/dashboard/nav-header.jsxcomponents/molecules/dashboard/nav-main.jsxcomponents/molecules/dashboard/nav-routers.jsxcomponents/molecules/ladingpage/Navbar.jsxcomponents/organisms/dashboard/sidebar-left.jsxcomponents/stellar/WalletConnectButton.jsxi18n/navigation.jsi18n/request.jsi18n/routing.jsmessages/ar.jsonmessages/en.jsonmiddleware.jsnext.config.mjspackage.jsonstyles/globals.css
💤 Files with no reviewable changes (1)
- app/(pages)/(landingPage)/WhyDeenBridge.jsx
There was a problem hiding this comment.
Caution
Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.
🛑 Comments failed to post (16)
app/[locale]/(pages)/(auth)/login/page.jsx (1)
12-12: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash set -euo pipefail printf '\n== files ==\n' git ls-files 'app/[locale]/(pages)/(auth)/login/page.jsx' 'app/[locale]/(pages)/(auth)/signup/page.jsx' 'app/[locale]/profile-setup/page.jsx' 'app/**/navigation*' 'i18n*' 'middleware*' | sed 's#^`#-` #' printf '\n== login page ==\n' sed -n '1,120p' 'app/[locale]/(pages)/(auth)/login/page.jsx' printf '\n== signup page ==\n' sed -n '1,120p' 'app/[locale]/(pages)/(auth)/signup/page.jsx' printf '\n== profile-setup page ==\n' sed -n '1,160p' 'app/[locale]/profile-setup/page.jsx' printf '\n== navigation / middleware helpers ==\n' for f in $(git ls-files | grep -E '(^|/)(navigation|i18n|middleware).*\.(js|jsx|ts|tsx)$' || true); do echo "--- $f" sed -n '1,220p' "$f" doneRepository: Deen-Bridge/dnb-frontend
Length of output: 13148
🏁 Script executed:
#!/bin/bash set -euo pipefail # Narrow search for Link usage and locale-aware navigation helpers rg -n --glob 'app/**/*.jsx' "from 'next/link'|from \"next/link\"|href=\"/\"|href='/'|`@/i18n/navigation`|next-intl|useLocale|locale" appRepository: Deen-Bridge/dnb-frontend
Length of output: 1829
🌐 Web query:
next-intl navigation Link from "@/i18n/navigation" locale-aware href="/" current locale💡 Result:
In next-intl, you can create a locale-aware Link component by using the navigation APIs created via the createNavigation (or previously createSharedPathnamesNavigation) factory function [1][2][3]. By importing Link from your configured navigation file (e.g.,
@/i18n/navigation), the component automatically handles the current locale and applies the correct path prefixes based on your routing configuration [1][3]. Usage: 1. Setup your navigation configuration (typically in src/i18n/navigation.ts): import {createNavigation} from 'next-intl/navigation'; import {routing} from './routing'; export const {Link, redirect, usePathname, useRouter, getPathname} = createNavigation(routing); 2. Use the Link component in your components: import {Link} from '@/i18n/navigation'; // When on /en, this renders a link to /en/about About // To switch the locale, you can pass the locale prop: // This will point to the root of the specified locale Switch to German Key features of this Link component: - Locale awareness: It automatically prepends the current locale to the href based on your localePrefix setting (e.g., 'always' or 'as-needed') [1][4]. - Type safety: If using localized pathnames, the href prop is strictly typed according to your routing configuration [1][5]. - Overriding: You can explicitly pass a locale prop to change the language of the target page, which also updates the hreflang attribute [1].Citations:
- 1: https://next-intl.dev/docs/routing/navigation
- 2: https://github.com/amannn/next-intl/blob/main/docs/src/pages/docs/routing/setup.mdx
- 3: https://next-intl-docs.vercel.app/blog/next-intl-3-0
- 4: amannn/next-intl#444
- 5: amannn/next-intl#586
🏁 Script executed:
#!/bin/bash set -euo pipefail # Inspect any i18n navigation helper and middleware references if present for f in $(git ls-files | grep -E '(^|/)(i18n|navigation|middleware).*\.(js|jsx|ts|tsx)$' || true); do echo "--- $f" sed -n '1,240p' "$f" doneRepository: Deen-Bridge/dnb-frontend
Length of output: 8184
Use the locale-aware
Linkhere.href="/"bypasses the app’s locale handling and sends users to the locale-neutral root, which can drop the active language on these locale-scoped pages.
app/[locale]/(pages)/(auth)/login/page.jsx#L12app/[locale]/(pages)/(auth)/signup/page.jsx#L10app/[locale]/profile-setup/page.jsx#L26📍 Affects 3 files
app/[locale]/(pages)/(auth)/login/page.jsx#L12-L12(this comment)app/[locale]/(pages)/(auth)/signup/page.jsx#L10-L10app/[locale]/profile-setup/page.jsx#L26-L26🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/(pages)/(auth)/login/page.jsx at line 12, Update the Link components in app/[locale]/(pages)/(auth)/login/page.jsx:12-12, app/[locale]/(pages)/(auth)/signup/page.jsx:10-10, and app/[locale]/profile-setup/page.jsx:26-26 to use the project’s locale-aware Link implementation while preserving the existing destination and styling. Ensure navigation retains the active locale instead of using the locale-neutral root.Source: Path instructions
app/[locale]/(pages)/(landingPage)/Partners.jsx (1)
16-22: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Localize the newly added landing sections.
These sections bypass the new message catalogs, so
/arstill renders English content instead of satisfying the localized-landing objective.
app/[locale]/(pages)/(landingPage)/Partners.jsx#L16-L22: move the heading and description into thelandingmessage namespace and render them withuseTranslations.app/[locale]/(pages)/(landingPage)/Stats.jsx#L8-L37: move stat labels and descriptions into translated message keys.app/[locale]/(pages)/(landingPage)/Stats.jsx#L97-L105: translate the statistics section heading, eyebrow, and description.📍 Affects 2 files
app/[locale]/(pages)/(landingPage)/Partners.jsx#L16-L22(this comment)app/[locale]/(pages)/(landingPage)/Stats.jsx#L8-L37app/[locale]/(pages)/(landingPage)/Stats.jsx#L97-L105🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/(pages)/(landingPage)/Partners.jsx around lines 16 - 22, Localize the new landing-page content through the landing message namespace: in app/[locale]/(pages)/(landingPage)/Partners.jsx lines 16-22, use useTranslations and replace the heading and description with message keys; in app/[locale]/(pages)/(landingPage)/Stats.jsx lines 8-37, move stat labels and descriptions to translated keys; and in app/[locale]/(pages)/(landingPage)/Stats.jsx lines 97-105, translate the statistics eyebrow, heading, and description.Source: Path instructions
app/[locale]/(pages)/(landingPage)/Stats.jsx (1)
45-77: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Format statistics from structured values, not display strings.
AnimatedCounteralways emits Western digits and./$ordering, so/ardoes not get locale-aware formatting and monetary values can render with incorrect bidi ordering. Keep numeric values/unit metadata separately, format withIntl.NumberFormatfor the active locale, and isolate monetary output withdir="ltr"/<bdi>.🧰 Tools
🪛 ast-grep (0.44.1)
[warning] 59-59: Avoid using the initial state variable in setState
Context: setCount(numericValue)
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.(setstate-same-var)
[warning] 62-62: Avoid using the initial state variable in setState
Context: setCount(current)
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.(setstate-same-var)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/(pages)/(landingPage)/Stats.jsx around lines 45 - 77, Update AnimatedCounter to receive and preserve numeric values and unit metadata separately instead of parsing prefixes and suffixes from display strings. Format the animated count with Intl.NumberFormat using the active locale, preserving the intended decimal precision and localized digits. For monetary statistics, isolate the formatted output with dir="ltr" and/or bdi so currency ordering and bidi rendering remain correct.app/[locale]/(pages)/blog/layout.jsx (1)
3-48: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash set -euo pipefail printf '\n## blog layout\n' cat -n 'app/[locale]/(pages)/blog/layout.jsx' | sed -n '1,220p' printf '\n## blog page\n' cat -n 'app/[locale]/(pages)/blog/page.jsx' | sed -n '1,260p' printf '\n## locale-related files\n' git ls-files 'app/[locale]/**' | sed -n '1,200p' printf '\n## search for i18n/locale helpers\n' rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' --glob '!coverage' '\b(locale|locales|i18n|translate|translations|t\()' app lib src . 2>/dev/null | sed -n '1,260p'Repository: Deen-Bridge/dnb-frontend
Length of output: 27288
🏁 Script executed:
#!/bin/bash set -euo pipefail cat /tmp/sandbox_stdout.log | sed -n '1,260p'Repository: Deen-Bridge/dnb-frontend
Length of output: 218
🏁 Script executed:
#!/bin/bash set -euo pipefail printf '\n## files under app/[locale]\n' git ls-files 'app/[locale]/**' | sed -n '1,260p' printf '\n## /blog link patterns\n' rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' --glob '!coverage' 'to=\{?`?/blog|href=\{?`?/blog|"/blog/|\'/blog/' app components lib src 2>/dev/null | sed -n '1,260p' printf '\n## locale segment patterns\n' rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' --glob '!coverage' '\[\s*locale\s*\]|params\.locale|locale\/' app components lib src 2>/dev/null | sed -n '1,260p'Repository: Deen-Bridge/dnb-frontend
Length of output: 276
🏁 Script executed:
#!/bin/bash set -euo pipefail printf '\n## home page\n' cat -n 'app/[locale]/(pages)/home/page.jsx' | sed -n '1,220p' printf '\n## courses page\n' cat -n 'app/[locale]/(pages)/courses/page.jsx' | sed -n '1,180p' printf '\n## blog slug page\n' cat -n 'app/[locale]/(pages)/blog/[slug]/page.jsx' | sed -n '1,260p' printf '\n## locale helpers / link wrappers\n' rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' --glob '!coverage' 'from "`@/components`|from ".*/Link|locale.*href|href.*locale|useLocale|NextIntl|next-intl|i18n' app components lib src 2>/dev/null | sed -n '1,260p'Repository: Deen-Bridge/dnb-frontend
Length of output: 245
🏁 Script executed:
#!/bin/bash set -euo pipefail printf '\n## root routing files\n' git ls-files | rg '^(middleware\.js|middleware\.ts|next\.config\.(js|mjs|ts)|app/.*/layout\.(js|jsx|ts|tsx)|app/.*/page\.(js|jsx|ts|tsx))$' | sed -n '1,240p' printf '\n## search for locale rewrite / redirect / middleware logic\n' rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' --glob '!coverage' 'redirect\(|rewrite\(|NextResponse|matcher|locale|i18n|defaultLocale|locales' middleware.* next.config.* app lib src 2>/dev/null | sed -n '1,260p' printf '\n## metadata in other pages\n' rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' --glob '!coverage' 'export const metadata|generateMetadata' app/[locale] 2>/dev/null | sed -n '1,260p'Repository: Deen-Bridge/dnb-frontend
Length of output: 2454
🏁 Script executed:
#!/bin/bash set -euo pipefail printf '\n## root page\n' cat -n 'app/page.jsx' | sed -n '1,220p' printf '\n## home metadata\n' cat -n 'app/[locale]/(pages)/home/page.jsx' | sed -n '1,60p' printf '\n## about metadata\n' cat -n 'app/[locale]/(pages)/about/page.jsx' | sed -n '1,80p' printf '\n## contact metadata\n' cat -n 'app/[locale]/(pages)/contact/page.jsx' | sed -n '1,80p'Repository: Deen-Bridge/dnb-frontend
Length of output: 221
🏁 Script executed:
#!/bin/bash set -euo pipefail printf '\n## button component files\n' git ls-files 'components/**' | rg 'button|link|nav|header|footer' | sed -n '1,260p' printf '\n## button implementation\n' fd -a 'button.*' components . | sed -n '1,80p' printf '\n## read button source\n' for f in $(fd -a 'button.*' components .); do echo "\n### $f" cat -n "$f" | sed -n '1,220p' done printf '\n## search for custom link helper\n' rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' --glob '!coverage' 'function Button|const Button|export .*Button|to=' components app lib src 2>/dev/null | sed -n '1,260p'Repository: Deen-Bridge/dnb-frontend
Length of output: 35364
🏁 Script executed:
#!/bin/bash set -euo pipefail cat -n 'components/ui/button.jsx' | sed -n '1,220p'Repository: Deen-Bridge/dnb-frontend
Length of output: 2472
🏁 Script executed:
#!/bin/bash set -euo pipefail printf '\n## i18n/routing.js\n' cat -n 'i18n/routing.js' | sed -n '1,220p' printf '\n## middleware.js\n' cat -n 'middleware.js' | sed -n '1,220p' printf '\n## i18n/navigation.js\n' cat -n 'i18n/navigation.js' | sed -n '1,220p'Repository: Deen-Bridge/dnb-frontend
Length of output: 937
Keep the blog surface locale-aware
app/[locale]/(pages)/blog/layout.jsxhardcodeshttps://deenbridge.com/blog, andapp/[locale]/(pages)/blog/page.jsx/app/[locale]/(pages)/blog/[slug]/page.jsxuse plain/blogpaths for the CTA and back link. WithlocalePrefix: "as-needed", Arabic visitors fall back to the default locale instead of staying on the localized route. The same/blog/...links also appear inapp/[locale]/(pages)/home/page.jsxandapp/[locale]/(pages)/courses/page.jsx; move the blog copy into locale messages as well.📍 Affects 2 files
app/[locale]/(pages)/blog/layout.jsx#L3-L48(this comment)app/[locale]/(pages)/blog/page.jsx#L4-L95app/[locale]/(pages)/blog/page.jsx#L97-L111app/[locale]/(pages)/blog/page.jsx#L145-L147🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/(pages)/blog/layout.jsx around lines 3 - 48, Make the blog metadata and navigation locale-aware: update app/[locale]/(pages)/blog/layout.jsx lines 3-48 to generate the canonical URL with the active locale, and update app/[locale]/(pages)/blog/page.jsx lines 4-95, 97-111, and 145-147 to use locale-preserving blog routes for the CTA and back link. Move the affected blog copy into locale messages, and also update the `/blog/...` links in app/[locale]/(pages)/home/page.jsx and app/[locale]/(pages)/courses/page.jsx to preserve the current locale.Source: MCP tools
app/[locale]/(pages)/blog/page.jsx (1)
2-2: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash set -euo pipefail printf '\n## app/[locale]/(pages)/blog/page.jsx\n' cat -n app/[locale]/(pages)/blog/page.jsx printf '\n## locale-aware navigation helpers and blog slug routes\n' rg -n "locale-aware|navigation helper|Link from \"next/link\"|/blog/\$\{post\.slug\}|post\.slug|useRouter|Link" app -g '!**/*.map' || true printf '\n## blog route files\n' fd -a "page.jsx" app | sed 's#^\./##' | sortRepository: Deen-Bridge/dnb-frontend
Length of output: 254
🏁 Script executed:
#!/bin/bash set -euo pipefail printf '\n## app/[locale]/(pages)/blog/page.jsx\n' cat -n "app/[locale]/(pages)/blog/page.jsx" printf '\n## locale-aware navigation helpers and blog slug routes\n' rg -n "locale-aware|navigation helper|Link from \"next/link\"|/blog/\$\{post\.slug\}|post\.slug|useRouter|Link" app -g '!**/*.map' || true printf '\n## blog route files\n' fd -a "page.jsx" app | sed 's#^\./##' | sortRepository: Deen-Bridge/dnb-frontend
Length of output: 13572
🏁 Script executed:
#!/bin/bash set -euo pipefail cat -n "app/[locale]/(pages)/blog/page.jsx"Repository: Deen-Bridge/dnb-frontend
Length of output: 7783
Keep blog detail links locale-scoped. Both
href={/blog/${post.slug}}andto={/blog/${post.slug}}drop the active locale, and there isn’t a matchingapp/[locale]/(pages)/blog/[slug]/page.jsxroute for them to land on. Build these URLs with the current locale so the title and CTA reach the localized post page.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/(pages)/blog/page.jsx at line 2, Update the blog post title and CTA links to include the active locale when constructing each post URL, using the locale-aware route under the blog slug page. Apply the same localized URL construction to both the href and to link props.app/[locale]/account/wallet/page.jsx (1)
92-122: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
RTL: wrap the wallet address and balances in
dir="ltr"to match the PR's own objective.One of this PR's goals is to keep wallet addresses, transaction hashes, and monetary values rendering left-to-right inside RTL layouts — and the shared
WalletConnectButtonalready does exactly this (<span dir="ltr">…</span>around the truncated address and balances). On this page the address (line 92) and both balances (lines 110, 121) are unwrapped, so under/arthey'll be reordered/mirrored and become hard to read or copy. Addingdir="ltr"keeps them correct:🌐 Suggested fix
- <p className="font-mono text-sm">{truncateAddress(connectedWallet)}</p> + <p dir="ltr" className="font-mono text-sm">{truncateAddress(connectedWallet)}</p>- <p className="text-2xl font-bold text-primary"> - ${parseFloat(walletInfo?.usdcBalance || 0).toFixed(2)} - </p> + <p dir="ltr" className="text-2xl font-bold text-primary"> + ${parseFloat(walletInfo?.usdcBalance || 0).toFixed(2)} + </p>- <p className="text-2xl font-bold"> - {parseFloat(walletInfo?.xlmBalance || 0).toFixed(4)} XLM - </p> + <p dir="ltr" className="text-2xl font-bold"> + {parseFloat(walletInfo?.xlmBalance || 0).toFixed(4)} XLM + </p>📝 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.<p dir="ltr" className="font-mono text-sm">{truncateAddress(connectedWallet)}</p> </div> <a href={getExplorerUrl(connectedWallet)} target="_blank" rel="noopener noreferrer" className="inline-flex items-center gap-1 text-sm text-primary hover:underline" > View on Explorer <ExternalLink className="h-3 w-3" /> </a> </div> {/* Balances */} <div className="grid grid-cols-1 sm:grid-cols-2 gap-4"> <div className="p-4 border rounded-lg"> <p className="text-sm text-muted-foreground">USDC Balance</p> <p dir="ltr" className="text-2xl font-bold text-primary"> ${parseFloat(walletInfo?.usdcBalance || 0).toFixed(2)} </p> {!walletInfo?.hasTrustline && ( <p className="text-xs text-orange-500 mt-1"> No USDC trustline. Add USDC asset to your wallet. </p> )} </div> <div className="p-4 border rounded-lg"> <p className="text-sm text-muted-foreground">XLM Balance</p> <p dir="ltr" className="text-2xl font-bold"> {parseFloat(walletInfo?.xlmBalance || 0).toFixed(4)} XLM </p>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/account/wallet/page.jsx around lines 92 - 122, Wrap the wallet address rendered by truncateAddress(connectedWallet) and both formatted balance values in the wallet balance section with dir="ltr" containers. Update the relevant markup around the address, USDC balance, and XLM balance while preserving their existing formatting and surrounding layout.app/[locale]/dashboard/courses/[courseId]/page.jsx (1)
4-6: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Await
paramsin these async server pages (Next.js 15 made it a Promise). In Next.js 15, dynamic APIs includingparamsare asynchronous; synchronous property access is deprecated (currently a warning, removed in the next major) and can already break under Turbopack. Since each of these is anasyncserver component, awaiting is a one-line fix.
app/[locale]/dashboard/courses/[courseId]/page.jsx#L4-L6: change toconst { courseId } = await params;.app/[locale]/dashboard/library/[bookid]/page.jsx#L4-L6: change toconst { bookid } = await params;.app/[locale]/dashboard/spaces/[spacesid]/page.jsx#L10-L11: change toconst { spacesid } = await params;.app/[locale]/dashboard/library/read/[bookid]/page.jsx#L5-L6: change toconst { bookid } = await params;.As per path instructions: "Flag use of deprecated patterns (synchronous params/cookies, pages-router idioms)".
📍 Affects 4 files
app/[locale]/dashboard/courses/[courseId]/page.jsx#L4-L6(this comment)app/[locale]/dashboard/library/[bookid]/page.jsx#L4-L6app/[locale]/dashboard/spaces/[spacesid]/page.jsx#L10-L11app/[locale]/dashboard/library/read/[bookid]/page.jsx#L5-L6🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/dashboard/courses/[courseId]/page.jsx around lines 4 - 6, Await the dynamic params object before destructuring it in the async page components: update the Page components in app/[locale]/dashboard/courses/[courseId]/page.jsx (lines 4-6), app/[locale]/dashboard/library/[bookid]/page.jsx (lines 4-6), app/[locale]/dashboard/spaces/[spacesid]/page.jsx (lines 10-11), and app/[locale]/dashboard/library/read/[bookid]/page.jsx (lines 5-6) to await params while preserving each existing identifier and downstream logic.Source: Path instructions
app/[locale]/dashboard/library/[bookid]/BookDetailPageClient.jsx (1)
158-158: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Guard against a missing
book.authorhere to avoid a render crash.Everywhere else you defensively use
book?.author?._id(e.g., Line 45), but this comparison dereferencesbook.author._iddirectly. If a book ever comes back without a populatedauthor, this line throwsTypeError: Cannot read properties of undefinedand takes down the whole page render. Optional chaining keeps it safe.🛡️ Suggested guard
- {user?._id !== book.author._id && ( + {user?._id !== book.author?._id && (📝 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.{user?._id !== book.author?._id && (🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/dashboard/library/[bookid]/BookDetailPageClient.jsx at line 158, Update the author comparison in BookDetailPageClient so it safely handles books without an author by using the same optional-chaining pattern as the existing book?.author?._id usage, while preserving the current conditional rendering behavior.app/[locale]/dashboard/library/read/[bookid]/BookReaderClient.jsx (1)
19-21: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash # Confirm bundler config + how the worker is wired fd -t f 'next.config' rg -nP "webpack|turbopack|\?url|pdf\.worker" next.config.* 2>/dev/null rg -nP "GlobalWorkerOptions|pdf\.worker" -g '!**/node_modules/**' # Check installed pdfjs-dist version and worker file presence cat package.json | jq '.dependencies["pdfjs-dist"], .devDependencies["pdfjs-dist"]' fd -t f 'pdf.worker' node_modules/pdfjs-dist 2>/dev/null | headRepository: Deen-Bridge/dnb-frontend
Length of output: 272
🌐 Web query:
Next.js webpack import asset with ?url query support💡 Result:
In Next.js, importing assets with a?url query parameter—a feature common in pure Vite or Webpack projects to force an asset to be treated as a URL—is not a built-in standard pattern, as Next.js manages static assets through its own specific mechanisms [1][2]. Instead of using webpack-specific query suffixes, you should use the following approaches to handle assets as URLs or imports: 1. Recommended Approach: Static Imports For local assets (images, fonts, etc.), import the file directly. Next.js handles these imports by providing an object that contains the URL, width, and height [3][1][2]. import logo from '../assets/logo.png'; // Access the URL directly via.src
2. Standard Web API: new URL(..., import.meta.url) If you need to treat an asset as a URL (e.g., for Web Workers, WebAssembly, or passing a path to a browser API), the standard, supported way in modern Next.js (including Edge environments) is to use the URL constructor [4][5][6][7]: const assetUrl = new URL('../assets/file.wasm', import.meta.url); console.log(assetUrl.pathname); // Returns the processed public path 3. Webpack Configuration (Advanced) If you specifically require the webpack-style?url behavior for custom file types or legacy integration, you must manually extend the webpack configuration in next.config.js to define an asset module rule [8][9]. However, note that with Next.js 16 defaulting to Turbopack, custom webpack configurations may need to be translated to turbopack.rules or replaced by native support [10][11]. // Example for next.config.js (Webpack only) module.exports = { webpack: (config) => { config.module.rules.push({ test: /.custom-ext$/, type: 'asset/resource', }); return config; }, }; If you are using Turbopack, you should avoid custom webpack logic and use standard imports or the new URL constructor whenever possible to ensure full compatibility [7][10].
Citations:
- 1: https://falytom.com.ng/web-development/nextjs/static-assets
- 2: https://nextjs.org/docs/app/getting-started/images
- 3: vercel/next.js@90be089
- 4: vercel/next.js#63209
- 5: vercel/next.js#38492
- 6: https://nextjs.org/docs/15/app/api-reference/config/next-config-js/urlImports
- 7: https://rikublock.dev/docs/tutorials/nextjs-turbo-wasm/
- 8: https://stackoverflow.com/questions/71325794/module-not-found-invalid-generator-object-asset-modules-plugin-has-been-initia
- 9: vercel/next.js#22581
- 10: https://ishu.dev/post/turbopack-nextjs-16-migration-guide-2026-04-27
- 11: https://oneuptime.com/blog/post/2026-01-24-nextjs-turbopack-compatibility/view
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "== next.config.mjs ==" cat -n next.config.mjs | sed -n '1,220p' echo echo "== BookReaderClient.jsx relevant lines ==" cat -n app/[locale]/dashboard/library/read/[bookid]/BookReaderClient.jsx | sed -n '1,80p' echo echo "== package.json pdfjs-dist / next version ==" jq '.dependencies.next, .dependencies["pdfjs-dist"], .devDependencies.next, .devDependencies["pdfjs-dist"]' package.json echo echo "== pdfjs-dist worker files present? ==" fd -t f 'pdf.worker' node_modules/pdfjs-dist 2>/dev/null | sed -n '1,20p'Repository: Deen-Bridge/dnb-frontend
Length of output: 4453
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "== search for ?url and resourceQuery rules ==" rg -n --hidden --glob '!node_modules/**' '\?url|resourceQuery|asset/resource|new URL\(' . echo echo "== next.config.mjs file contents around webpack config ==" sed -n '1,120p' next.config.mjsRepository: Deen-Bridge/dnb-frontend
Length of output: 1382
Use a Next-compatible worker URL
pdfjs-dist/build/pdf.worker.min.js?urlrelies on Vite-style query handling, but this Next.js setup doesn’t add any asset rule for it. Switch tonew URL(..., import.meta.url)or an explicit worker/asset rule soGlobalWorkerOptions.workerSrcresolves to a real URL and PDF rendering stays reliable.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/dashboard/library/read/[bookid]/BookReaderClient.jsx around lines 19 - 21, Update the worker source setup near GlobalWorkerOptions.workerSrc to use a Next-compatible URL resolution approach instead of importing pdf.worker.min.js with the Vite-style ?url query. Ensure GlobalWorkerOptions.workerSrc receives a real emitted worker URL and preserve the existing PDF rendering behavior.Source: Linters/SAST tools
app/[locale]/dashboard/messages/layout.js (2)
5-12: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash # Inspect routing config + confirm the locale-aware navigation helpers are exported. fd -t f 'routing.(js|ts)' i18n 2>/dev/null -x cat -n fd -t f 'navigation.(js|ts)' i18n 2>/dev/null -x cat -n # See how other files consume usePathname vs the i18n helper rg -nP "usePathname" --type=js --type=jsx -g '!node_modules' -C1Repository: Deen-Bridge/dnb-frontend
Length of output: 645
🌐 Web query:
next-intl usePathname next/navigation locale prefix included💡 Result:
When using the
next-intlnavigation API, theusePathnamehook returns the pathname without the locale prefix [1]. For example, if a user is visiting/en/about,usePathname()will return/about[1]. This behavior ensures that your components remain agnostic of the locale prefix, simplifying logic for active state detection or link generation [2][1]. ### Key Details * Implementation: You must use theusePathnameexported from your configurednext-intlnavigation file (e.g.,import {usePathname} from '@/i18n/navigation'), rather than the one fromnext/navigation[1][3]. * Locale Prefix Handling: Thenext-intlwrapper handles the stripping of the prefix automatically [3]. If you are using thepathnamesfeature, the returned value will correspond to the internal, non-localized pathname template [1]. * Reconstruction: If you need to construct a URL that includes the locale prefix, use thegetPathnamefunction, which is also provided by the samenext-intlnavigation configuration [1][3]. Example usage:tsx 'use client'; import {usePathname} from '`@/i18n/navigation`'; export default function MyComponent() { const pathname = usePathname(); // e.g., "/about" return <div>Current path: {pathname}</div>; }Citations:
- 1: https://github.com/amannn/next-intl/blob/main/docs/src/pages/docs/routing/navigation.mdx
- 2: https://github.com/aymericzip/intlayer/blob/main/docs/blog/en/i18n_using_next-intl.md
- 3: https://next-intl.dev/docs/routing/navigation
🏁 Script executed:
#!/bin/bash set -euo pipefail # Show the target file with line numbers. if [ -f "app/[locale]/dashboard/messages/layout.js" ]; then cat -n "app/[locale]/dashboard/messages/layout.js" fi # Inspect the i18n navigation setup and routing one more time. echo "--- i18n/routing.js ---" if [ -f "i18n/routing.js" ]; then cat -n "i18n/routing.js" fi echo "--- i18n/navigation.js ---" if [ -f "i18n/navigation.js" ]; then cat -n "i18n/navigation.js" fiRepository: Deen-Bridge/dnb-frontend
Length of output: 3171
Use the locale-aware pathname hook here Import
usePathnamefrom@/i18n/navigationinstead ofnext/navigationso the path comparison ignores the locale prefix. With the current import,/ar/dashboard/messageswon’t match"/dashboard/messages", so the sidebar/chat toggle breaks on the Arabic route.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/dashboard/messages/layout.js around lines 5 - 12, Update the Layout component’s usePathname import to use the locale-aware hook from `@/i18n/navigation`, preserving the existing isInChat comparison so locale-prefixed routes are normalized before checking the dashboard messages path.Source: Path instructions
9-31: 🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win
hasConversationsis set but never read — and the fetch behind it is expensive. Nothing in the returned JSX consumeshasConversations, so this whole effect is dead weight. Worse,fetchUserConversationseagerly reads every conversation plus each conversation's entiremessagessubcollection (seelib/actions/messages/fetchConversations.js) just to compute a boolean that's discarded — that's a lot of Firestore reads on every mount of the messages shell.There's also a latent hang:
isLoadingis only cleared inside this effect, which early-returns whenuser?._idis falsy, so if the id never resolves theLoadershows forever.If the flag really is unused, drop the state and the fetch (and gate the loader on auth resolution instead). If you do need "has any conversation", prefer a lightweight count/existence query rather than hydrating all messages.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/dashboard/messages/layout.js around lines 9 - 31, Remove the unused hasConversations state and the checkConversations effect that calls fetchUserConversations. Update the loader logic in the layout to depend on the auth-resolution state rather than isLoading being cleared by a user-dependent effect, ensuring it cannot remain visible when user._id is unavailable; if the flag is required elsewhere, replace the fetch with a lightweight conversation existence query.app/[locale]/dashboard/search/[searchparam]/page.jsx (2)
56-68: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win
Client-component
paramsis a Promise in Next.js 15 — unwrap it withuse().Since this file is
"use client", Next.js 15 passesparamsas a Promise, soparams?.searchparamreads a non-existent property and evaluates toundefined. TheuseEffectthen early-returns onif (!searchparam)and the search request never fires — the page always shows "No results found." Your siblingaccount/profile/[profileid]/page.jsxalready uses the correctuse(params)pattern; mirroring it fixes this.🔧 Suggested fix
-import React, { useEffect, useState } from "react"; +import React, { use, useEffect, useState } from "react"; ... const Page = ({ params }) => { - const searchparam = params?.searchparam || ""; + const { searchparam = "" } = use(params);As per path instructions: "Flag use of deprecated patterns (synchronous params/cookies, pages-router idioms)".
📝 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.import React, { use, useEffect, useState } from "react"; const Page = ({ params }) => { const { searchparam = "" } = use(params); const [results, setResults] = useState([]); const [loading, setLoading] = useState(false); useEffect(() => { if (!searchparam) return; setLoading(true); searchQuery(searchparam) .then((data) => setResults(data)) .catch(() => setResults([])) .finally(() => setLoading(false)); }, [searchparam]);🧰 Tools
🪛 ast-grep (0.44.1)
[warning] 64-64: Avoid using the initial state variable in setState
Context: setResults(data)
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.(setstate-same-var)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/dashboard/search/[searchparam]/page.jsx around lines 56 - 68, Update the client component Page to unwrap the Promise-based params with React’s use() before reading searchparam, mirroring the existing pattern in the sibling profile page. Replace the synchronous params?.searchparam access while preserving the current useEffect searchQuery flow and loading/result behavior.Source: Path instructions
259-271: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win
reelresults will crash the page —typeLinks/typeLabelshave noreelkey.The card renders a dedicated
reelbranch (Line 259), buttypeLinksandtypeLabels(Lines 9-21) only definecourse,book,user,space. For a reel item,typeLinks[item.type]isundefined, sotypeLinks[item.type](item.id)throwsTypeError: typeLinks.reel is not a functionduring render — and because it's insideresults.map, a single reel result blanks the entire results grid. Please add areelentry (or guard the link).🛡️ Suggested fix (add reel mappings + guard)
const typeLabels = { course: "Course", book: "Book", user: "User", space: "Space", + reel: "Reel", }; const typeLinks = { course: (id) => `/dashboard/courses/${id}`, book: (id) => `/dashboard/library/${id}`, user: (id) => `/account/profile/${id}`, space: (id) => `/dashboard/spaces/${id}`, + reel: (id) => `/dashboard/reels/${id}`, };And defensively skip the link if the type is unknown:
- <Link - href={typeLinks[item.type](item.id)} + {typeLinks[item.type] && ( + <Link + href={typeLinks[item.type](item.id)} className="block w-full text-center px-4 py-2 rounded-full bg-accent text-white text-sm font-semibold shadow hover:bg-highlight transition-colors mt-2" > View {typeLabels[item.type]} - </Link> + </Link> + )}📝 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.{item.type === "reel" && ( <> <p className="text-sm text-muted-foreground line-clamp-2 mb-2"> {item.description} </p> </> )} {typeLinks[item.type] && ( <Link href={typeLinks[item.type](item.id)} className="block w-full text-center px-4 py-2 rounded-full bg-accent text-white text-sm font-semibold shadow hover:bg-highlight transition-colors mt-2" > View {typeLabels[item.type]} </Link> )}🧰 Tools
🪛 ast-grep (0.44.1)
[warning] 155-271: A list component should have a key to prevent re-rendering
Context:
{/* Detailed rendering by type */}
{item.type === "course" && (
<>
{item.description}
{item.price !== undefined && (
{item.price ?$${item.price}: "Free"}
)}
</>
)}
{item.type === "book" && (
<>
{item.description}
{item.category && (
{item.category}
)}
{item.price !== undefined && (
{item.price ?$${item.price}: "Free"}
)}
{item.author && (
By{" "}
{typeof item.author === "object"
? item.author.name
: item.author}
)}
</>
)}
{item.type === "user" && (
<>
{item.role && (
Role: {item.role}
)}
</>
)}
{item.type === "space" && (
<>
{item.description}
{item.status && (
{item.status.toUpperCase()}
)}
{item.price !== undefined && (
{item.price ?$${item.price}: "Free"}
)}
{item.eventDate && (
Event: {formatDate(item.eventDate)}
)}
{item.duration && (
Duration: {item.duration} min
)}
{item.host && (
Host:{" "}
{typeof item.host === "object"
? item.host.name
: item.host}
)}
</>
)}
{item.type === "reel" && (
<>
{item.description}
</>
)}
View {typeLabels[item.type]}
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.(list-component-needs-key)
[warning] 259-263: A list component should have a key to prevent re-rendering
Context: <>
{item.description}
</>
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.(list-component-needs-key)
[warning] 260-262: A list component should have a key to prevent re-rendering
Context:
{item.description}
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.(list-component-needs-key)
[warning] 265-270: A list component should have a key to prevent re-rendering
Context:
View {typeLabels[item.type]}
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.(list-component-needs-key)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/dashboard/search/[searchparam]/page.jsx around lines 259 - 271, Update the typeLinks and typeLabels mappings used by the results card to include a reel entry matching the application’s reel destination and display label, so the existing View link works for reel items. Also guard the link rendering against unsupported item types before calling typeLinks[item.type](item.id), while preserving the current mappings and rendering for known types.app/[locale]/dashboard/spaces/[spacesid]/page.jsx (1)
43-45: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Guard
space.statusbefore.toUpperCase().Unlike the price/host fields,
space.statusis dereferenced without a guard, so a space missingstatuswill crash this server-rendered page with aTypeError(→ 500). A fallback keeps the badge resilient.🛡️ Suggested guard
- <Badge variant="accent" className="bg-white/10 text-highlight"> - {space.status.toUpperCase()} - </Badge> + {space.status && ( + <Badge variant="accent" className="bg-white/10 text-highlight"> + {space.status.toUpperCase()} + </Badge> + )}📝 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.{space.status && ( <Badge variant="accent" className="bg-white/10 text-highlight"> {space.status.toUpperCase()} </Badge> )}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/dashboard/spaces/[spacesid]/page.jsx around lines 43 - 45, Update the status rendering in the Badge component to guard space.status before calling toUpperCase, and render a safe fallback when status is missing. Preserve the existing uppercase display for defined status values.app/[locale]/profile-setup/page.jsx (1)
10-20: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash set -euo pipefail printf '\n== file list ==\n' git ls-files 'app/[locale]/profile-setup/*' 'app/**/StepTwo*' 'app/**/useAuth*' 'app/**/auth*' | sed 's#^`#-` #' printf '\n== outline page ==\n' ast-grep outline app/[locale]/profile-setup/page.jsx --view expanded || true printf '\n== page contents ==\n' cat -n app/[locale]/profile-setup/page.jsx | sed -n '1,220p' printf '\n== search for updateUser and user._id ==\n' rg -n "updateUser\\(|user\\._id|useAuth|auth loading|loading|unauthenticated|redirect\\(" app --glob '!**/node_modules/**' || trueRepository: Deen-Bridge/dnb-frontend
Length of output: 8990
🏁 Script executed:
#!/bin/bash set -euo pipefail printf '\n== locate profile setup step-two and auth hook ==\n' fd -a 'step-two.*|useAuth.*' app components src . 2>/dev/null | sed 's#^`#-` #' printf '\n== ast outline for step-two candidates ==\n' for f in $(fd -a 'step-two.*' app components src 2>/dev/null | head -n 5); do echo "--- $f" ast-grep outline "$f" --view expanded || true done printf '\n== ast outline for useAuth candidates ==\n' for f in $(fd -a 'useAuth.*' app components src hooks 2>/dev/null | head -n 5); do echo "--- $f" ast-grep outline "$f" --view expanded || true done printf '\n== read step-two and hook snippets ==\n' for f in $(fd -a 'step-two.*' app components src 2>/dev/null | head -n 5); do echo "--- $f" wc -l "$f" cat -n "$f" | sed -n '1,260p' done for f in $(fd -a 'useAuth.*' app components src hooks 2>/dev/null | head -n 5); do echo "--- $f" wc -l "$f" cat -n "$f" | sed -n '1,260p' doneRepository: Deen-Bridge/dnb-frontend
Length of output: 17949
Guard profile setup until
useris available.
StepTwocallsupdateUser(user._id, ...), but this page renders the wizard before auth has settled. Ifuseris still null, the final submit will throw. Use theuseAuthloading/auth state to gate the wizard or disable submission until a user exists.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/profile-setup/page.jsx around lines 10 - 20, Update ProfileSetupPage to consume useAuth and prevent the setup wizard, especially StepTwo submission, from rendering or being usable while authentication is loading or user is unavailable. Render the wizard only once a valid user exists, preserving the existing step navigation and form behavior for authenticated users.Source: Path instructions
messages/ar.json (1)
12-13: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Keep the locale catalogs schema-compatible.
messages/en.jsondefinesauth.dashboard,auth.login, andauth.signup, butmessages/ar.jsonhas noauthnamespace. Add Arabic translations for those keys or implement the fallback described ini18n/request.js.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@messages/ar.json` around lines 12 - 13, Add the missing auth namespace to the Arabic locale catalog, including auth.dashboard, auth.login, and auth.signup with Arabic translations matching the English catalog schema; preserve the existing dashboard translations and key structure.
|
Thank you for your work here, @Ayinkx. This PR has been inactive for ~3+ weeks, so we're reclaiming #104 for the current campaign — and the issue description has been substantially refreshed with a clearer, more detailed spec and acceptance criteria. Closing this PR for now so the issue can be reassigned. You're very welcome to apply for another open campaign issue, and if you'd like to pick this one back up, please reach out to the maintainers. JazakumAllahu khayran 🙏 |
Closes #104
Added locale routing, Arabic RTL document direction/font, locale switchers, message catalogs, and RTL logical-property fixes.
Localized key landing/dashboard shell surfaces and preserved LTR Stellar values.
Summary by CodeRabbit
New Features
Style