/* ============================================================ page-ops.jsx — PTO, Teams, Rooms ============================================================ */ /* i18n helper — returns Arabic when language=Arabic, else the English string */ const T = (s) => (window.appT || ((x) => x))(s); /* Re-bind parseDetail from primitives.jsx */ const parseDetail = window.parseDetail || ((body, status) => { const d = body?.detail; if (typeof d === 'string') return d; if (Array.isArray(d)) return d.map(x => x?.msg || JSON.stringify(x)).join('; '); if (d && typeof d === 'object') return d.message || d.error || JSON.stringify(d); const m = body?.message; if (typeof m === 'string') return m; if (Array.isArray(m)) return m.map(x => (typeof x === 'string' ? x : (x?.message || JSON.stringify(x)))).join('; '); if (m && typeof m === 'object') return m.message || m.error || JSON.stringify(m); return `HTTP ${status}`; }); /* ── Request PTO Modal ── */ function RequestPtoModal({ onClose, onCreated }) { const D = window.STATUS_DATA; const [startDate, setStartDate] = useState(() => new Date().toISOString().slice(0,10)); const [endDate, setEndDate] = useState(() => new Date().toISOString().slice(0,10)); const [ptoType, setPtoType] = useState('pto'); const [userId, setUserId] = useState(D.ME?.id || ''); const [reason, setReason] = useState(''); const [busy, setBusy] = useState(false); const [err, setErr] = useState(''); const toast = useToast(); useEffect(() => { const onKey = (e) => { if (e.key === 'Escape') onClose(); }; window.addEventListener('keydown', onKey); return () => window.removeEventListener('keydown', onKey); }, [onClose]); const submit = async () => { setBusy(true); setErr(''); try { const r = await fetch('/api/pto', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'same-origin', body: JSON.stringify({ user_id: userId, start_date: startDate, end_date: endDate, pto_type: ptoType, reason }), }); if (!r.ok) { const body = await r.json().catch(() => null); throw new Error(parseDetail(body, r.status)); } toast.push({ msg: T('PTO request created'), kind: 'ok' }); onCreated && onCreated(); onClose(); } catch(e) { setErr(e.message); } finally { setBusy(false); } }; return (
| {T('Person')} | {T('Type')} | {T('Dates')} | {T('Days')} | {T('Status')} | {T('Actions')} |
|---|---|---|---|---|---|
| {p.pto_type} |
{p.start_date && p.end_date ? `${p.start_date} → ${p.end_date}` : |
{p.days || '—'} |
{p.status === 'pending' ? (
|
{T('Permanently remove')} {room.display_name || room.room_id} {T('from the dashboard?')}
{T('Note: The bot will still be in the K9 room. Leave manually in Element/Synapse if desired.')}
{err &&{T('Permanently delete team')} {team.team_name}? {T('This cannot be undone.')}
{memberCount > 0 && ({memberCount} {T('member(s) will become unassigned from this team.')}
)} {err &&