- add optional collection_photo field to OrderItem type and backend support for pickup photo uploads - implement in-memory + localStorage cache for order items to eliminate tab-switch loading skeletons - update service worker to use stale-while-revalidate for navigation requests to reduce perceived lag - fix LocationTracker to only activate when logged in and hoist to root layout for persistent tracking - adjust InstallPrompt positioning to avoid overlapping bottom navigation - throttle map cluster recomputation to reduce unnecessary work during pan/zoom - clear cached items on logout to prevent cross-driver data leakage
144 lines
4.5 KiB
TypeScript
144 lines
4.5 KiB
TypeScript
export interface Supplier {
|
|
id: string;
|
|
suppliername: string;
|
|
email: string;
|
|
suppliernumber: string;
|
|
supplieraddress: string;
|
|
supply_tags: string;
|
|
coordinates: string; // Raw coordinates text (e.g. "-33.9249, 18.4241")
|
|
closingtime: string;
|
|
}
|
|
|
|
export interface Order {
|
|
id: string;
|
|
order_number: string;
|
|
status: string;
|
|
notes: string;
|
|
}
|
|
|
|
export interface PurchaseOrder {
|
|
id: string;
|
|
po_number: string;
|
|
status: string;
|
|
}
|
|
|
|
export interface OrderItem {
|
|
id: string;
|
|
order: string;
|
|
// Customer-facing line. Use this for label / list / customer view.
|
|
description: string;
|
|
// Supplier-facing line. Use this on the PO pickup screen — supplier
|
|
// paperwork references this exact wording. Falls back to description.
|
|
po_description?: string;
|
|
// Customer-side quantity. Nullable on legacy rows.
|
|
quantity: number;
|
|
// Supplier-side quantity. Per the brief, falls back to quantity when
|
|
// blank (zero is treated as blank in getItemDisplayQty).
|
|
order_qty?: number;
|
|
// Pricing — operator-side (cost), customer-side (selling), and audit
|
|
// source ('quote' | 'catalogue' | 'manual').
|
|
cost_price?: number;
|
|
selling_price?: number | null;
|
|
pricing_source?: 'quote' | 'catalogue' | 'manual' | string;
|
|
matched_quote_item?: string;
|
|
// Supplier part number. Use this on PO paperwork over description.
|
|
sku?: string;
|
|
// Workflow states. item_status is the operator-side state, drv_status
|
|
// is the driver-side state. They're independent enums — an item can
|
|
// be item_status='collected' (operator marked it received) while
|
|
// drv_status is still 'en_route' (driver hasn't checked in), etc.
|
|
item_status:
|
|
| 'pending'
|
|
| 'processed'
|
|
| 'po_generated'
|
|
| 'collection_pool'
|
|
| 'assigned'
|
|
| 'collected'
|
|
| 'stock_verified'
|
|
| 'picking'
|
|
| 'ready_delivery'
|
|
| 'delivered'
|
|
| 'cancelled';
|
|
drv_status?: 'unassigned' | 'assigned' | 'en_route' | 'collected' | 'failed' | string;
|
|
driver_status?: string;
|
|
delivery_status?: 'pending' | 'ready' | 'in_transit' | 'delivered' | 'failed';
|
|
invoice_status?: 'pending' | 'invoiced' | 'paid' | 'cancelled';
|
|
// Driver assignment. The canonical driver field per the brief is
|
|
// `drv_id` (relation -> users); the older `driver` field is a legacy
|
|
// shadow that only a handful of rows set. Use drv_id in every filter.
|
|
drv_id?: string;
|
|
driver?: string;
|
|
// Server-side ISO timestamp of when drv_id was set. Surface in detail.
|
|
assigned_at?: string;
|
|
// Audit trail of failed-collection attempts. The driver writes here.
|
|
// Distinct from notes (operator-side).
|
|
notes?: string;
|
|
problem_notes?: string;
|
|
problem_flag?: boolean;
|
|
problem_type?: 'stock' | 'supplier' | 'driver' | 'delivery' | 'pricing' | 'other' | string;
|
|
// Optional proof-of-pickup photo from the driver app's Collect modal.
|
|
// Single image (maxSelect: 1, 10MB). Stamped alongside qty_collected
|
|
// and drv_collected_at so operators can audit quantity mismatches
|
|
// against the visual record. The field is optional — drivers can
|
|
// collect without a photo for low-value routine pickups.
|
|
collection_photo?: string;
|
|
// Per-row quantities used for proving/dashboard math.
|
|
qty_processed?: number;
|
|
qty_assigned?: number;
|
|
qty_collected?: number;
|
|
qty_delivered?: number;
|
|
drv_assigned_at?: string;
|
|
drv_collected_at?: string;
|
|
delivered_at?: string;
|
|
markup?: number;
|
|
markup_percent?: number;
|
|
legacy_order_item_id?: string;
|
|
// Backwards-compat shim the app uses in some spots
|
|
is_stock_item?: boolean;
|
|
collected_date?: string;
|
|
collection_date?: string;
|
|
// Expanded fields
|
|
expand?: {
|
|
supplier?: Supplier; // PB expand key matches relation field name
|
|
order?: Order;
|
|
purchase_order?: PurchaseOrder;
|
|
};
|
|
}
|
|
|
|
export interface DriverLocation {
|
|
id: string;
|
|
driver: string;
|
|
latitude: number;
|
|
longitude: number;
|
|
accuracy?: number;
|
|
altitude?: number;
|
|
speed?: number;
|
|
heading?: number;
|
|
timestamp: string;
|
|
}
|
|
|
|
export interface AppSettings {
|
|
locationInterval: number;
|
|
minimumAccuracy: number;
|
|
enableHighAccuracy: boolean;
|
|
darkMode: boolean;
|
|
fontSize: 'small' | 'normal' | 'large';
|
|
offlineMode: boolean;
|
|
}
|
|
|
|
export const DEFAULT_SETTINGS: AppSettings = {
|
|
locationInterval: 60,
|
|
minimumAccuracy: 50,
|
|
enableHighAccuracy: true,
|
|
darkMode: false,
|
|
fontSize: 'normal',
|
|
offlineMode: false,
|
|
};
|
|
|
|
export const PROBLEM_TYPES = [
|
|
{ value: 'out_of_stock', label: 'Out of Stock' },
|
|
{ value: 'partial_stock', label: 'Partial Stock' },
|
|
{ value: 'quality_issue', label: 'Quality Issue' },
|
|
{ value: 'wrong_item', label: 'Wrong Item' },
|
|
{ value: 'other', label: 'Other' },
|
|
] as const;
|