diff --git a/docs/superpowers/specs/2026-07-09-new-quote-form-redesign-design.md b/docs/superpowers/specs/2026-07-09-new-quote-form-redesign-design.md new file mode 100644 index 0000000..f58b465 --- /dev/null +++ b/docs/superpowers/specs/2026-07-09-new-quote-form-redesign-design.md @@ -0,0 +1,266 @@ +# New Quote Form Redesign + +**Goal:** Redesign the `New Quote` sheet so operators can select a customer/company in one combined field, capture item descriptions without pricing noise, and attach photos or voice notes directly to each quote item. + +## Scope + +### In Scope + +- Replace the separate `Customer` and `Company` dropdowns in `New Quote` with one combined searchable picker +- Reuse the same interaction pattern already used on the `New Order` form +- Show customer choices in a company-first visual hierarchy +- Auto-link the selected customer to its company +- Keep company-only selection available when there is no customer/contact record +- Remove `Supplier`, `Cost`, and `Sell` from quote item creation +- Change quote item entry from a dense pricing table into stacked item cards +- Make each quote item description a multi-line field +- Keep one small quote-level summary field for overall RFQ context +- Allow per-item uploads for photos, voice notes, and other supporting files +- Persist per-item uploads into the existing `quote_item_attachments` collection + +### Out of Scope + +- Redesigning the quote detail page or quote process page +- AI transcription of voice notes +- Auto-splitting one pasted block into multiple quote items +- Quote-level attachment redesign +- Changes to sprint pricing workflow beyond supporting attachments created from `New Quote` + +## Current State + +- `New Quote` currently uses two separate dropdowns: + - `Customer` + - `Company` +- The customer dropdown shows only one label per option, which hides the company/customer relationship +- Quote items currently ask for: + - description + - qty + - supplier + - cost + - sell +- That layout assumes the operator is pricing the quote at creation time, which does not match the intended workflow +- The app already has: + - a combined customer/company picker on `New Order` + - an existing `quote_item_attachments` collection + - an existing server upload route pattern for `quote_item_attachments` + +## User Decisions Locked In + +- Use a combined customer/company field, not two separate dropdowns +- Follow the same pattern as the `New Order` form +- Keep a small quote-level summary instead of removing it entirely +- Use quote item descriptions as the main place for the requested items +- Quote item descriptions should be multi-line +- Photos and voice notes should attach to individual quote items + +## Proposed UX + +### Header Fields + +The quote header becomes: + +- `Customer or Company` +- `RFQ Number` +- `Customer Request` (rename from the current generic quote description) +- `Internal Notes` + +`Customer or Company` is the primary selector and replaces the current split header fields. + +### Combined Customer / Company Picker + +Use the same searchable popover + command list pattern already used in `New Order`. + +#### Option Types + +1. Customer-linked option + - Visual format: + - line 1: company name + - line 2: customer name + - Selecting it sets: + - `customer = selected customer id` + - `company = linked company id` + +2. Company-only option + - Used when a company exists without a customer/contact record + - Visual format: + - line 1: company name + - line 2: `No contact` + - Selecting it sets: + - `company = selected company id` + - `customer = ""` + +#### Display Rules + +- The trigger button must show readable names, never raw ids +- After selection, the sheet should show a compact summary of: + - selected company + - selected customer, when present +- Search should match both company and customer names + +## Quote Item Entry + +### Replace the Table With Item Cards + +The current compact table is too constrained for: + +- multi-line descriptions +- per-item notes +- uploads + +Replace it with vertically stacked item cards inside the sheet. + +Each card contains: + +- `Qty` +- `Item Description` (multi-line textarea) +- `Item Notes` (optional, smaller textarea) +- `Attachments` +- remove button + +### Fields Removed From New Quote + +Do not capture these at quote-creation time: + +- supplier +- cost price +- selling price + +Those belong later in the pricing workflow, not during intake. + +### Description Behavior + +- `Item Description` is the main capture field +- It must support messy RFQ input +- One card can hold one long request if the operator wants to keep everything together +- Quantity defaults to `1` + +## Attachments + +### Per-Item Uploads + +Each quote item card gets its own upload area. + +Supported intent: + +- photos +- voice notes +- PDFs +- screenshots +- other common operator proof/reference files + +### Storage Model + +Reuse the existing `quote_item_attachments` collection. + +For items created from `New Quote`: + +- files are uploaded only after the quote and quote items are successfully created +- each uploaded file creates a `quote_item_attachments` row pointing to the created `quote_item` +- `source` should use `"manual"` + +### Upload Timing + +Recommended flow: + +1. operator fills the quote form +2. operator picks files on one or more item cards +3. submit creates: + - the `quotes` record + - the `quote_items` records +4. after each quote item exists, upload its files through a server route that writes to `quote_item_attachments` +5. if an attachment upload fails: + - the quote still exists + - the operator gets a clear partial-failure message naming the affected item/file + +## Data Model + +### Quote Record + +Keep the current relational shape: + +- `customer`: PocketBase relation id +- `company`: PocketBase relation id + +Do not switch the quote record to plain-text-only customer/company storage. + +Reason: + +- relational links are still required for downstream quote, order, and reporting flows +- the UI problem is display and selection, not the underlying relation model + +### Quote Item Record + +Create `quote_items` with: + +- `quote` +- `description` +- `quantity` +- `notes` +- `user_edited = true` + +Do not write supplier/cost/sell from `New Quote`. + +## Validation + +- `Customer or Company` selection is required +- At least one quote item is required +- Every quote item needs a non-empty description +- Quantity must be `>= 1` +- Files are optional + +## Error Handling + +### Form Load + +- If customer/company data fails to load, show the existing toast error and disable submission + +### Create Flow + +- If quote creation fails, stop and show error +- If quote creation succeeds but some item creation fails: + - stop creating additional items + - do not upload any attachments + - keep the created quote and any already-created items + - show a blocking error that the quote was only partially created and must be reviewed manually +- If item creation succeeds but some attachment uploads fail: + - keep the created quote/items + - show a partial-success toast summarizing which uploads failed + +### Upload UX + +- Show selected files inside the relevant item card before save +- Allow removing a pending file before save +- Show lightweight file chips/list, not a heavy gallery UI + +## Testing + +### Form Behavior + +- selecting a customer option auto-fills the linked company +- selecting a company-only option leaves customer blank +- combined picker renders company/customer labels in the right hierarchy +- submit requires at least one valid item + +### Shape Changes + +- new quote form no longer renders supplier/cost/sell item fields +- item description uses a textarea, not a one-line input +- item cards support pending attachment display + +### Submit Flow + +- quote record is created before quote item attachments upload +- created item attachments are associated with the right quote item ids +- item creation failure stops later uploads and reports partial creation clearly +- partial attachment failure reports correctly without deleting the quote + +## Acceptance Criteria + +- Operators can create a quote using one combined `Customer or Company` field +- Customer options clearly show the company/customer relationship +- The selected UI shows readable names rather than ids +- Quote intake no longer asks for supplier/cost/sell +- Operators can type detailed multi-line item descriptions +- Operators can attach photos or voice notes directly to a quote item +- Attachments are stored against `quote_item_attachments` +- The form remains usable on smaller screens inside the existing sheet pattern