diff --git a/public/service-worker.js b/public/service-worker.js index b900d40..369e7cf 100644 --- a/public/service-worker.js +++ b/public/service-worker.js @@ -1,8 +1,8 @@ const isLocalhost = self.location.hostname === "localhost" || self.location.hostname === "127.0.0.1"; if (!isLocalhost) { - const STATIC_CACHE = "construction-delivery-static-v60"; - const RUNTIME_CACHE = "construction-delivery-runtime-v60"; + const STATIC_CACHE = "construction-delivery-static-v61"; + const RUNTIME_CACHE = "construction-delivery-runtime-v61"; const APP_SHELL_URLS = ["/", "/index.html", "/manifest.webmanifest", "/icons/icon-192.png", "/icons/icon-512.png"]; self.addEventListener("install", (event) => { diff --git a/src/components/admin/SmsCampaignPanel.jsx b/src/components/admin/SmsCampaignPanel.jsx index ac3787b..9e33369 100644 --- a/src/components/admin/SmsCampaignPanel.jsx +++ b/src/components/admin/SmsCampaignPanel.jsx @@ -87,6 +87,7 @@ const NOTIF_LABELS = { "manual_required": "🔧 Ручное управление", "paid_storage_sending": "📡 Отправляется…", "paid_storage_sent": "✓ Платное хранение: отправлено", + "completed": "✅ Завершено", "confirmed": "✅ Согласовано клиентом", "address_required": "⚠ Требуется адрес", "draft": "Черновик", @@ -103,6 +104,7 @@ const NOTIF_TONES = { "manual_required": "warning", "paid_storage_sending": "info", "paid_storage_sent": "accent", + "completed": "accent", "confirmed": "accent", "address_required": "danger", "draft": "neutral", @@ -209,7 +211,18 @@ const fmtAgreement = (g) => { if (!g) return { text: "—", tone: "neutral", icon: "⏳" }; const ds = g.delivery_status; - // If client already chose date/time — show it regardless of delivery_status + // Terminal states first — delivery already happened or cancelled + if (ds === "picked_up") { + return { text: "✅ Самовывоз завершён", tone: "accent", icon: "✅" }; + } + if (ds === "delivered") { + return { text: "✅ Доставлено", tone: "accent", icon: "✅" }; + } + if (ds === "cancelled") { + return { text: "❌ Отменён", tone: "danger", icon: "❌" }; + } + + // If client already chose date/time — show it if (g.delivery_type === "pickup" || g.pickup_date) { const date = g.pickup_date ? new Date(g.pickup_date).toLocaleDateString("ru-RU", { day: "2-digit", month: "2-digit" }) : ""; const slot = g.pickup_time_slot || ""; @@ -236,9 +249,6 @@ const fmtAgreement = (g) => { if (ds === "paid_storage") { return { text: "📦 Платное хранение", tone: "warning", icon: "📦" }; } - if (ds === "cancelled") { - return { text: "❌ Отменён", tone: "danger", icon: "❌" }; - } if (ds === "problem") { return { text: "⚠ Проблема", tone: "danger", icon: "⚠" }; } diff --git a/src/components/orders/SmsStatusCard.jsx b/src/components/orders/SmsStatusCard.jsx index c6b1f44..a850fef 100644 --- a/src/components/orders/SmsStatusCard.jsx +++ b/src/components/orders/SmsStatusCard.jsx @@ -21,6 +21,7 @@ const NOTIF_LABELS = { manual_required: "Требуется ручное управление", paid_storage_sending: "Отправляется…", paid_storage_sent: "Платное хранение: отправлено", + completed: "✅ Завершено", draft: "Черновик", }; @@ -35,6 +36,7 @@ const NOTIF_TONES = { manual_required: "warning", paid_storage_sending: "info", paid_storage_sent: "accent", + completed: "accent", draft: "neutral", }; @@ -106,6 +108,7 @@ export const SmsStatusCard = ({ order, userRole }) => { const canManage = ["mega_admin", "admin"].includes(userRole); const notifStatus = order.notificationStatus || order.notification_status || "not_started"; + const deliveryStatus = order.deliveryStatus || order.delivery_status || ""; const nextCheck = order.nextNotificationCheckAt || order.next_notification_check_at; const firstSmsAt = order.firstSmsSentAt || order.first_sms_sent_at; const secondSmsAt = order.secondSmsSentAt || order.second_sms_sent_at; @@ -113,6 +116,14 @@ export const SmsStatusCard = ({ order, userRole }) => { const smsAttempts = order.smsAttempts ?? order.sms_attempts ?? 0; const lastError = order.lastSmsError || order.last_sms_error; + // Terminal delivery states — SMS flow should be fully stopped + const TERMINAL_STATUSES = ["picked_up", "delivered", "cancelled"]; + const isTerminal = TERMINAL_STATUSES.includes(deliveryStatus); + const terminalLabel = deliveryStatus === "picked_up" ? "Самовывоз завершён" + : deliveryStatus === "delivered" ? "Доставка завершена" + : deliveryStatus === "cancelled" ? "Заказ отменён" + : ""; + // Restart: reset this group's notification_status to link_ready const handleRestart = async () => { if (!order?.id) return; @@ -205,11 +216,13 @@ export const SmsStatusCard = ({ order, userRole }) => { {/* 2nd SMS */}
- +
2-е SMS
{hasSecondSms ? (
{fmtTime(secondSmsAt)} ✓ доставлено
+ ) : isTerminal ? ( +
— {terminalLabel}, SMS не отправляется
) : notifStatus === "second_sms_sending" && hasSmsSent ? (
{fmtTime(smsSentAt)} · отправлено, ждём подтверждения…
) : notifStatus === "first_sms_sent" && countdown ? ( @@ -225,7 +238,7 @@ export const SmsStatusCard = ({ order, userRole }) => {
{/* Next check countdown */} - {countdown && notifStatus !== "second_sms_sent" && ( + {countdown && notifStatus !== "second_sms_sent" && !isTerminal && (
⏱ Следующая проверка: {countdown} @@ -268,8 +281,8 @@ export const SmsStatusCard = ({ order, userRole }) => {
)} - {/* Restart buttons */} - {canManage && ( + {/* Restart buttons — hidden when delivery is terminal (picked_up/delivered/cancelled) */} + {canManage && !isTerminal && (