generated from muhtadeetaron/nextjs-template
107 lines
2.7 KiB
TypeScript
107 lines
2.7 KiB
TypeScript
"use client";
|
|
|
|
import { create } from "zustand";
|
|
import { Test, Answer, Question } from "@/types/exam";
|
|
import { API_URL, getToken } from "@/lib/auth";
|
|
import { ExamResult } from "@/types/exam";
|
|
|
|
// Result type (based on your API response)
|
|
|
|
interface ExamState {
|
|
test: Test | null;
|
|
answers: Answer[];
|
|
result: ExamResult | null;
|
|
|
|
startExam: (testType: string, testId: string) => Promise<Test | null>;
|
|
setAnswer: (questionIndex: number, answer: Answer) => void;
|
|
submitExam: (testType: string) => Promise<ExamResult | null>;
|
|
cancelExam: () => void;
|
|
clearResult: () => void;
|
|
}
|
|
|
|
export const useExamStore = create<ExamState>((set, get) => ({
|
|
test: null,
|
|
answers: [],
|
|
result: null,
|
|
|
|
// start exam
|
|
startExam: async (testType: string, testId: string) => {
|
|
try {
|
|
const token = await getToken();
|
|
const res = await fetch(`${API_URL}/tests/${testType}/${testId}`, {
|
|
method: "GET",
|
|
headers: {
|
|
Authorization: `Bearer ${token}`,
|
|
},
|
|
});
|
|
|
|
if (!res.ok) throw new Error(`Failed to fetch test: ${res.status}`);
|
|
const data: Test = await res.json();
|
|
|
|
set({
|
|
test: data,
|
|
answers: Array(data.questions.length).fill(null),
|
|
result: null, // clear old result
|
|
});
|
|
|
|
return data;
|
|
} catch (err) {
|
|
console.error("startExam error:", err);
|
|
return null;
|
|
}
|
|
},
|
|
|
|
// set an answer
|
|
setAnswer: (questionIndex: number, answer: Answer) => {
|
|
set((state) => {
|
|
const updated = [...state.answers];
|
|
updated[questionIndex] = answer;
|
|
return { answers: updated };
|
|
});
|
|
},
|
|
|
|
// submit exam
|
|
submitExam: async (testType: string) => {
|
|
const { test, answers } = get();
|
|
if (!test) return null;
|
|
|
|
const token = await getToken();
|
|
|
|
try {
|
|
const { test_id, attempt_id } = test.metadata;
|
|
const res = await fetch(
|
|
`${API_URL}/tests/${testType}/${test_id}/${attempt_id}`,
|
|
{
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
Authorization: `Bearer ${token}`,
|
|
},
|
|
body: JSON.stringify({ answers }),
|
|
}
|
|
);
|
|
|
|
if (!res.ok) throw new Error("Failed to submit exam");
|
|
const result: ExamResult = await res.json();
|
|
|
|
// save result, clear test+answers
|
|
set({ test: null, answers: [], result });
|
|
|
|
return result;
|
|
} catch (err) {
|
|
console.error("Failed to submit exam. Reason:", err);
|
|
return null;
|
|
}
|
|
},
|
|
|
|
// cancel exam
|
|
cancelExam: () => {
|
|
set({ test: null, answers: [], result: null });
|
|
},
|
|
|
|
// clear result manually (e.g., when leaving results page)
|
|
clearResult: () => {
|
|
set({ result: null });
|
|
},
|
|
}));
|