feat(orders): filter list to the logged-in rep's own orders
This commit is contained in:
parent
d23c811b91
commit
defa481661
1 changed files with 23 additions and 4 deletions
|
|
@ -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}
|
||||
|
|
|
|||
Loading…
Reference in a new issue