Skip to content

Commit b010dd4

Browse files
committed
Improve capacity matrix performance with lazy loading and better UX
- Add beautiful skeleton loading placeholders for initial page load - Add individual cell skeletons during data refresh - Create click-to-manage dialog for easy schedule adjustment per day - Add day navigation (prev/next) within the schedule dialog - Memoize components and data lookups for better performance - Replace full page reload with React Query cache invalidation - Add staleTime to queries for better caching - Use conditional query fetching (operations only loaded as fallback) - Add hover effects and click hints for better UX
1 parent 641e1d8 commit b010dd4

File tree

4 files changed

+724
-128
lines changed

4 files changed

+724
-128
lines changed
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import { Skeleton } from "@/components/ui/skeleton";
2+
import { Card, CardContent, CardHeader } from "@/components/ui/card";
3+
4+
interface CapacityMatrixSkeletonProps {
5+
rowCount?: number;
6+
columnCount?: number;
7+
}
8+
9+
export function CapacityMatrixSkeleton({
10+
rowCount = 6,
11+
columnCount = 14
12+
}: CapacityMatrixSkeletonProps) {
13+
return (
14+
<div className="p-6 space-y-6">
15+
{/* Header skeleton */}
16+
<div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
17+
<div className="space-y-2">
18+
<Skeleton className="h-9 w-48" />
19+
<Skeleton className="h-5 w-72" />
20+
</div>
21+
<div className="flex items-center gap-4">
22+
<Skeleton className="h-10 w-32" />
23+
<div className="flex items-center gap-2">
24+
<Skeleton className="h-10 w-10" />
25+
<Skeleton className="h-6 w-44" />
26+
<Skeleton className="h-10 w-10" />
27+
</div>
28+
</div>
29+
</div>
30+
31+
{/* Legend skeleton */}
32+
<div className="flex flex-wrap gap-2">
33+
{[1, 2, 3, 4, 5].map((i) => (
34+
<Skeleton key={i} className="h-6 w-24" />
35+
))}
36+
</div>
37+
38+
{/* Table skeleton */}
39+
<Card>
40+
<CardHeader className="pb-2">
41+
<Skeleton className="h-6 w-44" />
42+
<Skeleton className="h-4 w-64 mt-1" />
43+
</CardHeader>
44+
<CardContent className="overflow-x-auto">
45+
<div className="w-full">
46+
{/* Header row */}
47+
<div className="flex border-b pb-2 mb-2">
48+
<div className="min-w-[150px] p-2">
49+
<Skeleton className="h-5 w-12" />
50+
</div>
51+
{Array.from({ length: columnCount }).map((_, i) => (
52+
<div key={i} className="min-w-[80px] p-2 text-center">
53+
<Skeleton className="h-4 w-8 mx-auto mb-1" />
54+
<Skeleton className="h-5 w-5 mx-auto" />
55+
</div>
56+
))}
57+
</div>
58+
59+
{/* Body rows */}
60+
{Array.from({ length: rowCount }).map((_, rowIndex) => (
61+
<div
62+
key={rowIndex}
63+
className="flex border-b py-1"
64+
style={{
65+
animationDelay: `${rowIndex * 100}ms`,
66+
opacity: 1 - (rowIndex * 0.1)
67+
}}
68+
>
69+
<div className="min-w-[150px] p-3">
70+
<div className="flex items-center gap-2">
71+
<Skeleton className="w-3 h-3 rounded-full" />
72+
<Skeleton className="h-5 w-20" />
73+
</div>
74+
<Skeleton className="h-3 w-24 mt-1 ml-5" />
75+
</div>
76+
{Array.from({ length: columnCount }).map((_, colIndex) => (
77+
<div key={colIndex} className="min-w-[80px] p-1">
78+
<Skeleton
79+
className="h-12 w-full rounded-md"
80+
style={{
81+
animationDelay: `${(rowIndex * columnCount + colIndex) * 20}ms`
82+
}}
83+
/>
84+
</div>
85+
))}
86+
</div>
87+
))}
88+
</div>
89+
</CardContent>
90+
</Card>
91+
</div>
92+
);
93+
}
94+
95+
// Inline skeleton for individual cells when updating
96+
export function CellSkeleton() {
97+
return (
98+
<div className="rounded-md p-2 bg-muted animate-pulse">
99+
<Skeleton className="h-4 w-8 mx-auto mb-1" />
100+
<Skeleton className="h-3 w-12 mx-auto" />
101+
</div>
102+
);
103+
}

0 commit comments

Comments
 (0)