Update BuyerOrderInfo.tsx
This commit is contained in:
@@ -10,22 +10,23 @@ import {
|
|||||||
TooltipProvider,
|
TooltipProvider,
|
||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from "@/components/ui/tooltip";
|
} from "@/components/ui/tooltip";
|
||||||
import { getCookie } from "@/lib/client-utils";
|
import { clientFetch } from "@/lib/client-utils";
|
||||||
import axios from "axios";
|
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
|
interface OrderProduct {
|
||||||
|
productId: string;
|
||||||
|
quantity: number;
|
||||||
|
pricePerUnit: number;
|
||||||
|
totalItemPrice: number;
|
||||||
|
}
|
||||||
|
|
||||||
interface Order {
|
interface Order {
|
||||||
_id: string;
|
_id: string;
|
||||||
orderId: number;
|
orderId: number;
|
||||||
status: string;
|
status: string;
|
||||||
totalPrice: number;
|
totalPrice: number;
|
||||||
orderDate: string;
|
orderDate: string;
|
||||||
products: Array<{
|
products: OrderProduct[];
|
||||||
productId: string;
|
|
||||||
quantity: number;
|
|
||||||
pricePerUnit: number;
|
|
||||||
totalItemPrice: number;
|
|
||||||
}>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BuyerOrderInfoProps {
|
interface BuyerOrderInfoProps {
|
||||||
@@ -33,17 +34,26 @@ interface BuyerOrderInfoProps {
|
|||||||
chatId: string;
|
chatId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component that displays order information for a buyer in a chat
|
||||||
|
* Shows a tooltip with recent orders and allows navigation to order details
|
||||||
|
*/
|
||||||
export default function BuyerOrderInfo({ buyerId, chatId }: BuyerOrderInfoProps) {
|
export default function BuyerOrderInfo({ buyerId, chatId }: BuyerOrderInfoProps) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
// State
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [orders, setOrders] = useState<Order[]>([]);
|
const [orders, setOrders] = useState<Order[]>([]);
|
||||||
const [hasOrders, setHasOrders] = useState<boolean | null>(null);
|
const [hasOrders, setHasOrders] = useState<boolean | null>(null);
|
||||||
const [isTooltipOpen, setIsTooltipOpen] = useState(false);
|
const [isTooltipOpen, setIsTooltipOpen] = useState(false);
|
||||||
|
|
||||||
|
// Refs to prevent unnecessary re-renders and API calls
|
||||||
const lastFetchedRef = useRef<number>(0);
|
const lastFetchedRef = useRef<number>(0);
|
||||||
const isFetchingRef = useRef<boolean>(false);
|
const isFetchingRef = useRef<boolean>(false);
|
||||||
const tooltipDelayRef = useRef<NodeJS.Timeout | null>(null);
|
|
||||||
|
|
||||||
// Fetch data without unnecessary dependencies to reduce render cycles
|
/**
|
||||||
|
* Fetch buyer orders from the API
|
||||||
|
*/
|
||||||
const fetchBuyerOrders = useCallback(async (force = false) => {
|
const fetchBuyerOrders = useCallback(async (force = false) => {
|
||||||
// Prevent multiple simultaneous fetches
|
// Prevent multiple simultaneous fetches
|
||||||
if (isFetchingRef.current) return;
|
if (isFetchingRef.current) return;
|
||||||
@@ -62,27 +72,12 @@ export default function BuyerOrderInfo({ buyerId, chatId }: BuyerOrderInfoProps)
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const authToken = getCookie("Authorization");
|
// Use clientFetch to handle auth and API routing automatically
|
||||||
|
const response = await clientFetch(`/chats/${chatId}/orders?limit=10`);
|
||||||
|
|
||||||
if (!authToken) {
|
if (response && response.orders) {
|
||||||
isFetchingRef.current = false;
|
setOrders(response.orders);
|
||||||
setLoading(false);
|
setHasOrders(response.orders.length > 0);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const authAxios = axios.create({
|
|
||||||
baseURL: process.env.NEXT_PUBLIC_API_URL,
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${authToken}`
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Use the new endpoint that works with sub-users
|
|
||||||
const response = await authAxios.get(`/chats/${chatId}/orders?limit=10`); // Limit to fewer orders for faster response
|
|
||||||
|
|
||||||
if (response.data && response.data.orders) {
|
|
||||||
setOrders(response.data.orders);
|
|
||||||
setHasOrders(response.data.orders.length > 0);
|
|
||||||
} else {
|
} else {
|
||||||
setHasOrders(false);
|
setHasOrders(false);
|
||||||
}
|
}
|
||||||
@@ -95,48 +90,44 @@ export default function BuyerOrderInfo({ buyerId, chatId }: BuyerOrderInfoProps)
|
|||||||
setLoading(false);
|
setLoading(false);
|
||||||
isFetchingRef.current = false;
|
isFetchingRef.current = false;
|
||||||
}
|
}
|
||||||
}, [chatId]); // Minimize dependencies even further
|
}, [chatId, orders.length, hasOrders]);
|
||||||
|
|
||||||
// Start fetching immediately when component mounts
|
// Fetch orders when component mounts
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (chatId) {
|
if (chatId) {
|
||||||
// Immediately attempt to fetch in the background
|
|
||||||
fetchBuyerOrders();
|
fetchBuyerOrders();
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
|
||||||
// Clean up any pending timeouts
|
|
||||||
if (tooltipDelayRef.current) {
|
|
||||||
clearTimeout(tooltipDelayRef.current);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, [chatId, fetchBuyerOrders]);
|
}, [chatId, fetchBuyerOrders]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigate to order details page
|
||||||
|
*/
|
||||||
const handleViewOrder = (orderId: string) => {
|
const handleViewOrder = (orderId: string) => {
|
||||||
router.push(`/dashboard/orders/${orderId}`);
|
router.push(`/dashboard/orders/${orderId}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle hover with immediate tooltip opening
|
/**
|
||||||
|
* Handle mouse enter on the button to start loading data
|
||||||
|
*/
|
||||||
const handleButtonMouseEnter = () => {
|
const handleButtonMouseEnter = () => {
|
||||||
// Start fetching data, but don't wait for it to complete
|
|
||||||
if (!isFetchingRef.current) {
|
if (!isFetchingRef.current) {
|
||||||
queueMicrotask(() => {
|
queueMicrotask(() => fetchBuyerOrders());
|
||||||
fetchBuyerOrders();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle tooltip state change
|
/**
|
||||||
|
* Handle tooltip state change, load data if opening
|
||||||
|
*/
|
||||||
const handleTooltipOpenChange = (open: boolean) => {
|
const handleTooltipOpenChange = (open: boolean) => {
|
||||||
setIsTooltipOpen(open);
|
setIsTooltipOpen(open);
|
||||||
if (open && !isFetchingRef.current) {
|
if (open && !isFetchingRef.current) {
|
||||||
queueMicrotask(() => {
|
queueMicrotask(() => fetchBuyerOrders());
|
||||||
fetchBuyerOrders();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Format the price as currency
|
/**
|
||||||
|
* Format price as currency
|
||||||
|
*/
|
||||||
const formatPrice = (price: number) => {
|
const formatPrice = (price: number) => {
|
||||||
return `£${price.toFixed(2)}`;
|
return `£${price.toFixed(2)}`;
|
||||||
};
|
};
|
||||||
@@ -146,13 +137,26 @@ export default function BuyerOrderInfo({ buyerId, chatId }: BuyerOrderInfoProps)
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Precompute product count for button display (only if we have orders)
|
// Calculate total products across all orders
|
||||||
const productCount = orders.length > 0
|
const productCount = orders.length > 0
|
||||||
? orders.reduce((total, order) => {
|
? orders.reduce((total, order) => {
|
||||||
return total + order.products.reduce((sum, product) => sum + product.quantity, 0);
|
return total + order.products.reduce((sum, product) => sum + product.quantity, 0);
|
||||||
}, 0)
|
}, 0)
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get badge variant based on order status
|
||||||
|
*/
|
||||||
|
const getStatusBadgeVariant = (status: string) => {
|
||||||
|
switch (status) {
|
||||||
|
case "paid": return "paid";
|
||||||
|
case "unpaid": return "unpaid";
|
||||||
|
case "shipped": return "shipped";
|
||||||
|
case "completed": return "completed";
|
||||||
|
default: return "secondary";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TooltipProvider>
|
<TooltipProvider>
|
||||||
<Tooltip onOpenChange={handleTooltipOpenChange}>
|
<Tooltip onOpenChange={handleTooltipOpenChange}>
|
||||||
@@ -211,13 +215,10 @@ export default function BuyerOrderInfo({ buyerId, chatId }: BuyerOrderInfoProps)
|
|||||||
<Package className="h-3.5 w-3.5" />
|
<Package className="h-3.5 w-3.5" />
|
||||||
<span className="text-xs font-medium">Order #{order.orderId}</span>
|
<span className="text-xs font-medium">Order #{order.orderId}</span>
|
||||||
</div>
|
</div>
|
||||||
<Badge variant={
|
<Badge
|
||||||
order.status === "paid" ? "paid" :
|
variant={getStatusBadgeVariant(order.status)}
|
||||||
order.status === "unpaid" ? "unpaid" :
|
className="text-[10px] h-5 px-1.5"
|
||||||
order.status === "shipped" ? "shipped" :
|
>
|
||||||
order.status === "completed" ? "completed" :
|
|
||||||
"secondary"
|
|
||||||
} className="text-[10px] h-5 px-1.5">
|
|
||||||
{order.status.toUpperCase()}
|
{order.status.toUpperCase()}
|
||||||
</Badge>
|
</Badge>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user