Skip to content

Commit 8448da6

Browse files
authored
adding undrop trainee feature (#532)
1 parent 30dff33 commit 8448da6

File tree

3 files changed

+187
-66
lines changed

3 files changed

+187
-66
lines changed

src/Mutations/manageStudentMutations.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,12 @@ export const DROP_TRAINEE = gql`
3535
dropTrainee(traineeId: $traineeId, reason: $reason, date: $date)
3636
}
3737
`;
38-
38+
// Define the mutation
39+
export const UNDROP_TRAINEE = gql`
40+
mutation UndropTrainee($traineeId: String!) {
41+
undropTrainee(traineeId: $traineeId)
42+
}
43+
`;
3944
export const GET_TRAINEES_QUERY = gql`
4045
query GetTrainees($orgToken: String) {
4146
getTrainees(orgToken: $orgToken) {

src/pages/AdminTraineeDashboard.tsx

Lines changed: 179 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
GET_TEAM_QUERY,
2828
ADD_MEMBER_TO_TEAM,
2929
GET_GITHUB_STATISTICS,
30+
UNDROP_TRAINEE,
3031
} from '../Mutations/manageStudentMutations';
3132
import { useNavigate } from 'react-router-dom';
3233

@@ -70,6 +71,8 @@ function AdminTraineeDashboard() {
7071
const [editTeam, setEditTeam] = useState('');
7172
const [inviteEmail, setInviteEmail] = useState('');
7273
const [buttonLoading, setButtonLoading] = useState(false);
74+
const [restoreTraineeModel, setRestoreTraineeModel] = useState(false);
75+
7376
const [toggle, setToggle] = useState(false);
7477
const [showOptions, setShowOptions] = useState(false);
7578
const options: any = [];
@@ -81,9 +84,11 @@ function AdminTraineeDashboard() {
8184
const { traineeData, setAllTrainees } = useTraineesContext() || [];
8285
const [actionTraineeOptions, setActionTraineeOptions] = useState<any>(null);
8386
const modalRef = useRef<any>(null);
84-
85-
const [selectedTraineeId, setSelectedTraineeId]= useState<string[]>()
86-
87+
// restoreTraineeModel
88+
// restoreTraineeMod
89+
// unDropTrainee
90+
// restoreMemberFromCohort
91+
const [selectedTraineeId, setSelectedTraineeId] = useState<string[]>();
8792

8893
useEffect(() => {
8994
const handleClickOutside = (event: any) => {
@@ -166,7 +171,10 @@ function AdminTraineeDashboard() {
166171
const newState = !removeTraineeModel;
167172
setRemoveTraineeModel(newState);
168173
};
169-
174+
const restoreTraineeMod = () => {
175+
const newState = !restoreTraineeModel;
176+
setRestoreTraineeModel(newState);
177+
};
170178
const removeModel = () => {
171179
const newState = !registerTraineeModel;
172180
setRegisterTraineeModel(newState);
@@ -261,18 +269,18 @@ function AdminTraineeDashboard() {
261269
}
262270
>
263271
<button
264-
className={`${row.original?.Status?.status === 'drop'
265-
? 'bg-gray-500'
266-
: 'bg-black'
267-
} text-white rounded-xl px-3`}
268-
onClick={() => {
269-
setSelectedTraineeId(row.original?.email);
270-
handleClickOpen2();
271-
}}
272-
>
273-
{row.original?.Status?.status === 'drop' ? 'Dropped' : 'View'}
274-
</button>
275-
272+
className={`${
273+
row.original?.Status?.status === 'drop'
274+
? 'bg-gray-500'
275+
: 'bg-black'
276+
} text-white rounded-xl px-3`}
277+
onClick={() => {
278+
setSelectedTraineeId(row.original?.email);
279+
handleClickOpen2();
280+
}}
281+
>
282+
{row.original?.Status?.status === 'drop' ? 'Dropped' : 'View'}
283+
</button>
276284
</div>
277285
);
278286
},
@@ -293,8 +301,9 @@ function AdminTraineeDashboard() {
293301
/>
294302
{selectedRow === row.original.email && (
295303
<div
296-
ref={modalRef}
297-
className="absolute z-50 w-64 p-4 mt-2 overflow-hidden border border-gray-300 rounded-lg shadow-md dropdown right-4 bg-light-bg max-h-30 dark:bg-dark-bg">
304+
ref={modalRef}
305+
className="absolute z-50 w-64 p-4 mt-2 overflow-hidden border border-gray-300 rounded-lg shadow-md dropdown right-4 bg-light-bg max-h-30 dark:bg-dark-bg"
306+
>
298307
<>
299308
<div className="mb-4"></div>
300309
<div className="mb-4">
@@ -360,30 +369,58 @@ function AdminTraineeDashboard() {
360369
</div>
361370
</div>
362371
<div className="mb-4">
363-
<div
364-
className="flex items-center p-2 rounded-md cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-800"
365-
onClick={() => {
366-
dropModel(row.original.email);
367-
setdropTraineeID(row.original.userId);
368-
setReason(row.original.reason);
369-
toggleOptions(row.original.email);
370-
}}
371-
>
372-
<Icon
373-
icon="mdi:close-circle"
374-
width="40"
375-
height="40"
376-
cursor="pointer"
377-
color="#9e85f5"
378-
/>
379-
<div>
380-
<span className="font-bold">Drop</span>{' '}
381-
<>
382-
<br />
383-
Drop trainee
384-
</>
372+
{row.original?.Status?.status !== 'drop' ? (
373+
<div
374+
className="flex items-center p-2 rounded-md cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-800"
375+
onClick={() => {
376+
dropModel(row.original.email);
377+
setdropTraineeID(row.original.userId);
378+
setReason(row.original.reason);
379+
toggleOptions(row.original.email);
380+
}}
381+
>
382+
<Icon
383+
icon="mdi:close-circle"
384+
width="40"
385+
height="40"
386+
cursor="pointer"
387+
color="#9e85f5"
388+
/>
389+
<div>
390+
<span className="font-bold">Drop</span>
391+
{row.original.status}
392+
<>
393+
<br />
394+
Drop trainee
395+
</>
396+
</div>
385397
</div>
386-
</div>
398+
) : (
399+
<div
400+
className="flex items-center p-2 rounded-md cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-800"
401+
onClick={() => {
402+
restoreTraineeMod();
403+
setdropTraineeID(row.original.userId);
404+
setReason(row.original.reason);
405+
toggleOptions(row.original.email);
406+
}}
407+
>
408+
<Icon
409+
icon="mdi:close-circle"
410+
width="40"
411+
height="40"
412+
cursor="pointer"
413+
color="#9e85f5"
414+
/>
415+
<div>
416+
<span className="font-bold">Restore</span>{' '}
417+
<>
418+
<br />
419+
Restore Dropped Trainee
420+
</>
421+
</div>
422+
</div>
423+
)}
387424
</div>
388425
<div>
389426
<div
@@ -556,6 +593,32 @@ function AdminTraineeDashboard() {
556593
},
557594
});
558595

596+
const [unDropTrainee] = useMutation(UNDROP_TRAINEE, {
597+
variables: {
598+
traineeId: dropTraineeID,
599+
},
600+
onCompleted: (data) => {
601+
setTimeout(() => {
602+
setButtonLoading(false);
603+
if (data.undropTrainee) {
604+
// Check the response structure
605+
refetch();
606+
toast.success('Trainee Undropped successfully');
607+
setDropTraineeModel(false);
608+
restoreTraineeMod();
609+
} else {
610+
toast.error('Failed to undrop trainee');
611+
}
612+
}, 1000);
613+
},
614+
onError: (err) => {
615+
setTimeout(() => {
616+
setButtonLoading(false);
617+
console.error('Mutation error:', err); // Log the error
618+
toast.error(err.message);
619+
}, 500);
620+
},
621+
});
559622
const [removeMemberFromCohort] = useMutation(
560623
REMOVE_MEMBER_FROM_COHORT_MUTATION,
561624
{
@@ -655,7 +718,6 @@ function AdminTraineeDashboard() {
655718
teamOptions[index].label = team?.name;
656719
});
657720
}
658-
659721

660722
return (
661723
<>
@@ -669,20 +731,21 @@ function AdminTraineeDashboard() {
669731
className="rounded-lg"
670732
fullWidth
671733
>
672-
{traineeData?.map((data:any) => {
673-
if (data.email === selectedTraineeId) {
674-
return <ViewWeeklyRatings
675-
traineeName={data?.profile?.name || 'Unknown Name'}
676-
traineeEmail={data?.email || 'Unknown Email'}
677-
traineeId={data?.profile?.user?.id || 'Unknown ID'}
678-
traineeCohort={data?.team?.cohort?.id || 'Unknown Cohort'}
679-
traineeStatus={
680-
data?.profile?.user?.status || 'Status Unavailable'
681-
}
682-
/>
734+
{traineeData?.map((data: any) => {
735+
if (data.email === selectedTraineeId) {
736+
return (
737+
<ViewWeeklyRatings
738+
traineeName={data?.profile?.name || 'Unknown Name'}
739+
traineeEmail={data?.email || 'Unknown Email'}
740+
traineeId={data?.profile?.user?.id || 'Unknown ID'}
741+
traineeCohort={data?.team?.cohort?.id || 'Unknown Cohort'}
742+
traineeStatus={
743+
data?.profile?.user?.status || 'Status Unavailable'
744+
}
745+
/>
746+
);
683747
}
684-
}
685-
)}
748+
})}
686749
<FaTimes
687750
size={24}
688751
color="red"
@@ -1470,6 +1533,57 @@ function AdminTraineeDashboard() {
14701533
</div>
14711534
</div>
14721535
{/* =========================== End:: AddTraineeModel =============================== */}
1536+
{/* =========================== Start:: RestoreTraineeModel =============================== */}
1537+
1538+
<div
1539+
className={`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 ${
1540+
restoreTraineeModel === true ? 'block' : 'hidden'
1541+
}`}
1542+
>
1543+
<div className="w-full p-4 pb-8 bg-white rounded-lg dark:bg-dark-bg sm:w-3/4 xl:w-4/12">
1544+
<div className="flex flex-wrap items-center justify-center w-full card-title ">
1545+
<h3 className="w-11/12 text-sm font-bold text-center dark:text-white ">
1546+
{t('Restore Trainee')}
1547+
</h3>
1548+
<hr className="w-full my-3 border-b bg-primary" />
1549+
</div>
1550+
<div className="card-body">
1551+
<form className="px-8 py-3 ">
1552+
<div className="flex flex-wrap items-center justify-center w-full card-title ">
1553+
<h3 className="w-11/12 text-sm font-bold text-center dark:text-white ">
1554+
{t('Are you sure you want to undrop this trainee?')}
1555+
</h3>
1556+
</div>
1557+
1558+
<div className="flex justify-between w-full">
1559+
<Button
1560+
data-testid="restoreModel2"
1561+
variant="info"
1562+
size="sm"
1563+
style="w-[40%] md:w-1/4 text-sm font-sans"
1564+
onClick={() => restoreTraineeMod()}
1565+
>
1566+
{t('Cancel')}
1567+
</Button>
1568+
<Button
1569+
variant="primary"
1570+
size="sm"
1571+
data-testid="restoreMemberFromCohort"
1572+
style="w-[40%] md:w-1/4 text-sm font-sans"
1573+
onClick={() => {
1574+
setButtonLoading(true);
1575+
unDropTrainee();
1576+
}}
1577+
loading={buttonLoading}
1578+
>
1579+
{t('Proceed')}
1580+
</Button>
1581+
</div>
1582+
</form>
1583+
</div>
1584+
</div>
1585+
</div>
1586+
{/* =========================== End:: RemoveTraineeModel =============================== */}
14731587

14741588
<div className="flex flex-col">
14751589
<div className="flex flex-row">
@@ -1504,15 +1618,15 @@ function AdminTraineeDashboard() {
15041618
</div>
15051619
</div>
15061620
<div className="">
1507-
{loading? (
1508-
<TtlSkeleton/>
1509-
):(
1510-
<DataTable
1511-
data={traineeData?.length > 0 ? datum : []}
1512-
columns={columns}
1513-
loading={loading}
1514-
title={t('Trainee list')}
1515-
/>
1621+
{loading ? (
1622+
<TtlSkeleton />
1623+
) : (
1624+
<DataTable
1625+
data={traineeData?.length > 0 ? datum : []}
1626+
columns={columns}
1627+
loading={loading}
1628+
title={t('Trainee list')}
1629+
/>
15161630
)}
15171631
</div>
15181632
</div>
@@ -1524,4 +1638,4 @@ function AdminTraineeDashboard() {
15241638
);
15251639
}
15261640

1527-
export default AdminTraineeDashboard;
1641+
export default AdminTraineeDashboard;

src/pages/Organization/AdminLogin.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ function AdminLogin() {
106106
},
107107
onError: (err) => {
108108
/* istanbul ignore next */
109+
console.log(err.message);
110+
109111
if (err.networkError)
110112
toast.error('There was a problem contacting the server');
111113
else if (err.message.toLowerCase() !== 'invalid credential') {

0 commit comments

Comments
 (0)