feat: add word import and class type display controls
Build Docker Package / docker-package (push) Successful in 6m34s

This commit is contained in:
2026-07-02 14:34:00 +08:00
parent 0378504be0
commit 17fc24edc7
16 changed files with 844 additions and 66 deletions
+37 -8
View File
@@ -17,20 +17,41 @@ export function usePkSetup() {
useEffect(() => {
async function loadInitialSetup() {
setLoadingSetup(true);
const [classTypesResponse, nextSettings] = await Promise.all([
fetch("/api/class-types?includeDisabled=false", { cache: "no-store" }),
loadSettings(),
]);
const classTypesData = (await classTypesResponse.json()) as { classTypes: ClassType[] };
setClassTypes(classTypesData.classTypes);
const nextSettings = await loadSettings();
setSettings(mergeSettings(nextSettings));
setSelectedClassTypeId((current) => current || classTypesData.classTypes[0]?.id || 0);
setLoadingSetup(false);
}
void loadInitialSetup();
}, []);
useEffect(() => {
let ignore = false;
async function loadClassTypes() {
setLoadingSetup(true);
setSelectedClassTypeId(0);
const params = new URLSearchParams({
includeDisabled: "false",
grade: selectedGrade,
});
const response = await fetch(`/api/class-types?${params.toString()}`, { cache: "no-store" });
const data = (await response.json()) as { classTypes: ClassType[] };
if (!ignore) {
setClassTypes(data.classTypes);
setSelectedClassTypeId(data.classTypes[0]?.id || 0);
setLoadingSetup(false);
}
}
void loadClassTypes();
return () => {
ignore = true;
};
}, [selectedGrade]);
useEffect(() => {
function refreshSettingsOnFocus() {
void loadSettings().then((nextSettings) => setSettings(mergeSettings(nextSettings)));
@@ -41,6 +62,8 @@ export function usePkSetup() {
}, []);
useEffect(() => {
let ignore = false;
async function loadWords() {
if (!selectedClassTypeId) {
setAvailableWords([]);
@@ -54,10 +77,16 @@ export function usePkSetup() {
});
const response = await fetch(`/api/words?${params.toString()}`, { cache: "no-store" });
const data = (await response.json()) as { words: WordItem[] };
setAvailableWords(data.words);
if (!ignore) {
setAvailableWords(data.words);
}
}
void loadWords();
return () => {
ignore = true;
};
}, [selectedGrade, selectedClassTypeId]);
return {