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({ function TariffModal({
tariff, onSave, onClose, mealPlans, allInclusions, tariff, onSave, onClose, mealPlans, allInclusions, saving, error,
}: { }: {
tariff?: Tariff tariff?: Tariff
onSave: (t: Omit<Tariff, 'id'>) => void onSave: (t: Omit<Tariff, 'id'>) => void
onClose: () => void onClose: () => void
mealPlans: Array<{ id: string; label: string; description: string; inclusions: string[] }> mealPlans: Array<{ id: string; label: string; description: string; inclusions: string[] }>
allInclusions: Array<{ id: string; label: string; icon: React.ElementType }> allInclusions: Array<{ id: string; label: string; icon: React.ElementType }>
saving?: boolean
error?: string
}) { }) {
const [form, setForm] = useState<Omit<Tariff, 'id'>>( const [form, setForm] = useState<Omit<Tariff, 'id'>>(
tariff ? { ...tariff } : { ...EMPTY_TARIFF } tariff ? { ...tariff } : { ...EMPTY_TARIFF }
@@ -214,16 +216,18 @@ function TariffModal({
size="2xl" size="2xl"
footer={ 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 <button
onClick={() => { 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)}` const code = form.code || autoCode(form.name) || `T${Date.now().toString(36).toUpperCase().slice(-4)}`
onSave({ ...form, code }) onSave({ ...form, code })
}} }}
className="btn-primary" className="btn-primary gap-1.5 disabled:opacity-50"
disabled={!form.name} disabled={!form.name || saving}
> >
{saving && <Loader2 size={14} className="animate-spin" />}
{tariff ? 'Сохранить' : 'Создать тариф'} {tariff ? 'Сохранить' : 'Создать тариф'}
</button> </button>
</> </>
@@ -412,6 +416,8 @@ export function TariffsPage() {
const [loading, setLoading] = useState(true) const [loading, setLoading] = useState(true)
const [modal, setModal] = useState<'create' | Tariff | null>(null) const [modal, setModal] = useState<'create' | Tariff | null>(null)
const [deleteTarget, setDeleteTarget] = useState<Tariff | null>(null) const [deleteTarget, setDeleteTarget] = useState<Tariff | null>(null)
const [saveError, setSaveError] = useState('')
const [saving, setSaving] = useState(false)
useEffect(() => { useEffect(() => {
if (!slug) return if (!slug) return
@@ -442,23 +448,31 @@ export function TariffsPage() {
const save = async (data: Omit<Tariff, 'id'>) => { const save = async (data: Omit<Tariff, 'id'>) => {
if (!slug) return if (!slug) return
const payload = { setSaving(true)
name: data.name, code: data.code, meal_plan: data.mealPlan, setSaveError('')
inclusions: data.inclusions, modifier_type: data.modifierType, try {
modifier_value: data.modifierValue, min_nights: data.minNights, const payload = {
cancellation_policy: data.cancellationPolicy, name: data.name, code: data.code, meal_plan: data.mealPlan,
description: data.description, is_active: data.isActive, 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) => { const toggleActive = async (id: string) => {
@@ -740,9 +754,11 @@ export function TariffsPage() {
<TariffModal <TariffModal
tariff={typeof modal === 'object' ? modal : undefined} tariff={typeof modal === 'object' ? modal : undefined}
onSave={save} onSave={save}
onClose={() => setModal(null)} onClose={() => { setModal(null); setSaveError('') }}
mealPlans={mealPlans} mealPlans={mealPlans}
allInclusions={allInclusions} allInclusions={allInclusions}
saving={saving}
error={saveError}
/> />
)} )}