Files
rc-compat/src/app/admin/models/[id]/add-part/page.js
T

168 lines
4.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"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>
);
}