initial commit
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
# v2 RepairOrders Dashboard — Time Management & Interactive Features
|
||||
|
||||
## File: `src/pages/RepairOrders.tsx`
|
||||
## Statuses (6 total): `active | in_progress | waiting_parts | waiting_pickup | completed | delivered`
|
||||
|
||||
## Time Calculation
|
||||
|
||||
### calcDueTime(ro)
|
||||
```typescript
|
||||
const baseTime = ro.writeupTime || ro.created; // fall back to creation timestamp
|
||||
const duration = ro.estimatedDuration || 60; // default 1 hour
|
||||
if (baseTime) return new Date(baseTime).getTime() + duration * 60000;
|
||||
// fallback: ro.promisedTime (legacy field)
|
||||
```
|
||||
|
||||
### formatTimeRemaining(ro, now)
|
||||
Returns `"2h 15m"`, `"45m"`, or `"-10m"` (past due).
|
||||
- Completed/delivered → `"—"`
|
||||
- Null due time → `"—"`
|
||||
|
||||
### getUrgencyClass(ro, now)
|
||||
- Completed/delivered → `''`
|
||||
- Past due → `'urgent'` (red row bg)
|
||||
- Within 30 min → `'warning'` (amber text)
|
||||
- Otherwise → `''`
|
||||
|
||||
## Multi-Tier Sort (sortOrders)
|
||||
|
||||
1. **Waiting For Parts** → pinned to bottom, sorted by due time ascending within group
|
||||
2. **Customer type**: Waiters above Drop-Offs
|
||||
3. **Due time**: Most urgent (closest to due) first
|
||||
|
||||
## Adding a New Status
|
||||
|
||||
To add a new status (e.g. `waiting_pickup`), update ALL of these:
|
||||
|
||||
1. **`types.ts`**: Add to `RepairOrder.status` union type
|
||||
2. **`STATUS_CONFIG`** in RepairOrders.tsx: Add label + Tailwind color classes
|
||||
3. **ROModal status dropdown**: Add `<option>`
|
||||
4. **ExpandedDetail action buttons**: Add conditional button — guard with `ro.status !== 'new_status' && ro.status !== 'completed' && ro.status !== 'delivered'`
|
||||
5. **Existing button guards**: Update all other button conditions to exclude the new status where appropriate
|
||||
6. **Active tab filter** (auto): If `new_status` is not `completed` or `delivered`, it's already active
|
||||
7. **Sort** (auto): If not `waiting_parts`, it sorts normally by customer type → due time
|
||||
|
||||
## Live Countdown
|
||||
|
||||
```typescript
|
||||
const [now, setNow] = useState(Date.now());
|
||||
const tickRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
tickRef.current = setInterval(() => setNow(Date.now()), 1000);
|
||||
return () => { if (tickRef.current) clearInterval(tickRef.current); };
|
||||
}, []);
|
||||
```
|
||||
|
||||
Drives re-render of `TimeRemainingCell` and urgency styling in the table + expanded detail every second. The `sortOrders` function is called inside the filtered-orders computation which re-runs on `now` changes.
|
||||
|
||||
## Interactive Waiter/Drop-Off Toggle
|
||||
|
||||
- `CustomerTypeBadge` component: clickable badge that calls `onToggleCustomerType`
|
||||
- Uses `window.confirm()` for safety ("Are you sure you want to change...")
|
||||
- Optimistic update on `setOrders`, then PB update; rolls back on failure
|
||||
- Triggers re-sort automatically (sort re-evaluates customerType)
|
||||
|
||||
## Add Time Feature
|
||||
|
||||
- "+ Add Time" button appears in ExpandedDetail action bar for non-completed, non-delivered, non-waiting-parts ROs
|
||||
- Uses `window.prompt('Add extra time (minutes):', '15')`
|
||||
- Adds to `estimatedDuration` field in PocketBase
|
||||
- Optimistic update via `setOrders` → updates the countdown, sorting, and urgency instantly
|
||||
|
||||
## Urgency Styling (table rows)
|
||||
|
||||
```typescript
|
||||
const rowClass = urgency === 'urgent'
|
||||
? 'bg-red-50 hover:bg-red-100 dark:bg-red-900/15 dark:hover:bg-red-900/25'
|
||||
: urgency === 'warning'
|
||||
? 'hover:bg-gray-50 dark:hover:bg-gray-700/50'
|
||||
: 'hover:bg-gray-50 dark:hover:bg-gray-700/50';
|
||||
```
|
||||
|
||||
Past-due expanded details also get `bg-red-50` via a className on the `<tr>`.
|
||||
|
||||
## Duration Input (Create/Edit Modal)
|
||||
|
||||
Two separate inputs — Hours and Minutes:
|
||||
- Hours: `Math.floor(estimatedDuration / 60)`
|
||||
- Minutes: `estimatedDuration % 60`
|
||||
- On change: `setEstimatedDuration(hours * 60 + Math.min(minutes, 59))`
|
||||
|
||||
## Fields in PocketBase
|
||||
|
||||
New fields added to RepairOrders collection (auto-created on first save):
|
||||
- `customerType: 'waiter' | 'drop-off'` (default: 'drop-off')
|
||||
- `estimatedDuration: number` (minutes, default: 60)
|
||||
- `writeupTime: string` (ISO timestamp, set to `new Date().toISOString()` on create)
|
||||
|
||||
Legacy field kept for backward compat:
|
||||
- `promisedTime?: string` — used as fallback in calcDueTime
|
||||
Reference in New Issue
Block a user