Files
food-add-edu/src/stores/modules/dialog.ts
T
2026-08-18 13:39:42 +08:00

137 lines
2.9 KiB
TypeScript

import { create } from "zustand";
import { persist } from "zustand/middleware";
import { appConfig } from "@/app.config";
import type { GuideDialogState } from "../types/dialog.types";
const getDialogKey = (courseId: string, dialogId: string) =>
`${courseId}:${dialogId}`;
const getInitialState = () => ({
open: false,
courseId: null,
dialogId: null,
steps: [],
current: 0,
showOnce: true,
});
export const useDialogStore = create<GuideDialogState>()(
persist(
(set, get) => ({
...getInitialState(),
completedDialogMap: {},
startDialog: ({
courseId,
dialogId,
steps,
showOnce = true,
initialStep = 0,
}) => {
if (steps.length === 0) return;
const key = getDialogKey(courseId, dialogId);
if (showOnce && get().completedDialogMap[key]) {
return;
}
set({
open: true,
courseId,
dialogId,
steps,
current: Math.min(Math.max(initialStep, 0), steps.length - 1),
showOnce,
});
},
closeDialog: () => {
set(getInitialState());
},
nextStep: () => {
const { current, steps, finishDialog } = get();
if (current >= steps.length - 1) {
finishDialog();
return;
}
set({ current: current + 1 });
},
prevStep: () => {
const { current } = get();
set({ current: Math.max(current - 1, 0) });
},
setStep: (index) => {
const { steps } = get();
if (steps.length === 0) return;
set({ current: Math.min(Math.max(index, 0), steps.length - 1) });
},
selectOption: (optionId) => {
const { current, steps, setStep, finishDialog, nextStep } = get();
const step = steps[current];
const option = step?.options?.find((item) => item.id === optionId);
if (!option) return;
if (option.finish) {
finishDialog();
return;
}
if (option.nextId) {
const nextIndex = steps.findIndex(
(item) => item.id === option.nextId,
);
if (nextIndex >= 0) {
setStep(nextIndex);
return;
}
}
nextStep();
},
finishDialog: () => {
const { courseId, dialogId, completedDialogMap } = get();
if (!courseId || !dialogId) {
set(getInitialState());
return;
}
const key = getDialogKey(courseId, dialogId);
set({
...getInitialState(),
completedDialogMap: {
...completedDialogMap,
[key]: true,
},
});
},
skipDialog: () => {
get().finishDialog();
},
resetDialog: (courseId, dialogId) => {
const key = getDialogKey(courseId, dialogId);
const { [key]: _removed, ...rest } = get().completedDialogMap;
const isCurrentDialog =
get().courseId === courseId && get().dialogId === dialogId;
set({
...(isCurrentDialog ? getInitialState() : {}),
completedDialogMap: rest,
});
},
}),
{
name: `${appConfig.storage.prefix}-dialog-storage`,
partialize: (state) => ({
completedDialogMap: state.completedDialogMap,
}),
},
),
);