refactor(sidebar): remove unused store
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
* 根级 Client Providers 包装
|
||||
*
|
||||
* 把所有功能 Provider 串起来:
|
||||
* AuthProvider → UserProvider → SidebarProvider → ChatProvider
|
||||
* AuthProvider → UserProvider → PaymentProvider → ChatProvider
|
||||
* + AuthStatusChecker(启动时一次:派发 AuthInit)
|
||||
* + OAuthSessionSync (持续监听 NextAuth session → auth machine)
|
||||
* + UserAuthSync (auth 登录态恢复后 hydrate user machine)
|
||||
@@ -22,7 +22,6 @@ import { OAuthSessionSync } from "@/stores/auth/oauth-session-sync";
|
||||
import { ChatAuthSync } from "@/stores/chat/chat-auth-sync";
|
||||
import { ChatProvider } from "@/stores/chat/chat-context";
|
||||
import { PaymentProvider, PaymentSuccessSync } from "@/stores/payment";
|
||||
import { SidebarProvider } from "@/stores/sidebar/sidebar-context";
|
||||
import { UserAuthSync } from "@/stores/user/user-auth-sync";
|
||||
import { UserProvider } from "@/stores/user/user-context";
|
||||
|
||||
@@ -41,14 +40,12 @@ export function RootProviders({ children }: RootProvidersProps) {
|
||||
<UserProvider>
|
||||
<UserAuthSync />
|
||||
<PaymentProvider>
|
||||
<SidebarProvider>
|
||||
<ChatProvider>
|
||||
<ChatAuthSync />
|
||||
<PaymentSuccessSync />
|
||||
{children}
|
||||
<div id="toast-portal" />
|
||||
</ChatProvider>
|
||||
</SidebarProvider>
|
||||
<ChatProvider>
|
||||
<ChatAuthSync />
|
||||
<PaymentSuccessSync />
|
||||
{children}
|
||||
<div id="toast-portal" />
|
||||
</ChatProvider>
|
||||
</PaymentProvider>
|
||||
</UserProvider>
|
||||
</AuthProvider>
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
@@ -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";
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 };
|
||||
@@ -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;
|
||||
@@ -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,
|
||||
};
|
||||
Reference in New Issue
Block a user