Update loading states

This commit is contained in:
2025-01-02 17:08:57 -05:00
parent 375ef6860b
commit 08ddba358a

View File

@@ -62,43 +62,73 @@ import {
// Mini skeleton components // Mini skeleton components
const MiniSkeletonChart = ({ type = "line" }) => ( const MiniSkeletonChart = ({ type = "line" }) => (
<div className="h-[200px] w-full bg-white dark:bg-gray-900/60 backdrop-blur-sm rounded-lg p-4"> <div className={`h-[230px] w-full ${
type === 'revenue' ? 'bg-emerald-50/10' :
type === 'orders' ? 'bg-blue-50/10' :
type === 'average_order' ? 'bg-violet-50/10' :
'bg-orange-50/10'
} rounded-lg p-4`}>
<div className="h-full relative"> <div className="h-full relative">
{/* Grid lines */} {/* Grid lines */}
{[...Array(5)].map((_, i) => ( {[...Array(5)].map((_, i) => (
<div <div
key={i} key={i}
className="absolute w-full h-px bg-muted" className={`absolute w-full h-px ${
type === 'revenue' ? 'bg-emerald-200/20' :
type === 'orders' ? 'bg-blue-200/20' :
type === 'average_order' ? 'bg-violet-200/20' :
'bg-orange-200/20'
}`}
style={{ top: `${(i + 1) * 20}%` }} style={{ top: `${(i + 1) * 20}%` }}
/> />
))} ))}
{/* Y-axis labels */} {/* Y-axis labels */}
<div className="absolute left-0 top-0 bottom-0 w-6 flex flex-col justify-between py-2"> <div className="absolute left-0 top-0 bottom-0 w-8 flex flex-col justify-between py-4">
{[...Array(5)].map((_, i) => ( {[...Array(5)].map((_, i) => (
<Skeleton key={i} className="h-2 w-4 bg-muted rounded-sm" /> <Skeleton key={i} className={`h-3 w-6 ${
type === 'revenue' ? 'bg-emerald-200/20' :
type === 'orders' ? 'bg-blue-200/20' :
type === 'average_order' ? 'bg-violet-200/20' :
'bg-orange-200/20'
} rounded-sm`} />
))} ))}
</div> </div>
{/* X-axis labels */} {/* X-axis labels */}
<div className="absolute left-6 right-2 bottom-0 flex justify-between"> <div className="absolute left-8 right-4 bottom-0 flex justify-between">
{[...Array(6)].map((_, i) => ( {[...Array(6)].map((_, i) => (
<Skeleton key={i} className="h-2 w-6 bg-muted rounded-sm" /> <Skeleton key={i} className={`h-3 w-8 ${
type === 'revenue' ? 'bg-emerald-200/20' :
type === 'orders' ? 'bg-blue-200/20' :
type === 'average_order' ? 'bg-violet-200/20' :
'bg-orange-200/20'
} rounded-sm`} />
))} ))}
</div> </div>
{type === "bar" ? ( {type === "bar" ? (
<div className="absolute inset-x-6 bottom-4 top-2 flex items-end justify-between gap-1"> <div className="absolute inset-x-8 bottom-6 top-4 flex items-end justify-between gap-1">
{[...Array(24)].map((_, i) => ( {[...Array(24)].map((_, i) => (
<div <div
key={i} key={i}
className="w-1 bg-muted rounded-sm" className={`w-2 ${
type === 'revenue' ? 'bg-emerald-200/20' :
type === 'orders' ? 'bg-blue-200/20' :
type === 'average_order' ? 'bg-violet-200/20' :
'bg-orange-200/20'
} rounded-sm`}
style={{ height: `${Math.random() * 80 + 10}%` }} style={{ height: `${Math.random() * 80 + 10}%` }}
/> />
))} ))}
</div> </div>
) : ( ) : (
<div className="absolute inset-x-6 bottom-4 top-2"> <div className="absolute inset-x-8 bottom-6 top-4">
<div className="h-full w-full relative"> <div className="h-full w-full relative">
<div <div
className="absolute inset-0 bg-muted rounded-sm" className={`absolute inset-0 ${
type === 'revenue' ? 'bg-emerald-200/20' :
type === 'orders' ? 'bg-blue-200/20' :
type === 'average_order' ? 'bg-violet-200/20' :
'bg-orange-200/20'
} rounded-sm`}
style={{ style={{
opacity: 0.5, opacity: 0.5,
clipPath: "polygon(0 50%, 100% 20%, 100% 100%, 0 100%)", clipPath: "polygon(0 50%, 100% 20%, 100% 100%, 0 100%)",
@@ -111,33 +141,68 @@ const MiniSkeletonChart = ({ type = "line" }) => (
</div> </div>
); );
const MiniSkeletonTable = ({ rows = 8 }) => ( const MiniSkeletonTable = ({ rows = 8, colorScheme = "orange" }) => (
<div className="rounded-lg border bg-white dark:bg-gray-900/60 backdrop-blur-sm"> <div className={`rounded-lg border ${
colorScheme === 'orange' ? 'bg-orange-50/10 border-orange-200/20' :
colorScheme === 'emerald' ? 'bg-emerald-50/10 border-emerald-200/20' :
colorScheme === 'blue' ? 'bg-blue-50/10 border-blue-200/20' :
'bg-violet-50/10 border-violet-200/20'
}`}>
<Table> <Table>
<TableHeader> <TableHeader>
<TableRow className="dark:border-gray-800"> <TableRow>
<TableHead> <TableHead>
<Skeleton className="h-3 w-24 bg-muted rounded-sm" /> <Skeleton className={`h-4 w-32 ${
colorScheme === 'orange' ? 'bg-orange-200/20' :
colorScheme === 'emerald' ? 'bg-emerald-200/20' :
colorScheme === 'blue' ? 'bg-blue-200/20' :
'bg-violet-200/20'
} rounded-sm`} />
</TableHead> </TableHead>
<TableHead className="text-right"> <TableHead className="text-right">
<Skeleton className="h-3 w-16 ml-auto bg-muted rounded-sm" /> <Skeleton className={`h-4 w-24 ml-auto ${
colorScheme === 'orange' ? 'bg-orange-200/20' :
colorScheme === 'emerald' ? 'bg-emerald-200/20' :
colorScheme === 'blue' ? 'bg-blue-200/20' :
'bg-violet-200/20'
} rounded-sm`} />
</TableHead> </TableHead>
<TableHead className="text-right"> <TableHead className="text-right">
<Skeleton className="h-3 w-16 ml-auto bg-muted rounded-sm" /> <Skeleton className={`h-4 w-24 ml-auto ${
colorScheme === 'orange' ? 'bg-orange-200/20' :
colorScheme === 'emerald' ? 'bg-emerald-200/20' :
colorScheme === 'blue' ? 'bg-blue-200/20' :
'bg-violet-200/20'
} rounded-sm`} />
</TableHead> </TableHead>
</TableRow> </TableRow>
</TableHeader> </TableHeader>
<TableBody> <TableBody>
{[...Array(rows)].map((_, i) => ( {[...Array(rows)].map((_, i) => (
<TableRow key={i} className="dark:border-gray-800"> <TableRow key={i}>
<TableCell> <TableCell>
<Skeleton className="h-3 w-32 bg-muted rounded-sm" /> <Skeleton className={`h-4 w-48 ${
colorScheme === 'orange' ? 'bg-orange-200/20' :
colorScheme === 'emerald' ? 'bg-emerald-200/20' :
colorScheme === 'blue' ? 'bg-blue-200/20' :
'bg-violet-200/20'
} rounded-sm`} />
</TableCell> </TableCell>
<TableCell className="text-right"> <TableCell className="text-right">
<Skeleton className="h-3 w-12 ml-auto bg-muted rounded-sm" /> <Skeleton className={`h-4 w-16 ml-auto ${
colorScheme === 'orange' ? 'bg-orange-200/20' :
colorScheme === 'emerald' ? 'bg-emerald-200/20' :
colorScheme === 'blue' ? 'bg-blue-200/20' :
'bg-violet-200/20'
} rounded-sm`} />
</TableCell> </TableCell>
<TableCell className="text-right"> <TableCell className="text-right">
<Skeleton className="h-3 w-12 ml-auto bg-muted rounded-sm" /> <Skeleton className={`h-4 w-16 ml-auto ${
colorScheme === 'orange' ? 'bg-orange-200/20' :
colorScheme === 'emerald' ? 'bg-emerald-200/20' :
colorScheme === 'blue' ? 'bg-blue-200/20' :
'bg-violet-200/20'
} rounded-sm`} />
</TableCell> </TableCell>
</TableRow> </TableRow>
))} ))}
@@ -465,7 +530,9 @@ const MiniStatCards = ({
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<span>Proj: </span> <span>Proj: </span>
{projectionLoading ? ( {projectionLoading ? (
<Skeleton className="h-4 w-15" /> <div className="w-20">
<Skeleton className="h-4 w-15 bg-emerald-700" />
</div>
) : ( ) : (
formatCurrency( formatCurrency(
projection?.projectedRevenue || stats.projectedRevenue projection?.projectedRevenue || stats.projectedRevenue
@@ -476,7 +543,16 @@ const MiniStatCards = ({
} }
progress={stats?.periodProgress < 100 ? stats.periodProgress : undefined} progress={stats?.periodProgress < 100 ? stats.periodProgress : undefined}
trend={projectionLoading && stats?.periodProgress < 100 ? undefined : revenueTrend?.trend} trend={projectionLoading && stats?.periodProgress < 100 ? undefined : revenueTrend?.trend}
trendValue={revenueTrend?.value ? formatPercentage(revenueTrend.value) : null} trendValue={
projectionLoading && stats?.periodProgress < 100 ? (
<div className="flex items-center gap-1">
<Skeleton className="h-4 w-4 bg-emerald-700 rounded-full" />
<Skeleton className="h-4 w-8 bg-emerald-700" />
</div>
) : revenueTrend?.value ? (
formatPercentage(revenueTrend.value)
) : null
}
colorClass="text-emerald-200" colorClass="text-emerald-200"
titleClass="text-emerald-100 font-bold text-md" titleClass="text-emerald-100 font-bold text-md"
descriptionClass="text-emerald-200 text-md font-semibold" descriptionClass="text-emerald-200 text-md font-semibold"
@@ -576,11 +652,20 @@ const MiniStatCards = ({
{detailDataLoading[selectedMetric] ? ( {detailDataLoading[selectedMetric] ? (
<div className="space-y-4 h-full"> <div className="space-y-4 h-full">
{selectedMetric === "shipping" ? ( {selectedMetric === "shipping" ? (
<MiniSkeletonTable rows={8} /> <MiniSkeletonTable
rows={8}
colorScheme={
selectedMetric === 'revenue' ? 'emerald' :
selectedMetric === 'orders' ? 'blue' :
selectedMetric === 'average_order' ? 'violet' :
'orange'
}
/>
) : ( ) : (
<> <>
<MiniSkeletonChart <MiniSkeletonChart
type={selectedMetric === "orders" ? "bar" : "line"} type={selectedMetric === "orders" ? "bar" : "line"}
metric={selectedMetric}
/> />
{selectedMetric === "orders" && ( {selectedMetric === "orders" && (
<div className="mt-8"> <div className="mt-8">
@@ -593,7 +678,7 @@ const MiniStatCards = ({
}`}> }`}>
Hourly Distribution Hourly Distribution
</h3> </h3>
<MiniSkeletonChart type="bar" /> <MiniSkeletonChart type="bar" metric={selectedMetric} />
</div> </div>
)} )}
</> </>