feat: UI optimizations - button feedback, layout fixes, cache clearing, work/exam records
- Add active: state feedback to all buttons across the app - Fix cache clearing to update Zustand store (not just localStorage) - Remove checkboxes from settings cache section, compact layout - Settings page: single outer scroll instead of dual-column scroll - CourseWorkspace: elastic log panel height, work/exam record counts - Integrate WorkList/ExamList types and display in UI - Delete unused CourseList.tsx component - Fix wk.ts: strict equality, remove unused import Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { createStore } from "zustand/vanilla";
|
||||
import { persist, createJSONStorage } from "zustand/middleware";
|
||||
import type { CourseKind, RecordItem, RecordType } from "~/service/wk";
|
||||
import type { CourseKind, RecordItem, RecordType, WorkListItem, ExamListItem } from "~/service/wk";
|
||||
import type { CourseType } from "~/types/Course";
|
||||
import type { userInfoType } from "~/types/Userinfo";
|
||||
|
||||
@@ -39,6 +39,8 @@ export type AccountItem = {
|
||||
|
||||
export type RecordCacheMap = Record<string, RecordItem[]>;
|
||||
|
||||
export type WorkExamCacheMap = Record<string, WorkListItem[] | ExamListItem[]>;
|
||||
|
||||
type PersistPreferences = {
|
||||
persistAccounts: boolean;
|
||||
persistRecords: boolean;
|
||||
@@ -87,6 +89,9 @@ type AccountState = {
|
||||
recordType: RecordType;
|
||||
records: RecordItem[];
|
||||
recordCacheMap: RecordCacheMap;
|
||||
workList: WorkListItem[];
|
||||
examList: ExamListItem[];
|
||||
workExamCacheMap: WorkExamCacheMap;
|
||||
studyLogsMap: Record<string, string[]>;
|
||||
runningStudyMap: Record<string, boolean>;
|
||||
studyHeartbeatMap: Record<string, number>;
|
||||
@@ -97,6 +102,9 @@ type AccountState = {
|
||||
setRecordType: (recordType: RecordType) => void;
|
||||
setRecords: (records: RecordItem[]) => void;
|
||||
setRecordCache: (cacheKey: string, records: RecordItem[]) => void;
|
||||
setWorkList: (list: WorkListItem[]) => void;
|
||||
setExamList: (list: ExamListItem[]) => void;
|
||||
setWorkExamCache: (cacheKey: string, data: WorkListItem[] | ExamListItem[]) => void;
|
||||
setAccountRunningStudy: (accountId: string, value: boolean) => void;
|
||||
touchStudyHeartbeat: (accountId: string, timestamp?: number) => void;
|
||||
clearStudyHeartbeat: (accountId: string) => void;
|
||||
@@ -107,6 +115,9 @@ type AccountState = {
|
||||
upsertAccount: (account: AccountItem) => void;
|
||||
setAccountCourses: (accountId: string, courses: CourseType[]) => void;
|
||||
removeAccount: (accountId: string) => void;
|
||||
clearAllData: () => void;
|
||||
clearRecordsData: () => void;
|
||||
clearAccountsData: () => void;
|
||||
};
|
||||
|
||||
export const accountStore = createStore<AccountState>()(
|
||||
@@ -120,6 +131,9 @@ export const accountStore = createStore<AccountState>()(
|
||||
recordType: "",
|
||||
records: [],
|
||||
recordCacheMap: {},
|
||||
workList: [],
|
||||
examList: [],
|
||||
workExamCacheMap: {},
|
||||
studyLogsMap: {},
|
||||
runningStudyMap: {},
|
||||
studyHeartbeatMap: {},
|
||||
@@ -138,6 +152,15 @@ export const accountStore = createStore<AccountState>()(
|
||||
[cacheKey]: records,
|
||||
},
|
||||
})),
|
||||
setWorkList: (list) => set({ workList: list }),
|
||||
setExamList: (list) => set({ examList: list }),
|
||||
setWorkExamCache: (cacheKey, data) =>
|
||||
set((state) => ({
|
||||
workExamCacheMap: {
|
||||
...state.workExamCacheMap,
|
||||
[cacheKey]: data,
|
||||
},
|
||||
})),
|
||||
setAccountRunningStudy: (accountId, value) =>
|
||||
set((state) => ({
|
||||
runningStudyMap: {
|
||||
@@ -189,6 +212,39 @@ export const accountStore = createStore<AccountState>()(
|
||||
set({
|
||||
studyLogsMap: {},
|
||||
}),
|
||||
clearAllData: () =>
|
||||
set({
|
||||
accounts: [],
|
||||
selectedAccountId: "",
|
||||
expandedAccountId: "",
|
||||
selectedCourseId: null,
|
||||
courseKind: "run" as CourseKind,
|
||||
recordType: "" as RecordType,
|
||||
records: [],
|
||||
recordCacheMap: {},
|
||||
workList: [],
|
||||
examList: [],
|
||||
workExamCacheMap: {},
|
||||
studyLogsMap: {},
|
||||
runningStudyMap: {},
|
||||
studyHeartbeatMap: {},
|
||||
}),
|
||||
clearRecordsData: () =>
|
||||
set({
|
||||
records: [],
|
||||
recordCacheMap: {},
|
||||
workList: [],
|
||||
examList: [],
|
||||
workExamCacheMap: {},
|
||||
selectedCourseId: null,
|
||||
}),
|
||||
clearAccountsData: () =>
|
||||
set({
|
||||
accounts: [],
|
||||
selectedAccountId: "",
|
||||
expandedAccountId: "",
|
||||
selectedCourseId: null,
|
||||
}),
|
||||
upsertAccount: (account) =>
|
||||
set((state) => ({
|
||||
accounts: [
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { createStore } from "zustand/vanilla";
|
||||
import { createJSONStorage, persist } from "zustand/middleware";
|
||||
import { accountStore } from "~/store/account";
|
||||
|
||||
export type HostOption = {
|
||||
label: string;
|
||||
@@ -37,6 +38,7 @@ type SettingsState = {
|
||||
};
|
||||
|
||||
const accountStorageKey = "account-storage";
|
||||
const settingsStorageKey = "settings-storage";
|
||||
type PersistedStorage = {
|
||||
state?: Record<string, unknown>;
|
||||
version?: number;
|
||||
@@ -115,53 +117,40 @@ export const settingsStore = createStore<SettingsState>()(
|
||||
}
|
||||
},
|
||||
clearPersistedSection: (section) => {
|
||||
const store = accountStore.getState();
|
||||
|
||||
if (section === "accounts") {
|
||||
patchAccountStorage((state) => {
|
||||
const {
|
||||
accounts,
|
||||
selectedAccountId,
|
||||
expandedAccountId,
|
||||
selectedCourseId,
|
||||
records,
|
||||
recordCacheMap,
|
||||
studyLogsMap,
|
||||
runningStudyMap,
|
||||
...rest
|
||||
} = state;
|
||||
void accounts;
|
||||
void selectedAccountId;
|
||||
void expandedAccountId;
|
||||
void selectedCourseId;
|
||||
void records;
|
||||
void recordCacheMap;
|
||||
void studyLogsMap;
|
||||
void runningStudyMap;
|
||||
return rest;
|
||||
});
|
||||
store.clearAccountsData();
|
||||
localStorage.removeItem(accountStorageKey);
|
||||
}
|
||||
|
||||
if (section === "records") {
|
||||
store.clearRecordsData();
|
||||
patchAccountStorage((state) => {
|
||||
const { records, recordCacheMap, selectedCourseId, ...rest } =
|
||||
state;
|
||||
const { records, recordCacheMap, workList, examList, workExamCacheMap, ...rest } = state;
|
||||
void records;
|
||||
void recordCacheMap;
|
||||
void selectedCourseId;
|
||||
void workList;
|
||||
void examList;
|
||||
void workExamCacheMap;
|
||||
return rest;
|
||||
});
|
||||
}
|
||||
|
||||
if (section === "logs") {
|
||||
store.clearAllStudyLogs();
|
||||
patchAccountStorage((state) => {
|
||||
const { studyLogsMap, runningStudyMap, ...rest } = state;
|
||||
const { studyLogsMap, ...rest } = state;
|
||||
void studyLogsMap;
|
||||
void runningStudyMap;
|
||||
return rest;
|
||||
});
|
||||
}
|
||||
},
|
||||
clearAllPersistedData: () => {
|
||||
accountStore.getState().clearAllData();
|
||||
localStorage.removeItem(accountStorageKey);
|
||||
localStorage.removeItem(settingsStorageKey);
|
||||
window.location.reload();
|
||||
},
|
||||
setDebugEnabled: (value) => set({ debugEnabled: value }),
|
||||
setAutoScrollLogs: (value) => set({ autoScrollLogs: value }),
|
||||
|
||||
Reference in New Issue
Block a user