feat: expand documents to include manuals
This commit is contained in:
74
MVP-COLOR-SCHEME.md
Normal file
74
MVP-COLOR-SCHEME.md
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
# MotoVaultPro Color Scheme
|
||||||
|
|
||||||
|
Complete collection of available colors for the MotoVaultPro Application
|
||||||
|
|
||||||
|
## Color Reference Table
|
||||||
|
|
||||||
|
| Color Name | Hex | RGB | CMYK | RAL |
|
||||||
|
|------------|-----|-----|------|-----|
|
||||||
|
| Argento Nurburgring | #CACBCE | RGB(202,203,206) | 2, 1, 0, 19 | RAL 7047 |
|
||||||
|
| Bianco Avorio | #E5DEDC | RGB(229,222,220) | 0, 3, 4, 10 | RAL 9003 |
|
||||||
|
| Bianco Avus | #F2F3F6 | RGB(242,243,246) | 2, 1, 0, 4 | RAL 9003 |
|
||||||
|
| Blu Abu Dhabi | #2885B5 | RGB(40,133,181) | 78, 27, 0, 29 | RAL 5012 |
|
||||||
|
| Blu Pozzi | #2C3970 | RGB(44,57,112) | 61, 49, 0, 56 | RAL 5022 |
|
||||||
|
| Blu Scozia | #505C77 | RGB(80,92,119) | 33, 23, 0, 53 | RAL 5000 |
|
||||||
|
| Blu Swaters | #163166 | RGB(22,49,102) | 78, 52, 0, 60 | RAL 5022 |
|
||||||
|
| Blu Tour De France | #2243AA | RGB(34,67,170) | 80, 61, 0, 33 | RAL 5002 |
|
||||||
|
| Canna Di Fucile | #7E8792 | RGB(126,135,146) | 14, 8, 0, 43 | RAL 7046 |
|
||||||
|
| Giallo Modena | #FCE903 | RGB(252,233,3) | 0, 8, 99, 1 | RAL 1016 |
|
||||||
|
| Grigio Alloy | #A3C7E9 | RGB(163,199,233) | 30, 15, 0, 9 | RAL 7047 |
|
||||||
|
| Grigio Ferro | #626062 | RGB(98,96,98) | 0, 2, 0, 62 | RAL 7012 |
|
||||||
|
| Grigio Ingrid | #756D62 | RGB(117,109,98) | 0, 7, 16, 54 | RAL 7006 |
|
||||||
|
| Grigio Scuro | #4C4E4D | RGB(76,78,77) | 3, 0, 1, 69 | RAL 7043 |
|
||||||
|
| Grigio Silverstone | #585C64 | RGB(88,92,100) | 12, 8, 0, 61 | RAL 7015 |
|
||||||
|
| Grigio Titanio | #A8B8C0 | RGB(168,184,192) | 13, 4, 0, 25 | RAL 7040 |
|
||||||
|
| Nero Daytona | #231F1C | RGB(35,31,28) | 0, 11, 20, 86 | RAL 8022 |
|
||||||
|
| Rosso 70 Anni | #C40C19 | RGB(196,12,25) | 0, 94, 87, 23 | RAL 3020 |
|
||||||
|
| Rosso Corsa | #D40000 | RGB(212,0,0) | 0, 100, 100, 17 | RAL 3028 |
|
||||||
|
| Rosso Dino | #FC652E | RGB(252,101,46) | 0, 60, 82, 1 | RAL 2008 |
|
||||||
|
| Rosso Fiorano | #5D0001 | RGB(93,0,1) | 0, 100, 99, 64 | RAL 3004 |
|
||||||
|
| Rosso Fuoco | #D13442 | RGB(209,52,66) | 0, 75, 68, 18 | RAL 3018 |
|
||||||
|
| Rosso Mugello | #7A212A | RGB(122,33,42) | 0, 73, 66, 52 | RAL 3032 |
|
||||||
|
| Rosso Scuderia | #FF2800 | RGB(255,40,0) | 0, 84, 100, 0 | RAL 3024 |
|
||||||
|
| Verde British | #004225 | RGB(0,66,37) | 100, 0, 44, 74 | RAL 6035 |
|
||||||
|
|
||||||
|
## Color Categories
|
||||||
|
|
||||||
|
### Whites & Silvers (3)
|
||||||
|
- Argento Nurburgring - Metallic silver
|
||||||
|
- Bianco Avorio - Cream white
|
||||||
|
- Bianco Avus - Classic white
|
||||||
|
|
||||||
|
### Blues (5)
|
||||||
|
- Blu Abu Dhabi - Light blue
|
||||||
|
- Blu Pozzi - Deep blue
|
||||||
|
- Blu Scozia - Dark blue
|
||||||
|
- Blu Swaters - Royal blue
|
||||||
|
- Blu Tour De France - Classic blue
|
||||||
|
|
||||||
|
### Greys (7)
|
||||||
|
- Canna Di Fucile - Metallic grey
|
||||||
|
- Grigio Alloy - Light grey (blue)
|
||||||
|
- Grigio Ferro - Light grey
|
||||||
|
- Grigio Ingrid - Beige grey
|
||||||
|
- Grigio Scuro - Deep grey
|
||||||
|
- Grigio Silverstone - Dark grey
|
||||||
|
- Grigio Titanio - Classic grey
|
||||||
|
|
||||||
|
### Yellows (1)
|
||||||
|
- Giallo Modena - Triple layer yellow
|
||||||
|
|
||||||
|
### Blacks (1)
|
||||||
|
- Nero Daytona - Classic black
|
||||||
|
|
||||||
|
### Reds (7)
|
||||||
|
- Rosso 70 Anni - 70th anniversary red
|
||||||
|
- Rosso Corsa - Classic Ferrari red
|
||||||
|
- Rosso Dino - Red/orange
|
||||||
|
- Rosso Fiorano - Ruby red
|
||||||
|
- Rosso Fuoco - Triple layer red
|
||||||
|
- Rosso Mugello - Dark red
|
||||||
|
- Rosso Scuderia - Bright red
|
||||||
|
|
||||||
|
### Greens (1)
|
||||||
|
- Verde British - British racing green
|
||||||
@@ -27,6 +27,7 @@ export class DocumentsRepository {
|
|||||||
issuedDate: row.issued_date,
|
issuedDate: row.issued_date,
|
||||||
expirationDate: row.expiration_date,
|
expirationDate: row.expiration_date,
|
||||||
emailNotifications: row.email_notifications,
|
emailNotifications: row.email_notifications,
|
||||||
|
scanForMaintenance: row.scan_for_maintenance,
|
||||||
createdAt: row.created_at,
|
createdAt: row.created_at,
|
||||||
updatedAt: row.updated_at,
|
updatedAt: row.updated_at,
|
||||||
deletedAt: row.deleted_at
|
deletedAt: row.deleted_at
|
||||||
@@ -48,11 +49,12 @@ export class DocumentsRepository {
|
|||||||
issuedDate?: string | null;
|
issuedDate?: string | null;
|
||||||
expirationDate?: string | null;
|
expirationDate?: string | null;
|
||||||
emailNotifications?: boolean;
|
emailNotifications?: boolean;
|
||||||
|
scanForMaintenance?: boolean;
|
||||||
}): Promise<DocumentRecord> {
|
}): Promise<DocumentRecord> {
|
||||||
const res = await this.db.query(
|
const res = await this.db.query(
|
||||||
`INSERT INTO documents (
|
`INSERT INTO documents (
|
||||||
id, user_id, vehicle_id, document_type, title, notes, details, issued_date, expiration_date, email_notifications
|
id, user_id, vehicle_id, document_type, title, notes, details, issued_date, expiration_date, email_notifications, scan_for_maintenance
|
||||||
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10)
|
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11)
|
||||||
RETURNING *`,
|
RETURNING *`,
|
||||||
[
|
[
|
||||||
doc.id,
|
doc.id,
|
||||||
@@ -65,6 +67,7 @@ export class DocumentsRepository {
|
|||||||
doc.issuedDate ?? null,
|
doc.issuedDate ?? null,
|
||||||
doc.expirationDate ?? null,
|
doc.expirationDate ?? null,
|
||||||
doc.emailNotifications ?? false,
|
doc.emailNotifications ?? false,
|
||||||
|
doc.scanForMaintenance ?? false,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
return this.mapDocumentRecord(res.rows[0]);
|
return this.mapDocumentRecord(res.rows[0]);
|
||||||
@@ -91,7 +94,7 @@ export class DocumentsRepository {
|
|||||||
await this.db.query(`UPDATE documents SET deleted_at = NOW() WHERE id = $1 AND user_id = $2`, [id, userId]);
|
await this.db.query(`UPDATE documents SET deleted_at = NOW() WHERE id = $1 AND user_id = $2`, [id, userId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateMetadata(id: string, userId: string, patch: Partial<Pick<DocumentRecord, 'title'|'notes'|'details'|'issuedDate'|'expirationDate'|'emailNotifications'>>): Promise<DocumentRecord | null> {
|
async updateMetadata(id: string, userId: string, patch: Partial<Pick<DocumentRecord, 'title'|'notes'|'details'|'issuedDate'|'expirationDate'|'emailNotifications'|'scanForMaintenance'>>): Promise<DocumentRecord | null> {
|
||||||
const fields: string[] = [];
|
const fields: string[] = [];
|
||||||
const params: any[] = [];
|
const params: any[] = [];
|
||||||
let i = 1;
|
let i = 1;
|
||||||
@@ -101,6 +104,7 @@ export class DocumentsRepository {
|
|||||||
if (patch.issuedDate !== undefined) { fields.push(`issued_date = $${i++}`); params.push(patch.issuedDate); }
|
if (patch.issuedDate !== undefined) { fields.push(`issued_date = $${i++}`); params.push(patch.issuedDate); }
|
||||||
if (patch.expirationDate !== undefined) { fields.push(`expiration_date = $${i++}`); params.push(patch.expirationDate); }
|
if (patch.expirationDate !== undefined) { fields.push(`expiration_date = $${i++}`); params.push(patch.expirationDate); }
|
||||||
if (patch.emailNotifications !== undefined) { fields.push(`email_notifications = $${i++}`); params.push(patch.emailNotifications); }
|
if (patch.emailNotifications !== undefined) { fields.push(`email_notifications = $${i++}`); params.push(patch.emailNotifications); }
|
||||||
|
if (patch.scanForMaintenance !== undefined) { fields.push(`scan_for_maintenance = $${i++}`); params.push(patch.scanForMaintenance); }
|
||||||
if (!fields.length) return this.findById(id, userId);
|
if (!fields.length) return this.findById(id, userId);
|
||||||
params.push(id, userId);
|
params.push(id, userId);
|
||||||
const sql = `UPDATE documents SET ${fields.join(', ')} WHERE id = $${i++} AND user_id = $${i++} AND deleted_at IS NULL RETURNING *`;
|
const sql = `UPDATE documents SET ${fields.join(', ')} WHERE id = $${i++} AND user_id = $${i++} AND deleted_at IS NULL RETURNING *`;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ export class DocumentsService {
|
|||||||
issuedDate: body.issuedDate ?? null,
|
issuedDate: body.issuedDate ?? null,
|
||||||
expirationDate: body.expirationDate ?? null,
|
expirationDate: body.expirationDate ?? null,
|
||||||
emailNotifications: body.emailNotifications ?? false,
|
emailNotifications: body.emailNotifications ?? false,
|
||||||
|
scanForMaintenance: body.scanForMaintenance ?? false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
export const DocumentTypeSchema = z.enum(['insurance', 'registration']);
|
export const DocumentTypeSchema = z.enum(['insurance', 'registration', 'manual']);
|
||||||
export type DocumentType = z.infer<typeof DocumentTypeSchema>;
|
export type DocumentType = z.infer<typeof DocumentTypeSchema>;
|
||||||
|
|
||||||
// API response type (camelCase for frontend)
|
// API response type (camelCase for frontend)
|
||||||
@@ -21,6 +21,7 @@ export interface DocumentRecord {
|
|||||||
issuedDate?: string | null;
|
issuedDate?: string | null;
|
||||||
expirationDate?: string | null;
|
expirationDate?: string | null;
|
||||||
emailNotifications?: boolean;
|
emailNotifications?: boolean;
|
||||||
|
scanForMaintenance?: boolean;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
deletedAt?: string | null;
|
deletedAt?: string | null;
|
||||||
@@ -36,6 +37,7 @@ export const CreateDocumentBodySchema = z.object({
|
|||||||
issuedDate: z.string().optional(),
|
issuedDate: z.string().optional(),
|
||||||
expirationDate: z.string().optional(),
|
expirationDate: z.string().optional(),
|
||||||
emailNotifications: z.boolean().optional(),
|
emailNotifications: z.boolean().optional(),
|
||||||
|
scanForMaintenance: z.boolean().optional(),
|
||||||
});
|
});
|
||||||
export type CreateDocumentBody = z.infer<typeof CreateDocumentBodySchema>;
|
export type CreateDocumentBody = z.infer<typeof CreateDocumentBodySchema>;
|
||||||
|
|
||||||
@@ -46,6 +48,7 @@ export const UpdateDocumentBodySchema = z.object({
|
|||||||
issuedDate: z.string().nullable().optional(),
|
issuedDate: z.string().nullable().optional(),
|
||||||
expirationDate: z.string().nullable().optional(),
|
expirationDate: z.string().nullable().optional(),
|
||||||
emailNotifications: z.boolean().optional(),
|
emailNotifications: z.boolean().optional(),
|
||||||
|
scanForMaintenance: z.boolean().optional(),
|
||||||
});
|
});
|
||||||
export type UpdateDocumentBody = z.infer<typeof UpdateDocumentBodySchema>;
|
export type UpdateDocumentBody = z.infer<typeof UpdateDocumentBodySchema>;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
-- Migration: Add 'manual' document type and scan_for_maintenance column
|
||||||
|
-- Purpose: Support vehicle/equipment manuals with future maintenance schedule scanning
|
||||||
|
|
||||||
|
-- Step 1: Extend document_type CHECK constraint to include 'manual'
|
||||||
|
-- Note: Must drop and recreate since PostgreSQL doesn't support ALTER CONSTRAINT
|
||||||
|
ALTER TABLE documents DROP CONSTRAINT IF EXISTS documents_document_type_check;
|
||||||
|
ALTER TABLE documents ADD CONSTRAINT documents_document_type_check
|
||||||
|
CHECK (document_type IN ('insurance', 'registration', 'manual'));
|
||||||
|
|
||||||
|
-- Step 2: Add scan_for_maintenance boolean column
|
||||||
|
-- Only applicable to 'manual' type, defaults to false
|
||||||
|
ALTER TABLE documents ADD COLUMN IF NOT EXISTS scan_for_maintenance BOOLEAN DEFAULT false;
|
||||||
|
|
||||||
|
-- Step 3: Create partial index for future maintenance scanning queries
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_documents_scan_for_maintenance
|
||||||
|
ON documents(scan_for_maintenance)
|
||||||
|
WHERE scan_for_maintenance = true AND deleted_at IS NULL AND document_type = 'manual';
|
||||||
@@ -22,25 +22,18 @@ You are a senior software engineer specializsing in NodeJS, Typescript, front en
|
|||||||
- Make no assumptions.
|
- Make no assumptions.
|
||||||
- Ask clarifying questions.
|
- Ask clarifying questions.
|
||||||
- Ultrathink
|
- Ultrathink
|
||||||
- You will be implementing a backup and restore functionality directly in this application.
|
- You will be extending the "Documents" feature to include manuals.
|
||||||
|
|
||||||
*** CONTEXT ***
|
*** CONTEXT ***
|
||||||
- This is a modern web app for managing a vehicle fleet. It has both a desktop and mobile versions of the site that both need to maintain feature parity. It's currently deployed via docker compose but in the future will be deployed via k8s.
|
- This is a modern web app for managing a vehicle fleet. It has both a desktop and mobile versions of the site that both need to maintain feature parity. It's currently deployed via docker compose but in the future will be deployed via k8s.
|
||||||
- Read README.md CLAUDE.md and AI-INDEX.md and follow relevant instructions to understand this code repository in the context of this change.
|
- Read README.md CLAUDE.md and AI-INDEX.md and follow relevant instructions to understand this code repository in the context of this change.
|
||||||
- There is no backup and restore functionality in this system.
|
- You need to extend the Documents feature to include a third "Document Type"
|
||||||
- There needs to be a new section added in the admin settings. Here are the files and line numbers of existing admin settings to base this change off of and mirror those.
|
- Right now the document has two types. Insurance and Registration
|
||||||
frontend/src/pages/admin/AdminEmailTemplatesPage.tsx
|
- The third type will be called "Manual"
|
||||||
192: Manage notification email templates
|
- This document will just have the uploaded file and a notes field and Title field
|
||||||
|
- When implementing this we need to play for the future feature of scanning the document for maintenance schedules
|
||||||
frontend/src/pages/SettingsPage.tsx
|
- Add a toggle for this scanning. Label it "Scan for Maintenance Schedule"
|
||||||
436: secondary="Manage notification email templates"
|
- Do not implement this feature at this time but put the toggle in the interface and the backend changes to facility this workflow.
|
||||||
|
|
||||||
frontend/src/features/settings/mobile/MobileSettingsScreen.tsx
|
|
||||||
430: <div className="text-sm text-blue-600 mt-1">Manage notification email templates</div>
|
|
||||||
- There currently is a folder data/backups/ that is empty. Evaluate if this should be used or if another one makes more sense.
|
|
||||||
- The admin page should show all the local backups. But also allow for uploading a backup.
|
|
||||||
- The admin page should have a option to create a manual backup and download it.
|
|
||||||
- The admin page should have the ability to schedule backups as hourly, daily, weekly, monthly. And also allow multiple schedules and retention policies.
|
|
||||||
|
|
||||||
*** CHANGES TO IMPLEMENT ***
|
*** CHANGES TO IMPLEMENT ***
|
||||||
- Research this code base and ask iterative questions to compile a complete plan.
|
- Research this code base and ask iterative questions to compile a complete plan.
|
||||||
|
|||||||
@@ -36,6 +36,9 @@ export const DocumentForm: React.FC<DocumentFormProps> = ({ onSuccess, onCancel
|
|||||||
const [registrationExpirationDate, setRegistrationExpirationDate] = React.useState<string>('');
|
const [registrationExpirationDate, setRegistrationExpirationDate] = React.useState<string>('');
|
||||||
const [registrationCost, setRegistrationCost] = React.useState<string>('');
|
const [registrationCost, setRegistrationCost] = React.useState<string>('');
|
||||||
|
|
||||||
|
// Manual fields
|
||||||
|
const [scanForMaintenance, setScanForMaintenance] = React.useState<boolean>(false);
|
||||||
|
|
||||||
const [file, setFile] = React.useState<File | null>(null);
|
const [file, setFile] = React.useState<File | null>(null);
|
||||||
const [uploadProgress, setUploadProgress] = React.useState<number>(0);
|
const [uploadProgress, setUploadProgress] = React.useState<number>(0);
|
||||||
const [error, setError] = React.useState<string | null>(null);
|
const [error, setError] = React.useState<string | null>(null);
|
||||||
@@ -57,6 +60,7 @@ export const DocumentForm: React.FC<DocumentFormProps> = ({ onSuccess, onCancel
|
|||||||
setLicensePlate('');
|
setLicensePlate('');
|
||||||
setRegistrationExpirationDate('');
|
setRegistrationExpirationDate('');
|
||||||
setRegistrationCost('');
|
setRegistrationCost('');
|
||||||
|
setScanForMaintenance(false);
|
||||||
setFile(null);
|
setFile(null);
|
||||||
setUploadProgress(0);
|
setUploadProgress(0);
|
||||||
setError(null);
|
setError(null);
|
||||||
@@ -94,15 +98,17 @@ export const DocumentForm: React.FC<DocumentFormProps> = ({ onSuccess, onCancel
|
|||||||
details.cost = registrationCost ? parseFloat(registrationCost) : undefined;
|
details.cost = registrationCost ? parseFloat(registrationCost) : undefined;
|
||||||
expiration_date = registrationExpirationDate || undefined;
|
expiration_date = registrationExpirationDate || undefined;
|
||||||
}
|
}
|
||||||
|
// Manual type: no details or dates, just scanForMaintenance flag
|
||||||
|
|
||||||
const created = await create.mutateAsync({
|
const created = await create.mutateAsync({
|
||||||
vehicleId: vehicleID,
|
vehicleId: vehicleID,
|
||||||
documentType: documentType,
|
documentType: documentType,
|
||||||
title: title.trim(),
|
title: title.trim(),
|
||||||
notes: notes.trim() || undefined,
|
notes: notes.trim() || undefined,
|
||||||
details,
|
details: Object.keys(details).length > 0 ? details : undefined,
|
||||||
issuedDate: issued_date,
|
issuedDate: issued_date,
|
||||||
expirationDate: expiration_date,
|
expirationDate: expiration_date,
|
||||||
|
scanForMaintenance: documentType === 'manual' ? scanForMaintenance : undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (file) {
|
if (file) {
|
||||||
@@ -175,6 +181,7 @@ export const DocumentForm: React.FC<DocumentFormProps> = ({ onSuccess, onCancel
|
|||||||
>
|
>
|
||||||
<option value="insurance">Insurance</option>
|
<option value="insurance">Insurance</option>
|
||||||
<option value="registration">Registration</option>
|
<option value="registration">Registration</option>
|
||||||
|
<option value="manual">Manual</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -184,7 +191,11 @@ export const DocumentForm: React.FC<DocumentFormProps> = ({ onSuccess, onCancel
|
|||||||
className="h-11 min-h-[44px] rounded-lg border border-slate-300 px-3 focus:outline-none focus:ring-2 focus:ring-primary-500"
|
className="h-11 min-h-[44px] rounded-lg border border-slate-300 px-3 focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||||
type="text"
|
type="text"
|
||||||
value={title}
|
value={title}
|
||||||
placeholder={documentType === 'insurance' ? 'e.g., Progressive Policy 2025' : 'e.g., Registration 2025'}
|
placeholder={
|
||||||
|
documentType === 'insurance' ? 'e.g., Progressive Policy 2025' :
|
||||||
|
documentType === 'registration' ? 'e.g., Registration 2025' :
|
||||||
|
'e.g., Honda CBR600RR Service Manual'
|
||||||
|
}
|
||||||
onChange={(e) => setTitle(e.target.value)}
|
onChange={(e) => setTitle(e.target.value)}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
@@ -336,6 +347,23 @@ export const DocumentForm: React.FC<DocumentFormProps> = ({ onSuccess, onCancel
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{documentType === 'manual' && (
|
||||||
|
<div className="flex items-center md:col-span-2">
|
||||||
|
<label className="flex items-center cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={scanForMaintenance}
|
||||||
|
onChange={(e) => setScanForMaintenance(e.target.checked)}
|
||||||
|
className="w-5 h-5 rounded border-slate-300 text-primary-600 focus:ring-primary-500"
|
||||||
|
/>
|
||||||
|
<span className="ml-2 text-sm font-medium text-slate-700">
|
||||||
|
Scan for Maintenance Schedule
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<span className="ml-2 text-xs text-slate-500">(Coming soon)</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="flex flex-col md:col-span-2">
|
<div className="flex flex-col md:col-span-2">
|
||||||
<label className="text-sm font-medium text-slate-700 mb-1">Notes</label>
|
<label className="text-sm font-medium text-slate-700 mb-1">Notes</label>
|
||||||
<textarea
|
<textarea
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export type DocumentType = 'insurance' | 'registration';
|
export type DocumentType = 'insurance' | 'registration' | 'manual';
|
||||||
|
|
||||||
export interface DocumentRecord {
|
export interface DocumentRecord {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -17,6 +17,7 @@ export interface DocumentRecord {
|
|||||||
issuedDate?: string | null;
|
issuedDate?: string | null;
|
||||||
expirationDate?: string | null;
|
expirationDate?: string | null;
|
||||||
emailNotifications?: boolean;
|
emailNotifications?: boolean;
|
||||||
|
scanForMaintenance?: boolean;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
deletedAt?: string | null;
|
deletedAt?: string | null;
|
||||||
@@ -31,6 +32,7 @@ export interface CreateDocumentRequest {
|
|||||||
issuedDate?: string;
|
issuedDate?: string;
|
||||||
expirationDate?: string;
|
expirationDate?: string;
|
||||||
emailNotifications?: boolean;
|
emailNotifications?: boolean;
|
||||||
|
scanForMaintenance?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UpdateDocumentRequest {
|
export interface UpdateDocumentRequest {
|
||||||
@@ -40,5 +42,6 @@ export interface UpdateDocumentRequest {
|
|||||||
issuedDate?: string | null;
|
issuedDate?: string | null;
|
||||||
expirationDate?: string | null;
|
expirationDate?: string | null;
|
||||||
emailNotifications?: boolean;
|
emailNotifications?: boolean;
|
||||||
|
scanForMaintenance?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user