Skip to content

Commit 4321d94

Browse files
fix(#404): add skeleton loader on login activities table (#600)
1 parent f08afd4 commit 4321d94

15 files changed

+3622
-991
lines changed
+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
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 LoginActivitiesSkeleton() {
6+
// Define an array with unique keys
7+
const skeletonRows = [{ id: 'row-1' }, { id: 'row-2' }, { id: 'row-3' }];
8+
9+
return (
10+
<div
11+
className="w-full p-4 overflow-auto"
12+
data-testid="login-activities-skeleton"
13+
>
14+
<table className="w-full table-fixed border border-gray-700 min-w-[600px]">
15+
<thead className="bg-[#27167439] text-white">
16+
<tr>
17+
<th className="p-4 border text-center w-1/6">Date</th>
18+
<th className="p-4 border text-center w-1/6">Country Name</th>
19+
<th className="p-4 border text-center w-1/6">City</th>
20+
<th className="p-4 border text-center w-1/6">State</th>
21+
<th className="p-4 border text-center w-1/6">IPV4</th>
22+
<th className="p-4 border text-center w-1/6">Attempt</th>
23+
</tr>
24+
</thead>
25+
<tbody>
26+
{skeletonRows.map((row) => (
27+
<tr key={row.id}>
28+
<td className="py-2 px-4 border">
29+
<Skeleton height={35} width="100%" />
30+
</td>
31+
<td className="py-2 px-4 border">
32+
<Skeleton height={35} width="100%" />
33+
</td>
34+
<td className="py-2 px-4 border">
35+
<Skeleton height={35} width="100%" />
36+
</td>
37+
<td className="py-2 px-4 border">
38+
<Skeleton height={35} width="100%" />
39+
</td>
40+
<td className="py-2 px-4 border">
41+
<Skeleton height={35} width="100%" />
42+
</td>
43+
<td className="py-2 px-4 border">
44+
<Skeleton height={35} width="100%" />
45+
</td>
46+
</tr>
47+
))}
48+
</tbody>
49+
</table>
50+
</div>
51+
);
52+
}

src/components/LoginActivitiesTable.tsx

+80-69
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import React, { useState, useEffect } from 'react';
77
import { useQuery } from '@apollo/client';
88
import { GET_LOGIN_ACTIVITIES } from '../queries/manageStudent.queries';
9+
import LoginActivitiesSkeleton from '../Skeletons/loginActivities.skeleton';
910

1011
interface LoginActivitiesData {
1112
loginActivities: LoginActivity[];
@@ -99,78 +100,88 @@ const LoginActivitiesTable: React.FC = () => {
99100
const displayActivities = loginActivities.slice(startIndex, endIndex);
100101
console.log('displayActivities', displayActivities);
101102

102-
if (loading && page === 1) {
103-
return <div>Loading login activities...</div>;
104-
}
105-
106-
/* istanbul ignore next */
107-
if (error) {
108-
return <div>Error retrieving login activities.</div>;
109-
}
110-
111-
/* istanbul ignore next */
112-
if (displayActivities.length === 0) {
113-
return <div>No login activities yet.</div>;
114-
}
115-
116103
/* istanbul ignore next */
117104
return (
118105
<div className="flex flex-col items-center mt-4 font-serif">
119-
<table className="w-full border border-gray-300">
120-
<thead className="bg-[#163274a3] text-white">
121-
<tr>
122-
<th className="py-2 px-4 border">Date</th>
123-
<th className="py-2 px-4 border">Country Name</th>
124-
<th className="py-2 px-4 border">City</th>
125-
<th className="py-2 px-4 border">State</th>
126-
<th className="py-2 px-4 border">IPv4</th>
127-
<th className="py-2 px-4 border">Attempt</th>
128-
</tr>
129-
</thead>
130-
<tbody>
131-
{displayActivities.map((activity, index) => (
132-
<tr
133-
key={`${activity.date || index}-${activity.IPv4 || index}`}
134-
className="transition-colors duration-200"
135-
>
136-
<td className="py-2 px-4 border">
137-
{new Date(Number(activity.date)).toLocaleString()}
138-
</td>
139-
<td className="py-2 px-4 border">
140-
{activity.country_name || 'N/A'}
141-
</td>
142-
<td className="py-2 px-4 border">{activity.city || 'N/A'}</td>
143-
<td className="py-2 px-4 border">{activity.state || 'N/A'}</td>
144-
<td className="py-2 px-4 border">{activity.IPv4 || 'N/A'}</td>
145-
<td className="py-2 px-4 border">
146-
{activity.failed > 0 ? 'Failed' : 'Success'}
147-
</td>
148-
</tr>
149-
))}
150-
</tbody>
151-
</table>
152-
153-
<div className="flex justify-center mb-20 mt-4">
154-
<span className="mr-2 text-gray-600">
155-
Page {page} of {totalPages}
156-
</span>
157-
{page > 1 && (
158-
<button
159-
className="px-4 py-2 mr-2 font-bold text-white bg-gray-500 rounded"
160-
onClick={handleGoBack}
161-
>
162-
Previous
163-
</button>
164-
)}
165-
{page < totalPages && (
166-
<button
167-
className="px-4 py-2 font-bold text-white bg-blue-500 rounded hover:bg-blue-700"
168-
onClick={handleLoadMore}
169-
>
170-
Next
171-
</button>
172-
)}
173-
</div>
106+
<h1 className="text-3xl font-bold font-lexend pb-3">Login Activities</h1>
107+
108+
{/* eslint-disable-next-line no-nested-ternary */}
109+
{loading && page === 1 ? (
110+
<div className="my-2 items-center">
111+
<LoginActivitiesSkeleton />
112+
</div>
113+
) : /* eslint-disable-next-line no-nested-ternary */
114+
error ? (
115+
<div>Error retrieving login activities.</div>
116+
) : displayActivities.length === 0 ? (
117+
<div>No login activities yet.</div>
118+
) : (
119+
<>
120+
<div className="w-full overflow-x-auto">
121+
<table className="w-full border border-gray-300 min-w-[800px]">
122+
<thead className="bg-[#163274a3] text-white">
123+
<tr>
124+
<th className="py-2 px-4 border">Date</th>
125+
<th className="py-2 px-4 border">Country Name</th>
126+
<th className="py-2 px-4 border">City</th>
127+
<th className="py-2 px-4 border">State</th>
128+
<th className="py-2 px-4 border">IPv4</th>
129+
<th className="py-2 px-4 border">Attempt</th>
130+
</tr>
131+
</thead>
132+
<tbody>
133+
{displayActivities.map((activity, index) => (
134+
<tr
135+
key={`${activity.date || index}-${activity.IPv4 || index}`}
136+
className="transition-colors duration-200"
137+
>
138+
<td className="py-2 px-4 border">
139+
{new Date(Number(activity.date)).toLocaleString()}
140+
</td>
141+
<td className="py-2 px-4 border">
142+
{activity.country_name || 'N/A'}
143+
</td>
144+
<td className="py-2 px-4 border">
145+
{activity.city || 'N/A'}
146+
</td>
147+
<td className="py-2 px-4 border">
148+
{activity.state || 'N/A'}
149+
</td>
150+
<td className="py-2 px-4 border">
151+
{activity.IPv4 || 'N/A'}
152+
</td>
153+
<td className="py-2 px-4 border">
154+
{activity.failed > 0 ? 'Failed' : 'Success'}
155+
</td>
156+
</tr>
157+
))}
158+
</tbody>
159+
</table>
160+
</div>
161+
162+
<div className="flex justify-center mb-20 mt-4">
163+
<span className="mr-2 text-gray-600">
164+
Page {page} of {totalPages}
165+
</span>
166+
{page > 1 && (
167+
<button
168+
className="px-4 py-2 mr-2 font-bold text-white bg-gray-500 rounded"
169+
onClick={handleGoBack}
170+
>
171+
Previous
172+
</button>
173+
)}
174+
{page < totalPages && (
175+
<button
176+
className="px-4 py-2 font-bold text-white bg-blue-500 rounded hover:bg-blue-700"
177+
onClick={handleLoadMore}
178+
>
179+
Next
180+
</button>
181+
)}
182+
</div>
183+
</>
184+
)}
174185
</div>
175186
);
176187
};

tests/components/__snapshots__/AdminTraineeDashboard.test.tsx.snap

+1-10
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ Array [
463463
name="date"
464464
readOnly={true}
465465
type="text"
466-
value="2024-10-06"
466+
value="2024-10-24"
467467
/>
468468
</div>
469469
<div
@@ -955,15 +955,6 @@ Array [
955955
+
956956
957957
</button>
958-
<button
959-
className="btn primary lg m-0 font-serif "
960-
data-testid="inviteModel"
961-
disabled={false}
962-
onClick={[Function]}
963-
type="button"
964-
>
965-
Invite
966-
</button>
967958
</div>
968959
</div>
969960
<div

tests/components/__snapshots__/DashHeader.test.tsx.snap

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
exports[`DashHeader test Should render DashHeader 1`] = `
44
<div
5-
className="font-serif w-full py-4 z-20 bg-indigo-100 dark:bg-dark-bg page-header"
5+
className="font-serif transform:sc w-full py-4 z-20 bg-indigo-100 dark:bg-dark-bg page-header"
66
>
77
<div
88
className="px-3 flex items-center w-full font-serif"

0 commit comments

Comments
 (0)