import {useUiText} from './UiLanguage'; import {useEffect,useRef,useState} from 'react'; import {Field,Modal,useDiscardConfirmation} from './FormElements'; import {ApiError,post,request} from './api'; type Stop={id:number;sequence:number;address:string;company:string;person:string;phone:string;reference:string;remark:string}; type Options={id:number;revision:string;canEdit:boolean;reason:string;remarks:boolean;referenceRequired:boolean;reference:string;notes:string;stops:Stop[]}; type Command={requestId:string;revision:string;reference:string;notes:string;stops:Stop[];confirmed:boolean}; type Preview={changes:{field:string;before:string;after:string}[]}; export function CustomerOrderTexts({job,onClose,onSaved}:{job:number;onClose:()=>void;onSaved:()=>void}){ const uiText=useUiText(); const [data,setData]=useState(null),[dirty,setDirty]=useState(false),[preview,setPreview]=useState(null),[confirmed,setConfirmed]=useState(false),[busy,setBusy]=useState(false),[uncertain,setUncertain]=useState(false),[stale,setStale]=useState(false),[error,setError]=useState(''),[done,setDone]=useState(false); const pending=useRef(null),sending=useRef(false),base=`/customer-portal/orders/${job}/texts`,locked=busy||uncertain||stale||done; const [discard,dialog]=useDiscardConfirmation(); useEffect(()=>{const c=new AbortController();request(base,{signal:c.signal}).then(d=>{if(!c.signal.aborted)setData(d);}).catch(e=>{if(!c.signal.aborted)setError(e.message);});return()=>c.abort();},[base]); useEffect(()=>{if(!dirty&&!uncertain)return;const prevent=(e:BeforeUnloadEvent)=>{e.preventDefault();e.returnValue='';};window.addEventListener('beforeunload',prevent);return()=>window.removeEventListener('beforeunload',prevent);},[dirty,uncertain]); function change(patch:Partial){if(locked)return;setData(d=>d?{...d,...patch}:d);setDirty(true);setPreview(null);setConfirmed(false);pending.current=null;setError('');} async function reload(){if(busy||uncertain||dirty&&!await discard('Die bisherigen Änderungen verwerfen und den aktuellen Auftrag laden?'))return;setBusy(true);setError('');try{setData(await request(base));setDirty(false);setPreview(null);setConfirmed(false);setStale(false);pending.current=null;}catch(e){setError((e as Error).message);}finally{setBusy(false);}} async function check(){if(!data||locked)return;setBusy(true);setError('');const command={requestId:crypto.randomUUID(),revision:data.revision,reference:data.reference,notes:data.notes,stops:data.stops,confirmed:true};try{setPreview(await post(base+'/preview',command));pending.current=command;}catch(e){setError((e as Error).message);setStale(e instanceof ApiError&&e.status===409);}finally{setBusy(false);}} async function save(){if(sending.current||!pending.current||!confirmed)return;sending.current=true;setBusy(true);setError('');try{await post(base,pending.current);setDone(true);setDirty(false);setUncertain(false);onSaved();}catch(e){setError((e as Error).message);const unknown=!(e instanceof ApiError)||e.status===0||e.status===408||e.status>=500;setUncertain(unknown);if(!unknown){setPreview(null);setConfirmed(false);pending.current=null;setStale(e instanceof ApiError&&e.status===409);}}finally{sending.current=false;setBusy(false);}} async function close(){if(busy||uncertain)return;if(!dirty||await discard('Ungespeicherte Änderungen am Kundenauftrag verwerfen?'))onClose();} return <>void close()} wide>
{error&&

{error}

}{!data&&!error&&

Auftrag wird geladen …

}{done?

Die Änderungen an Auftrag #{job} wurden gespeichert.

:data&&<>{!data.canEdit?

{data.reason}

:<>

Kommissionsnummern, Auftragstext, Namen und Stationskontakte korrigieren. Die Rechnungsdarstellung wird zur Aktualisierung vorgemerkt.

{e.preventDefault();void check();}}>
change({reference:e.target.value})}/>