fix(console): blank lead page — statusStrip const used blocked/stalled before they existed
The lifted status strip (e21e394) was defined right after `holds`, but its JSX
references `blocked` and `stalled`, which are declared ~80 lines lower. A const
that reads a const declared below it throws "Cannot access before
initialization" at render — a temporal dead zone the bundler does not catch, so
the build passed and the lead page rendered blank.
Moved the statusStrip definition to just after `stalled`, so every value it
reads exists first. The lifted-above-the-metrics position is unchanged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
e21e3949f5
commit
fda1247ee9
@ -301,81 +301,6 @@ export default function Lead() {
|
||||
const stage = phaseOf(STAGES.find((s) => s.name === stateName), row)
|
||||
const holds = holdsOf(stage)
|
||||
|
||||
/* WHAT IS HAPPENING NOW, lifted above the numbers. An operator's first
|
||||
question about a lead is "what is going on / what do I do", not "what is
|
||||
the premium" — so the status strip (an alert when blocked or stalled, the
|
||||
live state otherwise) sits directly under the header, before the metrics.
|
||||
Rendered full-width there rather than inside the narrow work column. */
|
||||
const statusStrip = (
|
||||
blocked ? (
|
||||
<div className="doing doing--blocked">
|
||||
<span className="doing__stop" aria-hidden="true" />
|
||||
<div>
|
||||
<strong>Stopped — {blocked.what}</strong>
|
||||
<span>
|
||||
{blocked.fix} The agents will pick the lead up again on their own once it
|
||||
is there; nothing else is running in the meantime.
|
||||
</span>
|
||||
<button
|
||||
type="button" className="doing__fix"
|
||||
onClick={() => setOpen(blocked.via)}
|
||||
>
|
||||
Open Collect Documents
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
) : stalled ? (
|
||||
<div className="doing doing--stalled">
|
||||
<span className="doing__stop" aria-hidden="true" />
|
||||
<div>
|
||||
<strong>{stage.doing} — nothing for {stalled.mins} minutes</strong>
|
||||
<span>
|
||||
{stage.by} has not come back. That is usually the model provider being
|
||||
slow or dropping a request, not a problem with this lead — the work so far
|
||||
is safe and nothing has been lost.
|
||||
{stalled.nudge
|
||||
? ` Running ${stalled.nudge.label.toLowerCase()} wakes ${stalled.nudge.by} to try again.`
|
||||
: ' There is no step to re-run from here; the actions below are the way on.'}
|
||||
</span>
|
||||
{stalled.nudge ? (
|
||||
<button
|
||||
type="button" className="doing__fix"
|
||||
onClick={() => setOpen(stalled.nudge.uid)}
|
||||
>
|
||||
{stalled.nudge.label}
|
||||
</button>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
) : stage?.kind === 'customer' && stage.doing ? (
|
||||
/* Not an agent working, and not a task of yours either — the lead
|
||||
is with someone outside the business. Without this the screen
|
||||
went blank at exactly the stage where an operator is most likely
|
||||
to wonder whether something has broken. */
|
||||
<div className="doing doing--waiting">
|
||||
<span className="doing__wait" aria-hidden="true" />
|
||||
<div>
|
||||
<strong>{stage.doing}</strong>
|
||||
<span>
|
||||
Their answer comes back to this lead on its own — Engage reads it and
|
||||
records the acceptance. Nothing is waiting on you.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
) : stage?.kind === 'auto' ? (
|
||||
<div className="doing">
|
||||
<span className="doing__pulse" aria-hidden="true" />
|
||||
<div>
|
||||
<strong>{stage.doing}</strong>
|
||||
<span>
|
||||
Handled by {stage.by}.
|
||||
{stage.after ? ` The lead stays in ${stateName} until a quote exists — nothing is waiting on you.` : ''}
|
||||
{' '}Typically completes within two minutes; this view refreshes automatically.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
) : null
|
||||
)
|
||||
// Only what THIS user may run. The workflow refuses the rest server-side
|
||||
// anyway; showing them a row of buttons that all 403 reads as a broken app
|
||||
// rather than as a control.
|
||||
@ -454,6 +379,83 @@ blocked ? (
|
||||
// the way out rather than going on promising two minutes.
|
||||
const stillFor = row.updated_at ? now - Date.parse(row.updated_at) : 0
|
||||
const stalled = !blocked && stage?.kind === 'auto' && stillFor > STALL_AFTER_MS
|
||||
|
||||
/* WHAT IS HAPPENING NOW, lifted above the numbers. An operator's first
|
||||
question about a lead is "what is going on / what do I do", not "what is
|
||||
the premium" — so the status strip (an alert when blocked or stalled, the
|
||||
live state otherwise) sits directly under the header, before the metrics.
|
||||
Rendered full-width there rather than inside the narrow work column. */
|
||||
const statusStrip = (
|
||||
blocked ? (
|
||||
<div className="doing doing--blocked">
|
||||
<span className="doing__stop" aria-hidden="true" />
|
||||
<div>
|
||||
<strong>Stopped — {blocked.what}</strong>
|
||||
<span>
|
||||
{blocked.fix} The agents will pick the lead up again on their own once it
|
||||
is there; nothing else is running in the meantime.
|
||||
</span>
|
||||
<button
|
||||
type="button" className="doing__fix"
|
||||
onClick={() => setOpen(blocked.via)}
|
||||
>
|
||||
Open Collect Documents
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
) : stalled ? (
|
||||
<div className="doing doing--stalled">
|
||||
<span className="doing__stop" aria-hidden="true" />
|
||||
<div>
|
||||
<strong>{stage.doing} — nothing for {stalled.mins} minutes</strong>
|
||||
<span>
|
||||
{stage.by} has not come back. That is usually the model provider being
|
||||
slow or dropping a request, not a problem with this lead — the work so far
|
||||
is safe and nothing has been lost.
|
||||
{stalled.nudge
|
||||
? ` Running ${stalled.nudge.label.toLowerCase()} wakes ${stalled.nudge.by} to try again.`
|
||||
: ' There is no step to re-run from here; the actions below are the way on.'}
|
||||
</span>
|
||||
{stalled.nudge ? (
|
||||
<button
|
||||
type="button" className="doing__fix"
|
||||
onClick={() => setOpen(stalled.nudge.uid)}
|
||||
>
|
||||
{stalled.nudge.label}
|
||||
</button>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
) : stage?.kind === 'customer' && stage.doing ? (
|
||||
/* Not an agent working, and not a task of yours either — the lead
|
||||
is with someone outside the business. Without this the screen
|
||||
went blank at exactly the stage where an operator is most likely
|
||||
to wonder whether something has broken. */
|
||||
<div className="doing doing--waiting">
|
||||
<span className="doing__wait" aria-hidden="true" />
|
||||
<div>
|
||||
<strong>{stage.doing}</strong>
|
||||
<span>
|
||||
Their answer comes back to this lead on its own — Engage reads it and
|
||||
records the acceptance. Nothing is waiting on you.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
) : stage?.kind === 'auto' ? (
|
||||
<div className="doing">
|
||||
<span className="doing__pulse" aria-hidden="true" />
|
||||
<div>
|
||||
<strong>{stage.doing}</strong>
|
||||
<span>
|
||||
Handled by {stage.by}.
|
||||
{stage.after ? ` The lead stays in ${stateName} until a quote exists — nothing is waiting on you.` : ''}
|
||||
{' '}Typically completes within two minutes; this view refreshes automatically.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
) : null
|
||||
)
|
||||
|
||||
? { mins: Math.round(stillFor / 60000), nudge: nudgeFor(stage, row) }
|
||||
: null
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user