42 lines
2.3 KiB
Markdown
42 lines
2.3 KiB
Markdown
# Recent Quotes Status Derivation (v2)
|
|
|
|
## The Bug
|
|
|
|
In the Recent Quotes panel (`src/pages/QuoteGenerator.tsx`), the status badge was showing "Draft" even when ALL services had been decided (approved or declined) by shop staff in the QuoteGenerator.
|
|
|
|
## Root Cause
|
|
|
|
The quote's `status` field in PocketBase is only a **lifecycle** field:
|
|
- `'draft'` — set on Save (QuoteSummary.tsx:123)
|
|
- `'sent'` — set on Share (QuoteSummary.tsx:246)
|
|
- `'approved'` / `'declined'` — set by the customer via QuoteApprove.tsx:221-225
|
|
|
|
When shop staff approve/decline individual services in the QuoteGenerator, the `customerDecision` values are saved inside the services JSON blob, but the quote-level `status` field is NOT updated. It stays `'draft'`.
|
|
|
|
## The Fix
|
|
|
|
In `loadRecentQuotes()` (QuoteGenerator.tsx:196), derive the display status from individual service decisions when ALL services have been decided:
|
|
|
|
```typescript
|
|
const hasPending = servicesList.some((s: any) => !s.customerDecision || s.customerDecision === 'pending');
|
|
let derivedStatus: QuoteRecord['status'] = record.status;
|
|
if (!hasPending && servicesList.length > 0) {
|
|
const allApproved = servicesList.every((s: any) => s.customerDecision === 'approved');
|
|
const allDeclined = servicesList.every((s: any) => s.customerDecision === 'declined');
|
|
if (allApproved) derivedStatus = 'approved';
|
|
else if (allDeclined) derivedStatus = 'declined';
|
|
}
|
|
// Use derivedStatus in the returned object's `status` field
|
|
```
|
|
|
|
This overrides status to:
|
|
- `'approved'` — when ALL services have `customerDecision === 'approved'`
|
|
- `'declined'` — when ALL services have `customerDecision === 'declined'`
|
|
- Keeps original PocketBase status — when some services are still pending, or when decisions are mixed (some approved, some declined)
|
|
|
|
Because the mapped object's `status` field feeds both the `RecentStatusBadge` component and the filter/count logic (`recentCounts`, `matchesRecentStatusFilter`), this single change fixes the badge, the filter tabs, and the filter counts.
|
|
|
|
## Also Fixed
|
|
|
|
The `hasPending` check was previously `servicesList.some(s => s.customerDecision === 'pending')`. A service with no `customerDecision` field at all would NOT be counted as pending. Changed to `servicesList.some(s => !s.customerDecision || s.customerDecision === 'pending')` to handle services that don't have the field yet (edge case with legacy data).
|