103 lines
2.8 KiB
TypeScript
103 lines
2.8 KiB
TypeScript
import { useState, useCallback } from 'react';
|
|
import { useAuthenticatedFetch } from './useAuthenticatedFetch';
|
|
import type { Quiz, QuizSource, SavedQuiz, QuizListItem } from '../types';
|
|
|
|
interface UseQuizLibraryReturn {
|
|
quizzes: QuizListItem[];
|
|
loading: boolean;
|
|
error: string | null;
|
|
fetchQuizzes: () => Promise<void>;
|
|
loadQuiz: (id: string) => Promise<SavedQuiz>;
|
|
saveQuiz: (quiz: Quiz, source: QuizSource, aiTopic?: string) => Promise<string>;
|
|
deleteQuiz: (id: string) => Promise<void>;
|
|
}
|
|
|
|
export const useQuizLibrary = (): UseQuizLibraryReturn => {
|
|
const { authFetch, isAuthenticated } = useAuthenticatedFetch();
|
|
const [quizzes, setQuizzes] = useState<QuizListItem[]>([]);
|
|
const [loading, setLoading] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
const fetchQuizzes = useCallback(async () => {
|
|
if (!isAuthenticated) return;
|
|
|
|
setLoading(true);
|
|
setError(null);
|
|
|
|
try {
|
|
const response = await authFetch('/api/quizzes');
|
|
if (!response.ok) {
|
|
throw new Error('Failed to fetch quizzes');
|
|
}
|
|
const data = await response.json();
|
|
setQuizzes(data);
|
|
} catch (err) {
|
|
setError(err instanceof Error ? err.message : 'Failed to fetch quizzes');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, [authFetch, isAuthenticated]);
|
|
|
|
const loadQuiz = useCallback(async (id: string): Promise<SavedQuiz> => {
|
|
const response = await authFetch(`/api/quizzes/${id}`);
|
|
if (!response.ok) {
|
|
throw new Error('Failed to load quiz');
|
|
}
|
|
return response.json();
|
|
}, [authFetch]);
|
|
|
|
const saveQuiz = useCallback(async (
|
|
quiz: Quiz,
|
|
source: QuizSource,
|
|
aiTopic?: string
|
|
): Promise<string> => {
|
|
const response = await authFetch('/api/quizzes', {
|
|
method: 'POST',
|
|
body: JSON.stringify({
|
|
title: quiz.title,
|
|
source,
|
|
aiTopic,
|
|
questions: quiz.questions.map(q => ({
|
|
text: q.text,
|
|
timeLimit: q.timeLimit,
|
|
options: q.options.map(o => ({
|
|
text: o.text,
|
|
isCorrect: o.isCorrect,
|
|
shape: o.shape,
|
|
color: o.color,
|
|
reason: o.reason,
|
|
})),
|
|
})),
|
|
}),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error('Failed to save quiz');
|
|
}
|
|
|
|
const data = await response.json();
|
|
return data.id;
|
|
}, [authFetch]);
|
|
|
|
const deleteQuiz = useCallback(async (id: string): Promise<void> => {
|
|
const response = await authFetch(`/api/quizzes/${id}`, {
|
|
method: 'DELETE',
|
|
});
|
|
|
|
if (!response.ok && response.status !== 204) {
|
|
throw new Error('Failed to delete quiz');
|
|
}
|
|
|
|
setQuizzes(prev => prev.filter(q => q.id !== id));
|
|
}, [authFetch]);
|
|
|
|
return {
|
|
quizzes,
|
|
loading,
|
|
error,
|
|
fetchQuizzes,
|
|
loadQuiz,
|
|
saveQuiz,
|
|
deleteQuiz,
|
|
};
|
|
};
|