import { useEffect, useState } from 'react' import { ChevronDown, ChevronUp, Plus, Trash2 } from 'lucide-react' import { Breadcrumbs } from '../components/Breadcrumbs' import { StepColorPicker } from '../components/StepColorPicker' import { Switch } from '../components/Switch' import { Tooltip } from '../components/Tooltip' import { useToast } from '../context/ToastContext' import { useT } from '../i18n/useT' import { ApiError } from '../lib/api' import { getSettings, updateStoreSettings, DEFAULT_ORDER_PROCESS_STEPS, type OrderProcessStep, type StoreSettings, } from '../services/settingsService' import { createId } from '../utils/id' import { defaultStepColorForId, normalizeStepColor, type StepColorPreset, } from '../utils/stepColors' import controlStyles from '../components/CategoryRow.module.css' import removeStyles from '../components/VariationsModal.module.css' import pageStyles from '../components/PageContent.module.css' import sharedStyles from './ProductSettingsPage.module.css' import styles from './StoreSettingsPage.module.css' const DEFAULT_STORE_SETTINGS: StoreSettings = { onlineSellEnabled: true, orderProcessSteps: DEFAULT_ORDER_PROCESS_STEPS, } function normalizeSteps(steps: OrderProcessStep[]) { return steps.map((step, index) => ({ id: step.id, label: step.label.trim(), labelFa: (step.labelFa ?? '').trim(), color: normalizeStepColor(step.color, defaultStepColorForId(step.id, index)), })) } function stepsAreEqual(a: OrderProcessStep[], b: OrderProcessStep[]) { if (a.length !== b.length) return false return a.every((step, index) => { const other = b[index] return ( step.id === other.id && step.label === other.label && step.labelFa === other.labelFa && step.color === other.color ) }) } export function StoreSettingsPage() { const t = useT() const { showToast } = useToast() const [settings, setSettings] = useState(DEFAULT_STORE_SETTINGS) const [draftSteps, setDraftSteps] = useState( DEFAULT_STORE_SETTINGS.orderProcessSteps, ) const [isLoading, setIsLoading] = useState(true) const [savingKey, setSavingKey] = useState(null) const [error, setError] = useState('') useEffect(() => { const controller = new AbortController() void loadSettings(controller.signal) return () => controller.abort() }, []) async function loadSettings(signal?: AbortSignal) { setIsLoading(true) setError('') try { const data = await getSettings(signal) setSettings(data.settings.store) setDraftSteps(data.settings.store.orderProcessSteps) } catch (err) { if (err instanceof DOMException && err.name === 'AbortError') return if (err instanceof ApiError) { setError(err.message) } else { setError(t('productSettings.errorLoad')) } } finally { setIsLoading(false) } } async function handleOnlineSellChange(checked: boolean) { setSavingKey('onlineSell') setError('') try { const data = await updateStoreSettings({ onlineSellEnabled: checked }) setSettings(data.settings.store) showToast(t('productSettings.saved'), 'success') } catch (err) { if (err instanceof ApiError) { setError(err.message) } else { setError(t('productSettings.errorSave')) } } finally { setSavingKey(null) } } function updateStepLabel(id: string, label: string) { setDraftSteps((current) => current.map((step) => (step.id === id ? { ...step, label } : step)), ) } function updateStepLabelFa(id: string, labelFa: string) { setDraftSteps((current) => current.map((step) => (step.id === id ? { ...step, labelFa } : step)), ) } function updateStepColor(id: string, color: StepColorPreset) { setDraftSteps((current) => current.map((step) => (step.id === id ? { ...step, color } : step)), ) } function addStep() { setDraftSteps((current) => { const id = createId() return [ ...current, { id, label: '', labelFa: '', color: defaultStepColorForId(id, current.length), }, ] }) } function removeStep(id: string) { setDraftSteps((current) => current.filter((step) => step.id !== id)) } function moveStep(id: string, direction: -1 | 1) { setDraftSteps((current) => { const index = current.findIndex((step) => step.id === id) if (index < 0) return current const targetIndex = index + direction if (targetIndex < 0 || targetIndex >= current.length) return current const next = [...current] const [item] = next.splice(index, 1) next.splice(targetIndex, 0, item) return next }) } async function handleSaveSteps() { const normalized = normalizeSteps(draftSteps) const hasEmptyLabel = normalized.some((step) => !step.label || !step.labelFa) if (!normalized.length) { setError(t('storeSettings.error.minSteps')) return } if (hasEmptyLabel) { setError(t('storeSettings.error.labels')) return } setSavingKey('orderSteps') setError('') try { const data = await updateStoreSettings({ orderProcessSteps: normalized }) setSettings(data.settings.store) setDraftSteps(data.settings.store.orderProcessSteps) showToast(t('storeSettings.stepsSaved'), 'success') } catch (err) { if (err instanceof ApiError) { setError(err.message) } else { setError(t('storeSettings.error.saveSteps')) } } finally { setSavingKey(null) } } const stepsDirty = !stepsAreEqual( normalizeSteps(draftSteps), normalizeSteps(settings.orderProcessSteps), ) const canSaveSteps = stepsDirty && draftSteps.length > 0 && draftSteps.every( (step) => step.label.trim().length > 0 && step.labelFa.trim().length > 0, ) return (

{t('storeSettings.title')}

{t('storeSettings.subtitle')}

{error && (
{error}
)}
{isLoading ? (

{t('productSettings.loading')}

) : (

{t('storeSettings.onlineSellDesc')}

void handleOnlineSellChange(checked)} />
)}

{t('storeSettings.orderProcess')}

{t('storeSettings.orderProcessDesc')}

{isLoading ? (

{t('productSettings.loading')}

) : ( <>
{draftSteps.map((step, index) => (
{index + 1} updateStepColor(step.id, color)} ariaLabel={t('storeSettings.stepColorAria', { index: index + 1 })} /> updateStepLabel(step.id, e.target.value)} /> updateStepLabelFa(step.id, e.target.value)} />
))} {!draftSteps.length && (

{t('storeSettings.emptySteps')}

)}
)}
) }