67 lines
2.0 KiB
TypeScript
67 lines
2.0 KiB
TypeScript
import { create } from 'zustand';
|
|
import type { SessionRow, QueueItem } from '@flashcard/shared';
|
|
import { sessionsApi } from '../api/sessions.js';
|
|
|
|
interface SessionState {
|
|
session: SessionRow | null;
|
|
current: QueueItem | null;
|
|
done: boolean;
|
|
showAnswer: boolean;
|
|
shownAt: number | null;
|
|
start: (input: { lessonId: number; maxCards: number | null; shuffle: boolean; direction: 'forward' | 'backward' | 'both' }) => Promise<void>;
|
|
reveal: () => void;
|
|
answer: (result: 'correct' | 'incorrect') => Promise<void>;
|
|
end: () => Promise<void>;
|
|
abandon: () => Promise<void>;
|
|
reset: () => void;
|
|
}
|
|
|
|
export const useSession = create<SessionState>((set, get) => ({
|
|
session: null, current: null, done: false, showAnswer: false, shownAt: null,
|
|
|
|
start: async (input) => {
|
|
const { session } = await sessionsApi.start(input);
|
|
const nx = await sessionsApi.next(session.id);
|
|
set({
|
|
session,
|
|
done: nx.done,
|
|
current: nx.done ? null : nx.item,
|
|
showAnswer: false,
|
|
shownAt: Date.now(),
|
|
});
|
|
},
|
|
|
|
reveal: () => set({ showAnswer: true }),
|
|
|
|
answer: async (result) => {
|
|
const s = get();
|
|
if (!s.session || !s.current) return;
|
|
const ttm = s.shownAt ? Date.now() - s.shownAt : null;
|
|
await sessionsApi.attempt(s.session.id, {
|
|
cardId: s.current.cardId, direction: s.current.direction, result, timeToAnswerMs: ttm,
|
|
});
|
|
const nx = await sessionsApi.next(s.session.id);
|
|
if (nx.done) {
|
|
set({ done: true, current: null, showAnswer: false });
|
|
} else {
|
|
set({ current: nx.item, showAnswer: false, shownAt: Date.now() });
|
|
}
|
|
},
|
|
|
|
end: async () => {
|
|
const s = get();
|
|
if (!s.session) return;
|
|
const finished = await sessionsApi.end(s.session.id);
|
|
set({ session: finished });
|
|
},
|
|
|
|
abandon: async () => {
|
|
const s = get();
|
|
if (!s.session) return;
|
|
await sessionsApi.abandon(s.session.id);
|
|
set({ session: null, current: null, done: false, showAnswer: false });
|
|
},
|
|
|
|
reset: () => set({ session: null, current: null, done: false, showAnswer: false, shownAt: null }),
|
|
}));
|