Workers P4 Endprüfung W2: „Vorschau bauen“ fragt vor dem Start nach und fehlt bei toten Interessenten
Der Knopf startete einen Opus-Lauf mit einem einzigen Klick (Handy: voll breit zwischen anderen Knöpfen), ohne dass sich der Bau in der Oberfläche zurücknehmen lässt. Wie Freigeben und Verwerfen fragt er jetzt zuerst nach („Wirklich bauen?“, 4 s) und zeigt dabei, dass ein Opus-Lauf startet und die Vorschau gebaut wird, als hätte der Interessent Ja gesagt (ohne „nur wenn Ja“: der Knopf gilt gerade für unklare Antworten). rowModel blendet den Knopf bei gesperrtem, verlorenem oder abgeschlossenem Interessenten (gesperrt, verloren, deal) aus; ohne Kurzfassung entscheidet weiter der Dienst. Prüfstand: die Fehler- und Fokus-Läufe klicken zweimal, Szenario bauen prüft Frage, Hinweis und Verfall. Doppeltipp-Schutz und Dienst-Härtung (bauLauf nur nach Ja) bleiben offen, siehe final-fix-report-woms.md. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1536a3bbc1
commit
871b87fac0
5 files changed
+99
-19
No files matched your search
@@ -10,7 +10,9 @@ import {
|
||||
} from '../../lib/workersPult'
|
||||
import ProspectPanel from './ProspectPanel'
|
||||
|
||||
const CONFIRM_MS = 4000 // so lange gilt die Rückfrage „Wirklich verwerfen?“ bzw. „Wirklich freigeben?“ nach dem ersten Klick
|
||||
const CONFIRM_MS = 4000 // so lange gilt die Rückfrage „Wirklich verwerfen?“, „Wirklich freigeben?“ bzw. „Wirklich bauen?“ nach dem ersten Klick
|
||||
// Kosten und Wirkung von „Vorschau bauen“ (Rückfrage und Hinweis am Knopf); bewusst ohne „nur wenn der Interessent Ja gesagt hat“: der Knopf gilt gerade für unklare Antworten
|
||||
const BUILD_HINT = 'Startet einen Opus-Lauf und baut die Vorschau, als hätte der Interessent Ja gesagt.'
|
||||
const NO_FIELDS = Object.freeze({}) // Eintrag ohne bearbeitete Felder
|
||||
|
||||
// Leerzustand je Filter
|
||||
@@ -65,7 +67,7 @@ function TextPanel({ className, label, hint, value, onChange, submitLabel, onSub
|
||||
// Reihenfolge (409 mit deutschem Satz); danach wird die Liste neu geholt.
|
||||
function PultRow({ api, item, row, text, fields, onText, onField, refresh, onFinished, onDetails }) {
|
||||
const [busy, setBusy] = useState(false)
|
||||
const [confirming, setConfirming] = useState(null) // null | 'discard' | 'approve': welche Rückfrage gerade gilt
|
||||
const [confirming, setConfirming] = useState(null) // null | 'discard' | 'approve' | 'build': welche Rückfrage gerade gilt
|
||||
const [open, setOpen] = useState(null) // null | 'reply' | 'paste': welches Feld aufgeklappt ist
|
||||
const [note, setNote] = useState(null) // { kind: 'ok' | 'err', text }
|
||||
const busyRef = useRef(false) // sperrt schon im selben Takt, in dem busy noch nicht greift (Doppelklick)
|
||||
@@ -76,7 +78,7 @@ function PultRow({ api, item, row, text, fields, onText, onField, refresh, onFin
|
||||
return () => { aliveRef.current = false }
|
||||
}, [])
|
||||
|
||||
// Die Rückfrage vor dem Verwerfen und vor dem Freigeben verfällt nach 4 s
|
||||
// Die Rückfrage vor dem Verwerfen, Freigeben und Bauen verfällt nach 4 s
|
||||
useEffect(() => {
|
||||
if (confirming === null) return undefined
|
||||
const timer = window.setTimeout(() => setConfirming(null), CONFIRM_MS)
|
||||
@@ -154,8 +156,15 @@ function PultRow({ api, item, row, text, fields, onText, onField, refresh, onFin
|
||||
run(() => api.pultAction(row.id, 'approve-preview'), 'freigegeben. Max sendet den Link im nächsten Sendefenster.', true, 'approve-preview')
|
||||
}
|
||||
|
||||
// Bau starten wie bei einem „Ja“ des Interessenten (für Einträge „unsicher“)
|
||||
const startBuild = () => run(() => api.pultAction(row.id, 'start-build'), 'wird gebaut.', true, 'start-build')
|
||||
// Bau starten wie bei einem „Ja“ des Interessenten (für Einträge „unsicher“): ein Opus-Lauf, der sich nicht zurücknehmen lässt. Wie beim Freigeben
|
||||
// fragt der erste Klick nach, der zweite binnen 4 s startet den Bau.
|
||||
const startBuild = () => {
|
||||
if (confirming !== 'build') {
|
||||
setConfirming('build')
|
||||
return
|
||||
}
|
||||
run(() => api.pultAction(row.id, 'start-build'), 'wird gebaut.', true, 'start-build')
|
||||
}
|
||||
|
||||
// Die Felder „Als Mensch antworten“ und „Antwort einfügen“ sind getrennt: die Antwort ist mit dem Entwurf (oder dem bearbeiteten Text)
|
||||
// vorbelegt, das Einfüge-Feld beginnt leer. Beide liegen in der Liste, damit der Text einen Wechsel des Filters überlebt.
|
||||
@@ -280,9 +289,12 @@ function PultRow({ api, item, row, text, fields, onText, onField, refresh, onFin
|
||||
</>
|
||||
)}
|
||||
{row.canStartBuild && (
|
||||
<Button type="button" onClick={startBuild} disabled={busy}>
|
||||
Vorschau bauen
|
||||
</Button>
|
||||
<>
|
||||
<Button type="button" onClick={startBuild} disabled={busy} title={BUILD_HINT}>
|
||||
{confirming === 'build' ? 'Wirklich bauen?' : 'Vorschau bauen'}
|
||||
</Button>
|
||||
{confirming === 'build' && <span className="wk-hint">{BUILD_HINT}</span>}
|
||||
</>
|
||||
)}
|
||||
{row.canPaste && (
|
||||
<Button type="button" onClick={() => toggle('paste')} aria-expanded={open === 'paste'} disabled={busy}>
|
||||
|
||||
@@ -55,6 +55,9 @@ const DONE_VIEW = Object.freeze({
|
||||
erledigt: Object.freeze({ label: 'Erledigt', tone: 'muted' }),
|
||||
})
|
||||
|
||||
// Status eines Interessenten, mit dem nichts mehr gebaut wird (Spiegel von TOT in src/gespraeche/pultMail.js des Dienstes)
|
||||
const DEAD_PROSPECT = Object.freeze(['gesperrt', 'verloren', 'deal'])
|
||||
|
||||
const PREVIEW_HOST = 'entwurf.project.webklar.com' // Vorschauen liegen nur hier (Vorschau-Server des Dienstes)
|
||||
|
||||
const MAIL_SUBJECT_MAX = 78
|
||||
@@ -227,8 +230,9 @@ export function rowModel(item, { me, nowMs, employees }) {
|
||||
// Mail-Antwort als Mensch: braucht einen Interessenten mit Adresse („Mail ohne Faden“ und Plattform-Interessenten haben keinen Mail-Weg)
|
||||
canReply: REPLY_KINDS.includes(item.kind) && free && prospect !== null && filled(prospect.email),
|
||||
canApprovePreview: freigabe && free,
|
||||
// Bau starten wie ein „Ja“: Eintrag „unsicher“ mit Interessent; ob der noch lebt, entscheidet der Dienst (409 mit deutschem Satz)
|
||||
canStartBuild: item.kind === 'unsicher' && free && filled(item.prospectId),
|
||||
// Bau starten wie ein „Ja“: Eintrag „unsicher“ mit Interessent. Ein toter Interessent (gesperrt, verloren, Deal) bekommt den Knopf nicht; ohne
|
||||
// Kurzfassung (prospect null) oder ohne Status entscheidet der Dienst (409 mit deutschem Satz, auch bei einer schon vorhandenen Vorschau)
|
||||
canStartBuild: item.kind === 'unsicher' && free && filled(item.prospectId) && !(prospect !== null && DEAD_PROSPECT.includes(prospect.status)),
|
||||
// Die Rückmeldung des Kunden kommt meist erst, nachdem jemand Claras Entwurf auf der Plattform gesendet hat: auch bei gesendet,
|
||||
// erledigt oder von einem Kollegen übernommen. Nur ein verworfener Eintrag nimmt nichts mehr an.
|
||||
canPaste: PASTE_KINDS.includes(item.kind) && item.status !== 'verworfen' && prospect !== null,
|
||||
|
||||
Reference in new issue
Block a user