Tour Dash
Report · 4 September 2026

Vendors Redesign

The directory where an agent finds a photographer, a stager or a locksmith — everyone who works a listing without working for the brokerage. It was eleven identical full-width cards in one pile, a locksmith given exactly as much room as a title company, with the trade an agent actually browses by set as the smallest text on the card. It is now shelved: the trade is the heading, vendors are rows beneath it, and the figures line up down the whole page so two photographers can be compared without scrolling between them. A second pass then put a map beside the shelves, which is where most of the thinking went: a vendor is not a point the way a job is, so the map is about reach rather than location. Same data layer, same tokens, nothing renamed.

Scope The Vendors page, the row that lists a vendor, and the coverage map beside them Status Committed as 44f2888 and a72220a on 2026-09-04; both deployed
01

What was wrong with it

The page had one job — answer "who is even out here?" — and it answered by handing you eleven slabs and asking you to read them all.

The previous Vendors page at 1440px: a bordered Filters panel with a heading over a search box and two dropdowns, then eleven identical full-width cards, each with a coloured initials circle, a name, a small grey trade line, a row of four facts spread across the card, four grey badges, two lines of bio, and Hire and View profile buttons.
Before. Eleven vendors, 2,891px of page, and no two facts in the same place twice.
02

What it is now

A shelf per trade. An agent does not browse people, they browse a trade: the question is "who shoots listings around here", and only then "which of these two". So the trade is the heading and the vendors are rows beneath it, which puts the two photographers next to each other where they can actually be compared. The shelves run in transaction order — everything you need before it lists, then while it is on market, then to close it out — the same order the hire wizard's picker uses, with the moment named once above its shelves instead of repeated on every one.

The redesigned page at 1440px: three controls sitting directly on the page, a count line reading 11 vendors across 10 trades within 25 miles, then a section headed Before it lists with the note Getting the property ready to photograph and show, under which a left rail names Listing photography with 2 vendors beside two rows for Mira Kovacs and Devon Achebe, then Staging, Deep clean and Landscaping shelves. Each row carries an avatar, the person's name, their business and credentials, then distance, rating, turnaround and rate in aligned columns, a Hire button and a bookmark. Further down, sections headed While it's on market and Closing it out.
After, at 1440px. Distance, rating, turnaround and rate hold the same four columns from the first row to the last.
03

What a row says now

Moving the trade into the heading freed the two lines that were spending themselves on it, and three facts already in the database went on the page for the first time.

The redesigned page in the light theme: the same shelves and aligned columns on a warm off-white ground, with saved rows carrying a slightly darker border and a faintly tinted card.
Light. Every surface and hairline comes from the same tokens, so the saved row's heavier border reads in both themes without a second definition.
The redesigned page at 390px: the trade name and count on one line, then per vendor an avatar with the name and business, one wrapped row carrying distance, rating, turnaround and rate, a Hire button with the bookmark beside it, and the bio on a line below.
Phone. The four figures wrap into one row instead of stacking into four, which is what keeps the page from getting taller than the one it replaced.
04

What it measures

Same eleven vendors, same demo account, measured on the full page.

WidthBeforeAfter the shelf pass
1440px2,891px1,842px
390px3,715px3,228px

Verified in both themes at 1440px and 390px on the demo account, which is the only account with vendors in range. Typecheck and production build both clean.

05

The coverage map

Nobody hires a cleaner because of where they sleep. A pin cloud of vendor home ZIPs would have been decoration, and the question a directory actually has to answer is reach: does this person travel far enough to get to my listing? So the map is a coverage map. Highlighting a row draws that vendor's service radius over the agent's own base.

The Vendors page at 1440px in the dark theme with a map filling the right half. The row for Teddy Hollis is highlighted in the list, his pin on the map is enlarged, a tinted circle covers the map, and an overlay at the top left of the map reads Teddy covers you, with 12 miles to spare.
Hovering a locksmith. The overlay states the conclusion; the circle is the evidence for it.
The same page in the light theme with the row for Mira Kovacs highlighted, her pin enlarged, a blue tinted coverage circle on the map, and an overlay reading Mira covers you, with 5 miles to spare.
Light. The coverage circle takes the highlighted vendor's own family hue, so it never needs a colour of its own.
06

Coverage gaps

A directory that lists who exists can only show an absence by drawing nothing. If there is no handyman within range, the old page simply had no handyman shelf, and the agent had no way to notice. A trade with nobody in it now keeps its place in the transaction order as an empty shelf, with the one useful action on it.

The Vendors page showing 9 vendors across 8 trades within 15 miles, 2 trades with nobody. Under Before it lists, the Deep clean shelf is a dashed row reading Nobody in range with a Post it openly button, and under While it's on market the Handyman shelf is the same.
Deep clean and Handyman have nobody in range, and say so where their vendors would have been. Captured with a 15-mile step added to the radius control for the purpose: every sample vendor sits between 11 and 19 miles out, so the shipped steps of 10, 25, 50 and 100 cannot produce a partial result on this data.
07

One thing left open

The schema comments stripe_payouts_enabled as "the one that matters: false means this provider cannot be booked". Nothing in the application reads it — not this page, not the hire wizard, not the checkout. So a vendor who has never finished Stripe onboarding is offered with a Hire button everywhere, and finds out later.

It was left out of this pass on purpose. Surfacing it only in the directory would imply a guarantee the rest of the app does not keep, and it is a question about the booking path rather than about how vendors are listed. It wants its own change.

08

Files

FileWhat changed
src/components/VendorShelf.tsxNew. Shelves by trade in transaction order, with the moment named once above its shelves and each vendor a fixed-grid row whose figures align down the page.
src/pages/Contractors.tsxRenders the shelf; filters lost their panel; the spinner became skeleton shelves; the count line reports trades as well as vendors.
src/components/VendorMap.tsxNew. The coverage map: hollow-ring pins in the trade's moment hue, the agent's base, the dashed search ring, and the highlighted vendor's service radius drawn as a circle.
src/components/ProviderCard.tsxKeeps the hire wizard's selectable shortlist and loses the onHire prop, which the directory was its only user of.