3.5 KiB
Maintenance Reminders (Phase 4.6)
Overview
Maintenance reminders allow shops to set mileage-based follow-up reminders for customers after service. Reminders are created from the RO Detail Modal and displayed on the Dashboard.
PocketBase Collection: reminders
| Field | Type | Notes |
|---|---|---|
customerId |
text | From RO's customerId |
customerName |
text | Pre-filled from RO |
vehicleInfo |
text | Pre-filled from RO |
shopUserId |
text | The shop's PB user ID |
mileageAtService |
number | User-entered, pre-filled from ro.mileage |
intervalMileage |
number | User-entered, defaults to 5000 |
dueMileage |
number | Computed: mileageAtService + intervalMileage |
notes |
text | Optional notes field |
active |
bool | Set true on creation |
Integration Points
1. RODetailModal.tsx — Set Reminder
Location: Header area, in the button group next to Print/PDF/Generate Quote buttons.
Button: BellRing icon, toggles the inline form. Pre-fills reminderMileage from ro.mileage when opened. Active state uses blue styling to indicate the form is open.
Inline Form (appears below header, above info bar):
- Blue-themed card (
border-blue-200 bg-blue-50) - Shows customer name and vehicle info from RO (read-only)
- Three fields in a grid:
- Mileage at Service (pre-filled from
ro.mileage) - Interval in miles (defaults to 5000)
- Due Mileage (computed live:
(parseInt(mileage)||0) + (parseInt(interval)||0))
- Mileage at Service (pre-filled from
- Notes textarea (optional)
- Cancel / Save Reminder buttons with loading spinner
State variables (in main RODetailModal component):
showReminderForm, reminderMileage, reminderInterval, reminderNotes, savingReminder
Handler: handleSaveReminder() — validates non-zero mileage + interval, creates record in reminders collection, shows success/error toast.
Imports used: BellRing from lucide-react (added to existing icon import line).
2. Dashboard.tsx — Reminders Widget
Location: Between the header row and the loading state section. Only renders when reminders.length > 0.
Widget: White card with ring shadow, contains:
- Header:
BellRingicon + "Maintenance Reminders" title + count badge ("N active" in blue pill) - Each reminder row shows:
- Customer name + vehicle info
- Optional notes (italic)
- Due mileage (right-aligned)
- "Active"/"Paused" badge (amber if
dueMileage > 0, green otherwise)
Data fetching: fetchReminders() callback queries reminders collection filtered by shopUserId and active = true, sorted -created. Called via useEffect on mount.
Interface: ReminderRecord interface defined locally in Dashboard.tsx.
Imports used: BellRing from lucide-react (added to existing icon import).
Verification
After changes to either file, run:
npm run build # tsc + vite build
npm run lint # oxlint
npm run test # vitest
Pitfalls
- Unused import errors: TypeScript
tsc -bis strict about unused variables/imports. If you importuseToastbut don't callshowToast, the build fails. Remove the unused import and destructuring. - Collection must exist in PocketBase: The
reminderscollection needs to be created via a PB migration or admin UI before the code will work at runtime. - Pre-fill mileage: The "Set Reminder" button click handler pre-fills from
ro.mileage— make sure the button'sonClickincludessetReminderMileage(ro.mileage || '')so the form opens with the current mileage.