// direction-a-fieldmode.jsx — "On the job" / Field Mode section. // Synced to CURRENT project_blackdevil source (July 2026): // Screen 1 (Arrival) ← src/components/arrived-flow/ArrivalScreen.tsx // Screen 2 (In Progress)← src/components/arrived-flow/InProgressScreen.tsx // NOTE: this screen has NO voice/mic hero — it's a plain timer + photo // tags + notes textarea + materials checklist. The old mockup showed a // "Live Job" voice cockpit that TodaySurface.tsx's own comments mark as // the legacy "v1 Open Live Job" — a separate, still-reachable but // unconverted door, not what starting a job from Arrival leads to. This // rebuild matches the screen the primary Start-Job path actually shows. // Screens 3/4 (Wrap-up/Complete) ← src/components/JobCompletionSheet.tsx // (confirmed real: hours/materials review, "While you were there" // cross-sell, send/cash/draft payment chooser — exact copy for the // completion-tag chips wasn't verifiable in source, so that part is // generalized rather than invented). // None of these three files use Shift Board tokens yet — they're still on // the older dark palette (ArrivalScreen/InProgressScreen: pre-Rams "Refined // Industrial" tokens; JobCompletionSheet: Rams). All now repaint with the // July 2 brand-color unification (--brand / --brand-rams → new orange). // Field-mode palette — resolved 1:1 from arrived-flow's REAL tokens // (arrived-flow/types.ts → globals.css :root, the pre-Rams "Refined // Industrial" block that ArrivalScreen/InProgressScreen still use). const FM = { bg: '#0a0a0b', // --app-bg raised: '#121110', // --surface-raised (darker/plainer than the warm Rams #22201c) raised2: '#1a1a1a', // --surface-overlay border: '#272727', // --border-default borderSubtle: 'rgba(255,255,255,0.1)', // --border-subtle brand: '#ff5c00', // --brand (July 2 unification) brandDark: '#d35400', brandMuted: 'rgba(255,92,0,0.12)', brandBorder: 'rgba(255,92,0,0.3)', success: '#10b981', // --success successDark: '#059669', successMuted: 'rgba(16,185,129,0.12)', successBorder: 'rgba(16,185,129,0.2)', danger: '#ef4444', warn: '#fbbf24', blue: '#06B6D4', // On My Way / Send ETA — hardcoded in ArrivalScreen blueMuted: 'rgba(6,182,212,0.10)', blueBorder: 'rgba(6,182,212,0.25)', text: '#ffffff', // --text-primary text2: '#c2c8d1', // --text-secondary text3: '#9ca3af', // --text-tertiary font: "'Inter', -apple-system, system-ui, sans-serif", }; function FMStatusBar() { return (
9:41
); } // ─── Screen 1: Arrival (ArrivalScreen.tsx) ─── function FMArrival() { return (
{/* Arrival banner (arrived = green) */}

You've arrived

2847 Birch Ln

{/* Customer card */}

Aria Russell

4 previous jobs · $4,820 lifetime

{[ ['wrench', 'AC condenser — not cooling'], ['clock', 'Scheduled 9:00 AM · est. 2 hrs'], ['dollar-sign', '$420 quoted'], ].map(([ic, tx], i) => (
{tx}
))}
Gate code 4417 · dog in yard
{/* Quick actions */}
{[['message-square', 'Text Aria'], ['phone', 'Call Aria']].map(([ic, tx], i) => (
{tx}
))}
{/* Send ETA & Navigate — cyan choreographed text-then-map action, distinct from the quick actions above (confirmed real, was missing from earlier mockups). */}
Send ETA (12 min) & Navigate
{/* Bottom CTA */}
Start Job Timer
); } // ─── Screen 2: In Progress (InProgressScreen.tsx) ─── // The REAL screen: timer header w/ progress bar, tagged photo grid, a plain // notes textarea, and a materials checklist — no voice assistant. function FMInProgress() { const photos = [ { label: 'Before', has: true }, { label: 'During', has: false }, ]; const materials = [ { name: 'Smart thermostat (Ecobee)', cost: '$185.00', preloaded: true, used: true }, { name: '18-gauge thermostat wire, 25ft', cost: '$12.50', preloaded: false }, ]; return (
{/* Timer header */}

In Progress

AC condenser — not cooling

34:12
Est. 2 hrs
{/* Scrollable content */}
{/* Job Photos */}

Job Photos

1 captured
Before
Add
{/* Job Notes */}

Job Notes

Capacitor read low on arrival — replacing 45/5 MFD dual-run. Customer mentioned a burning smell last week.
{/* Materials Used */}

Materials Used

{materials.map((m, i) => (
{m.name} {m.cost} {m.preloaded && ( Pre-loaded )}
))}
Add material
{/* Bottom CTA */}
Found Additional Work
Complete Job
); } // Shared dimmed backdrop + bottom-sheet shell for the completion screens. function FMSheetBackdrop() { return (
); } // ─── Screen 3: Wrap-up (JobCompletionSheet.tsx, review step) ─── // Confirmed real: hours + materials review, and the "While you were there" // cross-sell upsell (verbatim casing/heading from source). The exact // completion-tag UI wasn't verifiable in source, so this leads with what is. function FMWrapup() { const upsells = [ ['Hard-start kit', 'Extends compressor life on older units'], ['Replace the contactor', 'Common next failure — cheap to do while it’s open'], ]; return (

Review before you go

Aria Russell · 34 min on site

{/* Hours + materials summary — JobWorksurface.tsx: "hours/materials adjustment" */}
Hours
0.75 edit
Materials
$197.50
{/* WHILE YOU WERE THERE — confirmed real cross-sell section */}
While you were there
{upsells.map(([t, d], i) => (
{t}
{d}
Add
))}
Back
Complete & Invoice
); } // ─── Screen 4: success step — the invoice + send/cash/draft payment chooser // (JobWorksurface.tsx: "send/cash/draft chooser"). ─── function FMComplete() { return (

Job Complete!

Great work on Aria Russell

Invoice INV-1042 Ready
Review before sending $617.50
Send to customer
{[['message-square', 'Text payment link', false], ['check-circle', 'Mark paid (cash)', true], ['file-text', 'Save as draft', false]].map(([ic, label, ok], i) => (
{label}
))}
); } const FM_STEPS = [ { key: 'arrival', label: 'Arrive', title: 'You pull up. Werkd already knows the job.', body: 'GPS flips the screen to this job the second you arrive — customer history, the quote, and gate codes, all there. One tap starts the timer.', render: () => }, { key: 'inprogress', label: 'Work', title: 'Photos, notes, materials — as you go.', body: 'The timer runs while you work. Tag before/after photos, jot a note, check off materials as you use them — everything lands on the invoice automatically.', render: () => }, { key: 'wrapup', label: 'Wrap up', title: 'Werkd spots the work you’d have driven past.', body: 'Review the hours and materials it tracked, then "While you were there" surfaces the easy add-ons for THIS job — found money most apps never mention.', render: () => }, { key: 'complete', label: 'Get paid', title: 'Job done. Invoice already built.', body: 'Tap complete and the invoice is ready to review. Email it, text a payment link, or mark it paid in cash — before you leave the driveway.', render: () => }, ]; function AFieldMode() { const DA = window.DA; const m = window.useIsMobile(); const [i, setI] = React.useState(0); const [paused, setPaused] = React.useState(false); const [typed, setTyped] = React.useState(''); // Type the body out (~18ms/char) — reads like Werkd's AI narrating the job — // then dwell ~2.6s and advance. Paused shows the full text and halts advance. React.useEffect(() => { const full = FM_STEPS[i].body; if (paused) { setTyped(full); return; } setTyped(''); let idx = 0; const SPEED = 18; const typeId = setInterval(() => { idx += 1; setTyped(full.slice(0, idx)); if (idx >= full.length) clearInterval(typeId); }, SPEED); const advanceId = setTimeout(() => setI((p) => (p + 1) % FM_STEPS.length), full.length * SPEED + 6200); return () => { clearInterval(typeId); clearTimeout(advanceId); }; }, [i, paused]); const step = FM_STEPS[i]; // Derive the active index from `step` itself (which provably tracks the // phone + caption) so the rail/progress can't desync from them. const fmActive = FM_STEPS.indexOf(step); return (
FIELD MODE

The whole job,
on site

GPS knows the moment you pull up, and werkd takes over the whole visit — one full-screen flow from the driveway to paid. No hunting through menus with dirty hands.

{/* phone */}
{step.render()}
{/* caption + rail */}
{/* step rail */}
{FM_STEPS.map((s, idx) => ( ))}

{step.title}

{/* Body types out; a hidden full-text sizer reserves the height so nothing below jumps as lines fill in. minHeight reserves the tallest stage's body so the centered column never re-centers. */}

{typed}

{/* play / pause the walkthrough */}
{!paused && ( Auto-advancing… )}
); } window.AFieldMode = AFieldMode; window.FMInProgress = FMInProgress;