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

feat: implement vehicle management features including add, edit, and …#7

Merged
RandithaK merged 7 commits into
devfrom
feature/vehicle-service
Nov 5, 2025
Merged

feat: implement vehicle management features including add, edit, and …#7
RandithaK merged 7 commits into
devfrom
feature/vehicle-service

Conversation

@Akith-002

@Akith-002 Akith-002 commented Oct 31, 2025

Copy link
Copy Markdown
Contributor

…delete vehicle functionality

Summary by CodeRabbit

  • New Features
    • Added comprehensive vehicle management: create, edit, and delete vehicles with validation.
    • Added vehicle details page with multi-image gallery and service history display.
    • Added photo upload functionality with drag-and-drop support for vehicle images.
    • Updated dashboard layout with improved navigation to vehicles, appointments, history, and profile sections.

RandithaK and others added 2 commits October 11, 2025 12:51
docs: Add build status badges for all services in README.md for impro…
@Akith-002
Akith-002 requested a review from RandithaK October 31, 2025 18:39
@coderabbitai

coderabbitai Bot commented Oct 31, 2025

Copy link
Copy Markdown

Walkthrough

This PR adds a complete vehicle management frontend for a Next.js 14 TypeScript application. It introduces new React components for vehicle creation and editing, a vehicles list page with full CRUD operations, a vehicle details page with photo upload and service history display, and a vehicleService API client. The customer dashboard is refactored from content-heavy placeholders to a navigation-focused card layout. A .gitattributes configuration is added for line ending consistency across Frontend_Web and API_Gateway projects.

Changes

Cohort / File(s) Summary
Configuration & Documentation
.gitattributes, VEHICLE_MANAGEMENT_FRONTEND.md
Adds LF/CRLF line ending rules and binary file handling for two projects; comprehensive frontend implementation summary documenting components, API surface, routing, and user flows.
Vehicle Management Service
src/services/vehicleService.ts
New client-side service module exporting vehicleService object with CRUD methods: registerVehicle, getMyVehicles, getVehicleById, updateVehicle, deleteVehicle, uploadVehiclePhotos, and getServiceHistory via API client.
Vehicle Form Components
src/app/components/AddVehicleForm.tsx, src/app/components/EditVehicleForm.tsx
New form components for creating and editing vehicles; manage local form state, validate inputs, handle submission via vehicleService, and display errors. Include Cancel/Add or Cancel/Update action buttons.
Vehicle Display Component
src/app/components/VehicleCard.tsx
New card component rendering vehicle year, make, model, license, color badge, and mileage; provides View Details, Edit, and Delete (with confirmation) actions using props callbacks and Next.js Link navigation.
Dashboard & Pages
src/app/components/dashboards/CustomerDashboard.tsx, src/app/dashboard/vehicles/page.tsx, src/app/dashboard/vehicles/[vehicleId]/page.tsx
Refactored CustomerDashboard to navigation-focused layout with card-based links; new My Vehicles list page with modal forms for add/edit, grid of VehicleCard components, and delete functionality; new Vehicle Details page with photo upload workflow, responsive two-column layout (gallery + service history, details sidebar), and type exports (Vehicle, VehicleListItem, VehicleRequest, VehicleUpdateRequest, VehicleResponse, PhotoUploadResponse, ServiceHistory).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant VehiclesPage as Vehicles Page
    participant Modal as Modal Form
    participant VehicleService as Vehicle Service
    participant API as Backend API

    User->>VehiclesPage: Load /dashboard/vehicles
    VehiclesPage->>VehicleService: getMyVehicles()
    VehicleService->>API: GET /vehicles
    API-->>VehicleService: VehicleListItem[]
    VehicleService-->>VehiclesPage: vehicles
    VehiclesPage->>VehiclesPage: Render grid of VehicleCard

    User->>VehiclesPage: Click "Add New Vehicle"
    VehiclesPage->>Modal: Open AddVehicleForm
    User->>Modal: Fill form, submit
    Modal->>VehicleService: registerVehicle(payload)
    VehicleService->>API: POST /vehicles
    API-->>VehicleService: VehicleResponse
    VehicleService-->>Modal: response
    Modal->>VehiclesPage: onSuccess callback
    VehiclesPage->>VehiclesPage: Refresh vehicle list

    User->>VehiclesPage: Click Delete on VehicleCard
    User->>User: Confirm delete dialog
    VehiclesPage->>VehicleService: deleteVehicle(vehicleId)
    VehicleService->>API: DELETE /vehicles/{id}
    API-->>VehicleService: VehicleResponse
    VehicleService-->>VehiclesPage: response
    VehiclesPage->>VehiclesPage: Refresh vehicle list
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • API integration & error handling: Verify error handling patterns are consistent across all vehicleService methods and component implementations; review edge cases in upload and async operations.
  • Form validation & state management: Check AddVehicleForm and EditVehicleForm field validation rules, state initialization in EditVehicleForm from props, and form state resets after submission.
  • Photo upload workflow: Review file handling logic in VehicleDetailsPage, multipart/form-data construction, and user feedback mechanisms.
  • Modal lifecycle: Verify proper cleanup and state management when opening/closing modals in VehiclesPage, especially for AddVehicleForm and EditVehicleForm.
  • Navigation & routing: Confirm dynamic routing in VehicleDetailsPage and Link navigation targets are correct.
  • Type consistency: Ensure exported types from VehicleDetailsPage are properly imported and used across components and vehicleService.

Poem

🐰 A hop, skip, and form away,
Vehicles dance in grids today!
Add and edit with modal grace,
Delete with care, each in its place.
PhotosHop and historyFlow,
The dashboard blooms—watch it grow! 🚗✨

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: implementing vehicle management features including add, edit, and delete functionality, which matches the changeset's primary focus.
✨ 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 feature/vehicle-service

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🧹 Nitpick comments (6)
.gitattributes (2)

12-12: Remove duplicate Markdown file rule.

Lines 12 and 19 both specify *.md text eol=lf. Keep one and remove the duplicate.

Apply this diff to remove the duplicate:

  # Markdown
  *.md    text eol=lf
  
  # Mark common web files as LF
  *.json  text eol=lf
  *.css   text eol=lf
  *.scss  text eol=lf
  *.html  text eol=lf
- *.md    text eol=lf

Also applies to: 19-19


1-63: Clarify repository structure and scope rules if this is a monorepo.

This .gitattributes file defines rules for two separate projects (Frontend_Web and API_Gateway). If this file is at the monorepo root with both projects as subdirectories, the rules should be scoped with path patterns (e.g., Frontend_Web/**/*.ts) to avoid accidentally applying API_Gateway rules to Frontend_Web files and vice versa. This becomes increasingly important as the projects evolve and potentially add file types not yet covered.

Please clarify:

  1. Is this a monorepo with Frontend_Web/ and API_Gateway/ as subdirectories?
  2. If yes, should each project's rules be scoped with path patterns?

If this is confirmed to be a monorepo, the rules should be refactored like this:

- # TypeScript / JavaScript
- *.ts    text eol=lf
+ # Frontend_Web (Next.js / TypeScript project)
+ Frontend_Web/**/*.ts    text eol=lf
+ Frontend_Web/**/*.tsx   text eol=lf
+ Frontend_Web/**/*.js    text eol=lf
+ Frontend_Web/**/*.jsx   text eol=lf
  ...
  
- # Go
- *.go    text eol=lf
+ # API_Gateway (Go project)
+ API_Gateway/**/*.go    text eol=lf
+ API_Gateway/**/*.mod   text eol=lf
+ API_Gateway/**/*.sum   text eol=lf

Alternatively, if each project should have its own .gitattributes file at its root, move the Frontend_Web rules to Frontend_Web/.gitattributes and API_Gateway rules to API_Gateway/.gitattributes.

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

48-57: Consider replacing confirm() with a modal dialog.

The native confirm() dialog blocks the UI and lacks styling consistency. For better UX, consider using a custom modal component that matches your design system.

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

38-38: Replace alert() with a toast notification or error modal.

The alert() dialog blocks the UI and provides poor UX. Consider using a toast library (like react-hot-toast or sonner) or displaying error messages inline.

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

103-107: Use Next.js <Image> component for optimization.

Standard <img> tags bypass Next.js automatic image optimization, resulting in slower LCP and higher bandwidth. Replace with next/image for automatic optimization, lazy loading, and responsive sizing.

Apply this diff:

+import Image from 'next/image';

 // In the component:
-<img
+<Image
   src={vehicle.photos[0] as unknown as string}
   alt={`${vehicle.make} ${vehicle.model}`}
-  className="w-full h-72 object-cover"
+  width={800}
+  height={288}
+  className="w-full h-72 object-cover"
 />

 // For thumbnails:
-<img src={p as unknown as string} alt={`photo-${i}`} className="w-full h-full object-cover" />
+<Image src={p as unknown as string} alt={`photo-${i}`} width={96} height={64} className="w-full h-full object-cover" />

Also applies to: 120-120


53-53: Replace alert() with toast notifications.

Using alert() blocks the UI and provides poor UX. Consider using a toast notification library like react-hot-toast or sonner for non-blocking feedback.

Also applies to: 55-55

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7b560ce and d5a2520.

📒 Files selected for processing (9)
  • .gitattributes (1 hunks)
  • VEHICLE_MANAGEMENT_FRONTEND.md (1 hunks)
  • src/app/components/AddVehicleForm.tsx (1 hunks)
  • src/app/components/EditVehicleForm.tsx (1 hunks)
  • src/app/components/VehicleCard.tsx (1 hunks)
  • src/app/components/dashboards/CustomerDashboard.tsx (3 hunks)
  • src/app/dashboard/vehicles/[vehicleId]/page.tsx (1 hunks)
  • src/app/dashboard/vehicles/page.tsx (1 hunks)
  • src/services/vehicleService.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (6)
src/app/dashboard/vehicles/[vehicleId]/page.tsx (1)
src/services/vehicleService.ts (1)
  • vehicleService (13-84)
src/services/vehicleService.ts (1)
src/app/dashboard/vehicles/[vehicleId]/page.tsx (7)
  • VehicleRequest (238-246)
  • VehicleResponse (254-257)
  • VehicleListItem (228-236)
  • Vehicle (214-226)
  • VehicleUpdateRequest (248-252)
  • PhotoUploadResponse (259-262)
  • ServiceHistory (264-270)
src/app/components/VehicleCard.tsx (1)
src/app/dashboard/vehicles/[vehicleId]/page.tsx (1)
  • VehicleListItem (228-236)
src/app/components/AddVehicleForm.tsx (2)
src/app/dashboard/vehicles/[vehicleId]/page.tsx (1)
  • VehicleRequest (238-246)
src/services/vehicleService.ts (1)
  • vehicleService (13-84)
src/app/components/EditVehicleForm.tsx (2)
src/app/dashboard/vehicles/[vehicleId]/page.tsx (1)
  • VehicleUpdateRequest (248-252)
src/services/vehicleService.ts (1)
  • vehicleService (13-84)
src/app/dashboard/vehicles/page.tsx (5)
src/app/dashboard/vehicles/[vehicleId]/page.tsx (1)
  • VehicleListItem (228-236)
src/services/vehicleService.ts (1)
  • vehicleService (13-84)
src/app/components/AddVehicleForm.tsx (1)
  • AddVehicleForm (11-174)
src/app/components/EditVehicleForm.tsx (1)
  • EditVehicleForm (17-122)
src/app/components/VehicleCard.tsx (1)
  • VehicleCard (11-61)
🪛 Biome (2.1.2)
src/app/dashboard/vehicles/[vehicleId]/page.tsx

[error] 214-215: Shouldn't redeclare 'Vehicle'. Consider to delete it or rename it.

'Vehicle' is defined here:

(lint/suspicious/noRedeclare)


[error] 264-265: Shouldn't redeclare 'ServiceHistory'. Consider to delete it or rename it.

'ServiceHistory' is defined here:

(lint/suspicious/noRedeclare)

🪛 GitHub Actions: Build and Test Frontend_Web
src/app/components/AddVehicleForm.tsx

[error] 32-32: Unexpected any. Specify a different type. ESLint: @typescript-eslint/no-explicit-any.

🪛 GitHub Check: Install, Lint and Build
src/app/dashboard/vehicles/[vehicleId]/page.tsx

[warning] 120-120:
Using <img> could result in slower LCP and higher bandwidth. Consider using <Image /> from next/image or a custom image loader to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element


[warning] 103-103:
Using <img> could result in slower LCP and higher bandwidth. Consider using <Image /> from next/image or a custom image loader to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element


[failure] 54-54:
Unexpected any. Specify a different type


[failure] 40-40:
Unexpected any. Specify a different type


[failure] 29-29:
Unexpected any. Specify a different type


[warning] 21-21:
React Hook useEffect has missing dependencies: 'loadServiceHistory' and 'loadVehicleDetails'. Either include them or remove the dependency array

src/app/components/AddVehicleForm.tsx

[failure] 32-32:
Unexpected any. Specify a different type

src/app/components/EditVehicleForm.tsx

[failure] 39-39:
Unexpected any. Specify a different type

src/app/dashboard/vehicles/page.tsx

[failure] 37-37:
Unexpected any. Specify a different type


[failure] 22-22:
Unexpected any. Specify a different type

🪛 LanguageTool
VEHICLE_MANAGEMENT_FRONTEND.md

[style] ~5-~5: Some style guides suggest that commas should set off the year in a month-day-year date.
Context: ...LETE** Date Completed: October 17, 2025 Framework: Next.js 14 with TypeSc...

(MISSING_COMMA_AFTER_YEAR)

🔇 Additional comments (11)
src/app/components/EditVehicleForm.tsx (1)

46-52: LGTM!

The handleChange function correctly parses mileage as a number with a safe fallback to 0 for invalid input.

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

11-60: LGTM!

Clean component structure with proper prop handling and navigation integration.

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

98-111: LGTM!

VIN validation pattern is correct: 17 characters excluding I, O, and Q as per standard VIN format.


39-45: LGTM!

The parseInt fallback to 0 safely handles invalid numeric inputs for year and mileage fields.

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

82-91: LGTM!

Modal implementation for add and edit forms is clean and provides good UX with backdrop blur and proper z-index stacking.

Also applies to: 94-109

VEHICLE_MANAGEMENT_FRONTEND.md (1)

1-323: LGTM!

Comprehensive documentation covering implementation details, features, usage instructions, and technical stack. Well-structured and helpful for onboarding.

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

1-152: LGTM!

The dashboard refactoring successfully shifts from placeholder content to a clean, navigation-focused layout. The new card-based design with clear CTAs provides better user flow to vehicle management, appointments, and service history.

src/services/vehicleService.ts (2)

3-11: Verify type definitions exist in src/types/vehicle.ts.

The import references ../types/vehicle, but based on the PR files, these types appear to be defined in src/app/dashboard/vehicles/[vehicleId]/page.tsx instead. Ensure type definitions are properly centralized.

This verification is covered by the script in the EditVehicleForm.tsx review above.


13-84: LGTM!

Clean API service implementation with proper typing, good documentation, and correct handling of multipart form data for photo uploads.

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

18-21: LGTM!

The useEffect hook correctly depends on vehicleId. The static analysis warning about missing dependencies for loadVehicleDetails and loadServiceHistory is a false positive since these functions are defined inside the component and don't need to be in the dependency array (they're recreated on each render anyway).


85-210: LGTM!

The two-column responsive layout with vehicle details, photo gallery, and service history provides excellent UX. The sticky sidebar and empty states are well-implemented.

try {
await vehicleService.registerVehicle(formData);
onSuccess();
} catch (err: any) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Replace any with proper error type.

The pipeline is failing due to this any type. Use unknown and type narrowing for better type safety.

Apply this diff:

-  } catch (err: any) {
-    setError(err.response?.data?.message || 'Failed to add vehicle');
+  } catch (err: unknown) {
+    const message = err && typeof err === 'object' && 'response' in err
+      ? (err as { response?: { data?: { message?: string } } }).response?.data?.message
+      : undefined;
+    setError(message || 'Failed to add vehicle');
📝 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
} catch (err: any) {
} catch (err: unknown) {
const message = err && typeof err === 'object' && 'response' in err
? (err as { response?: { data?: { message?: string } } }).response?.data?.message
: undefined;
setError(message || 'Failed to add vehicle');
🧰 Tools
🪛 GitHub Actions: Build and Test Frontend_Web

[error] 32-32: Unexpected any. Specify a different type. ESLint: @typescript-eslint/no-explicit-any.

🪛 GitHub Check: Install, Lint and Build

[failure] 32-32:
Unexpected any. Specify a different type

🤖 Prompt for AI Agents
In src/app/components/AddVehicleForm.tsx around line 32, the catch block
currently types the error as "any"; change it to "unknown" and perform
type-narrowing before using the error. Specifically, update the catch parameter
to err: unknown, then inside the block check if (err instanceof Error) to access
err.message (or other Error properties), otherwise handle non-Error values
(e.g., stringify or use a default message) so that logging and downstream
handling are type-safe.

"use client";
import { useState } from 'react';
import { vehicleService } from '@/services/vehicleService';
import type { VehicleUpdateRequest } from '@/types/vehicle';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify type import path.

The import references @/types/vehicle, but the relevant code snippets show these types are exported from src/app/dashboard/vehicles/[vehicleId]/page.tsx. Either create a dedicated src/types/vehicle.ts file to centralize type definitions, or update the import path to reference the page file directly.

Run this script to check if the types file exists:


🏁 Script executed:

#!/bin/bash
# Check if src/types/vehicle.ts exists and examine type exports

if [ -f "src/types/vehicle.ts" ]; then
  echo "=== src/types/vehicle.ts exists ==="
  cat src/types/vehicle.ts
else
  echo "=== src/types/vehicle.ts NOT FOUND ==="
  echo "Types may need to be extracted to this location"
fi

# Search for VehicleUpdateRequest definition
echo ""
echo "=== All VehicleUpdateRequest definitions ==="
rg -n "interface VehicleUpdateRequest" -A 4

Length of output: 446



---

🏁 Script executed:

```shell
#!/bin/bash
# Check usages of @/types/vehicle import path
echo "=== Files importing from @/types/vehicle ==="
rg -n "@/types/vehicle" --type=ts --type=tsx

# Check all VehicleUpdateRequest usages
echo ""
echo "=== All VehicleUpdateRequest usages ==="
rg -n "VehicleUpdateRequest" --type=ts --type=tsx -B2 -A2

# Check EditVehicleForm.tsx imports
echo ""
echo "=== EditVehicleForm.tsx imports ==="
head -20 src/app/components/EditVehicleForm.tsx

Length of output: 276


🏁 Script executed:

#!/bin/bash
# Find EditVehicleForm.tsx file
echo "=== Locating EditVehicleForm.tsx ==="
fd -i "editvehicleform" --type f

echo ""
echo "=== All files with 'vehicle' in name ==="
fd "vehicle" --type f

echo ""
echo "=== Searching for @/types/vehicle import (no type restrictions) ==="
rg "@/types/vehicle" -n

echo ""
echo "=== Searching for VehicleUpdateRequest usage ==="
rg "VehicleUpdateRequest" -n -B1 -A1

Length of output: 2272



🏁 Script executed:

#!/bin/bash
# Examine full src/types/vehicle.ts
echo "=== Full src/types/vehicle.ts content ==="
cat src/types/vehicle.ts
echo "(END OF FILE)"

echo ""
echo "=== Check for VehicleUpdateRequest export in src/types/vehicle.ts ==="
rg "VehicleUpdateRequest" src/types/vehicle.ts

echo ""
echo "=== Check if page file exports VehicleUpdateRequest ==="
rg "export.*VehicleUpdateRequest" src/app/dashboard/vehicles/[vehicleId]/page.tsx

Length of output: 223


Centralize type definitions in src/types/vehicle.ts.

The file src/types/vehicle.ts is empty, yet multiple files (EditVehicleForm.tsx, vehicleService.ts, and others) import types from it, including VehicleUpdateRequest. The type is currently defined at src/app/dashboard/vehicles/[vehicleId]/page.tsx:248 but not exported from the centralized types file. All type definitions referenced in imports from @/types/vehicle must be moved to or re-exported from src/types/vehicle.ts to resolve the import failures.

🤖 Prompt for AI Agents
In src/app/components/EditVehicleForm.tsx around line 4, the import
VehicleUpdateRequest comes from an empty src/types/vehicle.ts; the actual type
is defined in src/app/dashboard/vehicles/[vehicleId]/page.tsx (around line 248).
Move the VehicleUpdateRequest type (and any other vehicle-related types used
across the codebase) into src/types/vehicle.ts and export them, then update or
keep imports to reference "@/types/vehicle". Alternatively, re-export the type
from src/types/vehicle.ts by importing it from the page.tsx and exporting it
from the central file, and remove any duplicate local type definitions so all
files consistently consume the centralized exported types.

try {
await vehicleService.updateVehicle(vehicleId, formData);
onSuccess();
} catch (err: any) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Replace any with proper error type.

Use a typed error interface or unknown with type narrowing to improve type safety.

Apply this diff:

-  } catch (err: any) {
+  } catch (err: unknown) {
-    setError(err.response?.data?.message || 'Failed to update vehicle');
+    const message = err instanceof Error && 'response' in err 
+      ? (err as any).response?.data?.message 
+      : 'Failed to update vehicle';
+    setError(message || 'Failed to update vehicle');

Or define an API error type:

interface ApiError {
  response?: {
    data?: {
      message?: string;
    };
  };
}

// Then use:
} catch (err: unknown) {
  const apiError = err as ApiError;
  setError(apiError.response?.data?.message || 'Failed to update vehicle');
}
🧰 Tools
🪛 GitHub Check: Install, Lint and Build

[failure] 39-39:
Unexpected any. Specify a different type

🤖 Prompt for AI Agents
In src/app/components/EditVehicleForm.tsx around line 39, the catch clause
currently types the caught error as `any`; change it to `unknown` and perform
type narrowing or define an ApiError interface (with optional
response.data.message) and cast the caught value to that interface before
accessing message. Specifically, replace `catch (err: any)` with `catch (err:
unknown)` and then either use a type guard to check shape or cast to the
ApiError type and setError using the optional chaining fallback (e.g.,
apiError.response?.data?.message || 'Failed to update vehicle').

import { useState, useEffect } from 'react';
import { useRouter, useParams } from 'next/navigation';
import { vehicleService } from '@/services/vehicleService';
import type { Vehicle, ServiceHistory } from '@/types/vehicle';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Type redeclaration causing build errors.

The types are imported from @/types/vehicle at line 5, then redeclared at lines 214-270. This causes the redeclaration errors flagged by Biome. These type definitions should be moved to a centralized src/types/vehicle.ts file and imported, not defined inline in the page component.

Create src/types/vehicle.ts:

export interface Vehicle {
  vehicleId: string;
  customerId: string;
  make: string;
  model: string;
  year: number;
  vin: string;
  licensePlate: string;
  color?: string;
  mileage: number;
  photos?: string[];  // Add missing photos property
  createdAt: string;
  updatedAt: string;
}

export interface VehicleListItem {
  vehicleId: string;
  make: string;
  model: string;
  year: number;
  licensePlate: string;
  color?: string;
  mileage: number;
}

export interface VehicleRequest {
  make: string;
  model: string;
  year: number;
  vin: string;
  licensePlate: string;
  color?: string;
  mileage?: number;
}

export interface VehicleUpdateRequest {
  color?: string;
  mileage?: number;
  licensePlate?: string;
}

export interface VehicleResponse {
  message: string;
  vehicleId: string;
}

export interface PhotoUploadResponse {
  photoIds: string[];
  urls: string[];
}

export interface ServiceHistory {
  serviceId: string;
  date: string;
  type: string;
  cost: number;
  description?: string;
}

Then remove lines 213-270 from this file and update the import at line 5 to only import Vehicle and ServiceHistory.

Also applies to: 214-270

🤖 Prompt for AI Agents
In src/app/dashboard/vehicles/[vehicleId]/page.tsx (import at line 5) and
duplicate type block at lines 214-270 (also referenced as 213-270), the inline
type declarations conflict with the import causing build errors; create a new
file src/types/vehicle.ts containing the Vehicle, VehicleListItem,
VehicleRequest, VehicleUpdateRequest, VehicleResponse, PhotoUploadResponse, and
ServiceHistory interfaces (include the photos?: string[] property on Vehicle),
update the import at line 5 to import the needed types (Vehicle and
ServiceHistory or others as required) from '@/types/vehicle', and remove the
inline type definitions from page.tsx (delete lines ~213-270) so types are
centralized and no longer redeclared.

const data = await vehicleService.getVehicleById(vehicleId);
setVehicle(data);
setError(null);
} catch (err: any) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Replace any types with proper error handling.

Three instances of any should be replaced with unknown for better type safety.

Apply this diff:

-  } catch (err: any) {
+  } catch (err: unknown) {
+    const message = err && typeof err === 'object' && 'response' in err
+      ? (err as { response?: { data?: { message?: string } } }).response?.data?.message
+      : undefined;
-    setError(err.response?.data?.message || 'Failed to load vehicle details');
+    setError(message || 'Failed to load vehicle details');
   }

Apply similar changes to lines 40 and 54.

Also applies to: 40-40, 54-54

🧰 Tools
🪛 GitHub Check: Install, Lint and Build

[failure] 29-29:
Unexpected any. Specify a different type

🤖 Prompt for AI Agents
In src/app/dashboard/vehicles/[vehicleId]/page.tsx around lines 29, 40 and 54,
replace the catch clause parameter type from "any" to "unknown" and update
subsequent error handling to safely narrow the type before accessing properties:
change catch (err: any) to catch (err: unknown), then when logging or reading
err.message use a type guard (e.g., if (err instanceof Error) { /* use
err.message */ } else { /* fallback: String(err) */ }) or extract a safe string
via String(err); make these three analogous changes at the indicated lines so
you no longer assume the error shape directly.

Comment on lines +102 to +112
{vehicle.photos && vehicle.photos.length > 0 ? (
<img
src={vehicle.photos[0] as unknown as string}
alt={`${vehicle.make} ${vehicle.model}`}
className="w-full h-72 object-cover"
/>
) : (
<div className="w-full h-72 flex items-center justify-center bg-gray-100 dark:bg-gray-800">
<span className="text-gray-500 dark:text-gray-400">No photo available</span>
</div>
)}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Vehicle interface missing photos property.

Lines 102-124 access vehicle.photos, but the Vehicle interface (lines 214-226) doesn't include a photos property. This will cause runtime errors.

Add photos property to the Vehicle interface:

 export interface Vehicle {
   vehicleId: string;
   customerId: string;
   make: string;
   model: string;
   year: number;
   vin: string;
   licensePlate: string;
   color?: string;
   mileage: number;
+  photos?: string[];
   createdAt: string;
   updatedAt: string;
 }

Also applies to: 116-124

🧰 Tools
🪛 GitHub Check: Install, Lint and Build

[warning] 103-103:
Using <img> could result in slower LCP and higher bandwidth. Consider using <Image /> from next/image or a custom image loader to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element

🤖 Prompt for AI Agents
In src/app/dashboard/vehicles/[vehicleId]/page.tsx around lines 102-112 (and
similarly 116-124), the code accesses vehicle.photos but the Vehicle interface
(lines ~214-226) does not declare a photos property; add a photos property to
the Vehicle interface (e.g., photos?: string[] or photos: string[] depending on
whether photos can be absent) so the code is type-safe, and update any places
that construct or fetch Vehicle objects to include photos (or handle undefined)
accordingly.

const data = await vehicleService.getMyVehicles();
setVehicles(data);
setError(null);
} catch (err: any) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Replace any types with proper error handling.

Both error handlers use any. Use unknown with type guards for better type safety.

Apply this diff:

   } catch (err: any) {
-    setError(err.response?.data?.message || 'Failed to load vehicles');
+  } catch (err: unknown) {
+    const message = err && typeof err === 'object' && 'response' in err
+      ? (err as { response?: { data?: { message?: string } } }).response?.data?.message
+      : undefined;
+    setError(message || 'Failed to load vehicles');
   }

   // And for handleDelete:
-  } catch (err: any) {
-    alert(err.response?.data?.message || 'Failed to delete vehicle');
+  } catch (err: unknown) {
+    const message = err && typeof err === 'object' && 'response' in err
+      ? (err as { response?: { data?: { message?: string } } }).response?.data?.message
+      : undefined;
+    alert(message || 'Failed to delete vehicle');

Also applies to: 37-37

🧰 Tools
🪛 GitHub Check: Install, Lint and Build

[failure] 22-22:
Unexpected any. Specify a different type

🤖 Prompt for AI Agents
In src/app/dashboard/vehicles/page.tsx around lines 22 and 37, change the catch
clauses that currently use "err: any" to "err: unknown" and add a small type
guard before using the error: check if the value is an instance of Error (or
create an isError function that verifies it has a message property of type
string) then read err.message for logging/handling; for non-Error values,
convert to a string (e.g., String(err)) or use a fallback message. Ensure you do
not assume properties on the unknown error before the guard and preserve
existing control flow (log, set state, or rethrow) after extracting a safe
message.


## ✅ **FRONTEND IMPLEMENTATION COMPLETE**

**Date Completed:** October 17, 2025

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Update completion date to match PR creation date.

The document shows "October 17, 2025" but the PR was created on October 31, 2025. Update the date for consistency.

Apply this diff:

-**Date Completed:** October 17, 2025  
+**Date Completed:** October 31, 2025  
🧰 Tools
🪛 LanguageTool

[style] ~5-~5: Some style guides suggest that commas should set off the year in a month-day-year date.
Context: ...LETE** Date Completed: October 17, 2025 Framework: Next.js 14 with TypeSc...

(MISSING_COMMA_AFTER_YEAR)

🤖 Prompt for AI Agents
In VEHICLE_MANAGEMENT_FRONTEND.md around line 5, the "Date Completed" entry
reads "October 17, 2025" but the PR was created on October 31, 2025; update that
line to "Date Completed: October 31, 2025" so the document matches the PR
creation date and save the file.

@Akith-002
Akith-002 changed the base branch from main to dev November 5, 2025 05:44
@RandithaK
RandithaK merged commit 6129a4e into dev Nov 5, 2025
1 of 3 checks passed
This was referenced Nov 5, 2025
Merged
Merged
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.

3 participants