Erweitere VoTiAn NG um Fachfunktionen und verbessere die Listenoberfläche
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.
This commit is contained in:
1 parent
363bc27c26
commit
781a2b82dc
1165 files changed
+74986
-1028
No files matched your search
@@ -0,0 +1,18 @@
|
||||
import {useEffect,useState,type CSSProperties} from 'react';
|
||||
import {request} from './api';
|
||||
import {Modal} from './FormElements';
|
||||
export type DispositionCard={id:number;lines:string[];details:string[];zipcode:string;verticalId:boolean;colour:string;category:string};
|
||||
export function useDispositionCards(path:string|null,board:unknown):{cards:Record<number,DispositionCard>;error:string;denied:boolean;hideHours:boolean}{
|
||||
const [result,setResult]=useState<{path:string;board:unknown;cards:Record<number,DispositionCard>;error:string;denied:boolean;hideHours:boolean}|null>(null);
|
||||
useEffect(()=>{const c=new AbortController();if(!path)return;request<{cards:DispositionCard[];hideHours?:boolean}>(path,{signal:c.signal}).then(v=>{if(!c.signal.aborted)setResult({path,board,cards:Object.fromEntries(v.cards.map(card=>[card.id,card])),error:'',denied:false,hideHours:v.hideHours===true});}).catch(e=>{if(!c.signal.aborted)setResult({path,board,cards:{},error:e.message,denied:e.status===403,hideHours:false});});return()=>c.abort();},[path,board]);
|
||||
return result&&result.board===board&&result.path===path?result:{cards:{},error:'',denied:false,hideHours:false};
|
||||
}
|
||||
export function cardStyle(card?:DispositionCard):CSSProperties{
|
||||
if(!card)return {};let hex=card.colour.slice(1);if(hex.length===3)hex=hex.split('').map(c=>c+c).join('');
|
||||
const values=[0,2,4].map(i=>{const v=parseInt(hex.slice(i,i+2),16)/255;return v<=.04045?v/12.92:((v+.055)/1.055)**2.4;});
|
||||
const luminance=values[0]*.2126+values[1]*.7152+values[2]*.0722;
|
||||
return {backgroundColor:card.colour,color:(luminance+.05)/.05>=1.05/(luminance+.05)?'#000':'#fff'};
|
||||
}
|
||||
export function cardDescription(card?:DispositionCard){return card?[card.category,...card.lines,...card.details].join('\n'):'';}
|
||||
export function DispositionCardText({job,card}:{job:number;card?:DispositionCard}){return <>{card?.verticalId&&<span className="fds-card-id-vertical" aria-hidden="true">{job}</span>}{card?.zipcode&&<span className="fds-card-zip" aria-label={`Postleitzahl ${card.zipcode}`}>{card.zipcode}</span>}<span className="fds-card-body"><strong>#{job}{card&&` · ${card.category}`}</strong>{card?.lines.map((line,i)=><span className="fds-card-line" key={i}>{line||'\u00a0'}</span>)}</span></>;}
|
||||
export function DispositionCardDetails({card,onClose}:{card:DispositionCard;onClose:()=>void}){return <Modal title={`Auftrag #${card.id} · ${card.category}`} onClose={onClose}><div className="modal-body"><div className="fds-card-detail">{card.details.map((line,i)=><p key={i}>{line}</p>)}</div><hr/>{card.lines.filter(line=>line&&!card.details.includes(line)&&!card.details.includes("Zusage: "+line)).map((line,i)=><p key={i}>{line}</p>)}</div><div className="modal-footer"><button className="button" onClick={onClose}>Schließen</button></div></Modal>;}
|
||||
Reference in new issue
Block a user