feat(repairs): external mode in create form + /repairs/new-external route
Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
@@ -39,6 +39,7 @@ export default function App() {
|
||||
<Route path="/repairs" element={<RequireAuth><RepairsFeedPage /></RequireAuth>} />
|
||||
<Route path="/repairs/new" element={<RequireAuth><CarSelectPage /></RequireAuth>} />
|
||||
<Route path="/repairs/new/:carId" element={<RequireAuth><CreateRepairPage /></RequireAuth>} />
|
||||
<Route path="/repairs/new-external" element={<RequireAuth><CreateRepairPage /></RequireAuth>} />
|
||||
<Route path="/repairs/:id" element={<RequireAuth><RepairDetailPage /></RequireAuth>} />
|
||||
<Route path="/repairs/:id/edit" element={<RequireAuth><EditRepairPage /></RequireAuth>} />
|
||||
<Route path="*" element={<Navigate to="/" replace />} />
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
* Сохранение: POST /repairs с `Idempotency-Key` (UUID v4 в state).
|
||||
*/
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { useNavigate, useParams, useLocation } from "react-router-dom";
|
||||
import { ChevronLeft, Plus, Trash2, Pencil, Camera } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import { Button } from "@/components/ui/button";
|
||||
@@ -94,6 +94,9 @@ function uuid4(): string {
|
||||
export default function CreateRepairPage() {
|
||||
const navigate = useNavigate();
|
||||
const { carId: carIdRaw } = useParams<{ carId: string }>();
|
||||
const location = useLocation();
|
||||
const isExternal = !carIdRaw;
|
||||
const externalState = location.state as { plate: string; make: string | null } | null;
|
||||
const carId = carIdRaw ? Number(carIdRaw) : 0;
|
||||
|
||||
// Idempotency-Key для этой формы — стабилен между ре-сабмитами (У20).
|
||||
@@ -120,6 +123,24 @@ export default function CreateRepairPage() {
|
||||
|
||||
// Initial: подгрузить контекст машины.
|
||||
useEffect(() => {
|
||||
if (isExternal) {
|
||||
if (!externalState) {
|
||||
// Прямой заход/рефреш без данных — возвращаем к выбору машины.
|
||||
navigate("/repairs/new", { replace: true });
|
||||
return;
|
||||
}
|
||||
setCtx({
|
||||
id: 0,
|
||||
plate: externalState.plate,
|
||||
brand: externalState.make,
|
||||
model: null,
|
||||
mileage_starline: null,
|
||||
driver_id: null,
|
||||
driver_name: null,
|
||||
});
|
||||
setMileage(null);
|
||||
return;
|
||||
}
|
||||
if (!carId) return;
|
||||
getCarContext(carId)
|
||||
.then((c) => {
|
||||
@@ -127,7 +148,8 @@ export default function CreateRepairPage() {
|
||||
setMileage(c.mileage_starline);
|
||||
})
|
||||
.catch((e) => setCtxError((e as Error).message || "Не удалось загрузить машину"));
|
||||
}, [carId]);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [carId, isExternal]);
|
||||
|
||||
// У24 упрощено: пробег ввода в форме теперь один — главный «Пробег (км)»
|
||||
// в шапке. На submit подставляется и в oil_change.mileage_at_change, чтобы
|
||||
@@ -307,7 +329,9 @@ export default function CreateRepairPage() {
|
||||
}));
|
||||
const result = await createRepair(
|
||||
{
|
||||
car_id: carId,
|
||||
...(isExternal
|
||||
? { external_car: { plate: externalState!.plate, make: externalState!.make } }
|
||||
: { car_id: carId }),
|
||||
mileage,
|
||||
works: works.map((w) => ({
|
||||
work_catalog_id: w.work_catalog_id,
|
||||
@@ -385,7 +409,11 @@ export default function CreateRepairPage() {
|
||||
<div className="font-medium">{ctx.plate}</div>
|
||||
<div className="text-muted-foreground">
|
||||
{[ctx.brand, ctx.model].filter(Boolean).join(" ")}
|
||||
{ctx.driver_name ? ` · ${ctx.driver_name}` : ` · Без водителя`}
|
||||
{isExternal
|
||||
? " · С улицы"
|
||||
: ctx.driver_name
|
||||
? ` · ${ctx.driver_name}`
|
||||
: " · Без водителя"}
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
Reference in New Issue
Block a user