Skip to content

Commit 6ca55ec

Browse files
committed
skeleton loader
1 parent 542c5d4 commit 6ca55ec

File tree

8 files changed

+4131
-2138
lines changed

8 files changed

+4131
-2138
lines changed

package-lock.json

+3,911-2,105
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@
9090
"react-i18next": "^11.18.6",
9191
"react-icons": "^4.10.1",
9292
"react-loader-spinner": "^5.4.5",
93+
"react-loading-skeleton": "^3.4.0",
9394
"react-pdf": "^7.3.3",
9495
"react-pdf-js": "^5.1.0",
9596
"react-router": "^6.14.1",

src/Skeletons/Calender.Skeleton.tsx

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import React from 'react';
2+
3+
function CalendarSkeleton() {
4+
// Define unique identifiers for calendar days
5+
const days = Array.from({ length: 35 }, (_, i) => ({ id: `day-${i + 1}` })); // 35 days with unique ids
6+
// Define unique identifiers for events
7+
const events = [{ id: 'event-1' }, { id: 'event-2' }]; // Define event placeholders with unique ids
8+
9+
return (
10+
<div className="bg-light-bg dark:bg-dark-frame-bg pb-10">
11+
<div className="animate-pulse">
12+
{/* Month and Year Display */}
13+
<div className="flex justify-between items-center mb-4">
14+
<div className="h-6 bg-gray-200 rounded w-24" />
15+
<div className="h-6 bg-gray-200 rounded w-16" />
16+
</div>
17+
18+
{/* Calendar Grid */}
19+
<div className="grid grid-cols-7 gap-1">
20+
{/* Weekdays Headers */}
21+
{[
22+
'Sunday',
23+
'Monday',
24+
'Tuesday',
25+
'Wednesday',
26+
'Thursday',
27+
'Friday',
28+
'Saturday',
29+
].map((day) => (
30+
<div key={day} className="h-6 bg-gray-200 rounded text-center">
31+
<div className="h-4 bg-gray-200 rounded w-1/2 mx-auto" />
32+
</div>
33+
))}
34+
35+
{/* Calendar Days */}
36+
{days.map((day) => (
37+
<div
38+
key={day.id}
39+
className="h-20 bg-gray-200 rounded p-2 flex flex-col justify-between"
40+
>
41+
<div className="h-4 bg-gray-200 rounded w-1/4" />
42+
{/* Additional skeleton elements can be added here */}
43+
</div>
44+
))}
45+
</div>
46+
47+
{/* Event List */}
48+
<div className="mt-4 space-y-2">
49+
{events.map((event) => (
50+
<div
51+
key={event.id}
52+
className="flex items-center justify-between p-2 bg-gray-800 rounded"
53+
>
54+
<div className="h-4 bg-gray-200 rounded w-3/4" />
55+
<div className="h-4 bg-gray-200 rounded w-6" />
56+
</div>
57+
))}
58+
</div>
59+
</div>
60+
</div>
61+
);
62+
}
63+
64+
export default CalendarSkeleton;
+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import React from 'react';
2+
3+
function OrganizationTableSkeleton() {
4+
// Define unique identifiers for rows and headers
5+
const rows = [{ id: 'row-1' }, { id: 'row-2' }, { id: 'row-3' }];
6+
const headers = [
7+
{ id: 'header-1' },
8+
{ id: 'header-2' },
9+
{ id: 'header-3' },
10+
{ id: 'header-4' },
11+
];
12+
13+
return (
14+
<div className="bg-light-bg dark:bg-dark-frame-bg pb-10">
15+
<div className="bg-white dark:bg-dark-bg shadow-lg px-5 py-8 rounded-md w-full">
16+
<div className="animate-pulse">
17+
{/* Table Title Skeleton */}
18+
<div className="flex ml-2 items-center justify-between mb-4">
19+
<div
20+
className="h-6 bg-gray-200 rounded w-1/3"
21+
aria-label="Loading table title"
22+
/>
23+
</div>
24+
25+
<div className="-mx-4 sm:-mx-8 px-4 sm:px-8 py-2 overflow-x-auto">
26+
<div className="inline-block w-full lg:min-w-full shadow rounded-lg overflow-hidden">
27+
<table className="min-w-full leading-normal">
28+
<thead>
29+
<tr>
30+
{headers.map((header) => (
31+
<th
32+
key={header.id} // Use header.id for unique keys
33+
className="p-6 border-b-2 border-gray-200 bg-gray-100 dark:bg-neutral-600 text-center text-xs font-semibold text-gray-600 dark:text-white uppercase tracking-wider"
34+
>
35+
<div
36+
className="h-4 bg-gray-200 rounded w-1/4 mx-auto"
37+
aria-label={`Loading content for ${header.id}`}
38+
/>
39+
</th>
40+
))}
41+
</tr>
42+
</thead>
43+
<tbody>
44+
{rows.map((row) => (
45+
<tr key={row.id}>
46+
{headers.map((header) => (
47+
<td
48+
key={`cell-${row.id}-${header.id}`} // Use a combination of row and header IDs for unique keys
49+
className="px-5 py-5 border-b border-gray-200 bg-white dark:bg-dark-bg text-sm"
50+
>
51+
<div
52+
className="h-4 bg-gray-200 rounded w-3/4 mx-auto"
53+
aria-label={`Loading content for row ${row.id}, column ${header.id}`}
54+
/>
55+
</td>
56+
))}
57+
</tr>
58+
))}
59+
</tbody>
60+
</table>
61+
</div>
62+
</div>
63+
</div>
64+
</div>
65+
</div>
66+
);
67+
}
68+
69+
export default OrganizationTableSkeleton;

src/Skeletons/ttl.Skeleton.tsx

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import React from 'react';
2+
import Skeleton from 'react-loading-skeleton';
3+
import 'react-loading-skeleton/dist/skeleton.css';
4+
5+
export default function TtlSkeleton() {
6+
// Define an array with unique keys
7+
const skeletonRows = [{ id: 'row-1' }, { id: 'row-2' }, { id: 'row-3' }];
8+
9+
return (
10+
<div className="p-4">
11+
{/* Header Skeleton */}
12+
<Skeleton height={30} width={80} />
13+
<Skeleton height={30} width="40%" className="mt-6" />
14+
<Skeleton height={60} className="mt-6 " />
15+
16+
{/* Skeleton for Table Rows */}
17+
{skeletonRows.map((row) => (
18+
<div key={row.id} className="flex items-center mb-4">
19+
{/* Name and Email Skeleton */}
20+
<div className="flex-1">
21+
<Skeleton height={20} width="85%" className="mt-2" />
22+
</div>
23+
24+
{/* Action Buttons Skeleton */}
25+
<div className="flex space-x-4 mr-8">
26+
<Skeleton width={30} height={30} />
27+
<Skeleton width={30} height={30} />
28+
<Skeleton width={30} height={30} />
29+
</div>
30+
</div>
31+
))}
32+
<div className="flex space-x-4 ">
33+
<Skeleton width={50} height={30} />
34+
<Skeleton width={50} height={30} />
35+
</div>
36+
</div>
37+
);
38+
}

src/components/Calendar.tsx

+23-14
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import useDocumentTitle from '../hook/useDocumentTitle';
1111
import { useLazyQuery, useMutation } from '@apollo/client';
1212
import { ADD_EVENT, GET_EVENTS } from '../Mutations/event';
1313
import moment from 'moment';
14+
import CalendarSkeleton from '../Skeletons/Calender.skeleton';
1415
/* istanbul ignore next */
1516

1617
const Calendar = () => {
@@ -25,6 +26,7 @@ const Calendar = () => {
2526
timeToFinish: '',
2627
});
2728
const [data, setData] = useState<EventInput[]>([]);
29+
const [loading, setLoading] = useState(true);
2830
const [getEvents] = useLazyQuery(GET_EVENTS);
2931
const [createEvent] = useMutation(ADD_EVENT);
3032
useEffect(() => {
@@ -48,6 +50,8 @@ const Calendar = () => {
4850
} catch (error) {
4951
console.log({ eventsError: data });
5052
// toast.error(error?.message || 'Something went wrong');
53+
} finally {
54+
setLoading(false);
5155
}
5256
};
5357
fetchData();
@@ -108,8 +112,9 @@ const Calendar = () => {
108112
<>
109113
{/* =========================== Start:: RegisterTraineeModel =========================== */}
110114
<div
111-
className={`font-serif h-screen w-screen bg-black bg-opacity-30 backdrop-blur-sm fixed top-0 left-0 z-20 flex items-center justify-center px-4 ${addEventModel === true ? 'block' : 'hidden'
112-
}`}
115+
className={`font-serif h-screen w-screen bg-black bg-opacity-30 backdrop-blur-sm fixed top-0 left-0 z-20 flex items-center justify-center px-4 ${
116+
addEventModel === true ? 'block' : 'hidden'
117+
}`}
113118
>
114119
<div className="bg-indigo-100 dark:bg-dark-bg w-full sm:w-3/4 md:w-1/2 xl:w-4/12 rounded-lg p-4 pb-8">
115120
<div className="card-title w-full flex flex-wrap justify-center items-center ">
@@ -155,9 +160,9 @@ const Calendar = () => {
155160
value={newEvent.hostName}
156161
onChange /* istanbul ignore next */={(e) =>
157162
/* istanbul ignore next */ setNewEvent({
158-
...newEvent,
159-
hostName: e.target.value,
160-
})
163+
...newEvent,
164+
hostName: e.target.value,
165+
})
161166
}
162167
/>
163168
</div>
@@ -172,9 +177,9 @@ const Calendar = () => {
172177
selected={newEvent.start}
173178
onChange /* istanbul ignore next */={(start: any) =>
174179
/* istanbul ignore next */ setNewEvent({
175-
...newEvent,
176-
start,
177-
})
180+
...newEvent,
181+
start,
182+
})
178183
}
179184
/>
180185
</div>
@@ -256,12 +261,16 @@ const Calendar = () => {
256261
>
257262
{t('Add event')}
258263
</button>
259-
<FullCalendar
260-
eventContent={renderEvent}
261-
events={data}
262-
plugins={[dayGridPlugin, interactionPlugin]}
263-
initialView="dayGridMonth"
264-
/>
264+
{loading ? (
265+
<CalendarSkeleton />
266+
) : (
267+
<FullCalendar
268+
eventContent={renderEvent}
269+
events={data}
270+
plugins={[dayGridPlugin, interactionPlugin]}
271+
initialView="dayGridMonth"
272+
/>
273+
)}
265274
</div>
266275
</>
267276
);

src/components/Organizations.tsx

+23-15
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { toast } from 'react-toastify';
1313
import { Icon } from '@iconify/react';
1414

1515
import DataTable from '../components/DataTable';
16+
import OrganizationTableSkeleton from '../Skeletons/Organazition.skeleton';
1617

1718
export interface Admin {
1819
id: string;
@@ -303,7 +304,7 @@ const Organizations = () => {
303304
);
304305

305306
return (
306-
<div className='font-serif'>
307+
<div className="font-serif">
307308
{/* =========================== Start:: CreateOrganizationModel =============================== */}
308309
<CreateOrganizationModal
309310
createOrganizationModel={createOrganizationModel}
@@ -314,8 +315,9 @@ const Organizations = () => {
314315

315316
{/* =========================== Start:: delete Session Model =============================== */}
316317
<div
317-
className={`h-screen w-screen bg-black fixed top-0 left-0 z-20 bg-opacity-30 backdrop-blur-sm flex items-center justify-center overflow-auto p-4 ${deleteOrganizationModel === true ? 'block' : 'hidden'
318-
}`}
318+
className={`h-screen w-screen bg-black fixed top-0 left-0 z-20 bg-opacity-30 backdrop-blur-sm flex items-center justify-center overflow-auto p-4 ${
319+
deleteOrganizationModel === true ? 'block' : 'hidden'
320+
}`}
319321
>
320322
<div className="bg-white dark:bg-dark-bg w-full sm:w-3/4 md:w-1/2 xl:w-4/12 rounded-lg p-4 pb-8">
321323
<div className="card-title w-full flex flex-wrap justify-center items-center ">
@@ -370,8 +372,9 @@ const Organizations = () => {
370372
{/* =========================== Start:: SendInviteModel =============================== */}
371373

372374
<div
373-
className={`h-screen w-screen bg-black fixed top-0 left-0 z-20 bg-opacity-30 backdrop-blur-sm flex items-center justify-center overflow-auto p-4 ${sendInviteModel === true ? 'block' : 'hidden'
374-
}`}
375+
className={`h-screen w-screen bg-black fixed top-0 left-0 z-20 bg-opacity-30 backdrop-blur-sm flex items-center justify-center overflow-auto p-4 ${
376+
sendInviteModel === true ? 'block' : 'hidden'
377+
}`}
375378
>
376379
<div className="bg-white dark:bg-dark-bg w-full sm:w-3/4 xl:w-4/12 rounded-lg p-4 pb-8">
377380
<div className="card-title w-full flex flex-wrap justify-center items-center ">
@@ -429,8 +432,9 @@ const Organizations = () => {
429432
{/* =========================== Start:: ApproveMode =============================== */}
430433

431434
<div
432-
className={`h-screen w-screen bg-black fixed top-0 left-0 z-20 bg-opacity-30 backdrop-blur-sm flex items-center justify-center overflow-auto p-4 ${approveOpen === true ? 'block' : 'hidden'
433-
}`}
435+
className={`h-screen w-screen bg-black fixed top-0 left-0 z-20 bg-opacity-30 backdrop-blur-sm flex items-center justify-center overflow-auto p-4 ${
436+
approveOpen === true ? 'block' : 'hidden'
437+
}`}
434438
>
435439
<div className="bg-white dark:bg-dark-bg w-full sm:w-3/4 xl:w-4/12 rounded-lg p-4 pb-8">
436440
<div className="card-title w-full flex flex-wrap justify-center items-center ">
@@ -488,8 +492,9 @@ const Organizations = () => {
488492
{/* =========================== Start:: RejectModal =============================== */}
489493

490494
<div
491-
className={`h-screen w-screen bg-black fixed top-0 left-0 z-20 bg-opacity-30 backdrop-blur-sm flex items-center justify-center overflow-auto p-4 ${rejectOpen === true ? 'block' : 'hidden'
492-
}`}
495+
className={`h-screen w-screen bg-black fixed top-0 left-0 z-20 bg-opacity-30 backdrop-blur-sm flex items-center justify-center overflow-auto p-4 ${
496+
rejectOpen === true ? 'block' : 'hidden'
497+
}`}
493498
>
494499
<div className="bg-white dark:bg-dark-bg w-full sm:w-3/4 xl:w-4/12 rounded-lg p-4 pb-8">
495500
<div className="card-title w-full flex flex-wrap justify-center items-center ">
@@ -560,12 +565,15 @@ const Organizations = () => {
560565
</div>
561566
</div>
562567
<div className="">
563-
<DataTable
564-
columns={organizationColumns}
565-
data={organizationData ? (organizationData as [any]) : []}
566-
title={t('Organizations list')}
567-
loading={getLoading}
568-
/>
568+
{getLoading ? (
569+
<OrganizationTableSkeleton />
570+
) : (
571+
<DataTable
572+
columns={organizationColumns}
573+
data={organizationData ? (organizationData as [any]) : []}
574+
title={t('Organizations list')}
575+
/>
576+
)}
569577
</div>
570578
</div>
571579
</div>

src/containers/admin-dashBoard/TtlsModal.tsx

+2-4
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import ControlledSelect from '../../components/ControlledSelect';
2525
import { GET_GITHUB_STATISTICS } from '../../Mutations/manageStudentMutations';
2626
import GitHubActivityChart from '../../components/chartGitHub';
2727
import { toast } from 'react-toastify';
28+
import TtlSkeleton from '../../Skeletons/ttl.skeleton';
2829
/* istanbul ignore next */
2930
export default function TtlsPage() {
3031
const { t } = useTranslation();
@@ -645,10 +646,7 @@ export default function TtlsPage() {
645646
<div className="bg-light-bg dark:bg-dark-frame-bg min-h-screen overflow-y-auto overflow-x-hidden">
646647
<div className="">
647648
{loading ? (
648-
<div className="flex justify-center items-center h-48">
649-
<Spinner />
650-
<div className="spinner" />
651-
</div>
649+
<TtlSkeleton />
652650
) : (
653651
<DataTable
654652
columns={columns}

0 commit comments

Comments
 (0)