Skip to content

Commit 1a90366

Browse files
committed
improve inhouse loading skeleton and theme
1 parent f90db51 commit 1a90366

7 files changed

Lines changed: 375 additions & 27 deletions

File tree

‎apps/codebility/app/home/in-house/_components/InHouseView.tsx‎

Lines changed: 46 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use client";
22

3-
import { useState } from "react";
3+
import { useState, useTransition } from "react";
44
import { H1 } from "@/components/shared/home";
55
import usePagination from "@/hooks/use-pagination";
66
import { Codev } from "@/types/home/codev";
@@ -10,6 +10,7 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@codevs/ui/tabs";
1010
import { getMemberStats } from "../_lib/utils";
1111
import { InHouseTable } from "./table/InHouseTable";
1212
import { TableFilters } from "./table/table-filters";
13+
import { InHouseTableSkeleton } from "./skeletons/InHouseLoadingSkeleton";
1314

1415
interface InHouseViewProps {
1516
initialData: Codev[];
@@ -18,6 +19,7 @@ interface InHouseViewProps {
1819
export default function InHouseView({ initialData }: InHouseViewProps) {
1920
const [data, setData] = useState<Codev[]>(initialData);
2021
const [activeTab, setActiveTab] = useState<"active" | "inactive">("active");
22+
const [isPending, startTransition] = useTransition();
2123
const stats = getMemberStats(data);
2224

2325
// Filters
@@ -123,7 +125,7 @@ export default function InHouseView({ initialData }: InHouseViewProps) {
123125
<div className="flex items-center gap-3">
124126
<H1 className="text-lg sm:text-xl">In-House Codebility</H1>
125127
<div className="flex items-center gap-1 text-[10px]">
126-
<span className="rounded-full bg-customBlue-500/10 px-1.5 py-0.5 text-[10px] font-medium text-customBlue-600 dark:text-customBlue-400">
128+
<span className="rounded-full bg-customBlue-500/10 px-1.5 py-0.5 text-[10px] font-medium text-customBlue-600 dark:text-blue-400">
127129
{stats.total} {stats.total === 1 ? "member" : "members"}
128130
</span>
129131
<span className="rounded-full bg-emerald-500/10 px-1.5 py-0.5 text-[10px] font-medium text-emerald-600 dark:text-emerald-400">
@@ -138,7 +140,11 @@ export default function InHouseView({ initialData }: InHouseViewProps) {
138140

139141
{/* Tabs for Active/Inactive */}
140142
<div className="flex flex-col gap-4">
141-
<Tabs value={activeTab} onValueChange={(value) => setActiveTab(value as "active" | "inactive")} className="w-full">
143+
<Tabs value={activeTab} onValueChange={(value) => {
144+
startTransition(() => {
145+
setActiveTab(value as "active" | "inactive");
146+
});
147+
}} className="w-full">
142148
<TabsList className="grid h-9 w-full max-w-[280px] grid-cols-2 bg-gray-100 dark:bg-gray-800">
143149
<TabsTrigger value="active" className="flex h-8 items-center gap-1 text-xs">
144150
Active
@@ -157,33 +163,47 @@ export default function InHouseView({ initialData }: InHouseViewProps) {
157163

158164
<TableFilters
159165
filters={filters}
160-
onFilterChange={(key, value) =>
161-
setFilters((prev) => ({ ...prev, [key]: value }))
162-
}
166+
onFilterChange={(key, value) => {
167+
startTransition(() => {
168+
setFilters((prev) => ({ ...prev, [key]: value }));
169+
});
170+
}}
163171
/>
164172
</div>
165173
</div>
166174

167-
{/* Table View */}
168-
<InHouseTable
169-
// pass only the paginated subset in:
170-
data={paginatedData}
171-
// but merge edits into the **full** data array here:
172-
onDataChange={(updatedItem: Codev) => {
173-
setData((prev) =>
174-
prev.map((d) => (d.id === updatedItem.id ? updatedItem : d)),
175-
);
176-
}}
177-
onDelete={(deletedId: string) => {
178-
setData((prev) => prev.filter((d) => d.id !== deletedId));
179-
}}
180-
pagination={{
181-
currentPage,
182-
totalPages,
183-
onNextPage: handleNextPage,
184-
onPreviousPage: handlePreviousPage,
185-
}}
186-
/>
175+
{/* Table View with Loading State */}
176+
{isPending ? (
177+
<InHouseTableSkeleton rows={10} />
178+
) : filteredData.length === 0 ? (
179+
<div className="flex min-h-[400px] flex-col items-center justify-center p-8 text-center">
180+
<div className="mb-4 text-4xl">🔍</div>
181+
<h3 className="mb-2 text-lg font-medium text-gray-900 dark:text-white">No members found</h3>
182+
<p className="text-gray-600 dark:text-gray-400">
183+
Try adjusting your filters or search terms to find what you're looking for.
184+
</p>
185+
</div>
186+
) : (
187+
<InHouseTable
188+
// pass only the paginated subset in:
189+
data={paginatedData}
190+
// but merge edits into the **full** data array here:
191+
onDataChange={(updatedItem: Codev) => {
192+
setData((prev) =>
193+
prev.map((d) => (d.id === updatedItem.id ? updatedItem : d)),
194+
);
195+
}}
196+
onDelete={(deletedId: string) => {
197+
setData((prev) => prev.filter((d) => d.id !== deletedId));
198+
}}
199+
pagination={{
200+
currentPage,
201+
totalPages,
202+
onNextPage: handleNextPage,
203+
onPreviousPage: handlePreviousPage,
204+
}}
205+
/>
206+
)}
187207
</div>
188208
);
189209
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { Skeleton } from "@codevs/ui/skeleton";
2+
3+
export function InHouseHeaderSkeleton() {
4+
return (
5+
<div className="flex flex-col gap-2">
6+
<div className="flex flex-col gap-2">
7+
{/* Title and stats skeleton */}
8+
<div className="flex items-center justify-between">
9+
<div className="flex items-center gap-3">
10+
{/* Page title skeleton */}
11+
<Skeleton className="h-6 w-48" />
12+
13+
{/* Stats badges skeleton */}
14+
<div className="flex items-center gap-1 text-[10px]">
15+
<Skeleton className="h-5 w-20 rounded-full" />
16+
<Skeleton className="h-5 w-16 rounded-full" />
17+
<Skeleton className="h-5 w-18 rounded-full" />
18+
</div>
19+
</div>
20+
</div>
21+
22+
{/* Tabs and filters skeleton */}
23+
<div className="flex flex-col gap-4">
24+
{/* Tabs skeleton */}
25+
<div className="flex gap-2">
26+
<div className="grid h-9 w-full max-w-[280px] grid-cols-2 gap-1 rounded-md bg-gray-100 p-1 dark:bg-gray-800">
27+
<Skeleton className="h-7 w-full rounded-sm" />
28+
<Skeleton className="h-7 w-full rounded-sm" />
29+
</div>
30+
</div>
31+
32+
{/* Filters skeleton */}
33+
<div className="flex flex-wrap gap-4">
34+
{/* Search filter skeleton */}
35+
<div className="min-w-[250px] flex-1">
36+
<Skeleton className="h-9 w-full rounded-md" />
37+
</div>
38+
39+
{/* Status filter skeleton */}
40+
<div className="min-w-[120px]">
41+
<Skeleton className="h-9 w-full rounded-md" />
42+
</div>
43+
44+
{/* Position filter skeleton */}
45+
<div className="min-w-[150px]">
46+
<Skeleton className="h-9 w-full rounded-md" />
47+
</div>
48+
49+
{/* Project filter skeleton */}
50+
<div className="min-w-[130px]">
51+
<Skeleton className="h-9 w-full rounded-md" />
52+
</div>
53+
54+
{/* NDA filter skeleton */}
55+
<div className="min-w-[120px]">
56+
<Skeleton className="h-9 w-full rounded-md" />
57+
</div>
58+
59+
{/* Role filter skeleton */}
60+
<div className="min-w-[110px]">
61+
<Skeleton className="h-9 w-full rounded-md" />
62+
</div>
63+
64+
{/* Available filter skeleton */}
65+
<div className="min-w-[140px]">
66+
<Skeleton className="h-9 w-full rounded-md" />
67+
</div>
68+
</div>
69+
</div>
70+
</div>
71+
</div>
72+
);
73+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { InHouseHeaderSkeleton } from "./InHouseHeaderSkeleton";
2+
import { InHouseTableSkeleton } from "./InHouseTableSkeleton";
3+
4+
interface InHouseLoadingSkeletonProps {
5+
rows?: number;
6+
}
7+
8+
export function InHouseLoadingSkeleton({ rows = 8 }: InHouseLoadingSkeletonProps) {
9+
return (
10+
<div className="flex flex-col gap-4">
11+
{/* Header with title, stats, tabs and filters skeleton */}
12+
<InHouseHeaderSkeleton />
13+
14+
{/* Table skeleton */}
15+
<InHouseTableSkeleton rows={rows} />
16+
</div>
17+
);
18+
}
19+
20+
// Export individual components for more granular use
21+
export { InHouseHeaderSkeleton, InHouseTableSkeleton };

0 commit comments

Comments
 (0)