forked from hb1998/CodeGaze
-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathQuestionsPage.tsx
More file actions
154 lines (145 loc) · 6.48 KB
/
QuestionsPage.tsx
File metadata and controls
154 lines (145 loc) · 6.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import { Button, Divider, List, Skeleton, Tag, Typography } from 'antd';
import jwt_decode from 'jwt-decode';
import { Content } from 'antd/es/layout/layout';
import { useEffect, useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { Challenge, difficultyMap } from '../../types/Models';
import { ROUTES } from '../../constants/Route.constants';
import './styles/Assessment.css';
import { supabase } from '../API/supabase';
import { FUNCTIONS } from '../../constants/functions.constants';
import { toast } from 'react-toastify';
import Timer from './components/Timer';
import { useDispatch, useSelector } from 'react-redux';
import { IDispatch, IRootState } from '../../store';
import CommonUtils from '../common/utils/Common.utils';
const { Title } = Typography;
const ChallengesListComponent = () => {
const navigate = useNavigate();
const { examId, candidateId } = useParams();
const candidate = useSelector((state: IRootState) => state.candidate);
const [loading, setLoading] = useState(true);
const [beginState, setBeginState] = useState<Record<string, '' | 'loading' | 'started'>>({});
const [challenges, setchallenges] = useState<Challenge[]>([]);
const dispatch = useDispatch<IDispatch>();
const fetchExam = async () => {
try {
if (!candidate?.token) throw new Error('No token found');
await supabase.functions.setAuth(candidate.token);
const { data, error } = await supabase.functions.invoke(FUNCTIONS.GET_EXAM, {
body: {
examId,
},
});
const challenges = data?.challenge as Challenge[];
setchallenges(challenges);
if (error) throw error;
setLoading(false);
} catch (error) {
setLoading(false);
console.error('Error fetching exam:', error);
toast.error(error?.message || 'Error fetching exam');
}
};
useEffect(() => {
fetchExam();
}, [examId]);
const beginExam = async (challenge: Challenge) => {
try {
setBeginState({ ...beginState, [challenge.id]: 'loading' });
if (!candidate?.token) throw new Error('No token found');
const { data, error } = await supabase.functions.invoke(FUNCTIONS.UPDATE_ASSESSMENT, {
body: {
exam_id: examId,
candidate_id: candidateId,
challenge_id: challenge.id,
},
});
if (error) throw error;
dispatch.assessment.update(data?.[0]);
setBeginState({ ...beginState, [challenge.id]: 'started' });
window.open(`${ROUTES.CANDIDATE_ASSESSMENT}/${examId}/${candidateId}/${challenge.id}`);
} catch (error) {
setBeginState({ ...beginState, [challenge.id]: '' });
console.error('Error fetching exam:', error);
toast.error(error?.message || 'Error fetching exam');
}
};
const handleTimeout = ()=>{
dispatch.assessment.clear();
navigate(ROUTES.ASSESSMENT_OVER);
}
const expiry = (jwt_decode(candidate?.token) as { exp: number })?.exp;
const now = Date.now() / 1000;
const timeLeft = Math.round(expiry - now);
return (
<Content style={{ padding: '2rem' }}>
<Title level={2}>Welcome to the Assessment</Title>
<div className="flex-container justify-between">
<Title level={4}>Instructions</Title>
<Timer timeLeft={timeLeft} onTimeout={handleTimeout}/>
</div>
<p>
Welcome to the coding test for your interview! Please select a challenge from the list below to begin.
You will have a limited amount of time to complete the challenge, and your progress will be tracked.
Please do not refresh the page or navigate away from the challenge while you are working on it.
</p>
<ul>
<li>
Please make sure that all the test cases are handled, there will be some test cases which are hidden
from you.
</li>
<li>
Do not modify the starter code, write all your logic inside the <code>solve</code> function
</li>
<li>
Don't use <code>console.log</code> or <code>print</code> when submitting the assessment or running
the test cases, you have to return the result.
</li>
</ul>
<Divider dashed />
<Title level={4}>Exams</Title>
{loading ? (
<Skeleton />
) : (
<List
itemLayout="horizontal"
dataSource={challenges}
renderItem={(challenge) => (
<List.Item>
<List.Item.Meta
title={
<div>
{challenge.name}
<Tag
style={{ marginLeft: 10 }}
color={CommonUtils.getColor(challenge.difficulty)}
>
{difficultyMap[challenge.difficulty]}
</Tag>
</div>
}
description={challenge.short_description}
/>
{beginState[challenge.id] === 'started' ? (
<Button disabled={true} type="primary">
Started
</Button>
) : (
<Button
loading={beginState[challenge.id] === 'loading'}
onClick={() => beginExam(challenge)}
className="begin-button"
type="primary"
>
Begin Exam
</Button>
)}
</List.Item>
)}
/>
)}
</Content>
);
};
export default ChallengesListComponent;