Optimize product detail analytics loading
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 43s

This commit is contained in:
Cauê Faleiros
2026-06-22 15:49:40 -03:00
parent 3cd4bfc426
commit 62e0239ee4
7 changed files with 280 additions and 60 deletions

View File

@@ -1,10 +1,10 @@
import { useMemo } from 'react';
import { useEffect, useState } from 'react';
import { useParams, Link, useOutletContext } from 'react-router-dom';
import { ArrowLeft, Package, DollarSign } from 'lucide-react';
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts';
import DateRangePicker from '../components/DateRangePicker';
import type { OrderData, DateRange } from '../types';
import { buildProductDetailsMetrics } from '../analytics/products';
import type { DateRange, ProductDetailsAnalytics } from '../types';
import { fetchProductDetailsAnalytics } from '../dataService';
type CustomTooltipProps = {
active?: boolean;
@@ -26,25 +26,46 @@ const CustomTooltip = ({ active, payload, label }: CustomTooltipProps) => {
const ProductDetails = () => {
const { id } = useParams<{ id: string }>();
const { dateRange, setDateRange, ordersData, isDataLoading } = useOutletContext<{
const { dateRange, setDateRange } = useOutletContext<{
dateRange: DateRange,
setDateRange: (range: DateRange) => void,
ordersData: OrderData[],
isDataLoading: boolean,
refreshInterval: number,
setRefreshInterval: (interval: number) => void,
loadData: (showLoading?: boolean) => void
setDateRange: (range: DateRange) => void
}>();
const [details, setDetails] = useState<ProductDetailsAnalytics | null>(null);
const [isLoading, setIsLoading] = useState(true);
const { productInfo, chartData, totalSold, totalRevenue } = useMemo(() => {
return buildProductDetailsMetrics(ordersData, id, dateRange);
}, [id, dateRange, ordersData]);
useEffect(() => {
let isMounted = true;
const loadProductDetails = async () => {
if (!id) {
if (isMounted) {
setDetails(null);
setIsLoading(false);
}
return;
}
setIsLoading(true);
const productDetails = await fetchProductDetailsAnalytics(id, dateRange);
if (isMounted) {
setDetails(productDetails);
setIsLoading(false);
}
};
void loadProductDetails();
return () => {
isMounted = false;
};
}, [dateRange, id]);
const formatCurrency = (value: number) => {
return new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(value);
};
if (!productInfo && isDataLoading) {
if (isLoading) {
return (
<div className="text-center py-12">
<p className="text-zinc-500 dark:text-dark-muted font-medium">Carregando produto...</p>
@@ -52,7 +73,7 @@ const ProductDetails = () => {
);
}
if (!productInfo) {
if (!details?.productInfo) {
return (
<div className="text-center py-12">
<p className="text-zinc-500 dark:text-dark-muted font-medium">Produto não encontrado.</p>
@@ -61,6 +82,8 @@ const ProductDetails = () => {
);
}
const { productInfo, chartData, totalSold, totalRevenue } = details;
return (
<div className="space-y-6">
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4">