/** * @file BusinessSchedulePanel.jsx * @description Admin panel for configuring work days: delivery, pickup, SMS. * Days stored in business_schedule_settings table as INT[] (1=Mon ... 7=Sun). */ import React, { useState, useEffect, useCallback } from "react"; import { Panel } from "../UI/Panel"; import { Button } from "../UI/Button"; import { Badge } from "../UI/Badge"; import { supabase } from "../../supabaseClient"; const DAY_LABELS = [ { num: 1, label: "Пн", full: "Понедельник" }, { num: 2, label: "Вт", full: "Вторник" }, { num: 3, label: "Ср", full: "Среда" }, { num: 4, label: "Чт", full: "Четверг" }, { num: 5, label: "Пт", full: "Пятница" }, { num: 6, label: "Сб", full: "Суббота" }, { num: 7, label: "Вс", full: "Воскресенье" }, ]; const DEFAULT_SCHEDULE = { deliveryDays: [1, 2, 3, 4, 5], pickupDays: [1, 2, 3, 4, 5], smsDays: [1, 2, 3, 4, 5], }; const DayPills = ({ selectedDays, onToggle, accentColor }) => { const toggle = (num) => { if (selectedDays.includes(num)) { onToggle(selectedDays.filter((d) => d !== num).sort()); } else { onToggle([...selectedDays, num].sort()); } }; return (
{DAY_LABELS.map((day) => { const isSelected = selectedDays.includes(day.num); return ( ); })}
); }; export const BusinessSchedulePanel = () => { const [schedule, setSchedule] = useState(DEFAULT_SCHEDULE); const [original, setOriginal] = useState(DEFAULT_SCHEDULE); const [isLoading, setIsLoading] = useState(true); const [isSaving, setIsSaving] = useState(false); const [error, setError] = useState(""); const [savedAt, setSavedAt] = useState(null); const loadSchedule = useCallback(async () => { setIsLoading(true); setError(""); try { const { data, error: rpcError } = await supabase.rpc("get_business_schedule"); if (rpcError) throw rpcError; if (data?.ok) { const loaded = { deliveryDays: data.deliveryDays || DEFAULT_SCHEDULE.deliveryDays, pickupDays: data.pickupDays || DEFAULT_SCHEDULE.pickupDays, smsDays: data.smsDays || DEFAULT_SCHEDULE.smsDays, }; setSchedule(loaded); setOriginal(loaded); } } catch (e) { setError(e instanceof Error ? e.message : "Не удалось загрузить расписание"); } finally { setIsLoading(false); } }, []); useEffect(() => { loadSchedule(); }, [loadSchedule]); const hasChanges = JSON.stringify(schedule.deliveryDays) !== JSON.stringify(original.deliveryDays) || JSON.stringify(schedule.pickupDays) !== JSON.stringify(original.pickupDays) || JSON.stringify(schedule.smsDays) !== JSON.stringify(original.smsDays); const handleSave = async () => { if (!hasChanges) return; // Validate at least one day per category if (schedule.deliveryDays.length === 0 || schedule.pickupDays.length === 0 || schedule.smsDays.length === 0) { setError("Каждая категория должна иметь хотя бы один рабочий день"); return; } setIsSaving(true); setError(""); try { const { data, error: rpcError } = await supabase.rpc("update_business_schedule", { p_delivery_days: schedule.deliveryDays, p_pickup_days: schedule.pickupDays, p_sms_days: schedule.smsDays, }); if (rpcError) throw rpcError; if (data?.ok) { setOriginal({ ...schedule }); setSavedAt(new Date()); } } catch (e) { setError(e instanceof Error ? e.message : "Не удалось сохранить расписание"); } finally { setIsSaving(false); } }; const formatDays = (days) => { return days .sort((a, b) => a - b) .map((d) => DAY_LABELS.find((dl) => dl.num === d)?.label) .filter(Boolean) .join(", "); }; if (isLoading) { return (

Загрузка расписания…

); } return (
{/* Header */}

Расписание

Рабочие дни

Настройте, в какие дни доступны доставка, самовывоз и отправка SMS-приглашений.

{savedAt && !hasChanges && ( Сохранено )}
{/* Delivery days */}
🚚

Доставка

Дни, в которые клиент может выбрать доставку. В остальные дни доставка не предлагается.

setSchedule((s) => ({ ...s, deliveryDays: days }))} />

Выбрано: {formatDays(schedule.deliveryDays) || "—"}

{/* Pickup days */}
🏪

Самовывоз

Дни, в которые клиент может выбрать самовывоз. В остальные дни самовывоз не предлагается.

setSchedule((s) => ({ ...s, pickupDays: days }))} />

Выбрано: {formatDays(schedule.pickupDays) || "—"}

{/* SMS days */}
📨

SMS-приглашения

Дни, в которые отправляются SMS-приглашения клиентам. В нерабочие дни SMS не отправляются (проверка статусов работает круглосуточно).

setSchedule((s) => ({ ...s, smsDays: days }))} />

Выбрано: {formatDays(schedule.smsDays) || "—"}

{/* Save */}
{hasChanges && !isSaving && ( )}
{error && ( {error} )}
); };