From dd924904c557e742be39b2993ab52c1afb9461e0 Mon Sep 17 00:00:00 2001 From: Ghassan Yusuf Date: Mon, 25 May 2026 14:15:17 +0300 Subject: [PATCH] docs: add supplier modal wizard implementation plan --- .../plans/2026-05-25-supplier-modal-wizard.md | 423 ++++++++++++++++++ 1 file changed, 423 insertions(+) create mode 100644 docs/superpowers/plans/2026-05-25-supplier-modal-wizard.md diff --git a/docs/superpowers/plans/2026-05-25-supplier-modal-wizard.md b/docs/superpowers/plans/2026-05-25-supplier-modal-wizard.md new file mode 100644 index 0000000..3c3d2bf --- /dev/null +++ b/docs/superpowers/plans/2026-05-25-supplier-modal-wizard.md @@ -0,0 +1,423 @@ +# Supplier Select Modal — Two-Step Wizard Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Replace the mutually-exclusive tab bar in the supplier select modal with a two-step wizard: Step 1 picks the supply method (Full Order / By Item), Step 2 shows the appropriate supplier selection UI with a "← Change method" back link that clears all selections. + +**Architecture:** Single Blade component file change only — no controller, route, or migration work. The HTML is restructured into `#sup-step1` (method cards) and `#sup-step2` (existing form), both children of the modal shell. Two new JS functions (`showStep` / `goBack`) drive transitions; the existing form, panes, and submission logic are untouched. + +**Tech Stack:** Laravel Blade, vanilla JS, inline CSS (Tailwind JIT not used — inline styles only per project convention) + +**Spec:** `docs/superpowers/specs/2026-05-25-supplier-modal-wizard-design.md` + +--- + +### Task 1: Replace the header tab bar with the mode badge row + +**Files:** +- Modify: `resources/views/components/purchase/supplier-select-modal.blade.php` + +The current header has a tab bar (`stab-global`, `stab-item`). Remove it. Replace with a hidden `#sup-mode-badge-row` div (shown only in Step 2). Also add `id="sup-modal-subtitle"` to the subtitle element so JS can update it dynamically. Change the initial title to "Request for Quotation" and subtitle to "How do you want to assign suppliers?". Change `padding:20px 24px 0` → `padding:20px 24px 16px` (the `0` bottom padding was a tab-flush hack no longer needed). + +- [ ] **Step 1: Replace the header block** + +In `resources/views/components/purchase/supplier-select-modal.blade.php`, find and replace this exact block: + +```blade + {{-- Header --}} +
+
+
+
Select Suppliers
+
Choose who receives the quote request
+
+ +
+ + {{-- Tab bar --}} +
+ + +
+
+``` + +Replace with: + +```blade + {{-- Header --}} +
+
+
+
Request for Quotation
+
How do you want to assign suppliers?
+
+ +
+ {{-- Mode badge row: hidden in Step 1, shown in Step 2 --}} + +
+``` + +- [ ] **Step 2: Verify the file saved correctly** + +Open `resources/views/components/purchase/supplier-select-modal.blade.php` and confirm: +- No `stab-global` or `stab-item` buttons exist +- `sup-mode-badge-row` div is present with `display:none` +- Title reads "Request for Quotation" +- Subtitle element has `id="sup-modal-subtitle"` + +--- + +### Task 2: Add Step 1 method-selection cards and wrap Step 2 + +**Files:** +- Modify: `resources/views/components/purchase/supplier-select-modal.blade.php` + +Insert `#sup-step1` (method cards + Step 1 Cancel footer) immediately after the header closing ``. Then wrap the existing `
` and the existing footer `
` inside a new `#sup-step2` div. Step 1 is `display:flex` on load; Step 2 is `display:none`. + +- [ ] **Step 1: Insert Step 1 cards immediately after the header** + +Find this exact line (the comment that opens the form section): + +```blade + {{-- Single form wrapping both panes --}} + +``` + +Replace with: + +```blade + {{-- Step 1: Method selection --}} +
+
+ + + + + +
+
+ +
+
+ + {{-- Step 2: Supplier selection --}} + +
+``` + +Replace with: + +```blade + {{-- Footer --}} +
+ +
+ + +
+
+ + {{-- /sup-step2 --}} + + +``` + +- [ ] **Step 4: Verify structure** + +Confirm the file now has this nesting order: +1. `#supplier-modal` → modal shell +2. Header (`#sup-mode-badge-row` inside) +3. `#sup-step1` with two card buttons + Cancel footer +4. `#sup-step2` containing `#sup-form` + the Step 2 footer +5. `#sup-step2` closing tag +6. Modal shell closing tags + +--- + +### Task 3: Update JavaScript — add showStep/goBack, update openSupplierModal, remove switchSupTab + +**Files:** +- Modify: `resources/views/components/purchase/supplier-select-modal.blade.php` (script block) + +- [ ] **Step 1: Replace `openSupplierModal` and remove `switchSupTab`** + +Find this exact block: + +```javascript +function openSupplierModal() { + document.getElementById('supplier-modal').classList.add('open'); + switchSupTab('global'); + document.getElementById('sup-search').focus(); +} +function closeSupplierModal() { + closeAllItemDd(); + document.getElementById('supplier-modal').classList.remove('open'); +} +``` + +Replace with: + +```javascript +function openSupplierModal() { + document.getElementById('supplier-modal').classList.add('open'); + goBack(); +} +function closeSupplierModal() { + closeAllItemDd(); + document.getElementById('supplier-modal').classList.remove('open'); +} +function showStep(method) { + _supTab = method; + document.getElementById('sup-mode').value = method === 'item' ? 'by_item' : 'global'; + + var badge = document.getElementById('sup-mode-badge'); + if (method === 'global') { + badge.textContent = '📦 Full Order'; + badge.style.background = '#eff6ff'; + badge.style.color = '#2563eb'; + } else { + badge.textContent = '🔀 By Item'; + badge.style.background = '#f0fdf4'; + badge.style.color = '#15803d'; + } + + document.getElementById('sup-modal-title').textContent = 'Select Suppliers'; + document.getElementById('sup-modal-subtitle').textContent = 'Choose who receives the quote request'; + document.getElementById('sup-mode-badge-row').style.display = 'flex'; + document.getElementById('sup-step1').style.display = 'none'; + document.getElementById('sup-step2').style.display = 'flex'; + + if (method === 'global') { + setTimeout(function(){ document.getElementById('sup-search').focus(); }, 50); + } + updateFooter(); +} +function goBack() { + document.querySelectorAll('#sup-form input[type="checkbox"]:not([disabled])').forEach(function(cb) { + cb.checked = false; + }); + document.querySelectorAll('[id^="gchan-"]').forEach(function(el) { el.style.display = 'none'; }); + var searchEl = document.getElementById('sup-search'); + if (searchEl) { searchEl.value = ''; filterGlobalSups(''); } + document.querySelectorAll('[id^="idd-label-"]').forEach(function(el) { + el.textContent = 'Select suppliers…'; + el.style.color = '#94a3b8'; + }); + var ics = document.getElementById('item-chan-section'); + if (ics) ics.style.display = 'none'; + document.querySelectorAll('[id^="ic-"]').forEach(function(el) { el.style.display = 'none'; }); + + document.getElementById('sup-mode').value = ''; + document.getElementById('sup-modal-title').textContent = 'Request for Quotation'; + document.getElementById('sup-modal-subtitle').textContent = 'How do you want to assign suppliers?'; + document.getElementById('sup-mode-badge-row').style.display = 'none'; + document.getElementById('sup-step1').style.display = 'flex'; + document.getElementById('sup-step2').style.display = 'none'; + closeAllItemDd(); +} +``` + +- [ ] **Step 2: Delete the now-dead `switchSupTab` function** + +Find and delete this entire block: + +```javascript +function switchSupTab(tab) { + _supTab = tab; + document.getElementById('sup-mode').value = tab === 'item' ? 'by_item' : 'global'; + + document.getElementById('sup-global-pane').style.display = tab === 'global' ? 'flex' : 'none'; + document.getElementById('sup-item-pane').style.display = tab === 'item' ? 'flex' : 'none'; + + var gBtn = document.getElementById('stab-global'); + var iBtn = document.getElementById('stab-item'); + if (tab === 'global') { + gBtn.style.color = '#2563eb'; gBtn.style.borderBottomColor = '#2563eb'; + iBtn.style.color = '#94a3b8'; iBtn.style.borderBottomColor = 'transparent'; + } else { + iBtn.style.color = '#2563eb'; iBtn.style.borderBottomColor = '#2563eb'; + gBtn.style.color = '#94a3b8'; gBtn.style.borderBottomColor = 'transparent'; + } + updateFooter(); +} +``` + +(Replace with nothing — delete the block entirely.) + +- [ ] **Step 3: Verify the script block** + +Confirm: +- `openSupplierModal` calls `goBack()` only +- `showStep` and `goBack` are both defined +- `switchSupTab` does not appear anywhere in the file +- `stab-global` and `stab-item` do not appear anywhere in the file + +--- + +### Task 4: Manual verification + +**Prerequisites:** Laravel dev server running (`php artisan serve`) and Vite running (`npm run dev`). + +- [ ] **Step 1: Open a purchase request that has the supplier modal** + +Navigate to `http://localhost:8000/purchase/requests`, open any request that has an "Assign Suppliers" or "Send RFQ" button, and click it. + +**Expected:** Modal opens showing Step 1 — two cards ("Full Order", "By Item") and a Cancel button. No tabs visible. + +- [ ] **Step 2: Test Full Order flow** + +Click the "Full Order" card. + +**Expected:** +- Modal transitions to Step 2 +- Header shows "← Change method · 📦 Full Order" badge row +- Title changes to "Select Suppliers", subtitle to "Choose who receives the quote request" +- Global supplier list is visible with search input +- Search input is auto-focused + +Select one or more suppliers via checkboxes. Confirm channel toggles appear per supplier selected. + +- [ ] **Step 3: Test back navigation clears state** + +Click "← Change method". + +**Expected:** +- Returns to Step 1 (method cards) +- Title resets to "Request for Quotation" +- Mode badge row hidden + +Click "Full Order" again. + +**Expected:** All checkboxes unchecked, search cleared — fresh state. + +- [ ] **Step 4: Test By Item flow** + +Click "By Item" card. + +**Expected:** +- Step 2 shows the per-item dropdown UI +- Mode badge shows "🔀 By Item" in green + +Assign a supplier to one item. Click "← Change method". Click "By Item" again. + +**Expected:** Item dropdown labels reset to "Select suppliers…", channel section hidden. + +- [ ] **Step 5: Test submission still works** + +Go to Full Order, select one supplier, click "Save & Continue →". + +**Expected:** Form submits to `purchase.requests.rfq.select` with `mode=global` and the selected `supplier_ids[]`. No JS errors in the browser console. + +- [ ] **Step 6: Test Escape key and backdrop click** + +Open modal, press Escape. + +**Expected:** Modal closes regardless of which step is active. + +Open modal, click outside the modal card. + +**Expected:** Modal closes. + +--- + +### Task 5: Commit + +- [ ] **Step 1: Stage the file** + +```bash +git add resources/views/components/purchase/supplier-select-modal.blade.php +``` + +- [ ] **Step 2: Commit** + +```bash +git commit -m "feat: replace supplier modal tabs with two-step wizard" +```