refactor(sidebar): remove unused store

This commit is contained in:
2026-06-29 10:58:15 +08:00
parent 1ebd29d1ed
commit 2207301ccb
7 changed files with 7 additions and 282 deletions
@@ -1,61 +0,0 @@
import { describe, expect, it } from "vitest";
import { createActor } from "xstate";
import { sidebarMachine } from "@/stores/sidebar/sidebar-machine";
import {
BottomNavItem,
SidebarPage,
} from "@/stores/sidebar/sidebar-state";
describe("sidebarMachine", () => {
it("shows a page and selects the matching bottom nav item", () => {
const actor = createActor(sidebarMachine).start();
actor.send({
type: "SidebarShowPage",
page: SidebarPage.Topics,
bottomNavItem: BottomNavItem.Topics,
});
expect(actor.getSnapshot().matches("idle")).toBe(true);
expect(actor.getSnapshot().context.currentPage).toBe(SidebarPage.Topics);
expect(actor.getSnapshot().context.selectedBottomNavItem).toBe(
BottomNavItem.Topics,
);
actor.stop();
});
it("clears bottom nav without changing the current page", () => {
const actor = createActor(sidebarMachine).start();
actor.send({
type: "SidebarShowPage",
page: SidebarPage.Gifts,
bottomNavItem: BottomNavItem.Gifts,
});
actor.send({ type: "SidebarClearBottomNav" });
expect(actor.getSnapshot().context.currentPage).toBe(SidebarPage.Gifts);
expect(actor.getSnapshot().context.selectedBottomNavItem).toBe(
BottomNavItem.None,
);
actor.stop();
});
it("updates character progress", () => {
const actor = createActor(sidebarMachine).start();
actor.send({
type: "SidebarUpdateCharacter",
name: "Elio",
progress: 72,
});
expect(actor.getSnapshot().context.characterName).toBe("Elio");
expect(actor.getSnapshot().context.characterProgress).toBe(72);
actor.stop();
});
});
-8
View File
@@ -1,8 +0,0 @@
/**
* @file Automatically generated by barrelsby.
*/
export * from "./sidebar-context";
export * from "./sidebar-events";
export * from "./sidebar-machine";
export * from "./sidebar-state";
-72
View File
@@ -1,72 +0,0 @@
"use client";
/**
* SidebarContext:基于 XState v5 的 React Context Provider
*
* 业务事件通过 `useMachine(sidebarMachine).send()` 派发。
* XState 自动处理状态转换(无异步副作用)。
*
* 兼容性:保持原 `useSidebarState()` / `useSidebarDispatch()` API。
* 内部将 XState 状态机快照映射回原 `SidebarState` 形状。
*/
import {
type Dispatch,
type ReactNode,
createContext,
useContext,
useMemo,
} from "react";
import { useMachine } from "@xstate/react";
import { sidebarMachine } from "./sidebar-machine";
import type {
SidebarState as MachineContext,
SidebarEvent,
} from "./sidebar-machine";
/**
* 对外暴露的 State 形状(保持与原 SidebarState 兼容)
*/
interface SidebarState {
currentPage: MachineContext["currentPage"];
selectedBottomNavItem: MachineContext["selectedBottomNavItem"];
characterName: string;
characterProgress: number;
}
const SidebarStateCtx = createContext<SidebarState | null>(null);
const SidebarDispatchCtx = createContext<Dispatch<SidebarEvent> | null>(null);
export function SidebarProvider({ children }: { children: ReactNode }) {
const [state, send] = useMachine(sidebarMachine, {});
// 映射 XState 状态机快照 → 原 SidebarState 形状
const sidebarState = useMemo<SidebarState>(
() => ({
currentPage: state.context.currentPage,
selectedBottomNavItem: state.context.selectedBottomNavItem,
characterName: state.context.characterName,
characterProgress: state.context.characterProgress,
}),
[state],
);
return (
<SidebarStateCtx.Provider value={sidebarState}>
<SidebarDispatchCtx.Provider value={send}>{children}</SidebarDispatchCtx.Provider>
</SidebarStateCtx.Provider>
);
}
export function useSidebarState(): SidebarState {
const ctx = useContext(SidebarStateCtx);
if (!ctx)
throw new Error("useSidebarState must be used inside <SidebarProvider>");
return ctx;
}
export function useSidebarDispatch(): Dispatch<SidebarEvent> {
const ctx = useContext(SidebarDispatchCtx);
if (!ctx)
throw new Error("useSidebarDispatch must be used inside <SidebarProvider>");
return ctx;
}
-13
View File
@@ -1,13 +0,0 @@
/**
* Sidebar 状态机:事件联合
*/
import type { SidebarPage, BottomNavItem } from "./sidebar-state";
export type SidebarEvent =
| {
type: "SidebarShowPage";
page: SidebarPage;
bottomNavItem?: BottomNavItem;
}
| { type: "SidebarClearBottomNav" }
| { type: "SidebarUpdateCharacter"; name: string; progress: number };
-76
View File
@@ -1,76 +0,0 @@
/**
* Sidebar 状态机(XState v5
*
* 原始 Dart: lib/ui/sidebar/bloc/sidebar bloc + sidebar state + sidebar event
*
* 设计要点:
* - XState v5 `setup({...}).createMachine({...})` 声明式 API
* - Sidebar 无异步副作用(纯 UI 状态),仅用 `assign` 处理
* - 保持事件类型名与原 Dart 一致
* - actions inline 在 setup() 中(确保类型推断正确)
*/
import { setup, assign } from "xstate";
import { BottomNavItem, SidebarState, initialState } from "./sidebar-state";
import type { SidebarEvent } from "./sidebar-events";
// 重新导出 State / Event 类型,保持 machine 文件的公共 API 不变
export type { SidebarState } from "./sidebar-state";
export { initialState } from "./sidebar-state";
export type { SidebarEvent } from "./sidebar-events";
// ============================================================
// Machine
// ============================================================
export const sidebarMachine = setup({
types: {
context: {} as SidebarState,
events: {} as SidebarEvent,
},
actions: {
showPage: assign(({ event }) => {
if (event.type !== "SidebarShowPage") return {};
return {
currentPage: event.page,
selectedBottomNavItem: event.bottomNavItem ?? BottomNavItem.None,
};
}),
clearBottomNav: assign(() => ({
selectedBottomNavItem: BottomNavItem.None,
})),
updateCharacter: assign(({ event }) => {
if (event.type !== "SidebarUpdateCharacter") return {};
return {
characterName: event.name,
characterProgress: event.progress,
};
}),
},
}).createMachine({
id: "sidebar",
initial: "idle",
context: initialState,
states: {
/**
* Sidebar 是纯数据状态(无异步副作用),仅用 idle 状态
* 所有事件均在 idle 状态内处理
*/
idle: {
on: {
SidebarShowPage: {
actions: "showPage",
},
SidebarClearBottomNav: {
actions: "clearBottomNav",
},
SidebarUpdateCharacter: {
actions: "updateCharacter",
},
},
},
},
});
export type SidebarMachine = typeof sidebarMachine;
-42
View File
@@ -1,42 +0,0 @@
/**
* Sidebar 状态机:State 形状 + 初始值
*
* 枚举 `SidebarPage` / `BottomNavItem` 与 state 形状强相关(`currentPage` /
* `selectedBottomNavItem` 字段的取值集合),因此与 state 同源定义在本文件,
* 避免与 `sidebar-machine.ts` 形成循环引用。
*/
/** 页面枚举(侧边栏主区域可显示的页面) */
export const SidebarPage = {
DefaultView: "defaultView",
Profile: "profile",
Topics: "topics",
Gifts: "gifts",
Activities: "activities",
} as const;
export type SidebarPage = (typeof SidebarPage)[keyof typeof SidebarPage];
/** 底部导航枚举(选中态) */
export const BottomNavItem = {
None: "none",
Topics: "topics",
Gifts: "gifts",
Activities: "activities",
} as const;
export type BottomNavItem = (typeof BottomNavItem)[keyof typeof BottomNavItem];
export interface SidebarState {
currentPage: SidebarPage;
selectedBottomNavItem: BottomNavItem;
characterName: string;
characterProgress: number;
}
export const initialState: SidebarState = {
currentPage: SidebarPage.DefaultView,
selectedBottomNavItem: BottomNavItem.None,
characterName: "Luna",
characterProgress: 0,
};