refactor(inventory): site selector via URL param (?siteId=) — no localStorage, no user preference

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Hardik 2026-05-15 11:57:53 +05:30
parent 4919b1d4e4
commit e887502e27
2 changed files with 27 additions and 24 deletions

View file

@ -1,10 +1,10 @@
"use client"; "use client";
import { useState, useMemo, useTransition } from "react"; import { useState, useMemo } from "react";
import { useRouter } from "next/navigation";
import { Search, X, ChevronDown, ChevronRight, MapPin, Tag } from "lucide-react"; import { Search, X, ChevronDown, ChevronRight, MapPin, Tag } from "lucide-react";
import { formatCurrency } from "@/lib/utils"; import { formatCurrency } from "@/lib/utils";
import { addToCart } from "@/lib/cart"; import { addToCart } from "@/lib/cart";
import { setPreferredSite } from "@/app/actions/site-preference";
type VendorOption = { type VendorOption = {
vendorId: string; vendorId: string;
@ -32,18 +32,18 @@ export function ItemsTable({
items, items,
hasSite, hasSite,
sites = [], sites = [],
preferredSiteId = null, currentSiteId = null,
}: { }: {
items: CatalogItem[]; items: CatalogItem[];
hasSite: boolean; hasSite: boolean;
sites?: SiteOption[]; sites?: SiteOption[];
preferredSiteId?: string | null; currentSiteId?: string | null;
}) { }) {
const router = useRouter();
const [query, setQuery] = useState(""); const [query, setQuery] = useState("");
const [expandedId, setExpandedId] = useState<string | null>(null); const [expandedId, setExpandedId] = useState<string | null>(null);
const [sortBy, setSortBy] = useState<"distance" | "price">(hasSite ? "distance" : "price"); const [sortBy, setSortBy] = useState<"distance" | "price">(hasSite ? "distance" : "price");
const [added, setAdded] = useState<Record<string, boolean>>({}); const [added, setAdded] = useState<Record<string, boolean>>({});
const [sitePending, startSiteTransition] = useTransition();
const filtered = useMemo(() => { const filtered = useMemo(() => {
const q = query.toLowerCase().trim(); const q = query.toLowerCase().trim();
@ -99,20 +99,19 @@ export function ItemsTable({
<MapPin className="h-4 w-4 text-neutral-400 shrink-0" /> <MapPin className="h-4 w-4 text-neutral-400 shrink-0" />
<label className="text-sm font-medium text-neutral-700 whitespace-nowrap">Working Site</label> <label className="text-sm font-medium text-neutral-700 whitespace-nowrap">Working Site</label>
<select <select
value={preferredSiteId ?? ""} value={currentSiteId ?? ""}
disabled={sitePending} onChange={(e) => {
onChange={(e) => const id = e.target.value;
startSiteTransition(() => setPreferredSite(e.target.value || null)) router.push(id ? `/inventory/items?siteId=${id}` : "/inventory/items");
} }}
className="flex-1 max-w-xs rounded-lg border border-neutral-200 bg-neutral-50 px-3 py-1.5 text-sm text-neutral-700 focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-primary-500/20 disabled:opacity-60" className="flex-1 max-w-xs rounded-lg border border-neutral-200 bg-neutral-50 px-3 py-1.5 text-sm text-neutral-700 focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-primary-500/20"
> >
<option value="">No site selected distances hidden</option> <option value="">No site selected distances hidden</option>
{sites.map((s) => ( {sites.map((s) => (
<option key={s.id} value={s.id}>{s.name} ({s.code})</option> <option key={s.id} value={s.id}>{s.name} ({s.code})</option>
))} ))}
</select> </select>
{sitePending && <span className="text-xs text-neutral-400">Updating</span>} {currentSiteId && (
{!sitePending && preferredSiteId && (
<span className="text-xs text-primary-600">Distances shown from selected site</span> <span className="text-xs text-primary-600">Distances shown from selected site</span>
)} )}
</div> </div>

View file

@ -7,17 +7,23 @@ import type { Metadata } from "next";
export const metadata: Metadata = { title: "Browse Items" }; export const metadata: Metadata = { title: "Browse Items" };
export default async function InventoryItemsPage() { interface Props {
searchParams: Promise<{ siteId?: string }>;
}
export default async function InventoryItemsPage({ searchParams }: Props) {
const session = await auth(); const session = await auth();
if (!session?.user) redirect("/login"); if (!session?.user) redirect("/login");
const [user, products, sites] = await Promise.all([ const { siteId } = await searchParams;
db.user.findUnique({
where: { id: session.user.id }, const [site, products, sites] = await Promise.all([
include: { siteId
preferredSite: { select: { id: true, name: true, latitude: true, longitude: true } }, ? db.site.findUnique({
}, where: { id: siteId, isActive: true },
}), select: { id: true, name: true, latitude: true, longitude: true },
})
: Promise.resolve(null),
db.product.findMany({ db.product.findMany({
where: { isActive: true }, where: { isActive: true },
include: { include: {
@ -40,8 +46,6 @@ export default async function InventoryItemsPage() {
}), }),
]); ]);
const site = user?.preferredSite ?? null;
const items = products.map((p) => ({ const items = products.map((p) => ({
id: p.id, id: p.id,
code: p.code, code: p.code,
@ -72,7 +76,7 @@ export default async function InventoryItemsPage() {
items={items} items={items}
hasSite={!!site} hasSite={!!site}
sites={sites} sites={sites}
preferredSiteId={user?.preferredSiteId ?? null} currentSiteId={siteId ?? null}
/> />
</div> </div>
); );