SANC-60-vehicle-logs-create-api-endpoints-and-connect-to-frontend#62
SANC-60-vehicle-logs-create-api-endpoints-and-connect-to-frontend#62
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughAdds CRUD mutations to the vehicle logs API router with filtering and validation, introduces edit-mode support in the form by capturing log ids, and enhances the table view with loading and error state UI. The page integrates these mutations with form submission logic and session-based defaults. Changes
Sequence DiagramsequenceDiagram
actor User
participant Form as Form Component
participant Page as Vehicle Logs Page
participant API as TRPC Router
participant DB as Database
rect rgba(100, 150, 255, 0.5)
Note over User,DB: Create Flow
User->>Form: Fill new log form
User->>Page: Click Submit
Page->>Page: Validate inputs
Page->>API: call createLog mutation
API->>API: Validate schema (odometer, times)
API->>API: Inject driverId from session
API->>DB: Insert vehicle log
DB-->>API: Return created log
API-->>Page: Success response
Page->>Form: Reset form, clear id
Page->>User: Show success notification
end
rect rgba(100, 200, 100, 0.5)
Note over User,DB: Edit Flow
User->>Form: Click table row
Form->>Page: Populate form with log data
Page->>Form: Set id and fields
User->>Form: Modify fields
User->>Page: Click Submit
Page->>API: call updateLog mutation
API->>DB: Update vehicle log by id
DB-->>API: Return updated log
API-->>Page: Success response
Page->>Page: Invalidate cache
Page->>Form: Reset form
Page->>User: Show success notification
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/app/admin/vehicle-logs/page.tsx (1)
74-83:⚠️ Potential issue | 🟠 MajorOdometer validation/submission is inconsistent with backend constraints.
Frontend permits equal values and silently rounds decimals, while backend enforces strict integer
odometerEnd > odometerStart. This can pass client validation but still fail mutation (or mutate values unexpectedly).💡 Suggested alignment with backend rules
odometerStart: (value) => { if (value.trim().length === 0) return "Odometer start is required"; const num = Number.parseFloat(value); if (Number.isNaN(num)) return "Must be a valid number"; - if (num < 0) return "Must be a positive number"; + if (num < 0) return "Must be a non-negative number"; + if (!Number.isInteger(num)) return "Must be a whole number"; return null; }, odometerEnd: (value, values) => { if (value.trim().length === 0) return "Odometer end is required"; const num = Number.parseFloat(value); if (Number.isNaN(num)) return "Must be a valid number"; - if (num < 0) return "Must be a positive number"; + if (num < 0) return "Must be a non-negative number"; + if (!Number.isInteger(num)) return "Must be a whole number"; const start = Number.parseFloat(values.odometerStart); - if (!Number.isNaN(start) && num < start) { - return "End reading must be greater than or equal to start reading"; + if (!Number.isNaN(start) && num <= start) { + return "End reading must be greater than start reading"; } return null; }, @@ - const odometerStart = Math.round(Number.parseFloat(values.odometerStart)); - const odometerEnd = Math.round(Number.parseFloat(values.odometerEnd)); + const odometerStart = Number(values.odometerStart); + const odometerEnd = Number(values.odometerEnd);Also applies to: 122-123
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/app/admin/vehicle-logs/page.tsx` around lines 74 - 83, The odometerEnd validation in page.tsx currently allows equal values and accepts decimals which frontend may round, causing backend failures; update the odometerEnd validator to require an integer (no decimals) and enforce strictly odometerEnd > odometerStart (not >=), and mirror the same integer constraint in the odometerStart validation so both client-side checks match the backend rule; ensure submission/parsing uses integer parsing (or rejects non-integer input) instead of implicit float rounding so the mutation receives the exact integer values the backend expects.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/app/admin/vehicle-logs/page.tsx`:
- Line 18: The VehicleLogsPage component should be moved from the current route
to the canonical route: create a new page at /admin/driver-logs with the same
implementation (or move the file and adjust path), rename the component/export
to DriverLogsPage (or keep default export but update references) and update any
imports/usages and the navbar link to point to /admin/driver-logs; ensure there
are no remaining placeholders at /admin/driver-logs and remove or redirect the
old /admin/vehicle-logs route so the feature lives only under the canonical path
(update route references in route tables, navigation components, and tests
accordingly).
In `@src/server/api/routers/vehicle-logs.ts`:
- Around line 139-157: The update schema's .refine checks for odometer and time
pairs allow single-field updates (e.g., only odometerEnd or arrivalTime) to
bypass validation; modify the same refine logic in the update input schema so
that if one of a pair is provided the other must also be provided and then
enforce the ordering (for odometer: require odometerStart when odometerEnd is
present and check odometerEnd > odometerStart; for times: require departureTime
when arrivalTime is present and check new Date(arrivalTime) > new
Date(departureTime)); update the two .refine blocks that reference
odometerEnd/odometerStart and arrivalTime/departureTime to implement these
presence+ordering guards so partial single-field edits no longer bypass
validation.
- Around line 15-16: The dateFrom and dateTo fields in the input Zod schema
accept any string and must be validated to avoid DB errors; update the Zod
schema (the schema where dateFrom and dateTo are defined) to use a stricter
validator such as z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional().refine(v =>
!v || !Number.isNaN(Date.parse(v)), { message: "Invalid ISO date (YYYY-MM-DD)"
}) so malformed values are rejected before SQL is built, then convert the
validated strings to Date (or normalized ISO) when you build SQL predicates;
also add a cross-field check to ensure dateFrom <= dateTo and apply the same
validation change to the other identical schema block referenced (lines 29-34).
---
Outside diff comments:
In `@src/app/admin/vehicle-logs/page.tsx`:
- Around line 74-83: The odometerEnd validation in page.tsx currently allows
equal values and accepts decimals which frontend may round, causing backend
failures; update the odometerEnd validator to require an integer (no decimals)
and enforce strictly odometerEnd > odometerStart (not >=), and mirror the same
integer constraint in the odometerStart validation so both client-side checks
match the backend rule; ensure submission/parsing uses integer parsing (or
rejects non-integer input) instead of implicit float rounding so the mutation
receives the exact integer values the backend expects.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
src/app/_components/vehiclelogcomponents/vehicle-log-form.tsxsrc/app/_components/vehiclelogcomponents/vehicle-log-table-view.module.scsssrc/app/_components/vehiclelogcomponents/vehicle-log-table-view.tsxsrc/app/admin/vehicle-logs/page.tsxsrc/server/api/routers/vehicle-logs.ts
| import { notify } from "@/lib/notifications"; | ||
| import { api } from "@/trpc/react"; | ||
|
|
||
| export default function VehicleLogsPage() { |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify canonical admin route usage for driver/vehicle logs
fd -t f 'navbar.tsx|page.tsx' src/app | head -20
rg -n '/admin/(driver-logs|vehicle-logs)' src/app src/lib --type tsx --type tsRepository: Code-the-Change-YYC/salvationarmy
Length of output: 696
🏁 Script executed:
#!/bin/bash
# Search for route patterns without file type flags
rg -n '/admin/(driver-logs|vehicle-logs)' src/app src/lib
# Also check navbar for navigation links
rg -n 'driver-logs|vehicle-logs' src/app/_components/common/navbar.tsx -A 2 -B 2Repository: Code-the-Change-YYC/salvationarmy
Length of output: 379
🏁 Script executed:
#!/bin/bash
# Check the content of both page files to understand their purpose
echo "=== /admin/driver-logs/page.tsx ==="
cat src/app/admin/driver-logs/page.tsx
echo -e "\n=== /admin/vehicle-logs/page.tsx ==="
cat src/app/admin/vehicle-logs/page.tsxRepository: Code-the-Change-YYC/salvationarmy
Length of output: 6723
Move this page to /admin/driver-logs to match the canonical route for this project.
The fully functional vehicle logs page is currently at /admin/vehicle-logs, but the canonical route for this feature is /admin/driver-logs. The navbar should link to /admin/driver-logs, and the placeholder at that location should be replaced with the actual implementation.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/app/admin/vehicle-logs/page.tsx` at line 18, The VehicleLogsPage
component should be moved from the current route to the canonical route: create
a new page at /admin/driver-logs with the same implementation (or move the file
and adjust path), rename the component/export to DriverLogsPage (or keep default
export but update references) and update any imports/usages and the navbar link
to point to /admin/driver-logs; ensure there are no remaining placeholders at
/admin/driver-logs and remove or redirect the old /admin/vehicle-logs route so
the feature lives only under the canonical path (update route references in
route tables, navigation components, and tests accordingly).
| dateFrom: z.string().optional(), // ISO date string "YYYY-MM-DD" | ||
| dateTo: z.string().optional(), // ISO date string "YYYY-MM-DD" |
There was a problem hiding this comment.
Validate dateFrom / dateTo format before building SQL predicates.
These fields currently accept any string. Malformed values can surface as DB errors instead of clean input errors.
💡 Suggested hardening
getAll: adminProcedure
.input(
z
.object({
vehicle: z.string().optional(),
driverName: z.string().optional(),
- dateFrom: z.string().optional(), // ISO date string "YYYY-MM-DD"
- dateTo: z.string().optional(), // ISO date string "YYYY-MM-DD"
+ dateFrom: z
+ .string()
+ .regex(/^\d{4}-\d{2}-\d{2}$/, "dateFrom must be YYYY-MM-DD")
+ .optional(),
+ dateTo: z
+ .string()
+ .regex(/^\d{4}-\d{2}-\d{2}$/, "dateTo must be YYYY-MM-DD")
+ .optional(),
})
+ .refine((v) => !v.dateFrom || !v.dateTo || v.dateFrom <= v.dateTo, {
+ message: "dateFrom must be on or before dateTo",
+ path: ["dateTo"],
+ })
.optional(),
)Also applies to: 29-34
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/server/api/routers/vehicle-logs.ts` around lines 15 - 16, The dateFrom
and dateTo fields in the input Zod schema accept any string and must be
validated to avoid DB errors; update the Zod schema (the schema where dateFrom
and dateTo are defined) to use a stricter validator such as
z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional().refine(v => !v ||
!Number.isNaN(Date.parse(v)), { message: "Invalid ISO date (YYYY-MM-DD)" }) so
malformed values are rejected before SQL is built, then convert the validated
strings to Date (or normalized ISO) when you build SQL predicates; also add a
cross-field check to ensure dateFrom <= dateTo and apply the same validation
change to the other identical schema block referenced (lines 29-34).
| .refine( | ||
| (data) => { | ||
| if (data.odometerEnd !== undefined && data.odometerStart !== undefined) { | ||
| return data.odometerEnd > data.odometerStart; | ||
| } | ||
| return true; | ||
| }, | ||
| { | ||
| message: "Odometer end must be greater than odometer start", | ||
| path: ["odometerEnd"], | ||
| }, | ||
| ) | ||
| .refine( | ||
| (data) => { | ||
| if (data.arrivalTime !== undefined && data.departureTime !== undefined) { | ||
| return new Date(data.arrivalTime) > new Date(data.departureTime); | ||
| } | ||
| return true; | ||
| }, |
There was a problem hiding this comment.
update allows single-field time/odometer edits that can bypass app validation.
If only one field in a pair is sent (e.g., only odometerEnd), current refinements skip pair checks and failures are deferred to DB constraints.
💡 Suggested guardrails
.object({
id: z.number().int().positive(),
date: z.string().min(1).optional(),
travelLocation: z.string().min(1).optional(),
departureTime: z.string().min(1).optional(),
arrivalTime: z.string().min(1).optional(),
odometerStart: z.number().int().nonnegative().optional(),
odometerEnd: z.number().int().nonnegative().optional(),
driverId: z.string().min(1).optional(),
driverName: z.string().min(1).optional(),
vehicle: z.string().min(1).optional(),
})
+ .refine(
+ (data) => (data.odometerStart === undefined) === (data.odometerEnd === undefined),
+ {
+ message: "Provide both odometerStart and odometerEnd together",
+ path: ["odometerEnd"],
+ },
+ )
+ .refine(
+ (data) => (data.departureTime === undefined) === (data.arrivalTime === undefined),
+ {
+ message: "Provide both departureTime and arrivalTime together",
+ path: ["arrivalTime"],
+ },
+ )
.refine(
(data) => {
if (data.odometerEnd !== undefined && data.odometerStart !== undefined) {
return data.odometerEnd > data.odometerStart;
}
return true;
},Also applies to: 168-172
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/server/api/routers/vehicle-logs.ts` around lines 139 - 157, The update
schema's .refine checks for odometer and time pairs allow single-field updates
(e.g., only odometerEnd or arrivalTime) to bypass validation; modify the same
refine logic in the update input schema so that if one of a pair is provided the
other must also be provided and then enforce the ordering (for odometer: require
odometerStart when odometerEnd is present and check odometerEnd > odometerStart;
for times: require departureTime when arrivalTime is present and check new
Date(arrivalTime) > new Date(departureTime)); update the two .refine blocks that
reference odometerEnd/odometerStart and arrivalTime/departureTime to implement
these presence+ordering guards so partial single-field edits no longer bypass
validation.
leftover from SANC58-vehicle-logs-frontend:
log.idbug by adding id to the forms initialValues so the update mutation can target the correct rowSANC60:
Summary by CodeRabbit