fix: add error handling and loading state to tariff save

This commit is contained in:
2026-03-31 11:36:46 +03:00
parent 1ffc171175
commit 7a3772d1cf

View File

@@ -151,13 +151,15 @@ const EMPTY_TARIFF: Omit<Tariff, 'id'> = {
}
function TariffModal({
tariff, onSave, onClose, mealPlans, allInclusions,
tariff, onSave, onClose, mealPlans, allInclusions, saving, error,
}: {
tariff?: Tariff
onSave: (t: Omit<Tariff, 'id'>) => void
onClose: () => void
mealPlans: Array<{ id: string; label: string; description: string; inclusions: string[] }>
allInclusions: Array<{ id: string; label: string; icon: React.ElementType }>
saving?: boolean
error?: string
}) {
const [form, setForm] = useState<Omit<Tariff, 'id'>>(
tariff ? { ...tariff } : { ...EMPTY_TARIFF }
@@ -214,16 +216,18 @@ function TariffModal({
size="2xl"
footer={
<>
<button onClick={onClose} className="btn-secondary">Отмена</button>
{error && <p className="text-sm text-red-600 dark:text-red-400 mr-auto">{error}</p>}
<button onClick={onClose} className="btn-secondary" disabled={saving}>Отмена</button>
<button
onClick={() => {
if (!form.name) return
if (!form.name || saving) return
const code = form.code || autoCode(form.name) || `T${Date.now().toString(36).toUpperCase().slice(-4)}`
onSave({ ...form, code })
}}
className="btn-primary"
disabled={!form.name}
className="btn-primary gap-1.5 disabled:opacity-50"
disabled={!form.name || saving}
>
{saving && <Loader2 size={14} className="animate-spin" />}
{tariff ? 'Сохранить' : 'Создать тариф'}
</button>
</>
@@ -412,6 +416,8 @@ export function TariffsPage() {
const [loading, setLoading] = useState(true)
const [modal, setModal] = useState<'create' | Tariff | null>(null)
const [deleteTarget, setDeleteTarget] = useState<Tariff | null>(null)
const [saveError, setSaveError] = useState('')
const [saving, setSaving] = useState(false)
useEffect(() => {
if (!slug) return
@@ -442,23 +448,31 @@ export function TariffsPage() {
const save = async (data: Omit<Tariff, 'id'>) => {
if (!slug) return
const payload = {
name: data.name, code: data.code, meal_plan: data.mealPlan,
inclusions: data.inclusions, modifier_type: data.modifierType,
modifier_value: data.modifierValue, min_nights: data.minNights,
cancellation_policy: data.cancellationPolicy,
description: data.description, is_active: data.isActive,
setSaving(true)
setSaveError('')
try {
const payload = {
name: data.name, code: data.code, meal_plan: data.mealPlan,
inclusions: data.inclusions, modifier_type: data.modifierType,
modifier_value: data.modifierValue, min_nights: data.minNights,
cancellation_policy: data.cancellationPolicy,
description: data.description, is_active: data.isActive,
}
const isEdit = typeof modal === 'object' && modal !== null
const saved = isEdit
? await api.tariffs.update(slug, (modal as Tariff).id, payload)
: await api.tariffs.create(slug, payload)
const converted = fromApi(saved)
setTariffs(prev => isEdit
? prev.map(t => t.id === (modal as Tariff).id ? converted : t)
: [...prev, converted],
)
setModal(null)
} catch (err) {
setSaveError(err instanceof Error ? err.message : 'Ошибка сохранения')
} finally {
setSaving(false)
}
const isEdit = typeof modal === 'object' && modal !== null
const saved = isEdit
? await api.tariffs.update(slug, modal.id, payload)
: await api.tariffs.create(slug, payload)
const converted = fromApi(saved)
setTariffs(prev => isEdit
? prev.map(t => t.id === modal.id ? converted : t)
: [...prev, converted],
)
setModal(null)
}
const toggleActive = async (id: string) => {
@@ -740,9 +754,11 @@ export function TariffsPage() {
<TariffModal
tariff={typeof modal === 'object' ? modal : undefined}
onSave={save}
onClose={() => setModal(null)}
onClose={() => { setModal(null); setSaveError('') }}
mealPlans={mealPlans}
allInclusions={allInclusions}
saving={saving}
error={saveError}
/>
)}