refactor(repairs): one status vocabulary, and the supplier scope input
This commit is contained in:
parent
c4936613e1
commit
283d970cb0
2 changed files with 54 additions and 53 deletions
|
|
@ -48,31 +48,12 @@ import {
|
|||
documentStageStyle,
|
||||
type DocumentStageTone,
|
||||
} from "@/lib/repair-document-stage";
|
||||
import {
|
||||
REPAIR_STATUS_LABEL,
|
||||
REPAIR_STATUS_VARIANT,
|
||||
} from "@/lib/repair-status";
|
||||
import type { Customer, Supplier, Repair } from "@/lib/types";
|
||||
|
||||
const statusColors: Record<
|
||||
string,
|
||||
"default" | "secondary" | "destructive" | "outline"
|
||||
> = {
|
||||
new: "outline",
|
||||
assessing: "secondary",
|
||||
quoted: "secondary",
|
||||
approved: "default",
|
||||
in_progress: "secondary",
|
||||
completed: "default",
|
||||
cancelled: "destructive",
|
||||
};
|
||||
|
||||
const statusLabels: Record<string, string> = {
|
||||
new: "New",
|
||||
assessing: "Sent to supplier",
|
||||
quoted: "Quote received",
|
||||
approved: "Approved",
|
||||
in_progress: "In progress",
|
||||
completed: "Completed",
|
||||
cancelled: "Cancelled",
|
||||
};
|
||||
|
||||
const ALL_STATUSES = [
|
||||
"new",
|
||||
"assessing",
|
||||
|
|
@ -123,6 +104,7 @@ export default function RepairDetailPage({
|
|||
serial_no: "",
|
||||
item_description: "",
|
||||
fault_description: "",
|
||||
supplier_scope: "",
|
||||
notes: "",
|
||||
status: "new" as (typeof ALL_STATUSES)[number],
|
||||
});
|
||||
|
|
@ -188,6 +170,7 @@ export default function RepairDetailPage({
|
|||
serial_no: data.serial_no ?? "",
|
||||
item_description: data.item_description ?? "",
|
||||
fault_description: data.fault_description ?? "",
|
||||
supplier_scope: data.supplier_scope ?? "",
|
||||
notes: data.notes ?? "",
|
||||
status: (data.status ?? "new") as (typeof ALL_STATUSES)[number],
|
||||
});
|
||||
|
|
@ -234,6 +217,7 @@ export default function RepairDetailPage({
|
|||
serial_no: edit.serial_no || null,
|
||||
item_description: edit.item_description,
|
||||
fault_description: edit.fault_description,
|
||||
supplier_scope: edit.supplier_scope,
|
||||
notes: edit.notes,
|
||||
status: edit.status,
|
||||
}),
|
||||
|
|
@ -580,8 +564,8 @@ export default function RepairDetailPage({
|
|||
<h1 className="text-2xl font-bold tracking-tight">
|
||||
{repair.repair_number}
|
||||
</h1>
|
||||
<Badge variant={statusColors[repair.status] || "secondary"}>
|
||||
{statusLabels[repair.status] || repair.status}
|
||||
<Badge variant={REPAIR_STATUS_VARIANT[repair.status] || "secondary"}>
|
||||
{REPAIR_STATUS_LABEL[repair.status] || repair.status}
|
||||
</Badge>
|
||||
</div>
|
||||
<p className="text-muted-foreground">{repair.item_description}</p>
|
||||
|
|
@ -718,6 +702,19 @@ export default function RepairDetailPage({
|
|||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="supplier_scope">
|
||||
What the supplier must look at
|
||||
</Label>
|
||||
<Textarea
|
||||
id="supplier_scope"
|
||||
placeholder="Strip and quote the strike mechanism"
|
||||
value={edit.supplier_scope}
|
||||
onChange={(e) =>
|
||||
setEdit((p) => ({ ...p, supplier_scope: e.target.value }))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label>Status</Label>
|
||||
<Select
|
||||
|
|
@ -732,7 +729,7 @@ export default function RepairDetailPage({
|
|||
<SelectContent>
|
||||
{ALL_STATUSES.map((s) => (
|
||||
<SelectItem key={s} value={s}>
|
||||
{statusLabels[s]}
|
||||
{REPAIR_STATUS_LABEL[s]}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
|
|
@ -763,6 +760,12 @@ export default function RepairDetailPage({
|
|||
<div className="col-span-2">
|
||||
<DetailRow label="Fault" value={repair.fault_description} />
|
||||
</div>
|
||||
<div className="col-span-2">
|
||||
<DetailRow
|
||||
label="Supplier to look at"
|
||||
value={repair.supplier_scope}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
|
|
|
|||
|
|
@ -22,6 +22,10 @@ import { CustomerSearch } from "@/components/ui/customer-search";
|
|||
import { SupplierSearch } from "@/components/ui/supplier-search";
|
||||
import { OrderSearch } from "@/components/ui/order-search";
|
||||
import { Camera, X as XIcon } from "lucide-react";
|
||||
import {
|
||||
REPAIR_STATUS_LABEL,
|
||||
REPAIR_STATUS_VARIANT,
|
||||
} from "@/lib/repair-status";
|
||||
import type { Customer, Supplier, Repair } from "@/lib/types";
|
||||
|
||||
const ALLOWED_PHOTO_TYPES = [
|
||||
|
|
@ -32,29 +36,6 @@ const ALLOWED_PHOTO_TYPES = [
|
|||
];
|
||||
const MAX_PHOTO_BYTES = 8 * 1024 * 1024;
|
||||
|
||||
const statusColors: Record<
|
||||
string,
|
||||
"default" | "secondary" | "destructive" | "outline"
|
||||
> = {
|
||||
new: "outline",
|
||||
assessing: "secondary",
|
||||
quoted: "secondary",
|
||||
approved: "default",
|
||||
in_progress: "secondary",
|
||||
completed: "default",
|
||||
cancelled: "destructive",
|
||||
};
|
||||
|
||||
const statusLabels: Record<string, string> = {
|
||||
new: "New",
|
||||
assessing: "Sent to supplier",
|
||||
quoted: "Quote received",
|
||||
approved: "Approved",
|
||||
in_progress: "In progress",
|
||||
completed: "Completed",
|
||||
cancelled: "Cancelled",
|
||||
};
|
||||
|
||||
type RepairsListItem = Repair & {
|
||||
expand?: {
|
||||
customer?: Customer;
|
||||
|
|
@ -103,6 +84,7 @@ export default function RepairsPage() {
|
|||
serial_no: "",
|
||||
item_description: "",
|
||||
fault_description: "",
|
||||
supplier_scope: "",
|
||||
notes: "",
|
||||
});
|
||||
const [photoPreviews, setPhotoPreviews] = useState<PhotoPreview[]>([]);
|
||||
|
|
@ -204,6 +186,7 @@ export default function RepairsPage() {
|
|||
serial_no: "",
|
||||
item_description: "",
|
||||
fault_description: "",
|
||||
supplier_scope: "",
|
||||
notes: "",
|
||||
});
|
||||
setPhotoPreviews((prev) => {
|
||||
|
|
@ -232,6 +215,7 @@ export default function RepairsPage() {
|
|||
serial_no: form.serial_no || null,
|
||||
item_description: form.item_description.trim(),
|
||||
fault_description: form.fault_description.trim(),
|
||||
supplier_scope: form.supplier_scope.trim(),
|
||||
notes: form.notes.trim(),
|
||||
}),
|
||||
});
|
||||
|
|
@ -331,8 +315,8 @@ export default function RepairsPage() {
|
|||
key: "status",
|
||||
label: "Status",
|
||||
render: (item: RepairsListItem) => (
|
||||
<Badge variant={statusColors[item.status] || "secondary"}>
|
||||
{statusLabels[item.status] || item.status}
|
||||
<Badge variant={REPAIR_STATUS_VARIANT[item.status] || "secondary"}>
|
||||
{REPAIR_STATUS_LABEL[item.status] || item.status}
|
||||
</Badge>
|
||||
),
|
||||
},
|
||||
|
|
@ -406,8 +390,8 @@ export default function RepairsPage() {
|
|||
</p>
|
||||
) : null}
|
||||
</div>
|
||||
<Badge variant={statusColors[item.status] || "secondary"}>
|
||||
{statusLabels[item.status] || item.status}
|
||||
<Badge variant={REPAIR_STATUS_VARIANT[item.status] || "secondary"}>
|
||||
{REPAIR_STATUS_LABEL[item.status] || item.status}
|
||||
</Badge>
|
||||
</div>
|
||||
<p className="text-sm">{item.item_description}</p>
|
||||
|
|
@ -502,6 +486,20 @@ export default function RepairsPage() {
|
|||
rows={3}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="supplier_scope">
|
||||
What the supplier must look at
|
||||
</Label>
|
||||
<Textarea
|
||||
id="supplier_scope"
|
||||
placeholder="Strip and quote the strike mechanism"
|
||||
value={form.supplier_scope}
|
||||
onChange={(e) =>
|
||||
setForm((p) => ({ ...p, supplier_scope: e.target.value }))
|
||||
}
|
||||
rows={3}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label>Notes</Label>
|
||||
<Textarea
|
||||
|
|
|
|||
Loading…
Reference in a new issue