Apply in one request, and say why a role cannot be applied to

Fixkamo-internal
Shipped
September 3, 2026 at 10:51 PM UTC
Author
Kamo
Commit
fcc10da

Follow-up to a review of my own commit. Six real findings. APPLYING IS NOW ONE REQUEST. The résumé used to upload after the application was created, and a failed second leg left a complete-looking application against a posting that had marked the résumé required — the dialog even said so and treated it as non-fatal, because the answers really were stored. The file now rides with the answers and DocsService rolls the row back if a required one never arrives. Editing an existing application stays two calls, correctly: the row is already there, so a failed re-attach orphans nothing. CANNOT-APPLY NOW EXPLAINS ITSELF. The server has always sent cannotApplyReason — ON_HOLD, ALREADY_APPLIED or CLOSED — with a comment saying it existed so the UI could explain rather than grey out. Nothing read it. A role past its closing date rendered with no chip, no affordance and no reason, which reads as a broken card rather than a shut door. The card and the dialog both say it now. THE MARK-READ CALL COULD DOUBLE-FIRE. ApplicationDrawer clears the "new" dot in an effect that depends on its onChanged callback, and the page passed a fresh inline arrow every render — so any parent re-render between mount and the response re-ran the effect (the openedByHr guard is still false at that point) and POSTed twice. It is a useCallback now. THE MEMBER BOARD'S MEMOS WERE INERT. `board?.listings ?? []` is a new array every render, so all four memos and callbacks keyed on it recomputed every render. Two frozen module constants fix it. THE HIRING MANAGER COULD BE SEEDED AND SHOWN BUT NEVER SET. The field was plumbed end to end — draft, save request, server resolver, and rendered on the member's advert — with no control anywhere, so the only way to populate it was duplicating a posting that already had one. It now uses the platform's own AgentSelector, with requiredRight null: a hiring manager is whoever owns the req, and narrowing the directory to holders of an HR right would hide most of the people who run one. TWO SOURCES FOR ONE NUMBER, TWICE. The Applicants sub-tab label read the console's own total while the masthead counted the list it renders; the member tab said "My applications (2)" over a list of three because it excluded withdrawn ones the list still showed. Both now read the list they label. Smaller: a résumé can be removed from an application again, offered only where the posting does not require one (the server refuses the rest, and a control whose one outcome is a refusal is not a control); an applicant's pay expectation is formatted like every other money value instead of printing the raw decimal; a posting card shows its ACTIVE applicant count when it differs from the total, because eleven applicants of whom nine were rejected is not eleven live candidates. Dead code removed: two client methods and their proxy routes that the board payload already made unnecessary, and a write-only ref in the posting editor.

All changes

Like what you see shipping?

Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.

Start Free ForeverView Pricing