Update loading states
This commit is contained in:
@@ -62,43 +62,73 @@ import {
|
||||
|
||||
// Mini skeleton components
|
||||
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">
|
||||
{/* Grid lines */}
|
||||
{[...Array(5)].map((_, i) => (
|
||||
<div
|
||||
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}%` }}
|
||||
/>
|
||||
))}
|
||||
{/* 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) => (
|
||||
<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>
|
||||
{/* 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) => (
|
||||
<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>
|
||||
{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) => (
|
||||
<div
|
||||
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}%` }}
|
||||
/>
|
||||
))}
|
||||
</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="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={{
|
||||
opacity: 0.5,
|
||||
clipPath: "polygon(0 50%, 100% 20%, 100% 100%, 0 100%)",
|
||||
@@ -111,33 +141,68 @@ const MiniSkeletonChart = ({ type = "line" }) => (
|
||||
</div>
|
||||
);
|
||||
|
||||
const MiniSkeletonTable = ({ rows = 8 }) => (
|
||||
<div className="rounded-lg border bg-white dark:bg-gray-900/60 backdrop-blur-sm">
|
||||
const MiniSkeletonTable = ({ rows = 8, colorScheme = "orange" }) => (
|
||||
<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>
|
||||
<TableHeader>
|
||||
<TableRow className="dark:border-gray-800">
|
||||
<TableRow>
|
||||
<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 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 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>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{[...Array(rows)].map((_, i) => (
|
||||
<TableRow key={i} className="dark:border-gray-800">
|
||||
<TableRow key={i}>
|
||||
<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 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 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>
|
||||
</TableRow>
|
||||
))}
|
||||
@@ -465,7 +530,9 @@ const MiniStatCards = ({
|
||||
<div className="flex items-center gap-1">
|
||||
<span>Proj: </span>
|
||||
{projectionLoading ? (
|
||||
<Skeleton className="h-4 w-15" />
|
||||
<div className="w-20">
|
||||
<Skeleton className="h-4 w-15 bg-emerald-700" />
|
||||
</div>
|
||||
) : (
|
||||
formatCurrency(
|
||||
projection?.projectedRevenue || stats.projectedRevenue
|
||||
@@ -476,7 +543,16 @@ const MiniStatCards = ({
|
||||
}
|
||||
progress={stats?.periodProgress < 100 ? stats.periodProgress : undefined}
|
||||
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"
|
||||
titleClass="text-emerald-100 font-bold text-md"
|
||||
descriptionClass="text-emerald-200 text-md font-semibold"
|
||||
@@ -576,11 +652,20 @@ const MiniStatCards = ({
|
||||
{detailDataLoading[selectedMetric] ? (
|
||||
<div className="space-y-4 h-full">
|
||||
{selectedMetric === "shipping" ? (
|
||||
<MiniSkeletonTable rows={8} />
|
||||
<MiniSkeletonTable
|
||||
rows={8}
|
||||
colorScheme={
|
||||
selectedMetric === 'revenue' ? 'emerald' :
|
||||
selectedMetric === 'orders' ? 'blue' :
|
||||
selectedMetric === 'average_order' ? 'violet' :
|
||||
'orange'
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<MiniSkeletonChart
|
||||
type={selectedMetric === "orders" ? "bar" : "line"}
|
||||
metric={selectedMetric}
|
||||
/>
|
||||
{selectedMetric === "orders" && (
|
||||
<div className="mt-8">
|
||||
@@ -593,7 +678,7 @@ const MiniStatCards = ({
|
||||
}`}>
|
||||
Hourly Distribution
|
||||
</h3>
|
||||
<MiniSkeletonChart type="bar" />
|
||||
<MiniSkeletonChart type="bar" metric={selectedMetric} />
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user