From 1e0344ee347b9ff1576c4e6be0c29c1617beb4a3 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 28 May 2026 10:17:29 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20action=20log=20=E2=80=94=20resolve=20UUI?= =?UTF-8?q?D=20to=20names,=20show=20old=E2=86=92new,=20add=20oldValue=20fo?= =?UTF-8?q?r=20driver=20reassignment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/admin/ActionLogPanel.jsx | 131 ++++++++++++------ src/services/supabase/orderGroupRepository.js | 2 +- 2 files changed, 89 insertions(+), 44 deletions(-) diff --git a/src/components/admin/ActionLogPanel.jsx b/src/components/admin/ActionLogPanel.jsx index 3191249..b25481b 100644 --- a/src/components/admin/ActionLogPanel.jsx +++ b/src/components/admin/ActionLogPanel.jsx @@ -4,6 +4,8 @@ import { Badge } from "../UI/Badge"; import { fetchActionLogs, getActionLabel } from "../../services/supabase/actionLogService"; import { useNavigate } from "react-router-dom"; import { useAuth } from "../../context/AuthContext"; +import { safeSupabaseCall } from "../../services/safeSupabaseCall"; +import { hasSupabaseConfig, supabase } from "../../supabaseClient"; const ACTIONS = [ "status_change", @@ -33,6 +35,16 @@ const ACTION_TONES = { invitation_created: "accent", }; +const ROLE_LABELS = { + mega_admin: "Мега-админ", + admin: "Админ", + manager: "Менеджер", + logistician: "Логист", + driver: "Водитель", +}; + +const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; + const formatMSKCorrect = (isoStr) => { if (!isoStr) return "—"; try { @@ -50,44 +62,6 @@ const formatMSKCorrect = (isoStr) => { } }; -const ROLE_LABELS = { - mega_admin: "Мега-админ", - admin: "Админ", - manager: "Менеджер", - logistician: "Логист", - driver: "Водитель", -}; - -/** Human-readable description of what happened */ -const getActionDescription = (log) => { - switch (log.action) { - case "status_change": - return `${log.old_value || "—"} → ${log.new_value || "—"}`; - case "driver_assigned": - return `Назначен: ${log.details?.driver_name || log.new_value || "водитель"}`; - case "driver_removed": - return `Снят: ${log.details?.driver_name || log.old_value || "водитель"}`; - case "date_assigned": - return `Дата: ${log.new_value || "—"}`; - case "client_confirmed": - return `Клиент подтвердил`; - case "client_cancelled": - return `Клиент отменил`; - case "cancelled": - return `Отменено`; - case "manual_confirmation": - return `Ручное подтверждение`; - case "paid_storage": - return `Платное хранение`; - case "sms_sent": - return `SMS отправлено`; - case "invitation_created": - return `Приглашение создано`; - default: - return log.new_value || getActionLabel(log.action); - } -}; - export const ActionLogPanel = ({ orderGroupId = null }) => { const { user } = useAuth(); const navigate = useNavigate(); @@ -99,6 +73,38 @@ export const ActionLogPanel = ({ orderGroupId = null }) => { const [filterDateTo, setFilterDateTo] = useState(""); const [filterSearch, setFilterSearch] = useState(""); const [expandedId, setExpandedId] = useState(null); + const [userNames, setUserNames] = useState({}); + + // Fetch user name map for resolving UUIDs + useEffect(() => { + const fetchNames = async () => { + if (!hasSupabaseConfig || !supabase) return; + const result = await safeSupabaseCall( + async () => { + const { data, error } = await supabase.from("users").select("id, name"); + if (error) throw error; + return data; + }, + "Ошибка загрузки пользователей" + ); + if (result && !result.error) { + const map = {}; + (Array.isArray(result) ? result : result.data || []).forEach((u) => { + map[u.id] = u.name; + }); + setUserNames(map); + } + }; + fetchNames(); + }, []); + + const resolveName = useCallback( + (uuid) => { + if (!uuid || !UUID_RE.test(uuid)) return uuid; + return userNames[uuid] || uuid; + }, + [userNames] + ); const loadLogs = useCallback(async () => { setLoading(true); @@ -142,6 +148,45 @@ export const ActionLogPanel = ({ orderGroupId = null }) => { ); }, [logs, filterSearch]); + /** Human-readable description */ + const getActionDescription = (log) => { + switch (log.action) { + case "status_change": { + const oldVal = resolveName(log.old_value) || "—"; + const newVal = resolveName(log.new_value) || "—"; + return `${oldVal} → ${newVal}`; + } + case "driver_assigned": { + const name = log.details?.driver_name || resolveName(log.new_value) || "водитель"; + return `Назначен: ${name}`; + } + case "driver_removed": { + const name = log.details?.driver_name || resolveName(log.old_value) || "водитель"; + return `Снят: ${name}`; + } + case "date_assigned": + return `Дата: ${log.new_value || "—"}`; + case "client_confirmed": + return "Клиент подтвердил"; + case "client_cancelled": + return "Клиент отменил"; + case "cancelled": + return "Отменено"; + case "manual_confirmation": + return "Ручное подтверждение"; + case "paid_storage": + return "Платное хранение"; + case "sms_sent": + return "SMS отправлено"; + case "invitation_created": + return "Приглашение создано"; + default: + return log.new_value || getActionLabel(log.action); + } + }; + + const getActionDesc = getActionDescription; + return (
@@ -240,7 +285,7 @@ export const ActionLogPanel = ({ orderGroupId = null }) => { - {getActionDescription(log)} + {getActionDesc(log)} {!orderGroupId && ( @@ -261,10 +306,10 @@ export const ActionLogPanel = ({ orderGroupId = null }) => {
{log.old_value && ( -
Было: {log.old_value}
+
Было: {resolveName(log.old_value)}
)} {log.new_value && ( -
Стало: {log.new_value}
+
Стало: {resolveName(log.new_value)}
)} {log.details && typeof log.details === "object" && (
@@ -273,8 +318,8 @@ export const ActionLogPanel = ({ orderGroupId = null }) => { .map(([k, v]) => (
- {{driver_name: "Водитель", driver_id: "ID водителя", problem_type: "Тип проблемы"}[k] || k}: - {String(v)} + {{driver_name: "Водитель", driver_id: "ID", problem_type: "Тип проблемы", delivery_date_source: "Источник даты"}[k] || k}: + {UUID_RE.test(String(v)) ? resolveName(String(v)) : String(v)}
))}
diff --git a/src/services/supabase/orderGroupRepository.js b/src/services/supabase/orderGroupRepository.js index a0ce834..c3ccefb 100644 --- a/src/services/supabase/orderGroupRepository.js +++ b/src/services/supabase/orderGroupRepository.js @@ -274,7 +274,7 @@ export const assignDriverToOrderGroup = async ({ const driverName = data?.assigned_driver?.name || driverId || "—"; const oldDriverName = currentGroup?.assigned_driver?.name || currentGroup?.assigned_driver_id || ""; const logPayload = driverId - ? { orderGroupId, action: "driver_assigned", newValue: driverName, details: { driver_id: driverId, driver_name: driverName } } + { orderGroupId, action: "driver_assigned", oldValue: oldDriverName || undefined, newValue: driverName, details: { driver_id: driverId, driver_name: driverName } } : { orderGroupId, action: "driver_removed", oldValue: oldDriverName, newValue: "Снят", details: { driver_name: oldDriverName } }; await logAction(logPayload).catch(() => {});