refactor(characters): drive shared UI from active character

This commit is contained in:
2026-07-17 19:33:59 +08:00
parent 8bb1e21886
commit 7bd5defa5e
42 changed files with 335 additions and 118 deletions
@@ -145,7 +145,10 @@ describe("character actor route providers", () => {
function renderChat(characterId: string): void {
act(() => {
root.render(
<ChatRouteProviders characterId={characterId}>
<ChatRouteProviders
characterId={characterId}
emptyChatGreeting={`Hello from ${characterId}`}
>
<span>chat</span>
</ChatRouteProviders>,
);
+7 -6
View File
@@ -2,13 +2,10 @@
import { createContext, type ReactNode, useContext } from "react";
import {
DEFAULT_CHARACTER,
type CharacterProfile,
} from "@/data/constants/character";
import type { CharacterProfile } from "@/data/constants/character";
import { getCharacterRoutes, type CharacterRoutes } from "@/router/routes";
const CharacterContext = createContext<CharacterProfile>(DEFAULT_CHARACTER);
const CharacterContext = createContext<CharacterProfile | null>(null);
export interface CharacterProviderProps {
character: CharacterProfile;
@@ -27,7 +24,11 @@ export function CharacterProvider({
}
export function useActiveCharacter(): CharacterProfile {
return useContext(CharacterContext);
const character = useContext(CharacterContext);
if (!character) {
throw new Error("useActiveCharacter must be used within CharacterProvider.");
}
return character;
}
export function useActiveCharacterRoutes(): CharacterRoutes {
+9 -4
View File
@@ -2,7 +2,6 @@
import type { ReactNode } from "react";
import { DEFAULT_CHARACTER_ID } from "@/data/constants/character";
import { ChatProvider } from "@/stores/chat/chat-context";
import { PaymentProvider } from "@/stores/payment/payment-context";
import { ChatAuthSync } from "@/stores/sync/chat-auth-sync";
@@ -11,17 +10,23 @@ import { PaymentSuccessSync } from "@/stores/sync/payment-success-sync";
export interface ChatRouteProvidersProps {
children: ReactNode;
characterId?: string;
characterId: string;
emptyChatGreeting: string;
}
export function ChatRouteProviders({
children,
characterId = DEFAULT_CHARACTER_ID,
characterId,
emptyChatGreeting,
}: ChatRouteProvidersProps) {
return (
<PaymentProvider key={characterId}>
<PaymentSuccessSync />
<ChatProvider key={characterId} characterId={characterId}>
<ChatProvider
key={characterId}
characterId={characterId}
emptyChatGreeting={emptyChatGreeting}
>
<ChatAuthSync />
<ChatPaymentSuccessSync />
{children}
@@ -2,17 +2,16 @@
import type { ReactNode } from "react";
import { DEFAULT_CHARACTER_ID } from "@/data/constants/character";
import { PrivateRoomProvider } from "@/stores/private-room";
export interface PrivateRoomRouteProviderProps {
children: ReactNode;
characterId?: string;
characterId: string;
}
export function PrivateRoomRouteProvider({
children,
characterId = DEFAULT_CHARACTER_ID,
characterId,
}: PrivateRoomRouteProviderProps) {
return (
<PrivateRoomProvider key={characterId} characterId={characterId}>