import { useEffect, useState, type FormEvent } from "react"; import { LoaderCircle, MessageSquare, Radio, Plus, Send } from "lucide-react"; import { Field, Modal, useDiscardConfirmation } from "./FormElements"; import { request, post, put } from "./api"; import { Newsletters } from "./Newsletters"; type Option={id:number;label:string;headquarters?:number;device?:string;available?:string}; type Options={newsletters?:boolean;devices:boolean;bulletins:boolean;manageGroups:boolean;allActive:boolean;today:string;headquartersId:number;headquarters:Option[];employees:Option[];maxBulletin:number;maxMessage:number}; type Group={id:number;name:string;groups:number[];revision:string}; type Member=Option&{member:boolean;revision:string}; type Bulletin={id:number;created:string;from:string;to:string;text:string;sender:string;senderId:number;recipient:string;headquarters:string;removable:boolean;revision:string}; type Message={id:number;created:string;delivery:string|null;acknowledged:string|null;state:number;priority:number;sender:string;recipient:string;reader:string;answerer:string;subject:string;body:string;replyTo:number;canRead:boolean;canReply:boolean;revision:string}; type Preview={token:string;recipients:Option[];subject:string;body:string;replyTo:number}; type SendResult={queued:number;total:number;uncertain:number;unattempted:number;warning:string}; type Page={total:number;items:T[]}; const when=(v:string|null)=>v?new Date(v).toLocaleString("de-DE"):"–"; const states=["Noch nicht ausgeliefert","Ausgeliefert, ungelesen","Gelesen","Beantwortet"]; function ErrorMessage({error}:{error:string}){return error?
{error}
:null;} function Pages({page,total,onChange,busy=false}:{page:number;total:number;onChange:(page:number)=>void;busy?:boolean}){return
{total} Einträge · Seite {page+1} von {Math.max(1,Math.ceil(total/100))}
;} export function Messages({refresh,onDirtyChange}:{refresh:number;onDirtyChange:(dirty:boolean)=>void}){ const [options,setOptions]=useState(null),[error,setError]=useState(""),[view,setView]=useState(""),[dirty,setDirty]=useState(false); const [discard,dialog]=useDiscardConfirmation(); useEffect(()=>{let live=true;request("/messages/options").then(o=>{if(live){setOptions(o);setError("");}}).catch(e=>{if(live)setError(e.message);});return()=>{live=false;};},[refresh]); useEffect(()=>{onDirtyChange(dirty);return()=>onDirtyChange(false);},[dirty,onDirtyChange]); const active=view||(options?.devices?"devices":options?.bulletins?"bulletins":"newsletters"); return <>{options?
{active==="devices"?:active==="bulletins"?:}
:!error&&}{dialog}; } function Bulletins({options,onDirty}:{options:Options;onDirty:(v:boolean)=>void}){ const [data,setData]=useState>({items:[],total:0}),[page,setPage]=useState(0),[expired,setExpired]=useState(false),[reload,setReload]=useState(0),[error,setError]=useState(""),[notice,setNotice]=useState(""),[busy,setBusy]=useState(false),[editor,setEditor]=useState<{employee:number}|null>(null),[removing,setRemoving]=useState(null); useEffect(()=>{let live=true;setBusy(true);request>(`/messages/bulletins?expired=${expired}&page=${page}`).then(d=>{if(live){setData(d);setError("");}}).catch(e=>{if(live)setError(e.message);}).finally(()=>{if(live)setBusy(false);});return()=>{live=false;};},[expired,page,reload]); async function remove(){if(!removing)return;setBusy(true);try{await request(`/messages/bulletins/${removing.id}`,{method:"DELETE",body:JSON.stringify({revision:removing.revision})});setRemoving(null);setReload(v=>v+1);setNotice("Mitteilung entfernt.");}catch(e){setError((e as Error).message);}finally{setBusy(false);}} return <>

Mitteilungen

Nachrichten an Mitarbeiter und Niederlassungen mit Gültigkeitszeitraum.

{notice&&

{notice}

}{busy&&}
{data.items.map(b=>)}
GültigkeitAbsender / EmpfängerMitteilungAktionen
{when(b.from)}
bis {when(b.to)}Erstellt: {when(b.created)}
{b.sender||"Unbekannt"}
An: {b.recipient||b.headquarters||"Alle"}
{b.text}{b.removable&&}
{!busy&&!data.items.length&&

Keine Mitteilungen vorhanden.

}
{editor&&setEditor(null)} onSaved={()=>{setEditor(null);setReload(v=>v+1);setNotice("Mitteilung veröffentlicht.");}}/>} {removing&&{if(!busy)setRemoving(null);}}>

Diese Mitteilung dauerhaft entfernen?

{removing.text}

}; } function BulletinEditor({options,employee,onDirty,onClose,onSaved}:{options:Options;employee:number;onDirty:(v:boolean)=>void;onClose:()=>void;onSaved:()=>void}){ const [text,setText]=useState(""),[from,setFrom]=useState(options.today),[to,setTo]=useState(options.today),[hq,setHq]=useState(options.headquartersId),[recipient,setRecipient]=useState(employee),[error,setError]=useState(""),[busy,setBusy]=useState(false),[preview,setPreview]=useState(false);const [discard,dialog]=useDiscardConfirmation(); const dirty=!!text||from!==options.today||to!==options.today||hq!==options.headquartersId||recipient!==employee; useEffect(()=>{onDirty(dirty||busy);return()=>onDirty(false);},[dirty,busy,onDirty]); async function close(){if(!busy&&(!dirty||await discard("Ungespeicherte Mitteilung verwerfen?")))onClose();} async function send(){setBusy(true);setError("");try{await post("/messages/bulletins",{from,to,headquarters:hq,employee:recipient,text});onSaved();}catch(e){setError((e as Error).message);setPreview(false);}finally{setBusy(false);}} return <>
{e.preventDefault();setPreview(true);}}>
setFrom(e.currentTarget.value)}/>options.today?from:options.today} value={to} onInput={e=>setTo(e.currentTarget.value)}/>