Commit graph

39 commits

Author SHA1 Message Date
Codex Review Integration
58fc323ea2 fix(work-orders): use local calendar day for Past Due and stabilize slow suites
computeIsPastDue and the day view's todayKey derived today from
toISOString() (UTC). West of UTC that rolls over hours early, so work
scheduled for today showed as Past Due every evening. Both now use the
local todayIso() helper the board already uses; regression tests pin
23:30 and 00:30 in America/Sao_Paulo with fake Date.

Test stability:
- adv-search page sync: scope pagination queries with within() instead of
  scanning ~330 buttons / 3000 nodes on every waitFor poll
- pm-schedules-list-actions: static import of the edit page so module
  transform does not count against the 5s test budget
- vendor create modal / detail drawer: userEvent.setup({ delay: null });
  15s describe budget for full MUI dialog renders under parallel load
2026-09-16 22:06:33 -03:00
Codex Review Integration
38ea40d6ca Merge origin/dev into feat/ab/sh-278-vendor-service-area 2026-09-16 16:08:12 -03:00
Alexandre Brandizzi
30c43a4d86
SH-281: group vendor directory rows by company (#188)
* fix(vendors): add accessible trade overflow tooltip

* fix(vendors): add accessible trade overflow tooltip

* refactor(vendors): satisfy row maintainability gate

* feat(vendors): group directory rows by company

* chore(vendors): trigger SH-281 review checks

* test(vendors): align company directory visuals

* test(vendors): complete company visual baselines

* fix(vendors): keep empty states in viewport

* test(vendors): align centered empty baseline

* fix(vendors): use grouped directory endpoint

* test(vendors): follow grouped directory endpoint

* test(vendors): refresh combined visual snapshots

---------

Co-authored-by: Codex Review Integration <codex-review@local.invalid>
2026-09-16 14:40:24 -03:00
Codex Review Integration
2bff7176be feat(vendors): add Service Area assignment, filter and column
Replace the free-text vendor State with a closed 50-state list, add an
admin-only Service Area select below Notes, a Service Area advanced filter
(stable ids plus Unassigned) and a Service Area directory column.
2026-09-16 11:55:40 -03:00
Alexandre Brandizzi
861f820715
SH-279: replace Vendor trade overflow title with MUI Tooltip (#187)
Some checks are pending
Frontend checks / Build and test (push) Waiting to run
Frontend checks / governance (push) Waiting to run
Frontend checks / Visual regression (push) Waiting to run
Deploy dev content / Deploy shoc-frontend-new-dev through Terraform (push) Waiting to run
* fix(vendors): add accessible trade overflow tooltip

* refactor(vendors): satisfy row maintainability gate

---------

Co-authored-by: Codex Review Integration <codex-review@local.invalid>
2026-09-15 16:23:14 -03:00
Codex Review Integration
fa1f4467e2 feat(vendors): merge dev after address changes 2026-09-15 16:15:04 -03:00
Alexandre Brandizzi
80be702733
feat(vendors): structure the address into Street/City/State with autocomplete (#176)
* feat(vendors): structure the address into Street/City/State with autocomplete

The Vendor form carried one free-text "Address (optional)" line, with City,
State and Zip already present but hidden behind display:none, and a separate
"Google Maps URL" input someone had to paste into by hand.

Street Address, City and State are now three required fields. Typing three
characters in Street Address offers up to four candidates; picking one fills
all three at once, and typing without picking stays plain free text. The
Google Maps URL input is gone — the location is derived from the address, the
Street Address itself is the link in view mode, and a keyless map preview
renders once all three parts are present. Zip stays in the payload but out of
the form; the ticket scopes the visible set to three.

The suggestion algorithm, candidate cities and copy are ported from the
approved prototype rather than invented, so dev and design agree on what a
dispatcher sees. Suggestions are deterministic for a given input on purpose:
a reshuffling list moves a row out from under the pointer mid-click.

Test fixtures that predate the requirement now carry an address, so each test
still fails for the reason it is about. The two drawer tests asserting the
stored-URL "Open in Google Maps" row are rewritten to the behaviour that
replaced it.

Delivers SH-271.

* feat(work-orders): show the vendor location map in the Vendor dialog

The last of SH-271's five acceptance bullets. The Work Order Vendor dialog
gets one composed address line from the vendor dropdown payload, not the
structured parts the form and detail drawer hold, so the preview takes the
line directly — it is saved data either way, and the completeness rule exists
to stop a map of half-typed input, not to reject a stored address.

The dialog's hand-built maps URL now goes through the shared helper, so the
link and the preview cannot drift apart.

* test(vendors): update the browser specs and pixel baselines for the new address

`npm run verify` does not run Playwright, so the first push went out with the
browser suite still asserting the UI this ticket removes. Three assertions
were stale: the combined "Address (optional)" input, the "Google Maps URL
(optional)" input, and the detail drawer's separate "Open in Google Maps"
row — now replaced by the Street Address itself being the link, checked
against the derived href. A fourth test created a vendor without an address,
which the new requirement blocks; it fills one, so the test still fails only
for the reason it is about.

Baselines regenerated in mcr.microsoft.com/playwright:v1.61.1-noble, the image
CI uses — macOS font rendering produces different pixels. Exactly three of the
sixteen were rewritten (vendor add, edit, detail); the rest, including every
Work Orders shot, are byte-identical, which is the evidence that this change
stays inside the surfaces it claims.

* test(vendors): keep the map preview out of the pixel baselines

The visual suite mocks `**/api/**` and nothing else, so the address map
preview's iframe reached maps.google.com for real. Whether that frame paints,
and what it paints, depends on the network and on what Google serves that
minute — which is why `vendor-edit` failed in CI at 18178 differing pixels
while passing in a container that could not reach Google. Regenerating the
baseline would not have fixed it; it would have moved the flake.

Aborting the request pins the frame to a blank box, so the shot measures our
layout and nothing else. The committed baselines are unchanged by this — they
were already correct — and a second container run with no --update passes
16/16, which is the evidence the shot is now stable rather than merely green
once.

* fix(vendors): complete structured address map flows

* test(vendors): align add visual baseline with CI

---------

Co-authored-by: Codex Review Integration <codex-review@local.invalid>
2026-09-15 16:13:15 -03:00
Codex Review Integration
99253587ef fix(vendors): use grouped directory endpoint 2026-09-14 15:24:55 -03:00
Codex Review Integration
1c90aa60f3 feat(vendors): group directory rows by company 2026-09-14 13:07:00 -03:00
Codex Review Integration
0b4dafc868 fix(vendors): add accessible trade overflow tooltip 2026-09-14 12:36:31 -03:00
Alexandre Brandizzi
d6755a63b6
fix(vendors): clarify blank technician draft state (#157)
Some checks failed
Frontend checks / Build and test (push) Has been cancelled
Frontend checks / governance (push) Has been cancelled
Frontend checks / Visual regression (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
* fix(vendors): clarify blank technician draft state

* test(vendors): update technician section snapshots

---------

Co-authored-by: Codex Review Integration <codex-review@local.invalid>
2026-08-28 15:00:02 -04:00
Alexandre Brandizzi
5e38c93b1e
fix(vendors): truncate long textual table values (#154)
Some checks are pending
Frontend checks / Build and test (push) Waiting to run
Frontend checks / governance (push) Waiting to run
Frontend checks / Visual regression (push) Waiting to run
Deploy / deploy (push) Waiting to run
* fix(vendors): truncate long locations in table

* fix(vendors): truncate textual table cells

---------

Co-authored-by: Codex Review Integration <codex-review@local.invalid>
2026-08-28 11:21:15 -04:00
Alexandre Brandizzi
7ec522e8ea
fix: complete SH-283 vendor QA paths (#148)
Some checks are pending
Frontend checks / Build and test (push) Waiting to run
Frontend checks / governance (push) Waiting to run
Frontend checks / Visual regression (push) Waiting to run
Deploy / deploy (push) Waiting to run
Co-authored-by: Codex Review Integration <codex-review@local.invalid>
2026-08-27 15:03:36 -03:00
Alexandre Brandizzi
3b1fe016fe
fix(vendors): clarify required company fields (#146)
Some checks are pending
Frontend checks / Build and test (push) Waiting to run
Frontend checks / governance (push) Waiting to run
Frontend checks / Visual regression (push) Waiting to run
Deploy / deploy (push) Waiting to run
* fix(vendors): clarify required company fields

* test(vendors): refresh company label snapshots

* refactor(vendors): isolate contact fields

---------

Co-authored-by: Codex Review Integration <codex-review@local.invalid>
Co-authored-by: Adam Moussa <166072409+amoussa1229@users.noreply.github.com>
2026-08-27 13:01:53 -04:00
Alexandre Brandizzi
338cc17b8a
fix(vendors): remove duplicate company heading (#139)
* fix(vendors): remove duplicate company heading

* test(vendors): align detail baseline with CI

---------

Co-authored-by: Codex Review Integration <codex-review@local.invalid>
Co-authored-by: Adam Moussa <166072409+amoussa1229@users.noreply.github.com>
2026-08-26 16:45:06 +00:00
Alexandre Brandizzi
8fa37cf430
fix(vendors): display company contact fallbacks (#135)
Some checks are pending
CI / ci (push) Waiting to run
CI / governance (push) Waiting to run
CI / visual-regression (push) Waiting to run
Deploy / deploy (push) Waiting to run
Co-authored-by: Codex Review Integration <codex-review@local.invalid>
2026-08-25 20:03:18 -04:00
Codex Review Integration
01a7a22c07 fix(vendors): remove obsolete trade reorder controls (SH-182) 2026-08-21 11:42:06 -03:00
Codex Review Integration
146491fafb fix(vendors): persist technician removal 2026-08-20 20:43:52 -03:00
Alexandre Brandizzi
35bfb9b7c8 fix(vendors): correct roster validation and editing 2026-08-20 18:25:34 -03:00
Alexandre Brandizzi
4d8e86b264
Merge branch 'dev' into feat/sh-249-fe-trades 2026-08-20 11:48:07 -03:00
Alexandre Brandizzi
3141adba13
Merge branch 'dev' into feat/sh-254-fe-deactivate-confirm 2026-08-20 11:24:12 -03:00
Alexandre Brandizzi
326ac18eb0
Merge branch 'dev' into feat/sh-254-fe-deactivate-confirm 2026-08-20 11:15:10 -03:00
Codex Review Integration
aebb2c6b1a Merge remote-tracking branch 'origin/dev' into feat/sh-253-vendor-detail-parity
# Conflicts:
#	src/test/app/(protected)/vendors/vendor-detail-drawer.test.tsx
2026-08-20 11:14:51 -03:00
Alexandre Brandizzi
98daf9832d
Merge branch 'dev' into feat/sh-255-deactivate-toggle-gate 2026-08-20 11:06:54 -03:00
Codex Review Integration
22b03b8ac0 fix(vendors): deactivation dialog follows the approved design (SH-254)
The dialog's wording, its actions and its behaviour all diverged from the
design prototype. It refused deactivation outright when the vendor had
open work orders, which SH-44 and SH-82 left as an open question rather
than a decided requirement.

Deactivation with open work orders now proceeds on explicit confirmation:
the design's title and body copy, the affected work orders listed as
links, and "Deactivate anyway" in place of a disabled button. The API
call carries confirmOpenWorkOrders so the server-side guard is cleared
deliberately rather than removed.
2026-08-19 13:36:37 -03:00
Codex Review Integration
038ce263da fix(vendors): vendor detail parity with the design prototype (SH-253)
Three divergences in the vendor detail drawer:

- The header rendered the company as a subtitle under a title that had
  already fallen back to the company, printing the same name twice when
  the row carried no technician. The subtitle is now dropped when it
  would repeat the title.
- The Google Maps link appeared only when a URL was stored, unlabelled,
  so an empty value left no trace of the field. It is now a labelled
  field below Address that reads em-dash when unset, as every other
  field in the panel does.
- The status sat immediately beside Total Jobs. It now sits opposite it
  at the right edge, and reuses the vendors table's dot-plus-text badge
  so the state never reads by colour alone.
2026-08-19 13:22:11 -03:00
Codex Review Integration
90a5256dee fix(vendors): gate deactivation prompt on saved status (SH-255)
The drawer's Active toggle asked to deactivate whenever the switch moved
from on to off, reading the unsaved form value. An inactive vendor toggled
on and back off without saving therefore raised "Deactivate this vendor"
for a vendor that was already inactive.

Gate on the persisted technician status from the loaded roster instead,
falling back to the clicked row. Deactivation is a property of the saved
vendor, not of the toggle.
2026-08-19 13:18:17 -03:00
Codex Review Integration
1305bf35dd fix(vendors): bypass the query cache when reloading after a conflict (SH-250)
The reload fix re-seeded the form from queryClient.fetchQuery, which inherits the
global 5-minute staleTime. A 409 never invalidates that key -
useSaveVendorCompanyRoster invalidates only in onSuccess and its onError returns
early for conflicts - and the Add flow has no mounted observer on it, so reload
returned the cached roster with the same stale rowVersion and every retry 409'd
again. Update mode was unaffected because it recovers via query.refetch(), which
bypasses staleTime.

Pass staleTime: 0 on that fetch, since its sole purpose is the freshest
rowVersion. The regression test uses a client with the app's real staleTime; the
default test client uses 0, which masked this entirely.
2026-08-19 10:26:28 -03:00
Codex Review Integration
9a066092b3 fix(vendors): correct additive add reload, phone and contact (SH-250, SH-246)
Three review findings on the additive add path:

- Create-mode reload refreshed selectedRoster (including rowVersion) but left
  the form company fields on their pre-conflict values, so a retry diffed stale
  fields against the reloaded roster and could overwrite the concurrent company
  update that caused the 409. Reload now resets the form from the fresh roster,
  matching the select path.
- mapVendorRosterAdditivePatchToBackend copied companyFields verbatim while the
  reconcile write mapper canonicalizes companyPhone, so PATCH and PUT could send
  different phone shapes for the same input.
- emptyRosterTechnician seeded preferredContact "Phone" even though that
  control was removed from the form, so filling the first blank row submitted a
  fabricated value. append already omitted it; both paths now agree.
2026-08-18 17:28:48 -03:00
Codex Review Integration
64caab1832 fix(vendors): do not fail open while the trades facet is loading (SH-249)
An empty tradeOptions array meant two different things: "facets query still in
flight" and "vocabulary genuinely unavailable". Both enabled fail-open free
text and showed the outage warning, so a normal cold fetch looked like an
outage. Anything committed in that window was added to knownTradesRef and stayed
selectable after the canonical list arrived, permanently undermining the gate.

Expose the facets query isLoading as tradesLoading, thread it to the field as
tradeOptionsLoading, and keep the canonical gate active while loading. The
outage warning now shows only once the query has settled empty.
2026-08-18 17:25:44 -03:00
Codex Review Integration
df00e56d6e fix(vendors): gate trades to canonical list, preserve legacy values (SH-249) 2026-08-18 13:12:10 -03:00
Codex Review Integration
a710e21281 fix(vendors): additive technician add for existing companies (SH-250, SH-246) 2026-08-18 13:09:33 -03:00
Arthur Bassi
4af826a1e0
feat(work-orders): query broadcast, remove auth bypass, dispatch polish (#100)
* fix(work-orders): address wizard create review findings

[recover] remove malicious eslint payload (was 166c63e4)

* fix(work-orders): remove legacy completedDate EditWorkorder path

[recover] remove malicious eslint payload (was f4e6132b)

* fix(work-orders): use local calendar day for completedDate

Restore todayIso() after parent merge reintroduced UTC slice, and keep the wizard-date-utils regression test.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(work-orders): send wizard status and clear POC notes on site change

Map draft.status to lifecycleStatus on board create, and reset pocNotes with POC fields when the wizard site changes.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(query): scope broadcast channel per account and clear on auth

Isolate TanStack Query broadcast by userId, dispose and clear on
logout/401, and extract vendor filter drawers for governance.

* feat(work-orders): board wizard create with service notes

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(work-orders): enforce single-service wizard create per SH-118

Use single service selection in the wizard and omit extraServices from board create.

* fix(vendors): restore filter drawer labels for e2e and visual CI

Use VendorFilterOptions again and keep the Apply filters footer label expected
by vendor Playwright specs and the committed visual baseline.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-14 11:52:48 -03:00
Alexandre Brandizzi
ec203e1f5b fix(vendors): preserve the selected edit state 2026-08-06 22:39:11 -03:00
Alexandre Brandizzi
b61d46ce4b fix(vendors): match prototype directory experience 2026-08-06 22:23:30 -03:00
Alexandre Brandizzi
ca7829036f
feat(vendors): add company roster workflows (SH-198) (#64)
Some checks failed
CI / ci (push) Has been cancelled
CI / governance (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
* feat(vendors): support company roster workflows

* fix(vendors): address roster review feedback

* test(vendors): preserve draft on roster load failure

* fix(vendors): preserve current roster selection
2026-08-04 09:53:48 -03:00
Alexandre Brandizzi
4b88a60751
fix(vendors): remove preferred contact and fix trade ordering (#63)
Some checks are pending
CI / ci (push) Waiting to run
CI / governance (push) Waiting to run
Deploy / deploy (push) Waiting to run
* fix(vendors): address SH-180 and SH-182

* refactor(vendors): satisfy maintainability gates
2026-08-03 17:53:39 -03:00
Alexandre Brandizzi
bbbb51aed5 feat(vendors): complete core vendor workflows 2026-07-23 17:36:21 -03:00
Alexandre Brandizzi
20237f8142
feat(vendors): align directory UI with current prototype (#46)
Some checks are pending
CI / ci (push) Waiting to run
Deploy / deploy (push) Waiting to run
* feat(vendors): align directory UI with prototype

* fix(vendors): report the filtered total

* fix(vendors): keep company input in sync

* fix(vendors): scope facets to directory status
2026-07-23 15:23:03 -03:00