Ergänze Auftragsbearbeitung, Disposition, Stammdaten, Kunden- und Transporteurportale, Lagerverwaltung, Abrechnung, Exporte und Statistik. Füge Kontoeinstellungen, Mitteilungen, Automatikdienste und Betriebsstatus sowie die zugehörigen Tests und PHP-Abgleichsdokumentation hinzu. Vergrößere die persönlichen Auftragslisten auf einheitliche Höhen und richte Statusanzeigen sowie die Ranking-Vorschau-Steuerelemente bündig aus. Validierung: 44 Frontendtests und Produktionsbuild erfolgreich. Backend funktional unverändert gegenüber dem vollständigen Lauf mit 1.624 erfolgreichen und drei übersprungenen Tests. Layout im Browser und lokale Bereitstellung geprüft.
17 lines
2.9 KiB
TypeScript
17 lines
2.9 KiB
TypeScript
import {useUiText} from './UiLanguage';
|
|
import { useEffect, useState } from 'react';
|
|
import { Field } from './FormElements';
|
|
import { request } from './api';
|
|
type Def={id:number;label:string;type:string};type Hq={id:number;label:string};
|
|
const kinds:Record<string,string>={'button:cs:cs_eid':'customer','button:cr:cr_eid':'courier','select:crvh:crvh_sid':'vehicle','select:vht':'vehicleType','select:grp':'group','select:br':'branch'};
|
|
export function EvaluationField({field,value,headquarters,headquartersOptions,onChange}:{field:Def;value:string;headquarters:number;headquartersOptions:Hq[];onChange:(v:string)=>void}){
|
|
const uiText=useUiText();
|
|
|
|
const [query,setQuery]=useState(''),[items,setItems]=useState<{id:number;value:string|number;label:string}[]>([]),[error,setError]=useState('');const kind=kinds[field.type];
|
|
useEffect(()=>{if(!kind)return;let live=true;const timer=setTimeout(()=>request<typeof items>('/evaluations/lookup?'+new URLSearchParams({headquarters:String(headquarters),kind,q:query})).then(v=>{if(live){setItems(v);setError('');}}).catch(e=>{if(live)setError(e.message);}),250);return()=>{live=false;clearTimeout(timer);};},[query,kind,headquarters]);
|
|
if(['date_begin','date_end','date'].includes(field.type)){const match=value.match(/^(\d{2})\.(\d{2})\.(\d{4})$/),iso=match?`${match[3]}-${match[2]}-${match[1]}`:'';return <Field label={field.label}><input type="date" value={iso} onInput={e=>{const v=e.currentTarget.value;onChange(v?v.split('-').reverse().join('.'):'');}}/></Field>;}
|
|
if(field.type==='checkboxes_hq'){const selected=value.split(',').filter(Boolean);return <fieldset><legend>{field.label}</legend><div className="admin-toolbar">{headquartersOptions.map(h=><label className="admin-check" key={h.id}><input type="checkbox" checked={selected.includes(String(h.id))} onChange={e=>onChange((e.target.checked?[...selected,String(h.id)]:selected.filter(v=>v!==String(h.id))).join(','))}/>{h.label}</label>)}<button type="button" className="button" onClick={()=>onChange(headquartersOptions.map(h=>h.id).join(','))}>{uiText("Alle")}</button><button type="button" className="button" onClick={()=>onChange('')}>{uiText("Keine")}</button></div></fieldset>;}
|
|
if(!kind)return <Field label={field.label}><input readOnly value={value}/></Field>;
|
|
return <div className="entry-lookup"><Field label={field.label}><input value={value} onChange={e=>onChange(e.target.value)} placeholder="Keine Auswahl"/></Field><Field label={`${field.label} suchen`}><input type="search" value={query} onChange={e=>setQuery(e.target.value)} placeholder="Nummer oder Name"/></Field>{error&&<p role="alert" className="alert error">{error}</p>}<select aria-label={`${field.label} auswählen`} value="" onChange={e=>{const v=e.target.value;if(v)onChange(v);}}><option value="">Treffer auswählen …</option>{items.map(v=><option key={v.id} value={v.value}>{v.label}</option>)}</select><p className="form-hint">Bis zu 100 Treffer. Leeres Feld hebt die Auswahl auf.</p></div>;
|
|
}
|