admin and candidate prefinal commit - #2
Conversation
| console.log('Candidates loaded: '); | ||
|
|
||
| this.candidates = [...attended, ...notAttended]; | ||
| this.candidates = [...(attended || []), ...(notAttended || [])]; |
There was a problem hiding this comment.
| this.candidates = [...(attended || []), ...(notAttended || [])]; | |
| this.candidates = attended.concat(notAttented); |
| describe('AppComponent', () => { | ||
| beforeEach(async () => { | ||
| await TestBed.configureTestingModule({ | ||
| imports: [AppComponent], |
There was a problem hiding this comment.
delete this file as there is no use as of now
| next: (count) => this.activeExams = count, | ||
| error: (err) => console.error(err) | ||
| error: (err) => { | ||
| console.error(err) |
| next: (count) => this.totalCandidates = count, | ||
| error: (err) => console.error(err) | ||
| error: (err) => { | ||
| console.error(err); |
| error: () => { | ||
| this.snackBar.open('Failed to load completed exams.', '', { duration: 5000 }); | ||
| error: (err) => { | ||
| this.snackBar.open(err?.error?.message || 'Failed to load completed exams.', '', { duration: 5000 }); |
There was a problem hiding this comment.
{ } should be use if there are multiple linse, on above only single line present so use instead error: (err) => this.snackBar.open(err?.error?.message || 'Failed to load completed exams.', '', { duration: 5000 });
| position: relative; | ||
| } | ||
| .submit-btn mat-spinner { | ||
| margin: 0 !important; |
There was a problem hiding this comment.
Try to avoid important here
| } | ||
| .submit-btn mat-spinner { | ||
| margin: 0 !important; | ||
| position: static !important; |
| this.examForm.get('title')?.valueChanges.subscribe((title: string) => { | ||
| if (title && title.trim().length > 0) { | ||
| const generatedKey = this.generateExamKey(title); | ||
| this.examForm.get('key')?.setValue(generatedKey, { emitEvent: false }); |
There was a problem hiding this comment.
this.examForm.get('key')?.setValue(this.generateExamKey(title), { emitEvent: false });
| }, | ||
| error: () => { | ||
| this.snackBar.open('Failed to load categories', 'Close', { | ||
| error: (err) => { |
There was a problem hiding this comment.
{ } remove , seems there is single line
| })), | ||
| }; | ||
|
|
||
| console.log(examPayload) |
| return errorMessages[errorKey]; | ||
| } | ||
| } | ||
| if (control?.hasError('required')) return 'This field is required'; |
There was a problem hiding this comment.
From Line 344 to 354, replaced with below one as repeated if (control?.hasError(...)) checks
const errors = control.errors;
if (errors['required']) return 'This field is required';
if (errors['min']) return Minimum value is ${errors['min'].min};
if (errors['max']) return Maximum value is ${errors['max'].max};
if (errors['minlength']) return Minimum length is ${errors['minlength'].requiredLength};
if (errors['maxlength']) return Maximum length is ${errors['maxlength'].requiredLength};
if (errors['pattern']) return 'Must be exactly 10 alphanumeric characters';
| .upload-button mat-spinner { | ||
| width: 20px; | ||
| height: 20px; | ||
| margin: 0 !important; |
There was a problem hiding this comment.
try to avoid !important
| font-weight: 700; | ||
| border-radius: 8px; | ||
| box-shadow: 0 2px 8px rgba(59, 24, 119, 0.08); | ||
| background: #3b1877 !important; |
There was a problem hiding this comment.
try to avoid !important in this file
| const token = this.route.snapshot.queryParamMap.get('token'); | ||
| if (token) { | ||
| this.http.get(`${environment.apiBaseUrl}/auth/verify-email?token=${token}`).subscribe({ | ||
| next: (res: any) => { |
There was a problem hiding this comment.
give proper type here instead of any
| this.router.navigate(['/landing']); | ||
| } | ||
|
|
||
| resendVerificationLink() { |
There was a problem hiding this comment.
if this function not in use then remove it
| padding: 12px 36px; | ||
| margin-bottom: 18px; | ||
| font-weight: 600; | ||
| background: #7c4dff !important; |
There was a problem hiding this comment.
try to avoid !important in file
| .logo { | ||
| font-size: 80px; | ||
| color: #3b1877; | ||
| background: none !important; |
There was a problem hiding this comment.
try to avoid !important in file
| this.loading = false; | ||
| console.log(this.registrationForm.value); | ||
| const errorMessage = err?.error?.message || 'Registration failed.'; | ||
| console.log(errorMessage); |
There was a problem hiding this comment.
remove console from here
| this.loading = true; | ||
| this.candidateRegService.register(this.registrationForm.value).subscribe({ | ||
| next: () => { | ||
| console.log(this.registrationForm.value); |
There was a problem hiding this comment.
remove console from here
| const email = this.registrationForm.get('email')?.value; | ||
| if (email) { | ||
| this.candidateRegService.resendVerification(email).subscribe({ | ||
| next: () => { |
There was a problem hiding this comment.
remove { } around single line
| next: () => { | ||
| this.snackBar.open('A new verification link has been sent to your email.', 'OK', { duration: 5000 }); | ||
| }, | ||
| error: (err) => { |
There was a problem hiding this comment.
remove { } around single line
| } | ||
| } | ||
|
|
||
| goToLanding() { |
There was a problem hiding this comment.
remove this function
| > | ||
| {{ loading ? 'Registering...' : 'Register' }} | ||
| </button> | ||
| <button |
There was a problem hiding this comment.
From Line 100 to 107 replace with below one, Use routerLink if navigation is static and router.navigate() if navigation needs to be conditional
mat-raised-button
type="button"
class="go-home-btn"
[routerLink] = "['/landing']"
>
Go to Homepage
| getStatus(index: number): 'not-seen' | 'seen-not-answered' | 'answered' | 'review' { | ||
| const q = this.questions[index]; | ||
| if (!q) return 'not-seen'; | ||
| if (this.answers[q.id]?.answer) return 'answered'; |
There was a problem hiding this comment.
const answer = this.answers[q.id];
if (answer?.answer) return 'answered';
| const q = this.questions[index]; | ||
| if (!q) return 'not-seen'; | ||
| if (this.answers[q.id]?.answer) return 'answered'; | ||
| if (this.answers[q.id]?.markedForReview) return 'review'; |
There was a problem hiding this comment.
if (answer?.markedForReview) return 'review';
| return this.http.post<any>(`${environment.apiBaseUrl}/candidate`, candidate).pipe( | ||
| tap((res) => { | ||
| const token = res?.data?.jwtToken || res?.data || res?.jwtToken || res; | ||
| if (token) { |
There was a problem hiding this comment.
Instead of if use : token && localStorage.setItem('jwt_token', token);
| // Get candidates by exam ID and status | ||
| getCandidatesByExamAndStatus(examId: number, status: string): Observable<Candidate[]> { | ||
| const url = `${this.apiUrl}/exam/${examId}/candidate?candidateStatus=${status}`; | ||
| return this.http.get<any>(url).pipe( |
There was a problem hiding this comment.
use proper type here instead of any
There was a problem hiding this comment.
remove any data types within file and use proper types
shubhangi-pio
left a comment
There was a problem hiding this comment.
@AbdulPIO Work on changes
| @@ -88,10 +88,10 @@ export class UploadQuestionsComponent { | |||
| this.uploading = false; | |||
| let errorMsg = 'Failed to upload question. Please try again'; | |||
| if ( | |||
There was a problem hiding this comment.
not required to check this condition, you can directly write let message = errorResponse?.error?.message || 'Failed to upload question. Please try again';
| next: (res) => { | ||
| this.loading = false; | ||
| // Save response data to sessionStorage for exam window | ||
| if (res && res.data) { |
There was a problem hiding this comment.
| if (res && res.data) { | |
| if (res?.data) { |
| ngOnInit(): void { | ||
| const token = this.route.snapshot.queryParamMap.get('token'); | ||
| if (token) { | ||
| this.http.get(`${environment.apiBaseUrl}/auth/verify-email?token=${token}`).subscribe({ |
There was a problem hiding this comment.
why writing API call in component, define the API calls in a function in service & use that function in component for clean code
| this.examService.saveExamSessionData(sessionData); | ||
|
|
||
| this.answers = {}; | ||
|
|
There was a problem hiding this comment.
REMOVE EXTRA BLANK LINES FROM FILE
| const examData = this.examService.getExamDataFromSession(); | ||
| examData.timeLeft = this.timeLeft; | ||
| this.examService.saveExamDataToSession(examData); | ||
| if (this.timeLeft === 15 * 60) { |
There was a problem hiding this comment.
15*60 these type of values are called magic numbers. store this in a const variable and call the variable rather than writing directly to follow a standard. check this in whole file
There was a problem hiding this comment.
the standard way to define a interceptor file name is NAME.interceptor.ts
| resendVerification(email: string): Observable<any> { | ||
| return this.http.post<any>( | ||
| `${environment.apiBaseUrl}/auth/send-verification-link?email=${encodeURIComponent(email)}`, | ||
| {} |
There was a problem hiding this comment.
| {} | |
| null |
this sounds better
|
|
||
|
|
||
| logout() { | ||
| localStorage.removeItem('jwt_token'); |
There was a problem hiding this comment.
| localStorage.removeItem('jwt_token'); | |
| localStorage.clear(); |
this will ensure to remove all items from local storage. also check if anything is to be removed from session storage or not
| } | ||
|
|
||
| logout() { | ||
| localStorage.removeItem('jwt_token'); |
There was a problem hiding this comment.
I noticed another logout() function above, why not create 1 single logout() function and use everywhere.
No description provided.