feat(orders): filter list to the logged-in rep's own orders

This commit is contained in:
Dave 2026-08-31 23:25:44 +02:00
parent d23c811b91
commit defa481661

View file

@ -26,6 +26,8 @@ import {
import getPocketBase from "@/lib/pocketbase";
import { displayContactName } from "@/lib/utils";
import { isOrderComplete } from "@/lib/server/order-completion";
import { useAuth } from "@/components/auth-provider";
import { isRepUser } from "@/lib/rep-visibility";
import type {
OrdersDashboardData,
OrderWithItems,
@ -112,6 +114,7 @@ async function fetchDashboardJson<T>(url: string): Promise<T> {
export default function OrdersPage() {
const router = useRouter();
const { user } = useAuth();
const [orders, setOrders] = useState<OrderWithItems[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
@ -275,11 +278,27 @@ export default function OrdersPage() {
const openReview = (orderId: string) => setReviewOrderId(orderId);
const closeReview = () => setReviewOrderId(null);
// Rep-scoped UI filter — reps only see orders tied to them, either
// via the denormalized `orders.rep` text field or via
// `customer.rep`. Everyone else (buyer/quoter/admin/boss/etc.) sees
// the unfiltered list. This filters the already-fetched page of
// orders; it does not change what the server returns, so tab
// counts / pagination totals stay unscoped — see the plan's "Known
// limitation" note.
const visibleOrders = useMemo(() => {
const userType = (user as { user_type?: string[] } | null)?.user_type;
if (!user || !isRepUser(userType)) return orders;
return orders.filter(
({ order }) =>
order.rep === user.id || order.expand?.customer?.rep === user.id,
);
}, [orders, user]);
// The server already filtered `orders` to those with at least one
// item in `activeTab` (via the `tab` query param). No client-side
// filter needed — re-applying it would drop orders the server
// intended to show.
const totalLoaded = orders.length;
const totalLoaded = visibleOrders.length;
const searching = search.trim().length > 0;
// Sum of orders across the other active tabs (for the empty-state
@ -387,7 +406,7 @@ export default function OrdersPage() {
<p className="text-sm text-destructive">{error}</p>
</CardContent>
</Card>
) : orders.length === 0 ? (
) : visibleOrders.length === 0 ? (
<Card>
<CardContent className="py-10 text-center text-muted-foreground">
<ShoppingCart className="h-8 w-8 mx-auto mb-3" />
@ -444,7 +463,7 @@ export default function OrdersPage() {
<>
{searching && (
<p className="text-sm text-muted-foreground">
{orders.length} match{orders.length === 1 ? "" : "es"} in
{visibleOrders.length} match{visibleOrders.length === 1 ? "" : "es"} in
{" "}
{TAB_GROUP_VISUAL[activeTab].label} for
{" "}
@ -463,7 +482,7 @@ export default function OrdersPage() {
</p>
)}
<div className="space-y-3">
{orders.map(({ order, items, repName, tabGroups }) => (
{visibleOrders.map(({ order, items, repName, tabGroups }) => (
<OrderCard
key={order.id}
order={order}