fix(product-edit): человечная ошибка 400 + блок Save при незаполненных IsRequired ценах
Сервер 400-нул сохранение товара когда обязательная цена пуста, а UI показывал «Request failed with status code 400» без указания причины. - onError save mutation: достаём response.data.error из axios-ответа и кладём в setError; общий generic message остаётся как fallback. - canSave дополнен проверкой что у каждого PriceType с IsRequired=true есть строка в form.prices с amount > 0 (та же что делает бэкенд, чтобы кнопка не отправляла запрос обречённый на 400). - Под секцией цен — красная подсказка-список незаполненных обязательных типов цен («Заполни обязательные цены: «Розничная2» (значение должно быть больше 0).»). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c257ee7e88
commit
a8717897b7
|
|
@ -166,7 +166,10 @@ export function ProductEditPage() {
|
|||
qc.invalidateQueries({ queryKey: ['/api/catalog/products'] })
|
||||
navigate(created ? `/catalog/products/${created.id}` : '/catalog/products')
|
||||
},
|
||||
onError: (e: Error) => setError(e.message),
|
||||
onError: (e: Error) => {
|
||||
const msg = (e as { response?: { data?: { error?: string } } }).response?.data?.error ?? e.message
|
||||
setError(msg)
|
||||
},
|
||||
})
|
||||
|
||||
const remove = useMutation({
|
||||
|
|
@ -190,10 +193,21 @@ export function ProductEditPage() {
|
|||
const updateBarcode = (i: number, patch: Partial<BarcodeRow>) =>
|
||||
setForm({ ...form, barcodes: form.barcodes.map((b, ix) => ix === i ? { ...b, ...patch } : b) })
|
||||
|
||||
// У каждого PriceType с IsRequired=true должна быть запись в form.prices
|
||||
// с Amount > 0. Сервер делает ту же проверку (400 иначе), но дублируем
|
||||
// на фронте чтобы кнопка Save не клатилась с непонятным «Request failed with status 400».
|
||||
const missingRequiredPrices = (priceTypes.data ?? [])
|
||||
.filter((pt) => pt.isRequired)
|
||||
.filter((pt) => {
|
||||
const row = form.prices.find((p) => p.priceTypeId === pt.id)
|
||||
return !row || row.amount <= 0
|
||||
})
|
||||
|
||||
const canSave = form.name.trim().length > 0
|
||||
&& !!form.unitOfMeasureId
|
||||
&& !!form.productGroupId
|
||||
&& form.barcodes.length > 0
|
||||
&& missingRequiredPrices.length === 0
|
||||
|
||||
return (
|
||||
<form onSubmit={onSubmit} className="flex flex-col h-full">
|
||||
|
|
@ -447,6 +461,11 @@ export function ProductEditPage() {
|
|||
{priceTypes.data?.length === 0 && (
|
||||
<div className="text-sm text-slate-400 py-2">Нет ни одного типа цен. Создай в «Настройки → Типы цен».</div>
|
||||
)}
|
||||
{missingRequiredPrices.length > 0 && (
|
||||
<div className="text-sm text-red-600 mt-2">
|
||||
Заполни обязательные цены: {missingRequiredPrices.map((pt) => `«${pt.name}»`).join(', ')} (значение должно быть больше 0).
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue