Skip to content
This repository was archived by the owner on Nov 23, 2025. It is now read-only.

Dev#37

Merged
RandithaK merged 40 commits intomainfrom
dev
Nov 23, 2025
Merged

Dev#37
RandithaK merged 40 commits intomainfrom
dev

Conversation

@RandithaK
Copy link
Member

@RandithaK RandithaK commented Nov 23, 2025

Summary by CodeRabbit

  • New Features

    • Implemented centralized theme system with light/dark mode support and semantic color tokens.
    • Added toast-based notifications for user feedback across all operations.
    • Integrated AI chat widget for customers in dashboard.
  • Bug Fixes

    • Fixed editable fields in vehicle editing form.
    • Improved error message clarity with better extraction from server responses.
  • Documentation

    • Updated README with environment and theming guidance.
  • Style

    • Replaced hardcoded colors with centralized theme classes throughout the app.
    • Updated branding from "TechTorque Auto" to "TechTorque."

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

RandithaK and others added 30 commits November 15, 2025 13:52
feat: enhance PayHere payment object with additional fields and logging
style: remove demo user information from login page
- Updated VehicleCard component to use theme classes for color and button styles.
- Refactored AIChatWidget to streamline state management and improve UI consistency with theme variables.
- Modified AdminDashboard, CustomerDashboard, EmployeeDashboard, and SuperAdminDashboard to replace hardcoded styles with theme classes.
- Enhanced AppointmentDetailPage and layout components to improve toast handling and navigation styles.
- Updated VehiclesPage and ProfilePhotoUpload components to utilize theme classes for loading indicators and alerts.
- Added new CSS classes for navigation items and progress bars to maintain design consistency across the application.
…ent classes in VehicleDetailsPage and Home components
…ading features, and update ReportResponse interface for improved data handling
@vercel
Copy link

vercel bot commented Nov 23, 2025

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

Project Deployment Preview Comments Updated (UTC)
techtorque Ready Ready Preview Comment Nov 23, 2025 4:01pm

@coderabbitai
Copy link

coderabbitai bot commented Nov 23, 2025

Walkthrough

This PR implements a centralized theming system with design tokens to replace hardcoded Tailwind colors, introduces a toast notification system across the dashboard, refactors the AI chat component to use a centralized API client, and adds validation scripts to enforce theme compliance.

Changes

Cohort / File(s) Summary
Theme System & Global Setup
src/app/globals.css, src/app/layout.tsx, src/app/page.tsx
Extensive CSS additions defining light/dark mode design tokens (colors, borders, backgrounds, status alerts), new semantic utility classes (theme-bg-*, theme-text-*, theme-alert-*), updated automotive-card styling, theme initialization script with pre-hydration FOUC prevention, and ThemeToggle component import.
Theme Validation & Documentation
scripts/check-hardcoded-colors.js, scripts/check-theme-setup.js, package.json, README.md
Two new Node.js scripts to validate theme setup and detect hardcoded colors in the codebase; new npm scripts (check:colors, check:theme) added; documentation updates describing centralized theming approach.
AI Chat System Refactor
src/app/components/chatbot/AIChatWidget.tsx, src/lib/apiClient.ts
AIChatWidget rewritten to use centralized apiClient instead of direct fetch; improved error handling with status-driven messages; apiClient enhanced with error message extraction and redirect guards for auth endpoints.
Toast Notification System
src/components/Toast.tsx, src/hooks/useToast.ts
New Toast component with auto-dismiss and type-based styling; useToast hook providing showToast, success, error, info, warning methods; type declarations for ToastType and ToastMessage.
Dashboard Layout & Integration
src/app/dashboard/layout.tsx, src/app/dashboard/appointments/\*, src/app/dashboard/payments/page.tsx, src/app/dashboard/invoices/page.tsx, src/app/dashboard/services/page.tsx, src/app/dashboard/projects/\*, src/app/dashboard/time-logs/page.tsx, src/app/dashboard/vehicles/\*, src/app/dashboard/schedule/page.tsx
Integrated AIChatWidget as customer-facing floating chat panel; replaced alert-based feedback with toast notifications; updated UI classes to semantic theme tokens (stat-card, filter-tabs-container, theme-alert-*); enhanced report generation workflow with download capability.
Authentication Pages Theme Migration
src/app/auth/login/page.tsx, src/app/auth/register/page.tsx, src/app/auth/forgot-password/page.tsx, src/app/auth/otp-verify/page.tsx, src/app/auth/resend-verification/page.tsx, src/app/auth/reset-password/page.tsx, src/app/auth/verify-email/page.tsx
Removed unused Icon/BoltIcon components; replaced BoltIcon with simpler TT badge using automotive-accent styling; updated site title from "TechTorque Auto" to "TechTorque"; replaced error text colors with theme-text-danger.
Component Theme Migrations
src/app/admin/page.tsx, src/app/components/AddVehicleForm.tsx, src/app/components/EditVehicleForm.tsx, src/app/components/VehicleCard.tsx, src/app/components/NotificationBell.tsx, src/app/components/PaymentGateway.tsx, src/app/components/RoleSwitcher.tsx, src/components/ProfilePhotoUpload.tsx, src/components/TimeTracker.tsx
Replaced hardcoded Tailwind color utilities with semantic theme classes (theme-alert-*, theme-button-*, theme-text-*, theme-bg-*); updated form inputs to use theme-input; enhanced NotificationBell with local error state; added toast integration to TimeTracker and ProfilePhotoUpload.
Dashboard Components Theme Migrations
src/app/components/dashboards/AdminDashboard.tsx, src/app/components/dashboards/CustomerDashboard.tsx, src/app/components/dashboards/EmployeeDashboard.tsx, src/app/components/dashboards/SuperAdminDashboard.tsx
Replaced error/status alert styling with theme-alert-* classes; updated border and text colors to theme tokens; removed AIChatWidget from CustomerDashboard (moved to layout); consolidated stat cards to stat-card structure.
Admin Dashboard Pages
src/app/dashboard/admin/page.tsx, src/app/dashboard/admin/audit-logs/page.tsx, src/app/dashboard/admin/service-types/page.tsx, src/app/dashboard/admin/users/page.tsx, src/app/dashboard/admin/reports/page.tsx
Replaced skeleton and card styling with theme tokens (theme-bg-tertiary, dashboard-content-card); added toast-based feedback for create/update/delete/toggle operations; enhanced report generation with fetch, download, and refresh capabilities; updated filter UI to filter-tabs-container with active/inactive states.
Service Layer Enhancements
src/services/adminService.ts, src/services/appointmentService.ts, src/services/authService.ts, src/services/projectService.ts, src/services/payhereService.ts, src/contexts/NotificationContext.tsx
Normalized API response handling to support multiple payload shapes; enhanced error handling with AxiosError extraction and user-friendly messages; added error tracking to NotificationContext; improved PayHere payload logging.
Type Updates
src/types/admin.ts
Updated ReportRequest interface (renamed reportType → type, from → fromDate, to → toDate; added optional title); expanded ReportResponse with generatedBy, downloadUrl, fileSize, data, errorMessage, isScheduled; status now includes GENERATING.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Theme as Theme Init Script
    participant React
    participant LocalStorage
    participant CSS as CSS Variables

    User->>Browser: Load page
    Theme->>LocalStorage: Check theme preference
    Theme->>CSS: Apply theme tokens to document
    Theme->>React: Hydrate (no FOUC)
    React->>CSS: Apply semantic classes
    CSS-->>User: Render with theme
    User->>React: Toggle theme
    React->>LocalStorage: Save preference
    React->>CSS: Update CSS variables
    CSS-->>User: Re-render with new theme
Loading
sequenceDiagram
    actor User
    participant Chat as Floating Chat Button
    participant AIChatWidget as Chat Widget
    participant apiClient as API Client
    participant Backend as Backend

    User->>Chat: Click chat button
    Chat->>AIChatWidget: Open chat panel
    User->>AIChatWidget: Type message
    AIChatWidget->>apiClient: post(/ai/chat)
    apiClient->>Backend: Send message + token
    Backend-->>apiClient: ChatResponse
    apiClient->>AIChatWidget: Typed response
    AIChatWidget->>AIChatWidget: Handle session_id
    AIChatWidget->>AIChatWidget: Display message
    Note over AIChatWidget: On error: extract<br/>status-driven message<br/>show system message
    AIChatWidget-->>User: Render in chat
Loading
sequenceDiagram
    actor User
    participant Component as Page Component
    participant useToast as useToast Hook
    participant Toast as Toast Component
    participant Display as DOM

    Component->>useToast: Call success(msg)
    useToast->>useToast: Generate toast id
    useToast->>useToast: Append to toasts array
    useToast-->>Component: Updated toasts
    Component->>Toast: Render ToastContainer
    Toast->>Display: Show toast at top-right
    Toast->>Toast: Auto-dismiss after 5s
    Toast->>useToast: Call closeToast(id)
    useToast->>useToast: Remove from array
    Display->>Display: Remove from DOM
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Areas requiring close attention:

  • src/app/components/chatbot/AIChatWidget.tsx — Substantial refactor from fetch-based to apiClient-driven; error handling and message typing changes; requires validation of ChatResponse shape compatibility and backward compatibility with backend API contract.
  • src/app/globals.css — Extensive token definitions for light/dark modes; verify CSS variable naming consistency, shadow/color token coverage, and that no tokens conflict with existing Tailwind classes.
  • src/lib/apiClient.ts — Enhanced error extraction and response interceptor logic with redirect guards; ensure extractShortErrorMessage handles all expected server payload shapes and that login redirects don't break on-login flows.
  • src/app/layout.tsx — Theme pre-hydration script must run before React hydration; verify script placement, error handling, and that suppressHydrationWarning is appropriate.
  • Toast integration across dashboard pages — Multiple pages now depend on useToast and ToastContainer; verify consistent error/success message handling and that all async operations properly wire toast calls.
  • NotificationContext.tsx — Added error field and AxiosError handling; ensure error extraction logic is consistent across all async methods and that context consumers handle the new error field gracefully.
  • Type changes in admin.ts — ReportRequest/ReportResponse interface changes (renamed fields, new status GENERATING); verify all callsites (components, services, backend integration) use correct field names.
  • Response normalization in services — Multiple service files now handle varying API response shapes (data, data.data, data.content); ensure fallback logic covers all observed backend response patterns and doesn't mask legitimate null/undefined.

Possibly related PRs

  • Dev #26 — Modifies src/app/components/chatbot/AIChatWidget.tsx for message types, token handling, and request flow; integrates chat into dashboard layout (overlaps with core AI chat refactor).
  • Dev #11 — Modifies Toast/useToast, vehicle form components, payment UI, and dashboard pages (direct overlap with toast system integration and form styling changes).
  • Dev #18 — Adds runtime-config and NotificationContext/NotificationProvider rewiring; modifies apiClient and dashboard chat integration (overlaps with notification and API client enhancements).

Poem

🎨 A rabbit hops through themes so bright,
From dark to light with CSS might,
Toast notifications pop and fade,
A chat widget blooms, design parade!
TechTorque's colors, now unified—
The codebase sings with tokens applied! 🐰✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.28% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'Dev' is vague and generic, providing no meaningful information about the changeset's primary objectives or contents. Use a descriptive title that summarizes the main change, such as 'Implement centralized theme system and add toast notifications' or 'Refactor styling to use semantic theme tokens'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dev

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

❤️ Share

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

@RandithaK RandithaK merged commit cd985e1 into main Nov 23, 2025
5 of 6 checks passed
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 10

Caution

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

⚠️ Outside diff range comments (6)
src/services/payhereService.ts (1)

124-134: Critical: Remove or redact sensitive data from logs.

Logging the payment hash (line 130) and the full payment object (line 134) exposes sensitive security tokens and PII that create serious risks:

  • Security risk: The hash is a cryptographic token for payment verification; exposing it in logs could enable replay attacks or tampering if logs are compromised.
  • Compliance violation: Logging customer PII (email, phone, address, names) violates GDPR, CCPA, and other privacy regulations, potentially resulting in significant fines.
  • Data breach exposure: Logs often flow to monitoring services, log aggregators, or filesystem storage with broader access than production databases.

Apply this diff to remove sensitive fields from logs:

     console.log('Starting PayHere payment:', {
       sandbox: payment.sandbox,
       orderId: payment.order_id,
       amount: payment.amount,
-      merchantId: payment.merchant_id,
       currency: payment.currency,
-      hash: payment.hash,
-      customerEmail: payment.email
     });

-    console.log('Full PayHere payment object:', payment);

If detailed logging is required for debugging, consider:

  1. Using a debug flag to conditionally log (disabled in production)
  2. Redacting sensitive fields before logging
  3. Logging only to secure, access-controlled destinations

Example with conditional logging:

if (process.env.NODE_ENV === 'development') {
  console.log('Starting PayHere payment:', {
    sandbox: payment.sandbox,
    orderId: payment.order_id,
    amount: payment.amount,
    currency: payment.currency,
  });
}
src/app/dashboard/appointments/book/page.tsx (1)

108-151: Inconsistent service type payload format.

Lines 110 and 148 send different formats for serviceType:

  • Line 110 (checkAvailability): sends form.serviceTypeId (ID)
  • Line 148 (bookAppointment): sends selectedServiceType?.name || '' (name string)

The AI summary indicates both should use IDs for consistency. This mismatch could cause issues if the backend expects uniform data types.

Apply this diff to use IDs consistently:

 await appointmentService.bookAppointment({
   vehicleId: form.vehicleId,
-  serviceType: selectedServiceType?.name || '',
+  serviceType: form.serviceTypeId,
   requestedDateTime: requestedDateTime,
   specialInstructions: form.notes || undefined,
 })
src/app/contexts/NotificationContext.tsx (1)

198-227: Align toast notification styling with centralized theming system.

The toast notification uses hardcoded Tailwind color classes (bg-green-50, border-green-200, etc.), which is inconsistent with the PR's objective to implement a centralized theming system. Other components in this PR use theme-alert-* classes.

Consider updating to use theme classes:

-          <div className={`
-            max-w-sm p-4 rounded-lg shadow-lg border
-            ${toastNotification.type === 'SUCCESS' ? 'bg-green-50 border-green-200' : ''}
-            ${toastNotification.type === 'INFO' ? 'bg-blue-50 border-blue-200' : ''}
-            ${toastNotification.type === 'WARNING' ? 'bg-yellow-50 border-yellow-200' : ''}
-            ${toastNotification.type === 'ERROR' ? 'bg-red-50 border-red-200' : ''}
-          `}>
+          <div className={`
+            max-w-sm p-4 rounded-lg shadow-lg
+            ${toastNotification.type === 'SUCCESS' ? 'theme-alert-success' : ''}
+            ${toastNotification.type === 'INFO' ? 'theme-alert-info' : ''}
+            ${toastNotification.type === 'WARNING' ? 'theme-alert-warning' : ''}
+            ${toastNotification.type === 'ERROR' ? 'theme-alert-danger' : ''}
+          `}>
src/components/TimeTracker.tsx (1)

102-179: ToastContainer missing in active timer state.

The ToastContainer is only rendered in the non-active state (Line 105) but not in the active timer state (lines 125-179). This means the success toast triggered on clock-out (Line 84) won't be visible to users. The component should render ToastContainer in both states.

Apply this fix to ensure toasts display in all states:

   return (
     <div className="space-y-4">
+      <ToastContainer toasts={toasts} onClose={closeToast} />
       {error && (
         <div className="theme-alert-danger text-sm">
src/app/components/dashboards/CustomerDashboard.tsx (1)

183-212: Fix invalid Tailwind syntax for CSS variable usage.

The hover border styling uses invalid syntax: hover:border-(--accent-primary). This is not valid Tailwind CSS and will not work. Tailwind doesn't support this syntax for CSS variables.

Apply this diff to fix the syntax:

          <Link
            href="/dashboard/vehicles"
-           className="p-4 border theme-border rounded-lg hover:border-(--accent-primary) transition-colors text-center"
+           className="p-4 border theme-border rounded-lg hover:border-blue-500 dark:hover:border-blue-400 transition-colors text-center"
          >
-           <svg className="mx-auto w-12 h-12 mb-2 theme-text-muted" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
+           <svg className="mx-auto w-12 h-12 mb-2 theme-text-primary" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M3 12l1.5-4.5A2 2 0 0 1 6.4 6h11.2a2 2 0 0 1 1.9 1.5L21 12" />
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M5 18a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zM19 18a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z" />
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M3 12h18v2H3v-2z" />
            </svg>
            <p className="theme-text-primary font-medium">Vehicles</p>
          </Link>
          <Link
            href="/dashboard/appointments"
-           className="p-4 border theme-border rounded-lg hover:border-(--accent-primary) transition-colors text-center"
+           className="p-4 border theme-border rounded-lg hover:border-blue-500 dark:hover:border-blue-400 transition-colors text-center"
          >
            <svg className="mx-auto w-12 h-12 mb-2 theme-text-primary" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
            </svg>
            <p className="theme-text-primary font-medium">Appointments</p>
          </Link>
          <Link
            href="/dashboard/projects"
-           className="p-4 border theme-border rounded-lg hover:border-(--accent-primary) transition-colors text-center"
+           className="p-4 border theme-border rounded-lg hover:border-blue-500 dark:hover:border-blue-400 transition-colors text-center"
          >
            <svg className="mx-auto w-12 h-12 mb-2 theme-text-primary" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M3 7h18M3 12h18M3 17h18" />
            </svg>
            <p className="theme-text-primary font-medium">Projects</p>
          </Link>
          <Link
            href="/profile"
-           className="p-4 border theme-border rounded-lg hover:border-(--accent-primary) transition-colors text-center"
+           className="p-4 border theme-border rounded-lg hover:border-blue-500 dark:hover:border-blue-400 transition-colors text-center"
          >
            <svg className="mx-auto w-12 h-12 mb-2 theme-text-primary" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
            </svg>
            <p className="theme-text-primary font-medium">Profile</p>
          </Link>

Note: If you want to use CSS variables for theming, you'll need to use arbitrary values like hover:border-[var(--accent-primary)], but ensure the variable is defined in your CSS.

src/app/dashboard/time-logs/page.tsx (1)

181-213: Watch for NaN in hours state and consider tightening table empty-state logic

  • For the “Hours Worked” field, onChange does parseFloat(e.target.value) and stores it directly, while the value prop is formData.hours || ''. If the user clears the field, parseFloat('') becomes NaN, which then lives in state (even though the displayed value falls back to ''). That could result in NaN being submitted if HTML validation is bypassed. A small guard like:
const value = parseFloat(e.target.value);
setFormData({ 
  ...formData, 
  hours: Number.isNaN(value) ? 0 : value,
});

would keep the state consistent.

  • In the table body, there’s a nested filteredLogs.length === 0 check inside a branch that only renders when filteredLogs.length !== 0 (outer ternary at Lines 314–327), so that inner branch is effectively dead code. It’s harmless but can be removed to simplify the JSX.

Also applies to: 235-261, 341-372

🧹 Nitpick comments (24)
src/services/appointmentService.ts (1)

31-33: Response normalization is reasonable; consider centralizing it

The listAppointments and getAppointmentDetails guards (res.data.data || res.data, plus Array.isArray and data.content fallback) should handle the common response wrappers safely and always return an array / DTO as promised.

Given similar patterns exist in other services, consider extracting a small helper (e.g., normalizeListResponse(res) / unwrapData(res)) to avoid copy‑pasting these checks in multiple places.

Also applies to: 37-38

src/app/auth/otp-verify/page.tsx (1)

7-8: OTP header branding matches the new pattern; consider minor readability tweak

The new “TT” automotive-accent logo and “TechTorque” brand text align nicely with the other auth pages. The entire <Link> tree on Line 42 is inlined, which is a bit dense—splitting the inner <div> and <h1> onto separate lines would improve readability, but it’s not required.

Also applies to: 42-43

src/lib/apiClient.ts (1)

57-141: LGTM! Robust error handling improvements.

The changes significantly improve error handling:

  1. Login redirect guard (lines 57-64): Prevents redirect loops by detecting login requests before removing tokens
  2. Message extraction (lines 67-110): Comprehensive helper handles various API response shapes (detail, message, error, msg) with proper fallbacks
  3. Sanitization (lines 116-121): Single-line, 300-char limit ensures safe display in UI/logs
  4. Enhanced error object (lines 126-141): Preserves axios metadata (status, response, config) for better debugging

These improvements align well with the PR's toast notification system by providing clean, actionable error messages.

Minor note: Line 58 uses .includes('/auth/login') which will match any URL containing that substring. If you have endpoints like /auth/login/refresh or /api/auth/login/verify, they'll also bypass the redirect. This is likely acceptable, but consider using exact matching (=== '/auth/login' or endsWith('/auth/login')) if you need stricter control.

src/app/profile/page.tsx (1)

281-291: Theming updates applied, minor inconsistency noted.

The error and success alerts now use theme-alert-danger and theme-alert-success wrappers, aligning with the centralized theming system. However, the success alert still contains hardcoded color classes on line 288 (text-green-600 dark:text-green-400), which could be replaced with a theme utility class for full consistency.

Optional improvement:

-            <p className="text-sm text-green-600 dark:text-green-400">
+            <p className="text-sm">
               {success}
             </p>

The theme-alert-success wrapper should already handle text color styling.

src/app/auth/login/page.tsx (1)

102-102: Minor: Extraneous empty line.

Line 102 contains an empty line that doesn't appear to serve a formatting purpose in this context. Consider removing it for cleaner code.

src/services/projectService.ts (1)

69-73: Approve normalization, but consider consistency across all methods.

The response normalization in listCustomerProjects is good defensive coding that handles varying API response shapes. However, this normalization pattern is inconsistent with other methods in the same service (e.g., listCustomerServices at line 20, getServiceDetails at line 30) that directly return res.data without normalization.

Consider applying consistent response normalization across all service methods to prevent potential runtime errors if the API response shape varies:

async listCustomerServices(status?: string): Promise<ServiceResponseDto[]> {
  const res = await api.get('/services', { params: { status } });
  const data = res.data.data || res.data;
  return Array.isArray(data) ? data : [];
},
src/hooks/useToast.ts (1)

9-13: Consider more robust ID generation.

Using Math.random().toString(36).substring(7) for ID generation has a small collision risk. While acceptable for toast notifications with short lifetimes, consider using a more robust approach for production code.

Alternative approaches:

Option 1: Use crypto.randomUUID() (modern browsers):

const id = crypto.randomUUID();

Option 2: Use a counter (simpler, guaranteed unique):

let toastIdCounter = 0;
const id = `toast-${++toastIdCounter}`;

Option 3: Timestamp + random (hybrid):

const id = `${Date.now()}-${Math.random().toString(36).substring(7)}`;
src/app/admin/page.tsx (1)

117-121: Remove redundant color classes inside theme wrapper.

Line 118 contains explicit color classes (text-green-600 dark:text-green-400) inside the theme-alert-success wrapper. The semantic theme class should handle all styling to maintain centralized theme control.

Apply this diff to remove the redundant classes:

         {success && (
           <div className="mb-6 theme-alert-success">
-            <p className="text-sm text-green-600 dark:text-green-400">
+            <p className="text-sm">
               {success}
             </p>
           </div>
src/app/dashboard/projects/[projectId]/page.tsx (1)

41-55: Minor syntax issue in finally block.

Line 52 has } finally{ without a space before the opening brace. While this works, it's inconsistent with the codebase style where spaces are used (see lines 67, 84, 105).

-    } finally{
+    } finally {
       setActionLoading(false);
     }
src/app/dashboard/invoices/page.tsx (1)

206-206: Consider performance impact of transition-all.

The hover effect uses transition-all which animates all properties. While this works, it can be less performant than specifying exact properties.

Apply this diff for better performance:

-              className="block rounded-xl border border-gray-200 dark:border-gray-800 hover:border-blue-400 dark:hover:border-blue-500 hover:shadow-lg transition-all"
+              className="block rounded-xl border border-gray-200 dark:border-gray-800 hover:border-blue-400 dark:hover:border-blue-500 hover:shadow-lg transition-[border-color,box-shadow] duration-200"
src/components/Toast.tsx (1)

21-27: Potential issue with useEffect dependencies.

The timer depends on the entire toast object, which could cause the timer to reset unnecessarily if the toast reference changes (even if the content is the same). Consider extracting only the necessary properties.

Apply this diff to optimize the effect:

  useEffect(() => {
    const timer = setTimeout(() => {
      onClose(toast.id);
-   }, toast.duration || 5000);
+   }, toast.duration ?? 5000);

    return () => clearTimeout(timer);
- }, [toast, onClose]);
+ }, [toast.id, toast.duration, onClose]);
src/app/dashboard/services/page.tsx (1)

141-141: Consider specifying transition properties.

Similar to the invoices page, transition-all can be less performant than specifying exact properties.

Apply this diff for better performance:

-            className="block rounded-xl border border-gray-200 dark:border-gray-800 hover:border-blue-400 dark:hover:border-blue-500 hover:shadow-lg transition-all"
+            className="block rounded-xl border border-gray-200 dark:border-gray-800 hover:border-blue-400 dark:hover:border-blue-500 hover:shadow-lg transition-[border-color,box-shadow] duration-200"
src/app/dashboard/vehicles/page.tsx (1)

8-9: Toast integration is sound; consider unifying error UX.

useToast is wired correctly (aliasing error as showError), and wiring ToastContainer at the page level cleanly scopes vehicle toasts. You might optionally route the initial load error (setError) through a toast as well for a more consistent feedback pattern between fetch, delete, and other actions.

Also applies to: 12-13, 37-45, 65-68

src/app/dashboard/layout.tsx (1)

152-186: Customer chat toggle works; consider tightening role gating and responsiveness.

The fixed chat launcher/panel wiring with chatOpen and AIChatWidget is straightforward and correctly gated on customer presence. If you want stricter behavior, you might gate purely on activeRole === 'CUSTOMER', and for very small viewports consider making the panel width/height responsive (e.g., max-w-[480px] w-full h-[60vh] max-h-[600px]) to avoid overflow.

src/app/components/dashboards/AdminDashboard.tsx (1)

59-63: Theming updates are consistent; inline accent override is reasonable.

Swapping to theme-alert-danger, theme-border, theme-text-info, and theme-bg-*/theme-bg-accent keeps the existing UX while aligning with the token system. The extra backgroundColor: 'var(--accent-primary)' on the revenue bar is slightly redundant with theme-bg-accent but fine if you want to guarantee the CSS variable accent; you could centralize that in the class later if desired.

Also applies to: 140-151, 176-180

src/app/dashboard/admin/users/page.tsx (3)

9-15: Toast-based feedback is well integrated; consider centralizing error parsing.

useToast is wired cleanly (success + showError) and you now surface meaningful messages for create, role edits, validation, and status toggles, which is a solid UX improvement. The custom extraction of API error messages in handleCreateUser (and the simpler patterns in other handlers) could eventually be pulled into a small shared helper (e.g., getApiErrorMessage(err, defaultMessage)) to avoid duplicating error-shape checks across pages.

Also applies to: 58-63, 69-80, 85-99, 112-129, 132-137, 145-163, 557-558


296-308: Table header still uses raw color utilities; optional future tokenization.

Header background, borders, and text colors remain on concrete bg-slate-*/border-gray-*/text-slate-* classes. That’s perfectly fine functionally; if the long‑term goal is full token usage, this would be a good future candidate for theme-* header tokens.


473-477: Modal content/forms now use shared tokens; consider reusing the overlay helper too.

Using modal-content and form-input greatly simplifies the create-user modal and keeps it consistent with other forms. If you’ve standardized a .modal-overlay class elsewhere (e.g., vehicles page), you might optionally swap the bg-black/50 wrapper to that for cross-page consistency.

Also applies to: 480-537

src/app/dashboard/notifications/page.tsx (1)

123-137: Filter tab theming is clean; consider avoiding new raw color utilities on the unread badge

The refactor to filter-tabs-container + filter-tab / filter-tab-active / filter-tab-inactive keeps the filter logic readable and aligns with the new design tokens.

The unread badge at Line 136 still introduces raw color utilities (bg-white, dark:bg-gray-800, bg-opacity-30, etc.). If the goal is to centralize colors behind tokens, consider a small wrapper class (e.g., a filter-tab-unread-badge or theme badge token) instead of additional hardcoded colors.

src/app/dashboard/admin/service-types/page.tsx (1)

7-13: Toast integration is solid; consider also surfacing load/toggle feedback and trimming debug logs

Using useToast with success / showError for create, update, and delete paths is wired correctly, and ToastContainer placement at the page root is appropriate.

Two small follow‑ups you might consider:

  • loadServiceTypes failures currently only hit console.error and clear the list; adding a showError('Failed to load service types...') there would make the issue visible to admins.
  • handleToggleActive surfaces an error toast but no success toast; if the intent is toast‑based feedback for all state‑changing operations, a short “Service status updated” success toast would keep UX consistent.

Also, there are still several console.log statements left in loadServiceTypes / handleSubmit; worth removing or guarding them behind a debug flag before merging.

Also applies to: 70-114, 116-129, 132-147, 396-397

src/app/dashboard/time-logs/page.tsx (1)

7-13: Toast-based error feedback is wired correctly; you may want to surface load failures too

The useToast integration (error aliased as showError) is correctly used in both the create and delete error paths, and ToastContainer placement at the bottom of the page is appropriate.

You might also consider calling showError in loadTimeLogs’s catch block so initial load failures don’t silently degrade to an empty table.

Also applies to: 56-78, 80-89, 392-393

src/app/dashboard/projects/page.tsx (1)

13-20: Status chip colors and new stat/filter/card theming are consistent; just keep an eye on future statuses

The updated statusStyles mappings and the move to stat-card, filter-tabs-container / filter-tab(-active|‑inactive), and themed empty-state/icon styles all look coherent with the new design tokens and don’t change behavior.

Because statusStyles is a Record<string, string> and the render uses a fallback for unknown statuses, this will degrade gracefully if new statuses are introduced later; just remember to add explicit mappings for any new status values so chips don’t all fall back to the gray default.

Also applies to: 115-119, 121-137, 140-152, 160-161, 183-187

src/app/components/chatbot/AIChatWidget.tsx (1)

18-38: Core chat flow and session handling via apiClient look solid; consider a message when no token is present

Using Cookies.get('tt_access_token') plus sessionId in the payload and centralizing the call through apiClient.post<ChatResponse>('/ai/chat', payload) is a good cleanup; the guard on blank messages and isLoading prevents overlapping requests.

One UX improvement to consider: when currentToken is missing, sendMessage currently just returns, so the user gets no feedback if they’ve been logged out. You could append a small 'system' message (similar to the 401 branch) explaining that they need to sign in again instead of silently ignoring the input.

Also applies to: 44-64

src/app/dashboard/admin/reports/page.tsx (1)

118-275: Reports UI, theming, and toast integration look solid.

The overall layout (2‑column grid, standardized dashboard-content-card/form controls), use of theme tokens, and integration of toasts for generate/load/download flows are coherent and readable. I don’t see functional issues in the main render path; just consider the hook-dependency tweak noted separately.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fba1755 and 2e11791.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (62)
  • README.md (1 hunks)
  • package.json (1 hunks)
  • scripts/check-hardcoded-colors.js (1 hunks)
  • scripts/check-theme-setup.js (1 hunks)
  • src/app/admin/page.tsx (2 hunks)
  • src/app/auth/forgot-password/page.tsx (3 hunks)
  • src/app/auth/login/page.tsx (4 hunks)
  • src/app/auth/otp-verify/page.tsx (2 hunks)
  • src/app/auth/register/page.tsx (3 hunks)
  • src/app/auth/resend-verification/page.tsx (3 hunks)
  • src/app/auth/reset-password/ResetPasswordForm.tsx (1 hunks)
  • src/app/auth/reset-password/page.tsx (2 hunks)
  • src/app/auth/verify-email/page.tsx (2 hunks)
  • src/app/components/AddVehicleForm.tsx (1 hunks)
  • src/app/components/EditVehicleForm.tsx (5 hunks)
  • src/app/components/NotificationBell.tsx (7 hunks)
  • src/app/components/PaymentGateway.tsx (2 hunks)
  • src/app/components/RoleSwitcher.tsx (5 hunks)
  • src/app/components/VehicleCard.tsx (3 hunks)
  • src/app/components/chatbot/AIChatWidget.tsx (1 hunks)
  • src/app/components/dashboards/AdminDashboard.tsx (4 hunks)
  • src/app/components/dashboards/CustomerDashboard.tsx (8 hunks)
  • src/app/components/dashboards/EmployeeDashboard.tsx (4 hunks)
  • src/app/components/dashboards/SuperAdminDashboard.tsx (3 hunks)
  • src/app/contexts/NotificationContext.tsx (7 hunks)
  • src/app/dashboard/admin/audit-logs/page.tsx (4 hunks)
  • src/app/dashboard/admin/page.tsx (6 hunks)
  • src/app/dashboard/admin/reports/page.tsx (4 hunks)
  • src/app/dashboard/admin/service-types/page.tsx (16 hunks)
  • src/app/dashboard/admin/users/page.tsx (15 hunks)
  • src/app/dashboard/appointments/[appointmentId]/page.tsx (9 hunks)
  • src/app/dashboard/appointments/availability/page.tsx (1 hunks)
  • src/app/dashboard/appointments/book/page.tsx (3 hunks)
  • src/app/dashboard/appointments/page.tsx (4 hunks)
  • src/app/dashboard/invoices/page.tsx (2 hunks)
  • src/app/dashboard/layout.tsx (7 hunks)
  • src/app/dashboard/notifications/page.tsx (5 hunks)
  • src/app/dashboard/payments/page.tsx (1 hunks)
  • src/app/dashboard/projects/[projectId]/page.tsx (10 hunks)
  • src/app/dashboard/projects/page.tsx (4 hunks)
  • src/app/dashboard/projects/request/page.tsx (3 hunks)
  • src/app/dashboard/schedule/page.tsx (5 hunks)
  • src/app/dashboard/services/page.tsx (2 hunks)
  • src/app/dashboard/time-logs/page.tsx (16 hunks)
  • src/app/dashboard/vehicles/[vehicleId]/page.tsx (6 hunks)
  • src/app/dashboard/vehicles/page.tsx (6 hunks)
  • src/app/globals.css (7 hunks)
  • src/app/layout.tsx (1 hunks)
  • src/app/page.tsx (7 hunks)
  • src/app/payment-gateway/page.tsx (1 hunks)
  • src/app/profile/page.tsx (1 hunks)
  • src/components/ProfilePhotoUpload.tsx (3 hunks)
  • src/components/TimeTracker.tsx (5 hunks)
  • src/components/Toast.tsx (1 hunks)
  • src/hooks/useToast.ts (1 hunks)
  • src/lib/apiClient.ts (1 hunks)
  • src/services/adminService.ts (2 hunks)
  • src/services/appointmentService.ts (1 hunks)
  • src/services/authService.ts (2 hunks)
  • src/services/payhereService.ts (1 hunks)
  • src/services/projectService.ts (2 hunks)
  • src/types/admin.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (15)
scripts/check-hardcoded-colors.js (1)
eslint.config.mjs (1)
  • __dirname (6-6)
src/app/dashboard/admin/service-types/page.tsx (3)
src/app/contexts/DashboardContext.tsx (1)
  • useDashboard (65-71)
src/hooks/useToast.ts (1)
  • useToast (6-44)
src/components/Toast.tsx (1)
  • ToastContainer (65-75)
src/hooks/useToast.ts (1)
src/components/Toast.tsx (2)
  • ToastMessage (8-13)
  • ToastType (6-6)
src/components/TimeTracker.tsx (2)
src/hooks/useToast.ts (1)
  • useToast (6-44)
src/components/Toast.tsx (1)
  • ToastContainer (65-75)
src/app/dashboard/projects/[projectId]/page.tsx (3)
src/app/contexts/DashboardContext.tsx (1)
  • useDashboard (65-71)
src/hooks/useToast.ts (1)
  • useToast (6-44)
src/components/Toast.tsx (1)
  • ToastContainer (65-75)
src/app/dashboard/admin/reports/page.tsx (5)
src/app/contexts/DashboardContext.tsx (1)
  • useDashboard (65-71)
src/hooks/useToast.ts (1)
  • useToast (6-44)
src/types/admin.ts (1)
  • ReportResponse (123-139)
src/services/adminService.ts (1)
  • adminService (17-192)
src/components/Toast.tsx (1)
  • ToastContainer (65-75)
src/app/components/NotificationBell.tsx (3)
src/app/contexts/NotificationContext.tsx (1)
  • useNotifications (23-29)
src/services/notificationService.ts (2)
  • markAsRead (28-33)
  • markAllAsRead (54-59)
src/services/websocketService.ts (1)
  • isConnected (125-127)
src/services/appointmentService.ts (1)
src/types/appointment.ts (1)
  • AppointmentResponseDto (15-30)
src/app/dashboard/vehicles/[vehicleId]/page.tsx (2)
src/hooks/useToast.ts (1)
  • useToast (6-44)
src/components/Toast.tsx (1)
  • ToastContainer (65-75)
src/app/contexts/NotificationContext.tsx (2)
src/types/notification.ts (1)
  • NotificationResponse (3-14)
src/services/notificationService.ts (1)
  • notificationService (12-60)
scripts/check-theme-setup.js (1)
eslint.config.mjs (1)
  • __dirname (6-6)
src/app/dashboard/appointments/[appointmentId]/page.tsx (2)
src/hooks/useToast.ts (1)
  • useToast (6-44)
src/components/Toast.tsx (1)
  • ToastContainer (65-75)
src/app/dashboard/vehicles/page.tsx (2)
src/hooks/useToast.ts (1)
  • useToast (6-44)
src/components/Toast.tsx (1)
  • ToastContainer (65-75)
src/app/dashboard/admin/users/page.tsx (3)
src/app/contexts/DashboardContext.tsx (1)
  • useDashboard (65-71)
src/hooks/useToast.ts (1)
  • useToast (6-44)
src/components/Toast.tsx (1)
  • ToastContainer (65-75)
src/app/dashboard/time-logs/page.tsx (3)
src/app/contexts/DashboardContext.tsx (1)
  • useDashboard (65-71)
src/hooks/useToast.ts (1)
  • useToast (6-44)
src/components/Toast.tsx (1)
  • ToastContainer (65-75)
🪛 GitHub Check: Install, Lint and Build
src/app/dashboard/admin/reports/page.tsx

[warning] 28-28:
React Hook useEffect has missing dependencies: 'hasAccess' and 'loadReports'. Either include them or remove the dependency array

🪛 markdownlint-cli2 (0.18.1)
README.md

63-63: Unordered list indentation
Expected: 2; Actual: 3

(MD007, ul-indent)


64-64: Unordered list indentation
Expected: 2; Actual: 3

(MD007, ul-indent)


65-65: Unordered list indentation
Expected: 2; Actual: 3

(MD007, ul-indent)


70-70: Unordered list indentation
Expected: 2; Actual: 3

(MD007, ul-indent)


71-71: Unordered list indentation
Expected: 2; Actual: 3

(MD007, ul-indent)

🔇 Additional comments (80)
src/app/auth/register/page.tsx (1)

9-10: Branding and copy updates align with the new theme system

The simplified “TT” logo, updated “TechTorque” text, and success message copy all look consistent with the new automotive-accent/themed branding and don’t affect behavior.

Also applies to: 122-127, 168-169

src/app/components/AddVehicleForm.tsx (1)

62-66: Error banner switch to theme-alert-danger looks good

Using theme-alert-danger here matches the new tokenized alert styles and keeps the same error semantics.

src/app/payment-gateway/page.tsx (1)

80-82: Header logo theming change is consistent with the new automotive accent

Switching the logo container to use automotive-accent matches the rest of the app’s updated branding without impacting behavior.

src/app/components/VehicleCard.tsx (1)

13-14: VehicleCard theming/token updates look consistent and non-breaking

Using theme-alert-info for the color badge, theme-text-danger/hover:theme-bg-hover for Delete, and adding hover:shadow-lg transition-all to the card all fit the new tokenized theme system without changing behavior.

Also applies to: 22-25, 54-55

src/app/dashboard/admin/audit-logs/page.tsx (1)

55-126: LGTM! Consistent theme token adoption.

The styling updates consistently use the new theme tokens (theme-bg-tertiary, theme-text-muted, dashboard-content-card, hover:theme-bg-hover) to replace hardcoded color classes. This aligns with the PR's centralized theming objective.

src/app/components/EditVehicleForm.tsx (2)

62-118: LGTM! Clean theme token migration.

The form styling has been successfully migrated to use semantic theme classes (theme-alert-danger, theme-input, theme-button-*), aligning with the centralized theming approach.


95-103: License plate validation logic is in external backend—manual verification required.

The form calls vehicleService.updateVehicle() which delegates to an external backend API (PUT /vehicles/{vehicleId}). No backend routes exist in this codebase, so server-side validation cannot be verified here. While the form has error handling for backend responses, you must verify that your backend enforces unique license plate constraints before allowing this change to production.

src/app/dashboard/appointments/book/page.tsx (1)

184-245: LGTM! Theme alert wrappers applied consistently.

The error, success, and info messages now use semantic theme classes (theme-alert-danger, theme-alert-success, theme-alert-info), improving consistency with the global theming system.

src/components/ProfilePhotoUpload.tsx (1)

128-186: LGTM! Comprehensive theme token migration.

All UI elements have been successfully migrated to use semantic theme classes for borders, backgrounds, text colors, and alert states. The changes maintain the component's functionality while ensuring consistency with the centralized theming system.

src/app/page.tsx (1)

2-230: LGTM! Clean refactor and theme token adoption.

The changes successfully:

  1. Extract ThemeToggle into a reusable component (improving modularity)
  2. Apply new theme tokens (automotive-accent, accent-badge, text-gradient-accent, bg-linear-to-br) consistently across hero, features, and footer sections

The refactoring maintains the existing layout and functionality while aligning with the centralized theming approach.

src/app/dashboard/schedule/page.tsx (1)

102-222: LGTM! Standardized theme tokens and semantic containers.

The updates consistently apply:

  • Semantic alert wrappers (theme-alert-danger)
  • Standardized card containers (dashboard-content-card, stat-card)
  • Theme utility classes (form-input, hover:theme-bg-hover, empty-state)

The stat blocks are now uniformly structured with stat-card-label and stat-card-value, improving maintainability.

src/types/admin.ts (1)

125-136: LGTM! Enhanced report response type.

The additions to ReportResponse improve tracking and flexibility:

  • New GENERATING status provides better progress visibility
  • Optional metadata fields (downloadUrl, fileSize, data, etc.) support various report formats and states
  • Field naming is clear and consistent
src/app/auth/reset-password/ResetPasswordForm.tsx (1)

146-146: LGTM! Theming update applied.

The error message styling has been updated to use theme-text-danger, aligning with the centralized theming system introduced in this PR.

src/services/adminService.ts (1)

26-27: LGTM! Robust response normalization.

The array normalization pattern handles multiple potential response structures (data.data, data.content, or direct array), ensuring consistent return types and preventing runtime errors from API response variations.

Also applies to: 56-57

src/app/dashboard/appointments/availability/page.tsx (1)

158-158: LGTM! Simplified error styling with theme classes.

The error alert now uses theme-alert-danger instead of multiple Tailwind utility classes, improving maintainability and consistency with the centralized theming system.

src/app/layout.tsx (1)

28-28: LGTM! Proper hydration warning suppression and theme initialization.

The additions correctly handle theme initialization before React hydration:

  • suppressHydrationWarning on the <html> element prevents React 19 from warning about server/client mismatches caused by the pre-hydration theme script
  • The inline beforeInteractive script applies the theme from localStorage or system preference, preventing FOUC (Flash of Unstyled Content)
  • Try/catch wrapper ensures errors don't break the page load

This is the recommended pattern for theme initialization in Next.js with React 19.

Also applies to: 35-36

src/app/auth/verify-email/page.tsx (1)

17-21: LGTM! Simplified branding and cleanup.

The changes remove unused icon components and standardize the branding to "TechTorque" with a simple "TT" badge, consistent with branding updates across other auth pages in this PR.

src/app/auth/reset-password/page.tsx (1)

6-7: LGTM! Clean branding consolidation.

The removal of unused icon helpers and the introduction of the automotive-accent styling with updated branding ("TechTorque") aligns well with the centralized theming system. The implementation is clean and consistent with the broader PR objectives.

Also applies to: 16-21

src/app/auth/forgot-password/page.tsx (1)

9-9: LGTM! Consistent theming applied.

The changes successfully replace hardcoded color classes with semantic theme tokens (theme-text-danger), and the header branding matches the consolidated approach across auth pages. The implementation maintains the existing functionality while improving theme consistency.

Also applies to: 49-49, 77-77

src/app/auth/login/page.tsx (1)

11-11: LGTM! Theming consistency achieved.

The updates successfully implement the centralized theming system with automotive-accent branding and theme-text-danger for error messages. The changes are consistent with the broader PR goals.

Also applies to: 72-76, 150-150

src/services/projectService.ts (1)

80-83: LGTM! Response normalization applied.

The fallback pattern res.data.data || res.data ensures robustness when the API response structure varies.

README.md (1)

52-73: Excellent documentation of new features!

The Environment and Theme & Styling sections provide clear, actionable guidance for developers working with the centralized theming system and environment configuration. The inclusion of quick check commands (npm run check:theme, npm run check:colors) is particularly helpful.

src/app/dashboard/vehicles/[vehicleId]/page.tsx (1)

7-8: Excellent toast integration!

The replacement of browser alert() calls with the new toast notification system significantly improves the user experience. The integration is clean and follows the established pattern from the useToast hook.

Also applies to: 14-14, 58-61, 93-93

src/hooks/useToast.ts (1)

6-44: Clean toast hook implementation!

The hook provides a well-structured API with typed functions for different toast types. The use of useCallback ensures stable references and prevents unnecessary re-renders.

src/app/admin/page.tsx (1)

97-97: LGTM! Theming applied correctly.

The updates successfully replace hardcoded color classes with semantic theme utilities (theme-button-primary, theme-alert-danger), aligning with the centralized theming system.

Also applies to: 111-113

src/app/dashboard/projects/request/page.tsx (3)

119-124: LGTM! Theme class applied correctly.

The button styling has been successfully migrated to use the centralized theme-button-action class, which improves maintainability and consistency across the application.


137-141: LGTM! Alert styling migrated to theme tokens.

The error alert has been properly updated to use theme-alert-danger and theme-text-danger, ensuring consistent error presentation across the application.


255-272: LGTM! Submit button styling migrated to theme tokens.

The submit button has been successfully updated to use theme-button-action, maintaining consistency with the rest of the form while centralizing styling.

src/app/components/dashboards/SuperAdminDashboard.tsx (3)

59-63: LGTM! Error alert migrated to theme token.

The error display has been properly updated to use theme-alert-danger, ensuring consistent error styling across the dashboard.


131-139: LGTM! Status text styling migrated to theme tokens.

The service status display now uses semantic theme tokens (theme-text-success for active, theme-text-muted for inactive), maintaining clear visual distinction while improving maintainability.


156-163: LGTM! Border styling migrated to theme token.

The audit log item borders now use theme-border, ensuring consistent border colors across the application.

package.json (2)

10-11: Excellent addition for theme compliance enforcement.

The new validation scripts will help maintain consistency by automatically checking for hardcoded colors and verifying theme setup. Consider integrating these into your CI pipeline or pre-commit hooks for automated enforcement.


19-19: No compatibility concerns found.

Next.js 16.0.3 (released Nov 13, 2025) is a patch release with stability improvements including Turbopack fixes, server-action logging fixes, and performance improvements. Next.js 16 is the supported version for React 19.2+, which confirms compatibility with the current React 19.1.0. This patch bump from 16.0.1 to 16.0.3 is safe to apply.

src/app/components/PaymentGateway.tsx (3)

125-129: LGTM! Error alert migrated to theme token.

The error display now uses theme-alert-danger, ensuring consistent error presentation throughout the payment flow.


131-135: LGTM! Success alert migrated to theme token.

The success message now uses theme-alert-success, providing consistent positive feedback across the application.


147-151: LGTM! Informational banner migrated to theme token.

The security notice now uses theme-alert-info, maintaining consistent informational styling throughout the payment gateway.

src/app/dashboard/appointments/page.tsx (3)

90-105: LGTM! Filter tabs migrated to semantic classes.

The filter tabs now use semantic classes (filter-tabs-container, filter-tab-active, filter-tab-inactive), providing a centralized and consistent filter UI pattern.


108-137: LGTM! Empty state and card hover styling improved.

The empty state now uses automotive-card-static for appropriate non-interactive styling, and appointment cards have enhanced hover feedback with border color transitions.


166-172: LGTM! Special instructions styling migrated to theme token.

The special instructions block now uses theme-alert-info, ensuring consistent presentation of supplementary information.

src/components/TimeTracker.tsx (3)

5-6: LGTM! Toast system integrated correctly.

The toast hook and container are properly imported and initialized for displaying user feedback.

Also applies to: 15-15


74-93: LGTM! Alert replaced with toast notification.

The clock-out confirmation now uses a toast notification instead of a browser alert, providing a better user experience and consistency with the application's notification system.


106-110: LGTM! Error alerts migrated to theme token.

Both error states now use theme-alert-danger, ensuring consistent error presentation throughout the time tracking flow.

Also applies to: 127-131

src/app/dashboard/projects/[projectId]/page.tsx (3)

36-107: LGTM! Toast notifications provide excellent user feedback.

The handlers now use toast notifications for both success and error scenarios, providing clear, non-intrusive feedback for quote and project approval/rejection actions. This is a significant UX improvement over previous error handling.


146-161: LGTM! Error state migrated to theme tokens.

The error page now uses consistent theme classes (theme-alert-danger, theme-text-danger, theme-button-action), ensuring uniform error presentation across the application.


197-230: LGTM! UI refinements and toast container added.

The icon containers now use shrink-0 for proper flex layout behavior, the progress bar uses the themed progress-accent class, and the ToastContainer is properly rendered to display notifications.

Also applies to: 233-265, 365-378, 382-382

src/app/dashboard/appointments/[appointmentId]/page.tsx (6)

12-13: LGTM! Alert replaced with toast notification for invoice generation.

The invoice generation success feedback now uses a toast notification instead of a browser alert (Line 289), providing a better user experience that's consistent with the application's notification system.

Also applies to: 33-33, 263-302


341-345: LGTM! Error alert migrated to theme token.

The error display now uses theme-alert-danger, ensuring consistent error presentation throughout the appointment detail page.


474-478: LGTM! Informational alerts migrated to theme token.

The informational notices now use theme-alert-info, providing consistent styling for supplementary information about employee assignments and vehicle arrival.

Also applies to: 529-534


576-585: LGTM! Work completion success state uses theme token.

The completed work display now uses theme-alert-success, providing consistent visual feedback for successful work completion.


801-808: Verify theme class usage on section border.

Line 802 applies theme-alert-success as a border class (border-2 theme-alert-success). Theme alert classes are typically designed for container backgrounds and text, not borders. This might not provide the expected styling.

Please verify that theme-alert-success is intended for use as a border class. If not, consider using a dedicated border theme token or explicit border color classes:

-          <section className="automotive-card p-6 border-2 theme-alert-success">
+          <section className="automotive-card p-6 border-2 border-green-200 dark:border-green-800">

829-829: LGTM! ToastContainer properly rendered.

The ToastContainer is appropriately placed at the end of the component to display all toast notifications.

src/app/components/dashboards/EmployeeDashboard.tsx (2)

97-97: LGTM! Clean theme token migration.

The error alert styling has been simplified to use the centralized theme-alert-danger class, replacing verbose Tailwind color combinations. This aligns with the PR's theming objectives.


173-204: LGTM! Consistent theme token usage.

Border and text color classes have been properly migrated to theme tokens (theme-border, theme-text-info), ensuring consistent styling across light and dark modes.

src/app/auth/resend-verification/page.tsx (1)

110-110: LGTM! Theme token applied correctly.

Error text styling properly uses theme-text-danger for centralized theming.

src/app/dashboard/payments/page.tsx (2)

145-166: LGTM! Consistent stat-card migration.

The summary statistics have been properly migrated from automotive-card to the standardized stat-card structure with semantic stat-card-label and stat-card-value classes. This improves consistency across the dashboard.


171-202: LGTM! Filter styling standardized.

The filter buttons now use the centralized filter-tabs-container with filter-tab-active and filter-tab-inactive states, ensuring consistent filter UI across all dashboard pages.

src/app/dashboard/invoices/page.tsx (1)

143-158: LGTM! Consistent stat-card implementation.

Statistics cards properly migrated to the standardized stat-card structure with appropriate label/value semantics.

src/components/Toast.tsx (2)

67-73: LGTM! Pointer events pattern is correct.

The pointer-events-none on the container with pointer-events-auto on the child div is a standard pattern that allows clicks to pass through the empty space while keeping the toasts interactive.


45-45: No issues found.

The animate-slide-in class is properly defined in src/app/globals.css (lines 135-147) with the corresponding @keyframes slide-in animation and .animate-slide-in CSS class. The Toast component's usage is correct.

src/app/dashboard/services/page.tsx (2)

76-97: LGTM! Consistent stat-card implementation.

The service statistics properly migrated to the standardized stat-card structure, maintaining consistency across dashboard pages.


101-115: LGTM! Filter styling standardized.

Filter tabs properly use the centralized filter-tabs-container with semantic active/inactive states.

src/app/components/dashboards/CustomerDashboard.tsx (1)

76-122: LGTM! Theme tokens applied correctly.

Error alert and theme-based border/text classes have been properly applied for consistent theming.

src/app/components/RoleSwitcher.tsx (2)

16-41: LGTM! Role configuration migrated to theme tokens.

The roleConfig has been properly updated to use theme-based color and background classes, ensuring consistent styling across the application.


115-159: LGTM! Dropdown styling properly themed.

The dropdown container and items use appropriate theme tokens for borders, backgrounds, and text, ensuring consistent appearance in light and dark modes.

src/app/dashboard/vehicles/page.tsx (1)

57-63: Theming and modal changes are consistent with the new design system.

Spinner, error alert, empty-state icon, and both Add/Edit modal wrappers correctly adopt theme-* and modal-* tokens and keep the structure unchanged, so behavior should remain stable while matching the new theme layer.

Also applies to: 81-85, 88-97, 100-115, 119-133

src/app/dashboard/layout.tsx (1)

45-47: Navigation theming refactor looks clean and non-breaking.

Switching to nav-item-active/nav-item-inactive, theme-border, and theme-bg-secondary preserves the existing layout and behaviors while aligning with the centralized theme tokens.

Also applies to: 53-63, 74-79, 100-103, 133-135

src/app/dashboard/admin/users/page.tsx (3)

247-277: Stat cards align nicely with the new design tokens.

The stat-card, stat-card-label, and stat-card-value usage makes the user metrics much more uniform; the per-status color accents on values (green/red/blue/orange) are clear and still easy to reason about.


279-289: Filter tab abstraction improves readability and consistency.

Wrapping the role filters in filter-tabs-container/filter-tab with active/inactive variants is a good cleanup over ad-hoc button classes and should make future styling changes trivial.


441-445: Action button theming is consistent with the design system.

Switching “Edit Roles” to theme-button-action keeps semantics clear (primary vs secondary vs action) and matches the broader button-token approach in the dashboard.

src/app/dashboard/admin/page.tsx (2)

34-42: Loading skeleton theming is consistent and non-breaking.

Replacing gray skeleton blocks with theme-bg-tertiary keeps the loading state readable while aligning with the new theme palette.


78-147: Quick actions and stats successfully adopt dashboard-content-card and stat-card tokens.

The new dashboard-content-card wrappers and stat-card/stat-card-label/stat-card-value usage make the admin overview much more consistent without touching behavior; the per-card hover borders and colored stat values also give good at-a-glance cues.

Also applies to: 153-167, 171-189, 193-203

src/app/dashboard/notifications/page.tsx (2)

90-99: Max width increase to max-w-6xl looks consistent but verify layout on narrow screens

Expanding the container from max-w-4xl to max-w-6xl in both loading and main views should be fine, but please sanity‑check that content still reads well on laptop‑sized viewports and doesn’t make lines too long for readability.

Also applies to: 102-104


162-168: Hover state refinements on notification cards look good

The added hover:shadow-lg and hover border variants for read vs unread cards are consistent and don’t affect the underlying logic for read state or actions. No issues from a functional standpoint.

src/app/components/NotificationBell.tsx (3)

7-12: Local error layering over context error is reasonable and clearly implemented

The way localError is used (cleared on open and on successful mark operations, then rendered as localError || error) provides a clear, user‑specific error signal without fighting the context‑level error. The minimal Axios‑shape casting inside the catch blocks is also defensive enough for typical API errors.

No functional issues; just make sure upstream fetchNotifications is already catching/reducing its own errors so you don’t end up with unhandled promise rejections when await fetchNotifications() runs on open.

Also applies to: 28-55, 105-109


57-88: Themed bell button, badge, and fixed panel alignment look fine

Switching the bell button to theme-toggle, applying theme-badge-danger for unread count, and pinning the panel with the fixed right-4 top-20 container is consistent with the new design system, and click‑outside detection via panelRef.contains will still work with a fixed child.

The ripple overlay div is inert but harmless; assuming CSS handles the visual effect, there’s no behavioral concern.

Also applies to: 90-92


112-117: List item theming and “View all notifications” CTA are consistent with the rest of the dashboard

The switch to theme-alert-info for unread items and theme-bg-tertiary / hover:theme-bg-hover for the footer link keeps the visual hierarchy clear without touching behavior. Mark‑as‑read behavior is unchanged; only the text styling moved to theme tokens, which looks fine.

Also applies to: 141-147

src/app/dashboard/admin/service-types/page.tsx (1)

187-201: Form and action button theming aligns with the new design system

Switching the primary actions to theme-button-action / btn btn-primary and the fields to form-input / form-select / form-textarea keeps the markup cleaner and centralizes styling. The modal modal-content wrapper also gives you a nice hook for consistent modal theming.

No behavioral changes here; the validation and submit logic are preserved.

Also applies to: 249-272, 279-391

src/app/dashboard/time-logs/page.tsx (1)

120-133: Theming updates for access-denied, form, stats, and table are coherent

Using theme-alert-danger for the access-denied block, form-input/form-select/form-textarea for fields, stat-card for summary tiles, and dashboard-content-card + theme-border / theme-bg-tertiary for the table keeps this page aligned with the rest of the dashboard theming.

Row hover (hover:theme-bg-hover) and muted placeholders for non-action cells (Line 380) read well and don’t affect the underlying permission logic.

Also applies to: 180-198, 284-297, 308-318, 330-331, 353-353, 380-381

src/app/components/chatbot/AIChatWidget.tsx (2)

75-152: Error normalization and system message handling are thorough and defensive

The helper functions for extracting status and server messages, plus sanitizeForLog, give you concise console output without dumping huge validation payloads. The status‑aware user messages (401 vs 4xx validation vs generic/server message) and use of a 'system' sender keep error feedback clear inside the chat history.

Dependencies on isLoading/sessionId in the useCallback are appropriate; no functional issues spotted here.


165-231: Ignore this review comment—the code is correct for Tailwind CSS v4.

In Tailwind CSS v4, linear-gradient utilities were renamed from bg-gradient-* to bg-linear-*. The codebase confirms this: package.json specifies "tailwindcss": "^4", and the code correctly uses bg-linear-to-r (line 169). The reviewer's suggested change to bg-gradient-to-r reflects Tailwind v3 syntax and would break the gradient in this v4 project.

Likely an incorrect or invalid review comment.

Comment on lines +63 to +65
- `.theme-button-primary`, `.theme-button-secondary` — semantic buttons
- `.theme-bg-primary`, `.theme-text-primary`, `.theme-border`, etc — consistent building blocks
- `.automotive-accent`, `.accent-badge`, `.text-gradient-accent`, `.progress-accent` — accent utilities
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix markdown list indentation.

The nested list items use 3-space indentation but should use 2 spaces per Markdown best practices.

Apply this diff to fix the indentation:

-- A single global stylesheet lives at `src/app/globals.css` and contains all theme variables for light & dark mode, plus utility classes like:
-   - `.theme-button-primary`, `.theme-button-secondary` — semantic buttons
-   - `.theme-bg-primary`, `.theme-text-primary`, `.theme-border`, etc — consistent building blocks
-   - `.automotive-accent`, `.accent-badge`, `.text-gradient-accent`, `.progress-accent` — accent utilities
+- A single global stylesheet lives at `src/app/globals.css` and contains all theme variables for light & dark mode, plus utility classes like:
+  - `.theme-button-primary`, `.theme-button-secondary` — semantic buttons
+  - `.theme-bg-primary`, `.theme-text-primary`, `.theme-border`, etc — consistent building blocks
+  - `.automotive-accent`, `.accent-badge`, `.text-gradient-accent`, `.progress-accent` — accent utilities

-- Quick checks added:
-   - `npm run check:theme` — verifies `globals.css` and `ThemeContext` contain expected hooks and variables.
-   - `npm run check:colors` — scans `src/` for hardcoded hex/rgb color usage (ignores `globals.css`).
+- Quick checks added:
+  - `npm run check:theme` — verifies `globals.css` and `ThemeContext` contain expected hooks and variables.
+  - `npm run check:colors` — scans `src/` for hardcoded hex/rgb color usage (ignores `globals.css`).

Based on static analysis hints.

Also applies to: 70-71

🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

63-63: Unordered list indentation
Expected: 2; Actual: 3

(MD007, ul-indent)


64-64: Unordered list indentation
Expected: 2; Actual: 3

(MD007, ul-indent)


65-65: Unordered list indentation
Expected: 2; Actual: 3

(MD007, ul-indent)

🤖 Prompt for AI Agents
In README.md around lines 63-65 (and also apply the same fix to lines 70-71),
the nested markdown list items are indented with 3 spaces instead of the
expected 2; update each nested list line to use 2-space indentation so nested
bullets align with Markdown best practices (change each leading indentation from
three spaces to two spaces) and verify surrounding list markers and spacing
remain consistent.

import fs from 'fs'
import path from 'path'

const root = path.resolve(__dirname, '..', 'src')
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

__dirname is not available in ES modules.

Line 5 uses __dirname, but this script uses ES module syntax (import statements). In ES modules, __dirname is undefined and will cause a runtime error.

Apply this diff to fix:

+import { fileURLToPath } from 'url'
+import { dirname } from 'path'
+
+const __filename = fileURLToPath(import.meta.url)
+const __dirname = dirname(__filename)
+
-const root = path.resolve(__dirname, '..', 'src')
+const root = path.resolve(__dirname, '..', 'src')
📝 Committable suggestion

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

Suggested change
const root = path.resolve(__dirname, '..', 'src')
import { fileURLToPath } from 'url'
import { dirname } from 'path'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
const root = path.resolve(__dirname, '..', 'src')
🤖 Prompt for AI Agents
In scripts/check-hardcoded-colors.js around line 5, __dirname is used but this
file is an ES module so __dirname is undefined; replace use of __dirname by
deriving the directory from import.meta.url: import fileURLToPath from 'url' (or
destructure fileURLToPath) and compute const __filename =
fileURLToPath(import.meta.url) and const __dirname = path.dirname(__filename),
then set root = path.resolve(__dirname, '..', 'src'); add the import for
fileURLToPath at top and remove any direct __dirname usages.

Comment on lines +1 to +7
#!/usr/bin/env node
import fs from 'fs'
import path from 'path'

const globals = fs.readFileSync(path.resolve(__dirname, '../src/app/globals.css'), 'utf8')
const themeContext = fs.readFileSync(path.resolve(__dirname, '../src/app/contexts/ThemeContext.tsx'), 'utf8')

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix ESM __dirname usage so the script can actually run

With import syntax, Node will treat this as an ES module (in a "type": "module" project), where __dirname is not defined. That means this script will currently error out instead of running your checks.

Define __dirname from import.meta.url (or drop __dirname entirely and resolve from process.cwd()), e.g.:

-#!/usr/bin/env node
-import fs from 'fs'
-import path from 'path'
-
-const globals = fs.readFileSync(path.resolve(__dirname, '../src/app/globals.css'), 'utf8')
-const themeContext = fs.readFileSync(path.resolve(__dirname, '../src/app/contexts/ThemeContext.tsx'), 'utf8')
+#!/usr/bin/env node
+import fs from 'fs';
+import path from 'path';
+import { fileURLToPath } from 'url';
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = path.dirname(__filename);
+
+const globals = fs.readFileSync(path.resolve(__dirname, '../src/app/globals.css'), 'utf8');
+const themeContext = fs.readFileSync(path.resolve(__dirname, '../src/app/contexts/ThemeContext.tsx'), 'utf8');
🤖 Prompt for AI Agents
In scripts/check-theme-setup.js around lines 1 to 7, the script uses __dirname
which is undefined in ESM; replace its usage by deriving a directory from
import.meta.url (e.g. const __filename = fileURLToPath(import.meta.url) and
const __dirname = path.dirname(__filename)) or switch to resolving paths from
process.cwd(); if you choose the import.meta.url approach, add the required
import from 'url' (fileURLToPath) and then update the path.resolve calls to use
the computed __dirname variable.

Comment on lines +136 to 141
<div className="automotive-accent w-12 h-12 rounded-full flex items-center justify-center shadow-lg transform transition-transform duration-300 group-hover:scale-110">
<span className="text-white font-bold text-lg">TT</span>
</div>
<h1 className="text-2xl font-bold theme-text-primary hidden sm:block">
TechTorque Auto
TechTorque
</h1>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

Verify branding change is intentional.

The header branding has been updated from "TechTorque Auto" to "TechTorque" and the logo changed from a gradient-based BoltIcon to a simple "TT" badge. Ensure this branding change is consistent across all pages and intentional.


🏁 Script executed:

#!/bin/bash
# Description: Verify branding consistency across the codebase

# Search for remaining instances of "TechTorque Auto" to ensure consistency
rg -n "TechTorque Auto" --type tsx --type ts

# Search for TechTorque (standalone) usage in headers
rg -n -A2 -B2 "TechTorque</h1>" --type tsx --type ts

Length of output: 55


🏁 Script executed:

#!/bin/bash
# Description: Verify branding consistency across the codebase with corrected syntax

# Search for remaining instances of "TechTorque Auto" (old branding)
echo "=== Searching for 'TechTorque Auto' (old branding) ==="
rg -n "TechTorque Auto" -g "*.tsx" -g "*.ts"

# Search for all header branding elements
echo -e "\n=== Searching for TechTorque header usage ==="
rg -n -A2 -B2 "TechTorque" -g "*.tsx" | grep -E "(TechTorque|<h1|className)" | head -40

# Search for BoltIcon usage (old logo component)
echo -e "\n=== Searching for BoltIcon usage ==="
rg -n "BoltIcon" -g "*.tsx" -g "*.ts"

# Search for "TT" badge or similar patterns
echo -e "\n=== Searching for TT badge or similar avatar patterns ==="
rg -n -B3 -A1 "TT" -g "*.tsx" | grep -E "(TT|avatar|badge)" | head -20

Length of output: 8358


Branding change is incomplete and inconsistent across the codebase.

The code under review correctly uses the new "TechTorque" branding with the TT badge, but several pages still retain the old "TechTorque Auto" branding with BoltIcon:

  • Homepage (src/app/page.tsx): lines 38, 233, 242 use "TechTorque Auto" + BoltIcon
  • Payment gateway (src/app/payment-gateway/page.tsx): line 84 uses "TechTorque Auto" + BoltIcon

Other auth and dashboard pages have been updated to use the new branding. This mixed state creates inconsistent brand presentation across the application.

🤖 Prompt for AI Agents
In src/app/auth/resend-verification/page.tsx lines 136-141 and also update
src/app/page.tsx (lines ~38, 233, 242) and src/app/payment-gateway/page.tsx
(line ~84): replace any remaining "TechTorque Auto" + BoltIcon branding with the
new "TechTorque" branding and the TT badge used in resend-verification (match
the TT rounded badge and plain "TechTorque" heading styling), ensure classNames,
accessible text, and any aria-labels match the new brand, and remove or replace
BoltIcon imports/usages so branding is consistent across pages.

isActive
? `${config.bgColor} ${config.color} font-medium`
: 'theme-text-secondary hover:bg-gray-100 dark:hover:bg-gray-800'
: 'theme-text-secondary hover:theme-bg-hover'
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix invalid Tailwind hover syntax.

The syntax hover:theme-bg-hover is invalid. Tailwind doesn't support applying hover modifiers to custom utility classes in this way. You need to define the hover state directly or use a proper Tailwind class.

Apply this diff to fix the syntax:

                  className={`w-full flex items-center gap-3 px-3 py-2 rounded-md text-sm transition-colors ${
                    isActive
                      ? `${config.bgColor} ${config.color} font-medium`
-                     : 'theme-text-secondary hover:theme-bg-hover'
+                     : 'theme-text-secondary hover:bg-gray-100 dark:hover:bg-gray-800'
                  }`}

Alternatively, if you want a theme-based hover state, define it in your globals.css:

.hover-theme-bg:hover {
  background-color: var(--bg-hover);
}

Then use:

-                     : 'theme-text-secondary hover:theme-bg-hover'
+                     : 'theme-text-secondary hover-theme-bg'
🤖 Prompt for AI Agents
In src/app/components/RoleSwitcher.tsx around line 136, the token
`hover:theme-bg-hover` is invalid Tailwind syntax; replace it with a valid hover
utility or a custom CSS class. Either change the class to a proper Tailwind
hover utility that sets background (e.g. a hover:bg-... variant or
hover:bg-[var(--bg-hover)]), or add a custom rule in globals.css such as
.hover-theme-bg:hover { background-color: var(--bg-hover); } and use that class
name in the JSX instead of `hover:theme-bg-hover`.

Comment on lines +57 to +68
} catch (err: unknown) {
// Prefer any attached `response?.data?.message` but fall back to
// the error message. Our apiClient now augments error objects with
// status/response fields so we can provide a better user message.
console.error('Failed to fetch notifications:', err);
const axiosErr = err as AxiosError<unknown> | undefined;
// Prefer response.data.message when available, otherwise use Error.message
const msg = axiosErr?.response?.data && typeof axiosErr.response.data === 'object' && 'message' in axiosErr.response.data
? // response.data typing varies; narrow to { message?: string }
(axiosErr.response.data as { message?: string }).message ?? (err instanceof Error ? err.message : 'Failed to fetch notifications')
: (err instanceof Error ? err.message : 'Failed to fetch notifications');
setError(msg);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Extract repetitive error handling logic to a helper function.

The error message extraction pattern is repeated identically in four places (fetchNotifications, markAsRead, markAllAsRead, deleteNotification). This violates DRY and makes maintenance harder.

Apply this refactor:

+// Helper to extract user-friendly error messages
+const extractErrorMessage = (err: unknown, fallback: string): string => {
+  const axiosErr = err as AxiosError<unknown> | undefined;
+  if (axiosErr?.response?.data && typeof axiosErr.response.data === 'object' && 'message' in axiosErr.response.data) {
+    return (axiosErr.response.data as { message?: string }).message ?? (err instanceof Error ? err.message : fallback);
+  }
+  return err instanceof Error ? err.message : fallback;
+};
+
 const fetchNotifications = useCallback(async (unreadOnly = false) => {
   // ... 
   } catch (err: unknown) {
-    console.error('Failed to fetch notifications:', err);
-    const axiosErr = err as AxiosError<unknown> | undefined;
-    const msg = axiosErr?.response?.data && typeof axiosErr.response.data === 'object' && 'message' in axiosErr.response.data
-      ? (axiosErr.response.data as { message?: string }).message ?? (err instanceof Error ? err.message : 'Failed to fetch notifications')
-      : (err instanceof Error ? err.message : 'Failed to fetch notifications');
-    setError(msg);
+    console.error('Failed to fetch notifications:', err);
+    setError(extractErrorMessage(err, 'Failed to fetch notifications'));
   }

Then apply the same simplification to markAsRead, markAllAsRead, and deleteNotification.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/app/contexts/NotificationContext.tsx around lines 57 to 68, the error
message extraction logic is duplicated; create a single helper function (e.g.
extractErrorMessage(err: unknown): string) in this file that encapsulates the
AxiosError/response.data.message checks and fallback to err.message or a default
string, reuse it from fetchNotifications, markAsRead, markAllAsRead, and
deleteNotification, and remove the in-place duplication so each catch simply
calls setError(extractErrorMessage(err)) after console.error.

Comment on lines +23 to +41
// Load reports on mount
useEffect(() => {
if (hasAccess) {
loadReports();
}
}, [roles]);

const loadReports = async () => {
try {
setLoadingReports(true);
const data = await adminService.getReports();
setReports(data);
} catch (err) {
console.error('Failed to load reports:', err);
showError('Failed to load reports history');
} finally {
setLoadingReports(false);
}
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

Tighten useEffect dependencies for loadReports / hasAccess (address lint warning).

useEffect currently depends only on roles while using hasAccess and loadReports, which is why the hook-deps rule is warning. It’s functionally okay today, but easy to drift into stale-closure bugs later.

A small refactor using useCallback will both satisfy lint and keep behavior clear:

-import { useState, useEffect } from 'react';
+import { useState, useEffect, useCallback } from 'react';
@@
-  const [reports, setReports] = useState<ReportResponse[]>([]);
-  const [loadingReports, setLoadingReports] = useState(false);
-
-  // Load reports on mount
-  useEffect(() => {
-    if (hasAccess) {
-      loadReports();
-    }
-  }, [roles]);
-
-  const loadReports = async () => {
+  const [reports, setReports] = useState<ReportResponse[]>([]);
+  const [loadingReports, setLoadingReports] = useState(false);
+
+  const loadReports = useCallback(async () => {
     try {
       setLoadingReports(true);
       const data = await adminService.getReports();
       setReports(data);
     } catch (err) {
       console.error('Failed to load reports:', err);
       showError('Failed to load reports history');
     } finally {
       setLoadingReports(false);
     }
-  };
+  }, [showError]);
+
+  // Load reports on mount / when access changes
+  useEffect(() => {
+    if (hasAccess) {
+      loadReports();
+    }
+  }, [hasAccess, loadReports]);

This keeps loadReports stable across renders (except when showError changes) and makes the effect’s dependency list explicit.

Also applies to: 30-41


🏁 Script executed:

#!/bin/bash
# Check if file exists and show lines 1-50 to understand context
if [ -f "src/app/dashboard/admin/reports/page.tsx" ]; then
  echo "=== File found, showing lines 1-50 ==="
  head -50 "src/app/dashboard/admin/reports/page.tsx"
else
  echo "File not found at src/app/dashboard/admin/reports/page.tsx"
  # Try to find similar files
  echo "=== Searching for similar files ==="
  find . -name "*reports*page*" -type f 2>/dev/null | head -10
fi

Length of output: 1747


🏁 Script executed:

#!/bin/bash
# Search for showError usage and hasAccess to understand their scope
echo "=== Searching for showError definition/import ==="
rg -n "showError|useToast" src/app/dashboard/admin/reports/page.tsx -A2 -B2

echo ""
echo "=== Searching for hasAccess definition/import ==="
rg -n "hasAccess" src/app/dashboard/admin/reports/page.tsx -A1 -B1

Length of output: 1494


🏁 Script executed:

#!/bin/bash
# Get more complete view of the useEffect and surrounding code
if [ -f "src/app/dashboard/admin/reports/page.tsx" ]; then
  echo "=== Full file content ==="
  cat "src/app/dashboard/admin/reports/page.tsx"
fi

Length of output: 12386


Verify the useEffect dependencies and confirm the useCallback refactor is necessary.

The review correctly identifies an ESLint exhaustive-deps violation. The useEffect at lines 24–29 uses both hasAccess (line 25) and loadReports (line 26), but includes only [roles] in its dependency array. Additionally, loadReports is redefined on every render and captures showError in a closure, which could become stale if the showError reference changes.

The proposed refactor using useCallback with dependencies [showError] and updating the effect to depend on [hasAccess, loadReports] is correct and necessary. This ensures:

  • loadReports remains stable across renders except when showError changes
  • The effect properly reruns when either hasAccess or the memoized loadReports function changes

Apply the suggested diff to resolve both the lint warning and prevent potential stale closure bugs.

🧰 Tools
🪛 GitHub Check: Install, Lint and Build

[warning] 28-28:
React Hook useEffect has missing dependencies: 'hasAccess' and 'loadReports'. Either include them or remove the dependency array

🤖 Prompt for AI Agents
In src/app/dashboard/admin/reports/page.tsx around lines 23 to 41, the useEffect
depends on roles but reads hasAccess and calls loadReports which is redefined
each render and closes over showError; refactor loadReports into a useCallback
that lists showError (and any other external vars it uses) in its dependency
array so the function is stable, then update the useEffect dependency array to
[hasAccess, loadReports] (remove roles) so the effect runs when access or the
memoized loader changes; ensure loadReports still sets loading state, calls
adminService.getReports, handles errors via the current showError, and resets
loading in finally.

<div className="lg:col-span-2 space-y-6">
<div className="automotive-card p-6">
<div className="w-full rounded-lg overflow-hidden shadow-md bg-gradient-to-b from-white to-gray-50 dark:from-gray-900 dark:to-gray-800">
<div className="w-full rounded-lg overflow-hidden shadow-md bg-linear-to-b from-white to-gray-50 dark:from-gray-900 dark:to-gray-800">
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix CSS class typo.

Line 108 uses bg-linear-to-b which is not a valid Tailwind class. This should be bg-gradient-to-b.

Apply this diff:

-            <div className="w-full rounded-lg overflow-hidden shadow-md bg-linear-to-b from-white to-gray-50 dark:from-gray-900 dark:to-gray-800">
+            <div className="w-full rounded-lg overflow-hidden shadow-md bg-gradient-to-b from-white to-gray-50 dark:from-gray-900 dark:to-gray-800">
📝 Committable suggestion

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

Suggested change
<div className="w-full rounded-lg overflow-hidden shadow-md bg-linear-to-b from-white to-gray-50 dark:from-gray-900 dark:to-gray-800">
<div className="w-full rounded-lg overflow-hidden shadow-md bg-gradient-to-b from-white to-gray-50 dark:from-gray-900 dark:to-gray-800">
🤖 Prompt for AI Agents
In src/app/dashboard/vehicles/[vehicleId]/page.tsx around line 108, the div uses
an invalid Tailwind class "bg-linear-to-b"; replace it with the correct
"bg-gradient-to-b" so the background gradient works as intended and remove the
typo.

Comment on lines +361 to +386
/* Legacy support - keep for backward compatibility */
.theme-filter-active {
background: linear-gradient(135deg, #0CA0E4 0%, #0CA0E4 100%);
color: white;
border: 1px solid #0CA0E4;
font-weight: 600;
box-shadow: 0 4px 6px -1px rgba(59, 130, 246, 0.3), 0 2px 4px -1px rgba(59, 130, 246, 0.2);
}

.theme-filter-inactive {
background-color: var(--bg-secondary);
color: var(--text-secondary);
border: 1px solid var(--border-color);
}

.theme-filter-inactive:hover {
background-color: #0CA0E4;
color: #0CA0E4;
border-color: #0CA0E4;
}

:root.dark .theme-filter-inactive:hover {
background-color:#0CA0E4;
color: #0CA0E4;
border-color: #60a5fa;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix invisible text on .theme-filter-inactive:hover.

In the legacy filter styles, the hover state sets text and background to the same color:

.theme-filter-inactive:hover {
  background-color: #0CA0E4;
  color: #0CA0E4;
  border-color: #0CA0E4;
}

This makes the label unreadable and hurts accessibility. Suggest something like:

 .theme-filter-inactive:hover {
-  background-color: #0CA0E4;
-  color: #0CA0E4;
-  border-color: #0CA0E4;
+  background-color: #0CA0E4;
+  color: #ffffff;
+  border-color: #0CA0E4;
 }

(or use the existing accent/text tokens if you prefer).

🤖 Prompt for AI Agents
In src/app/globals.css around lines 361 to 386, the hover rule for
.theme-filter-inactive sets background-color and color to the same hex
(#0CA0E4), making text invisible; update the hover styles so foreground and
background contrast (e.g., keep background #0CA0E4 but set color to a readable
value like white or the existing --text-accent/--text-primary token) and ensure
the border-color remains consistent (and adjust :root.dark variant to use a
contrasting text color as well).

Comment on lines +3 to 4
import axios from 'axios';
import Cookies from 'js-cookie';
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Remove or gate logging of tokens and full auth responses

The new login implementation works functionally, but the debug logging is problematic:

  • console.log('Login response:', res.data);
  • console.log('Extracted token:', token);
  • Similar logs in verifyEmail also print verification responses and access tokens.

Even on the client, logging tokens and full auth payloads is risky and noisy for production; they can leak into screenshots, error-reporting tools, or shared console logs.

I’d recommend either removing these logs entirely or gating them behind an explicit debug flag / non‑production check, e.g.:

   async login(payload: LoginRequest) {
-    try {
-      // api baseURL already includes '/api/v1'
-      const res = await api.post('/auth/login', payload);
-      // backend returns token in body
-      const token = res.data?.token || res.data?.accessToken || null;
-      console.log('Login response:', res.data);
-      console.log('Extracted token:', token);
+    try {
+      const res = await api.post('/auth/login', payload);
+      const token = res.data?.token || res.data?.accessToken || null;
       if (token) {
         Cookies.set(TOKEN_COOKIE, token, { expires: 7 });
-        console.log('Token saved to cookie');
       }
       return res.data;
@@
-  async verifyEmail(token: string) {
-    console.log('authService.verifyEmail called with token:', token);
+  async verifyEmail(token: string) {
     try {
       const res = await api.post('/auth/verify-email', { token });
-      console.log('Verification API response:', res.data);
-      // Save token to cookie after verification
       const accessToken = res.data?.token || res.data?.accessToken || null;
       if (accessToken) {
         Cookies.set(TOKEN_COOKIE, accessToken, { expires: 7 });
-        console.log('Access token saved to cookie');
       }
       return res.data;

The Axios-based error narrowing and rethrow logic itself looks fine.

Also applies to: 15-35, 85-95

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants