168 lines
4.7 KiB
JavaScript
168 lines
4.7 KiB
JavaScript
"use client";
|
||
|
||
import { use, useState, useEffect } from "react";
|
||
import { useRouter } from "next/navigation";
|
||
import { supabaseBrowser } from "@/lib/supabaseClient";
|
||
|
||
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
|
||
import { Button } from "@/components/ui/button";
|
||
import { Input } from "@/components/ui/input";
|
||
import { Label } from "@/components/ui/label";
|
||
import { Textarea } from "@/components/ui/textarea";
|
||
import {
|
||
Select,
|
||
SelectTrigger,
|
||
SelectValue,
|
||
SelectContent,
|
||
SelectItem,
|
||
} from "@/components/ui/select";
|
||
|
||
export default function AddPartToModelPage({ params }) {
|
||
const { id: modelId } = use(params); // React 19 unwrap
|
||
const router = useRouter();
|
||
|
||
const [search, setSearch] = useState("");
|
||
const [results, setResults] = useState([]);
|
||
const [selectedPart, setSelectedPart] = useState(null);
|
||
|
||
const [fitType, setFitType] = useState("direct");
|
||
const [notes, setNotes] = useState("");
|
||
|
||
// Search parts live
|
||
useEffect(() => {
|
||
async function load() {
|
||
if (!search.trim()) {
|
||
setResults([]);
|
||
return;
|
||
}
|
||
|
||
const { data } = await supabaseBrowser
|
||
.from("parts")
|
||
.select("*")
|
||
.ilike("name", `%${search}%`)
|
||
.limit(20);
|
||
|
||
setResults(data || []);
|
||
}
|
||
|
||
load();
|
||
}, [search]);
|
||
|
||
async function save() {
|
||
if (!selectedPart) return;
|
||
|
||
await supabaseBrowser.from("parts_compatible_models").insert({
|
||
part_id: selectedPart.id,
|
||
model_id: modelId,
|
||
fit_type: fitType,
|
||
notes: notes || null,
|
||
});
|
||
|
||
router.push(`/admin/models/${modelId}`);
|
||
}
|
||
|
||
return (
|
||
<Card className="max-w-2xl mx-auto p-4">
|
||
<CardHeader>
|
||
<CardTitle className="text-2xl">Add Compatible Part</CardTitle>
|
||
</CardHeader>
|
||
|
||
<CardContent className="space-y-6">
|
||
{/* SEARCH */}
|
||
<div className="space-y-2">
|
||
<Label>Search Parts</Label>
|
||
<Input
|
||
placeholder="Enter part name…"
|
||
value={search}
|
||
onChange={(e) => setSearch(e.target.value)}
|
||
/>
|
||
</div>
|
||
|
||
{/* SEARCH RESULTS */}
|
||
{!selectedPart && results.length > 0 && (
|
||
<div className="border rounded divide-y">
|
||
{results.map((p) => (
|
||
<button
|
||
key={p.id}
|
||
onClick={() => setSelectedPart(p)}
|
||
className="w-full text-left p-3 hover:bg-gray-50"
|
||
>
|
||
<div className="font-medium">{p.name}</div>
|
||
<div className="text-sm text-gray-500">
|
||
{p.manufacturer || "-"} – {p.category || "-"}
|
||
</div>
|
||
</button>
|
||
))}
|
||
</div>
|
||
)}
|
||
|
||
{/* SELECTED PART CARD */}
|
||
{selectedPart && (
|
||
<div className="p-4 border rounded bg-gray-50">
|
||
<div className="font-semibold">{selectedPart.name}</div>
|
||
<div className="text-sm text-gray-500">
|
||
{selectedPart.manufacturer || "-"} –{" "}
|
||
{selectedPart.category || "-"}
|
||
</div>
|
||
|
||
<Button
|
||
variant="secondary"
|
||
size="sm"
|
||
className="mt-2"
|
||
onClick={() => setSelectedPart(null)}
|
||
>
|
||
Change
|
||
</Button>
|
||
</div>
|
||
)}
|
||
|
||
{/* FIT TYPE + NOTES */}
|
||
{selectedPart && (
|
||
<>
|
||
<div className="space-y-2">
|
||
<Label>Fit Type</Label>
|
||
<Select value={fitType} onValueChange={setFitType}>
|
||
<SelectTrigger>
|
||
<SelectValue placeholder="Choose Fit Type" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="direct">Direct Fit</SelectItem>
|
||
<SelectItem value="mod_required">
|
||
Modification Required
|
||
</SelectItem>
|
||
<SelectItem value="not_recommended">
|
||
Not Recommended
|
||
</SelectItem>
|
||
<SelectItem value="unknown">Unknown</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
|
||
<div className="space-y-2">
|
||
<Label>Notes (optional)</Label>
|
||
<Textarea
|
||
value={notes}
|
||
onChange={(e) => setNotes(e.target.value)}
|
||
className="min-h-[100px]"
|
||
/>
|
||
</div>
|
||
|
||
{/* SAVE */}
|
||
<Button onClick={save} className="mt-4">
|
||
Save Compatibility
|
||
</Button>
|
||
</>
|
||
)}
|
||
|
||
<Button
|
||
variant="secondary"
|
||
className="mt-4"
|
||
onClick={() => router.back()}
|
||
>
|
||
Cancel
|
||
</Button>
|
||
</CardContent>
|
||
</Card>
|
||
);
|
||
}
|