/* History.jsx — Історія змін, live API. */
const { useState: useStateH, useEffect: useEffectH } = React;
const KIND_LABELS = {
publish: "Публікація",
edit: "Редагування",
create: "Створення",
pause: "Призупинення",
resume: "Відновлення",
delete: "Видалення",
restore: "Відновлення",
ack: "Підтвердження",
rollback:"Відкат",
settings:"Налаштування",
other: "Інше",
};
const KIND_ICONS = {
publish: "✅", edit: "✏️", create: "➕", pause: "⏸",
resume: "▶", delete: "🗑", restore: "↩", ack: "✓",
rollback: "↩", settings: "⚙", other: "•",
};
const KIND_COLORS = {
publish: { bg: "var(--ok-bg)", color: "var(--ok)", border: "var(--ok-border)" },
create: { bg: "var(--ok-bg)", color: "var(--ok)", border: "var(--ok-border)" },
edit: { bg: "var(--accent-soft)", color: "var(--accent)", border: "#c7d2fe" },
pause: { bg: "var(--warn-bg)", color: "var(--warn)", border: "var(--warn-border)" },
resume: { bg: "var(--ok-bg)", color: "var(--ok)", border: "var(--ok-border)" },
delete: { bg: "var(--bad-bg)", color: "var(--bad)", border: "var(--bad-border)" },
restore: { bg: "var(--ok-bg)", color: "var(--ok)", border: "var(--ok-border)" },
ack: { bg: "var(--surface-3)", color: "var(--text-2)", border: "var(--border)" },
rollback: { bg: "var(--warn-bg)", color: "var(--warn)", border: "var(--warn-border)" },
settings: { bg: "var(--surface-3)", color: "var(--text-2)", border: "var(--border)" },
other: { bg: "var(--surface-3)", color: "var(--text-2)", border: "var(--border)" },
};
function formatEventText(item) {
const target = item.target_id ? `#${item.target_id}` : "";
switch (item.action) {
case "passenger.stops.create": return `Створено зупинку ${target}`;
case "passenger.stops.update": return `Оновлено зупинку ${target}`;
case "passenger.stops.delete": return `Видалено зупинку ${target}`;
case "passenger.stops.restore": return `Відновлено зупинку ${target}`;
case "passenger.stops.publish": return `Опубліковано зупинку ${target}`;
case "passenger.stops.bulk_delete":return `Bulk-видалено ${(item.details && item.details.deleted) || ""} зупинок`;
case "passenger.routes.create": return `Створено маршрут ${target}`;
case "passenger.routes.update": return `Оновлено маршрут ${target}`;
case "passenger.routes.delete": return `Видалено маршрут ${target}`;
case "passenger.routes.restore": return `Відновлено маршрут ${target}`;
case "passenger.routes.pause": return `Призупинено маршрут ${target}`;
case "passenger.routes.resume": return `Відновлено маршрут ${target}`;
case "passenger.routes.publish": return `Опубліковано маршрут ${target}`;
case "passenger.settings.update": return `Оновлено налаштування`;
default: return item.action;
}
}
function formatDetail(item) {
if (!item.details) return null;
if (item.action === "passenger.stops.bulk_delete" && Array.isArray(item.details.ids)) {
return `IDs: ${item.details.ids.join(", ")}`;
}
if (item.details.changed) {
return Array.isArray(item.details.changed)
? `Поля: ${item.details.changed.join(", ")}`
: `Поля: ${Object.keys(item.details.changed).join(", ")}`;
}
if (item.details.reason) return `Причина: ${item.details.reason}`;
if (item.details.code && item.details.name) return `${item.details.code} · ${item.details.name}`;
if (item.details.name) return item.details.name;
return JSON.stringify(item.details);
}
function dateBucket(ts) {
if (!ts) return "—";
const d = new Date(ts);
const now = new Date();
const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime();
const eventStart = new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();
const diffDays = Math.round((todayStart - eventStart) / 86400000);
if (diffDays === 0) return "Сьогодні";
if (diffDays === 1) return "Вчора";
return d.toLocaleDateString("uk-UA", { day: "numeric", month: "long" });
}
function formatTime(ts) {
if (!ts) return "";
return new Date(ts).toLocaleTimeString("uk-UA", { hour: "2-digit", minute: "2-digit" });
}
function History() {
const [items, setItems] = useStateH([]);
const [loading, setLoading] = useStateH(true);
const [error, setError] = useStateH(null);
const [kindFilter, setKindFilter] = useStateH("all");
const [search, setSearch] = useStateH("");
const reload = async () => {
setLoading(true);
try {
const res = await window.passengerApi.history.list({ kind: kindFilter, search, limit: 200 });
setItems(res.items || []);
setError(null);
} catch (e) {
setError(e);
window.showToast && window.showToast("Не вдалося завантажити історію: " + (e.message || ""), "bad");
} finally {
setLoading(false);
}
};
useEffectH(() => { reload(); /* eslint-disable-next-line */ }, [kindFilter, search]);
window.passengerApi.usePolling(reload, 60000, [kindFilter, search]);
// Group by date.
const groups = items.reduce((acc, item) => {
const d = dateBucket(item.ts);
(acc[d] = acc[d] || []).push(item);
return acc;
}, {});
return (
<>