Files
readest/apps/readest-app/src/store/reviewModeStore.ts
T

143 lines
4.1 KiB
TypeScript

import { create } from 'zustand';
import type {
ReviewGptConfig,
ReviewRow,
ReviewSessionPayload,
} from '@/services/reviewEditorService';
export type ReviewBookState = {
enabled: boolean;
loading: boolean;
error: string;
baseUrl: string;
sessionId: string | null;
reviewRoot?: string;
version?: string;
rows: ReviewRow[];
session: ReviewSessionPayload | null;
gptConfig: ReviewGptConfig | null;
selectedRowId: string;
};
type ReviewModeStore = {
activeBookKey: string | null;
isPanelVisible: boolean;
isPanelPinned: boolean;
panelWidth: string;
panelHeight: string;
books: Record<string, ReviewBookState>;
getBookState: (bookKey: string | null) => ReviewBookState | null;
setActiveBookKey: (bookKey: string | null) => void;
setPanelVisible: (visible: boolean) => void;
togglePanelPin: () => void;
setPanelWidth: (width: string) => void;
setPanelHeight: (height: string) => void;
setBookLoading: (bookKey: string, loading: boolean) => void;
setBookError: (bookKey: string, error: string) => void;
setBookEnabled: (bookKey: string, enabled: boolean) => void;
setBookData: (
bookKey: string,
data: Partial<Omit<ReviewBookState, 'enabled' | 'loading' | 'error'>>,
) => void;
selectRow: (bookKey: string, rowId: string) => void;
updateRow: (bookKey: string, row: ReviewRow) => void;
clearBook: (bookKey: string) => void;
};
const emptyBookState = (): ReviewBookState => ({
enabled: false,
loading: false,
error: '',
baseUrl: '',
sessionId: null,
rows: [],
session: null,
gptConfig: null,
selectedRowId: '',
});
const withBookState = (
books: Record<string, ReviewBookState>,
bookKey: string,
patch: Partial<ReviewBookState>,
) => ({
...books,
[bookKey]: {
...(books[bookKey] || emptyBookState()),
...patch,
},
});
export const useReviewModeStore = create<ReviewModeStore>((set, get) => ({
activeBookKey: null,
isPanelVisible: false,
isPanelPinned: false,
panelWidth: '32%',
panelHeight: '68vh',
books: {},
getBookState: (bookKey) => (bookKey ? get().books[bookKey] || null : null),
setActiveBookKey: (bookKey) => set({ activeBookKey: bookKey }),
setPanelVisible: (visible) => set({ isPanelVisible: visible }),
togglePanelPin: () => set((state) => ({ isPanelPinned: !state.isPanelPinned })),
setPanelWidth: (width) => set({ panelWidth: width }),
setPanelHeight: (height) => set({ panelHeight: height }),
setBookLoading: (bookKey, loading) =>
set((state) => ({
books: withBookState(state.books, bookKey, loading ? { loading, error: '' } : { loading }),
})),
setBookError: (bookKey, error) =>
set((state) => ({
books: withBookState(state.books, bookKey, { error, loading: false }),
})),
setBookEnabled: (bookKey, enabled) =>
set((state) => ({
activeBookKey: enabled
? bookKey
: state.activeBookKey === bookKey
? null
: state.activeBookKey,
isPanelVisible: enabled
? true
: state.activeBookKey === bookKey
? false
: state.isPanelVisible,
books: withBookState(state.books, bookKey, { enabled }),
})),
setBookData: (bookKey, data) =>
set((state) => ({
books: withBookState(state.books, bookKey, {
...data,
loading: false,
error: '',
}),
})),
selectRow: (bookKey, rowId) =>
set((state) => ({
activeBookKey: bookKey,
isPanelVisible: true,
books: withBookState(state.books, bookKey, {
selectedRowId: rowId,
}),
})),
updateRow: (bookKey, row) =>
set((state) => {
const current = state.books[bookKey] || emptyBookState();
return {
books: withBookState(state.books, bookKey, {
rows: current.rows.map((item) => (item.id === row.id ? row : item)),
}),
};
}),
clearBook: (bookKey) =>
set((state) => {
const books = { ...state.books };
delete books[bookKey];
return {
books,
activeBookKey: state.activeBookKey === bookKey ? null : state.activeBookKey,
isPanelVisible: state.activeBookKey === bookKey ? false : state.isPanelVisible,
};
}),
}));