Commit 669ca3f1 authored by Aravind RK's avatar Aravind RK

feat : Violation notification comes to admin/HR

parent 71897859
...@@ -33,7 +33,8 @@ const interviewSchema = new mongoose.Schema({ ...@@ -33,7 +33,8 @@ const interviewSchema = new mongoose.Schema({
score: { type: Number, default: null }, score: { type: Number, default: null },
totalMarks: { type: Number, default: null }, totalMarks: { type: Number, default: null },
percentage: { type: Number, default: null }, percentage: { type: Number, default: null },
completed: { type: Boolean, default: false } completed: { type: Boolean, default: false },
violation: { type: Boolean, default: false }
}], }],
// Coding round // Coding round
......
...@@ -40,6 +40,10 @@ const submissionSchema = new mongoose.Schema({ ...@@ -40,6 +40,10 @@ const submissionSchema = new mongoose.Schema({
type: Number, // in seconds type: Number, // in seconds
default: 0 default: 0
}, },
violation: {
type: Boolean,
default: false
},
submittedAt: { submittedAt: {
type: Date, type: Date,
default: Date.now default: Date.now
......
...@@ -145,7 +145,7 @@ router.get('/quiz/:quizId', async (req, res) => { ...@@ -145,7 +145,7 @@ router.get('/quiz/:quizId', async (req, res) => {
router.post('/quiz/:quizId/submit', async (req, res) => { router.post('/quiz/:quizId/submit', async (req, res) => {
try { try {
const { quizId } = req.params; const { quizId } = req.params;
const { answers, timeTaken } = req.body; const { answers, timeTaken, violation } = req.body;
// Check if candidate already submitted // Check if candidate already submitted
const existingSubmission = await Submission.findOne({ const existingSubmission = await Submission.findOne({
...@@ -192,7 +192,8 @@ router.post('/quiz/:quizId/submit', async (req, res) => { ...@@ -192,7 +192,8 @@ router.post('/quiz/:quizId/submit', async (req, res) => {
score, score,
totalMarks, totalMarks,
percentage, percentage,
timeTaken: timeTaken || 0 timeTaken: timeTaken || 0,
violation: !!violation
}); });
// Update Interview if applicable // Update Interview if applicable
...@@ -204,7 +205,8 @@ router.post('/quiz/:quizId/submit', async (req, res) => { ...@@ -204,7 +205,8 @@ router.post('/quiz/:quizId/submit', async (req, res) => {
'quizzes.$.score': score, 'quizzes.$.score': score,
'quizzes.$.totalMarks': totalMarks, 'quizzes.$.totalMarks': totalMarks,
'quizzes.$.percentage': percentage, 'quizzes.$.percentage': percentage,
'quizzes.$.completed': true 'quizzes.$.completed': true,
'quizzes.$.violation': !!violation
} }
} }
); );
......
...@@ -373,7 +373,12 @@ ...@@ -373,7 +373,12 @@
<div class="quiz-result-card"> <div class="quiz-result-card">
<div class="qr-title">{{ q.title }}</div> <div class="qr-title">{{ q.title }}</div>
@if (q.completed) { @if (q.completed) {
<div class="qr-score">{{ q.score }}/{{ q.totalMarks }} ({{ q.percentage }}%)</div> <div class="qr-score" [class.violation]="q.violation">{{ q.score }}/{{ q.totalMarks }} ({{ q.percentage }}%)</div>
@if (q.violation) {
<div style="color: #ef4444; font-size: 11px; margin-top: 6px; display: flex; align-items: center; gap: 4px; font-weight: 500;">
<span class="material-symbols-rounded" style="font-size: 14px;">warning</span> Auto-submitted (Violation)
</div>
}
} @else { } @else {
<div class="qr-pending">Not Taken</div> <div class="qr-pending">Not Taken</div>
} }
......
...@@ -202,7 +202,12 @@ ...@@ -202,7 +202,12 @@
<div class="quiz-result-card"> <div class="quiz-result-card">
<div class="qr-title">{{ q.title }}</div> <div class="qr-title">{{ q.title }}</div>
@if (q.completed) { @if (q.completed) {
<div class="qr-score">{{ q.score }}/{{ q.totalMarks }} ({{ q.percentage }}%)</div> <div class="qr-score" [class.violation]="q.violation">{{ q.score }}/{{ q.totalMarks }} ({{ q.percentage }}%)</div>
@if (q.violation) {
<div style="color: #ef4444; font-size: 11px; margin-top: 6px; display: flex; align-items: center; gap: 4px; font-weight: 500;">
<span class="material-symbols-rounded" style="font-size: 14px;">warning</span> Auto-submitted (Violation)
</div>
}
} @else { } @else {
<div class="qr-pending">Not Taken</div> <div class="qr-pending">Not Taken</div>
} }
......
...@@ -373,7 +373,12 @@ ...@@ -373,7 +373,12 @@
<div class="quiz-result-card"> <div class="quiz-result-card">
<div class="qr-title">{{ q.title }}</div> <div class="qr-title">{{ q.title }}</div>
@if (q.completed) { @if (q.completed) {
<div class="qr-score">{{ q.score }}/{{ q.totalMarks }} ({{ q.percentage }}%)</div> <div class="qr-score" [class.violation]="q.violation">{{ q.score }}/{{ q.totalMarks }} ({{ q.percentage }}%)</div>
@if (q.violation) {
<div style="color: #ef4444; font-size: 11px; margin-top: 6px; display: flex; align-items: center; gap: 4px; font-weight: 500;">
<span class="material-symbols-rounded" style="font-size: 14px;">warning</span> Auto-submitted (Violation)
</div>
}
} @else { } @else {
<div class="qr-pending">Not Taken</div> <div class="qr-pending">Not Taken</div>
} }
......
...@@ -202,7 +202,12 @@ ...@@ -202,7 +202,12 @@
<div class="quiz-result-card"> <div class="quiz-result-card">
<div class="qr-title">{{ q.title }}</div> <div class="qr-title">{{ q.title }}</div>
@if (q.completed) { @if (q.completed) {
<div class="qr-score">{{ q.score }}/{{ q.totalMarks }} ({{ q.percentage }}%)</div> <div class="qr-score" [class.violation]="q.violation">{{ q.score }}/{{ q.totalMarks }} ({{ q.percentage }}%)</div>
@if (q.violation) {
<div style="color: #ef4444; font-size: 11px; margin-top: 6px; display: flex; align-items: center; gap: 4px; font-weight: 500;">
<span class="material-symbols-rounded" style="font-size: 14px;">warning</span> Auto-submitted (Violation)
</div>
}
} @else { } @else {
<div class="qr-pending">Not Taken</div> <div class="qr-pending">Not Taken</div>
} }
......
...@@ -617,7 +617,12 @@ ...@@ -617,7 +617,12 @@
<div class="quiz-result-card"> <div class="quiz-result-card">
<div class="qr-title">{{ q.title }}</div> <div class="qr-title">{{ q.title }}</div>
@if (q.completed) { @if (q.completed) {
<div class="qr-score">{{ q.score }}/{{ q.totalMarks }} ({{ q.percentage }}%)</div> <div class="qr-score" [class.violation]="q.violation">{{ q.score }}/{{ q.totalMarks }} ({{ q.percentage }}%)</div>
@if (q.violation) {
<div style="color: #ef4444; font-size: 11px; margin-top: 6px; display: flex; align-items: center; gap: 4px; font-weight: 500;">
<span class="material-symbols-rounded" style="font-size: 14px;">warning</span> Auto-submitted (Violation)
</div>
}
} @else { } @else {
<div class="qr-pending">Not Taken</div> <div class="qr-pending">Not Taken</div>
} }
......
...@@ -307,7 +307,12 @@ ...@@ -307,7 +307,12 @@
<div class="quiz-result-card"> <div class="quiz-result-card">
<div class="qr-title">{{ q.title }}</div> <div class="qr-title">{{ q.title }}</div>
@if (q.completed) { @if (q.completed) {
<div class="qr-score">{{ q.score }}/{{ q.totalMarks }} ({{ q.percentage }}%)</div> <div class="qr-score" [class.violation]="q.violation">{{ q.score }}/{{ q.totalMarks }} ({{ q.percentage }}%)</div>
@if (q.violation) {
<div style="color: #ef4444; font-size: 11px; margin-top: 6px; display: flex; align-items: center; gap: 4px; font-weight: 500;">
<span class="material-symbols-rounded" style="font-size: 14px;">warning</span> Auto-submitted (Violation)
</div>
}
} @else { } @else {
<div class="qr-pending">Not Taken</div> <div class="qr-pending">Not Taken</div>
} }
......
...@@ -229,7 +229,7 @@ export class TakeQuizComponent implements OnInit, OnDestroy { ...@@ -229,7 +229,7 @@ export class TakeQuizComponent implements OnInit, OnDestroy {
questionId, selectedAnswers questionId, selectedAnswers
})); }));
this.quizService.submitQuiz(this.quiz().id, answersArray, timeTaken).subscribe({ this.quizService.submitQuiz(this.quiz().id, answersArray, timeTaken, isAutoSubmit).subscribe({
next: () => { next: () => {
this.submitted.set(true); this.submitted.set(true);
this.submitting.set(false); this.submitting.set(false);
......
...@@ -618,7 +618,12 @@ ...@@ -618,7 +618,12 @@
<div class="quiz-result-card"> <div class="quiz-result-card">
<div class="qr-title">{{ q.title }}</div> <div class="qr-title">{{ q.title }}</div>
@if (q.completed) { @if (q.completed) {
<div class="qr-score">{{ q.score }}/{{ q.totalMarks }} ({{ q.percentage }}%)</div> <div class="qr-score" [class.violation]="q.violation">{{ q.score }}/{{ q.totalMarks }} ({{ q.percentage }}%)</div>
@if (q.violation) {
<div style="color: #ef4444; font-size: 11px; margin-top: 6px; display: flex; align-items: center; gap: 4px; font-weight: 500;">
<span class="material-symbols-rounded" style="font-size: 14px;">warning</span> Auto-submitted (Violation)
</div>
}
} @else { } @else {
<div class="qr-pending">Not Taken</div> <div class="qr-pending">Not Taken</div>
} }
......
...@@ -307,7 +307,12 @@ ...@@ -307,7 +307,12 @@
<div class="quiz-result-card"> <div class="quiz-result-card">
<div class="qr-title">{{ q.title }}</div> <div class="qr-title">{{ q.title }}</div>
@if (q.completed) { @if (q.completed) {
<div class="qr-score">{{ q.score }}/{{ q.totalMarks }} ({{ q.percentage }}%)</div> <div class="qr-score" [class.violation]="q.violation">{{ q.score }}/{{ q.totalMarks }} ({{ q.percentage }}%)</div>
@if (q.violation) {
<div style="color: #ef4444; font-size: 11px; margin-top: 6px; display: flex; align-items: center; gap: 4px; font-weight: 500;">
<span class="material-symbols-rounded" style="font-size: 14px;">warning</span> Auto-submitted (Violation)
</div>
}
} @else { } @else {
<div class="qr-pending">Not Taken</div> <div class="qr-pending">Not Taken</div>
} }
......
...@@ -175,8 +175,8 @@ ...@@ -175,8 +175,8 @@
return this.http.get(`${this.candidateUrl}/quiz/${quizId}`); return this.http.get(`${this.candidateUrl}/quiz/${quizId}`);
} }
submitQuiz(quizId: string, answers: any[], timeTaken: number): Observable<any> { submitQuiz(quizId: string, answers: any[], timeTaken: number, violation: boolean = false): Observable<any> {
return this.http.post(`${this.candidateUrl}/quiz/${quizId}/submit`, { answers, timeTaken }); return this.http.post(`${this.candidateUrl}/quiz/${quizId}/submit`, { answers, timeTaken, violation });
} }
getCandidateProfile(): Observable<any> { getCandidateProfile(): Observable<any> {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment