fix(pwa/repairs): drop duplicate mileage input under «Замена масла»

При создании/редактировании ремонта в форме был отдельный «Пробег на
момент замены» внутри блока замены масла — auto-sync от шапочного с
soft-dirty флагом по У24. На практике это всё равно заставляло механика
вводить значение дважды, если шапочный пробег вводился вручную (StarLine
недоступен): момент включения галочки случался после ручного ввода,
soft-sync не успевал отработать или механик не понимал что поле
автозаполнилось.

Упростили: единственный пробег — «Пробег (км)» в шапке формы. На submit
он же подставляется в oil_change.mileage_at_change. Поле «Следующая через»
оставили — это интервал, а не значение пробега.

Бэкенд не трогаем — схема та же (mileage_at_change всё ещё в payload).
This commit is contained in:
2026-05-25 21:29:26 +10:00
parent 8eac0b74fc
commit 205078c5ce
2 changed files with 18 additions and 54 deletions
@@ -67,8 +67,6 @@ interface PartRow {
interface OilChangeState { interface OilChangeState {
enabled: boolean; enabled: boolean;
mileage_at_change: number | null;
mileage_is_dirty: boolean; // У24: мягкая подписка с шапочным
next_in_km: number; next_in_km: number;
sticker: PhotoState | null; sticker: PhotoState | null;
} }
@@ -107,8 +105,6 @@ export default function CreateRepairPage() {
const [parts, setParts] = useState<PartRow[]>([]); const [parts, setParts] = useState<PartRow[]>([]);
const [oilChange, setOilChange] = useState<OilChangeState>({ const [oilChange, setOilChange] = useState<OilChangeState>({
enabled: false, enabled: false,
mileage_at_change: null,
mileage_is_dirty: false,
next_in_km: 10000, next_in_km: 10000,
sticker: null, sticker: null,
}); });
@@ -130,13 +126,9 @@ export default function CreateRepairPage() {
.catch((e) => setCtxError((e as Error).message || "Не удалось загрузить машину")); .catch((e) => setCtxError((e as Error).message || "Не удалось загрузить машину"));
}, [carId]); }, [carId]);
// У24: мягкая подписка пробега блока масла на шапочный. // У24 упрощено: пробег ввода в форме теперь один — главный «Пробег (км)»
useEffect(() => { // в шапке. На submit подставляется и в oil_change.mileage_at_change, чтобы
if (oilChange.enabled && !oilChange.mileage_is_dirty) { // не заставлять механика вводить одно и то же дважды.
setOilChange((oc) => ({ ...oc, mileage_at_change: mileage }));
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [mileage, oilChange.enabled]);
// ── Photo upload ───────────────────────────────────────────────────────── // ── Photo upload ─────────────────────────────────────────────────────────
@@ -325,7 +317,8 @@ export default function CreateRepairPage() {
oil_change: oilChange.enabled oil_change: oilChange.enabled
? { ? {
enabled: true, enabled: true,
mileage_at_change: oilChange.mileage_at_change, // Один источник истины — главный пробег ремонта (см. У24).
mileage_at_change: mileage,
next_in_km: oilChange.next_in_km, next_in_km: oilChange.next_in_km,
sticker_photo_uuid: sticker_photo_uuid:
oilChange.sticker?.status === "uploaded" oilChange.sticker?.status === "uploaded"
@@ -625,21 +618,6 @@ export default function CreateRepairPage() {
</label> </label>
{oilChange.enabled && ( {oilChange.enabled && (
<div className="mt-3 space-y-3"> <div className="mt-3 space-y-3">
<div>
<Label className="text-sm">Пробег на момент замены</Label>
<Input
type="number"
min={0}
value={oilChange.mileage_at_change ?? ""}
onChange={(e) =>
setOilChange((oc) => ({
...oc,
mileage_at_change: e.target.value === "" ? null : Number(e.target.value),
mileage_is_dirty: true,
}))
}
/>
</div>
<div> <div>
<Label className="text-sm">Следующая замена через (км)</Label> <Label className="text-sm">Следующая замена через (км)</Label>
<Input <Input
@@ -36,7 +36,6 @@ interface PartRow {
interface OilState { interface OilState {
enabled: boolean; enabled: boolean;
mileage_at_change: number | null;
next_in_km: number | null; next_in_km: number | null;
} }
@@ -60,7 +59,7 @@ export default function EditRepairPage() {
const [mileage, setMileage] = useState<number | null>(null); const [mileage, setMileage] = useState<number | null>(null);
const [works, setWorks] = useState<WorkRow[]>([]); const [works, setWorks] = useState<WorkRow[]>([]);
const [parts, setParts] = useState<PartRow[]>([]); const [parts, setParts] = useState<PartRow[]>([]);
const [oil, setOil] = useState<OilState>({ enabled: false, mileage_at_change: null, next_in_km: null }); const [oil, setOil] = useState<OilState>({ enabled: false, next_in_km: null });
const [worksPicker, setWorksPicker] = useState<{ open: boolean; q: string; results: MechWork[] }>( const [worksPicker, setWorksPicker] = useState<{ open: boolean; q: string; results: MechWork[] }>(
{ open: false, q: "", results: [] } { open: false, q: "", results: [] }
@@ -89,7 +88,6 @@ export default function EditRepairPage() {
if (d.oil_change) { if (d.oil_change) {
setOil({ setOil({
enabled: true, enabled: true,
mileage_at_change: d.oil_change.mileage_at_change,
next_in_km: d.oil_change.next_in_km, next_in_km: d.oil_change.next_in_km,
}); });
} }
@@ -174,7 +172,8 @@ export default function EditRepairPage() {
qty: p.qty, qty: p.qty,
})), })),
oil_change: oil.enabled oil_change: oil.enabled
? { enabled: true, mileage_at_change: oil.mileage_at_change, next_in_km: oil.next_in_km } // Один источник истины — главный пробег ремонта.
? { enabled: true, mileage_at_change: mileage, next_in_km: oil.next_in_km }
: { enabled: false, mileage_at_change: null, next_in_km: null }, : { enabled: false, mileage_at_change: null, next_in_km: null },
}); });
navigate(`/repairs/${detail.id}`, { replace: true }); navigate(`/repairs/${detail.id}`, { replace: true });
@@ -343,19 +342,7 @@ export default function EditRepairPage() {
Замена масла Замена масла
</label> </label>
{oil.enabled && ( {oil.enabled && (
<div className="mt-3 grid grid-cols-2 gap-2"> <div className="mt-3">
<div>
<Label className="text-xs">Пробег</Label>
<Input
type="number"
inputMode="numeric"
value={oil.mileage_at_change ?? ""}
onChange={(e) => setOil((o) => ({
...o, mileage_at_change: e.target.value === "" ? null : Number(e.target.value),
}))}
/>
</div>
<div>
<Label className="text-xs">Через, км</Label> <Label className="text-xs">Через, км</Label>
<Input <Input
type="number" type="number"
@@ -366,7 +353,6 @@ export default function EditRepairPage() {
}))} }))}
/> />
</div> </div>
</div>
)} )}
</section> </section>