Skip to content

Commit 72ce40e

Browse files
committed
skeleton loader match to respective layout
1 parent 40ddd61 commit 72ce40e

20 files changed

+506
-524
lines changed

package-lock.json

+93-74
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
@@ -88,6 +88,7 @@
8888
"react-i18next": "^11.18.6",
8989
"react-icons": "^4.10.1",
9090
"react-loader-spinner": "^5.4.5",
91+
"react-loading-skeleton": "^3.4.0",
9192
"react-pdf": "^7.3.3",
9293
"react-pdf-js": "^5.1.0",
9394
"react-router": "^6.14.1",

src/Skeletons/calSkeleton.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;

src/Skeletons/orgSkeleton.tsx

+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/ttlSkeleton.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

+44-58
Original file line numberDiff line numberDiff line change
@@ -11,7 +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-
/* istanbul ignore next */
14+
import CalendarSkeleton from '../Skeletons/calSkeleton';
1515

1616
const Calendar = () => {
1717
useDocumentTitle('Calendar');
@@ -25,11 +25,12 @@ const Calendar = () => {
2525
timeToFinish: '',
2626
});
2727
const [data, setData] = useState<EventInput[]>([]);
28+
const [loading, setLoading] = useState(true);
2829
const [getEvents] = useLazyQuery(GET_EVENTS);
2930
const [createEvent] = useMutation(ADD_EVENT);
31+
3032
useEffect(() => {
3133
const fetchData = async () => {
32-
/* istanbul ignore next */
3334
try {
3435
const { data: out } = await getEvents({
3536
variables: {
@@ -46,44 +47,41 @@ const Calendar = () => {
4647
}));
4748
setData(all);
4849
} catch (error) {
49-
console.log({ eventsError: data });
50+
console.log({ eventsError: error });
5051
// toast.error(error?.message || 'Something went wrong');
52+
} finally {
53+
setLoading(false);
5154
}
5255
};
5356
fetchData();
5457
}, []);
58+
5559
const { t } = useTranslation();
56-
const renderEvent =
57-
/* istanbul ignore next */
5860

59-
(e: EventContentArg) => (
60-
/* istanbul ignore next */
61-
<div
62-
data-html={true}
63-
data-tip={`<div>${e.event.title}<br> ${e.event.extendedProps.hostName} <br> ${e.event.extendedProps.timeToStart} - ${e.event.extendedProps.timeToFinish}</div> `}
64-
className="bg-primary text-white max-w-full min-w-full overflow-auto text-xs md:text-sm"
65-
>
66-
<p className="px-3 py-1 ">{e.event.title}</p>
67-
<p className="px-3 py-1 ">{e.event.extendedProps.hostName}</p>
68-
<p className="px-3 py-1 ">
69-
{e.event.extendedProps.timeToStart} -{' '}
70-
{e.event.extendedProps.timeToFinish}
71-
</p>
72-
<ReactTooltip data-html={true} />
73-
</div>
74-
);
61+
const renderEvent = (e: EventContentArg) => (
62+
<div
63+
data-html={true}
64+
data-tip={`<div>${e.event.title}<br> ${e.event.extendedProps.hostName} <br> ${e.event.extendedProps.timeToStart} - ${e.event.extendedProps.timeToFinish}</div> `}
65+
className="bg-primary text-white max-w-full min-w-full overflow-auto text-xs md:text-sm"
66+
>
67+
<p className="px-3 py-1 ">{e.event.title}</p>
68+
<p className="px-3 py-1 ">{e.event.extendedProps.hostName}</p>
69+
<p className="px-3 py-1 ">
70+
{e.event.extendedProps.timeToStart} -{' '}
71+
{e.event.extendedProps.timeToFinish}
72+
</p>
73+
<ReactTooltip data-html={true} />
74+
</div>
75+
);
7576

7677
const removeModel = (e: any) => {
7778
e.preventDefault();
78-
const newState = !addEventModel;
79-
setAddEventModel(newState);
79+
setAddEventModel(!addEventModel);
8080
};
8181

8282
const handleDateClick = () => {
83-
const newState = !addEventModel;
84-
setAddEventModel(newState);
83+
setAddEventModel(!addEventModel);
8584
};
86-
/* istanbul ignore next */
8785

8886
const handleAddEvent = (e: any) => {
8987
e.preventDefault();
@@ -119,14 +117,10 @@ const Calendar = () => {
119117
<hr className=" bg-primary border-gray-300 my-3 w-full" />
120118
</div>
121119
<div className="card-body">
122-
{/* istanbul ignore next */}
123120
<form
124121
data-testid="handleAddEvent"
125122
className=" py-3 px-8"
126-
onSubmit /* istanbul ignore next */={(e) =>
127-
/* istanbul ignore next */
128-
handleAddEvent(e)
129-
}
123+
onSubmit={handleAddEvent}
130124
>
131125
<div className="input my-3 h-9 ">
132126
<div className="grouped-input flex items-center h-full w-full rounded-md">
@@ -137,7 +131,6 @@ const Calendar = () => {
137131
className=" dark:bg-dark-tertiary border dark:text-white border-primary rounded outline-none px-5 font-sans text-xs py-2 w-full"
138132
placeholder={t('Event title')}
139133
value={newEvent.title}
140-
// eslint-disable-next-line prettier/prettier
141134
onChange={(e) =>
142135
setNewEvent({ ...newEvent, title: e.target.value })
143136
}
@@ -153,11 +146,8 @@ const Calendar = () => {
153146
className=" dark:bg-dark-tertiary dark:text-white border border-primary rounded outline-none px-5 font-sans text-xs py-2 w-full"
154147
placeholder={t('Host name')}
155148
value={newEvent.hostName}
156-
onChange /* istanbul ignore next */={(e) =>
157-
/* istanbul ignore next */ setNewEvent({
158-
...newEvent,
159-
hostName: e.target.value,
160-
})
149+
onChange={(e) =>
150+
setNewEvent({ ...newEvent, hostName: e.target.value })
161151
}
162152
/>
163153
</div>
@@ -170,11 +160,8 @@ const Calendar = () => {
170160
placeholderText={t('Start Date')}
171161
style={{ marginRight: '10px' }}
172162
selected={newEvent.start}
173-
onChange /* istanbul ignore next */={(start: any) =>
174-
/* istanbul ignore next */ setNewEvent({
175-
...newEvent,
176-
start,
177-
})
163+
onChange={(start: any) =>
164+
setNewEvent({ ...newEvent, start })
178165
}
179166
/>
180167
</div>
@@ -187,10 +174,7 @@ const Calendar = () => {
187174
placeholderText={t('End Date')}
188175
style={{ marginRight: '10px' }}
189176
selected={newEvent.end}
190-
onChange=/* istanbul ignore next */ {(end: any) =>
191-
/* istanbul ignore next */
192-
setNewEvent({ ...newEvent, end })
193-
}
177+
onChange={(end: any) => setNewEvent({ ...newEvent, end })}
194178
/>
195179
</div>
196180
</div>
@@ -203,8 +187,7 @@ const Calendar = () => {
203187
className="dark:bg-dark-tertiary dark:text-white border border-primary rounded outline-none px-5 font-sans text-xs py-2 w-full"
204188
placeholder={t('Start time')}
205189
value={newEvent.timeToStart}
206-
onChange /* istanbul ignore next */={(e) =>
207-
/* istanbul ignore next */
190+
onChange={(e) =>
208191
setNewEvent({ ...newEvent, timeToStart: e.target.value })
209192
}
210193
/>
@@ -219,8 +202,7 @@ const Calendar = () => {
219202
className="dark:bg-dark-tertiary dark:text-white border border-primary rounded outline-none px-5 font-sans text-xs py-2 w-full"
220203
placeholder={t('End time')}
221204
value={newEvent.timeToFinish}
222-
onChange=/* istanbul ignore next */ {(e) =>
223-
/* istanbul ignore next */
205+
onChange={(e) =>
224206
setNewEvent({ ...newEvent, timeToFinish: e.target.value })
225207
}
226208
/>
@@ -231,7 +213,7 @@ const Calendar = () => {
231213
<button
232214
data-testid="removeModel"
233215
className="py-2 w-[40%] md:w-1/3 bg-violet-400 rounded font-sans text-sm text-white"
234-
onClick={(e) => removeModel(e)}
216+
onClick={removeModel}
235217
>
236218
{t('cancel')}
237219
</button>
@@ -245,7 +227,7 @@ const Calendar = () => {
245227
</div>
246228
{/* =========================== End:: RegisterTraineeModel =============================== */}
247229

248-
<div className="px-4 pb-20 w-full dark:bg-dark-frame-bg dark:text-white h-full overflow-y-scroll font-serif">
230+
<div className="px-4 pb-20 w-full dark:bg-dark-frame-bg dark:text-white h-full overflow-y-scroll">
249231
<div className="w-full flex justify-center text-xl md:text-4xl dark:text-primary mb-10">
250232
<h2>{t('Calendar')}</h2>
251233
</div>
@@ -256,12 +238,16 @@ const Calendar = () => {
256238
>
257239
{t('Add event')}
258240
</button>
259-
<FullCalendar
260-
eventContent={renderEvent}
261-
events={data}
262-
plugins={[dayGridPlugin, interactionPlugin]}
263-
initialView="dayGridMonth"
264-
/>
241+
{loading ? (
242+
<CalendarSkeleton />
243+
) : (
244+
<FullCalendar
245+
eventContent={renderEvent}
246+
events={data}
247+
plugins={[dayGridPlugin, interactionPlugin]}
248+
initialView="dayGridMonth"
249+
/>
250+
)}
265251
</div>
266252
</>
267253
);

0 commit comments

Comments
 (0)