import React, { useState, useEffect, useRef } from "react";
import { STATUS_COLORS, STATUS_BG } from "../constants.js";
export function StatusBadge({ status }) {
const color = STATUS_COLORS[status] || "#888";
const bg = STATUS_BG[status] || "#f5f5f5";
return (
{status}
);
}
export function StatusSelect({ value, options, onChange }) {
const color = STATUS_COLORS[value] || "#888";
const bg = STATUS_BG[value] || "#f5f5f5";
return (
);
}
export function Header({ title, action }) {
return (
B
I
U
{/* Font size */}
{/* Color */}
{ setColorValue(e.target.value); exec("foreColor", e.target.value); }}
style={{ position: "absolute", width: 0, height: 0, opacity: 0, pointerEvents: "none" }}
/>
{/* Editor */}
{
isInternalChange.current = true;
const html = editorRef.current?.innerHTML || "";
lastValue.current = html;
onChange(html);
}}
onKeyUp={saveSelection}
onMouseUp={saveSelection}
onBlur={saveSelection}
onPaste={e => {
e.preventDefault();
const text = e.clipboardData.getData("text/plain");
restoreSelection();
document.execCommand("insertText", false, text);
saveSelection();
}}
style={{
minHeight, padding: compact ? "8px 10px" : "20px 24px", outline: "none",
fontSize: compact ? 12 : 13, lineHeight: 1.8, color: "var(--text)",
background: "var(--surface)",
fontFamily: "'DM Mono', 'Courier New', monospace",
}}
/>
);
}
export function CalendarPopup({ value, onChange, onClose, align = "left", showClear = true }) {
const [viewYM, setViewYM] = useState(() => {
const d = value ? new Date(value + "T00:00:00") : new Date();
return { year: d.getFullYear(), month: d.getMonth() };
});
const todayStr = new Date().toISOString().slice(0, 10);
const { year, month } = viewYM;
const firstDay = new Date(year, month, 1);
const lastDay = new Date(year, month + 1, 0);
const startWeekday = (firstDay.getDay() + 6) % 7;
const cells = [];
for (let i = 0; i < startWeekday; i++) cells.push(null);
for (let d = 1; d <= lastDay.getDate(); d++) {
cells.push(`${year}-${String(month + 1).padStart(2, "0")}-${String(d).padStart(2, "0")}`);
}
const prevMonth = () => { const d = new Date(year, month - 1, 1); setViewYM({ year: d.getFullYear(), month: d.getMonth() }); };
const nextMonth = () => { const d = new Date(year, month + 1, 1); setViewYM({ year: d.getFullYear(), month: d.getMonth() }); };
const select = (ds) => { onChange(ds); onClose(); };
return (
e.stopPropagation()}
>
{firstDay.toLocaleDateString("de-CH", { month: "long", year: "numeric" })}
{["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"].map(d => (
{d}
))}
{cells.map((ds, i) => {
if (!ds) return
;
const dow = new Date(ds + "T00:00:00").getDay();
const isWeekend = dow === 0 || dow === 6;
const isSelected = ds === value;
const isToday = ds === todayStr;
return (
);
})}
{showClear && value && (
)}
);
}
export function DatePicker({ value, onChange, style, placeholder, align = "left", ...props }) {
const [open, setOpen] = useState(false);
const wrapRef = useRef(null);
const toDE = (iso) => {
if (!iso || !/^\d{4}-\d{2}-\d{2}$/.test(iso)) return "";
return `${iso.slice(8, 10)}.${iso.slice(5, 7)}.${iso.slice(0, 4)}`;
};
useEffect(() => {
if (!open) return;
const close = (e) => { if (!wrapRef.current?.contains(e.target)) setOpen(false); };
document.addEventListener("mousedown", close);
return () => document.removeEventListener("mousedown", close);
}, [open]);
return (
setOpen(o => !o)}
placeholder={placeholder || "TT.MM.JJJJ"}
style={{ cursor: "pointer", ...style }}
{...props}
/>
{open && (
onChange({ target: { value: ds } })}
onClose={() => setOpen(false)}
align={align}
/>
)}
);
}
export function NavArrows({ onPrev, onNext, disabledNext = false }) {
const btn = (onClick, disabled, children) => (
);
return (
{btn(onPrev, false, "‹")}
{btn(onNext, disabledNext, "›")}
);
}
export function useCalendarNav() {
const [open, setOpen] = useState(false);
const ref = useRef(null);
useEffect(() => {
if (!open) return;
const close = (e) => { if (!ref.current?.contains(e.target)) setOpen(false); };
document.addEventListener("mousedown", close);
return () => document.removeEventListener("mousedown", close);
}, [open]);
return { open, setOpen, ref };
}