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
@@ -2,6 +2,8 @@ import { act } from "react";
import { createRoot, type Root } from "react-dom/client";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { getCharacterBySlug } from "@/data/constants/character";
import { CharacterProvider } from "@/providers/character-provider";
import { Result } from "@/utils/result";
import { FeedbackScreen } from "../feedback-screen";
@@ -48,7 +50,7 @@ describe("FeedbackScreen", () => {
});
it("renders all categories and defaults to Problem", () => {
act(() => root.render(<FeedbackScreen />));
renderFeedbackScreen(root);
expect(container.textContent).toContain("Help us improve CozSweet");
expect(container.textContent).toContain("Problem");
@@ -73,7 +75,7 @@ describe("FeedbackScreen", () => {
mocks.submitFeedback.mockResolvedValue(
Result.ok({ feedbackId: "feedback-123" }),
);
act(() => root.render(<FeedbackScreen />));
renderFeedbackScreen(root);
const textarea = container.querySelector("textarea");
if (!textarea) throw new Error("Expected feedback textarea");
@@ -104,6 +106,18 @@ describe("FeedbackScreen", () => {
});
});
function renderFeedbackScreen(root: Root): void {
const character = getCharacterBySlug("maya");
if (!character) throw new Error("Missing Maya character fixture");
act(() =>
root.render(
<CharacterProvider character={character}>
<FeedbackScreen />
</CharacterProvider>,
),
);
}
function setTextareaValue(element: HTMLTextAreaElement, value: string): void {
const setter = Object.getOwnPropertyDescriptor(
HTMLTextAreaElement.prototype,
+19 -3
View File
@@ -1,5 +1,21 @@
import { FeedbackScreen } from "./feedback-screen";
import { redirect } from "next/navigation";
export default function FeedbackPage() {
return <FeedbackScreen />;
import { DEFAULT_CHARACTER_SLUG } from "@/data/constants/character";
import {
appendRouteSearchParams,
getCharacterRoutes,
type RouteSearchParams,
} from "@/router/routes";
export default async function FeedbackPage({
searchParams,
}: {
searchParams: Promise<RouteSearchParams>;
}) {
redirect(
appendRouteSearchParams(
getCharacterRoutes(DEFAULT_CHARACTER_SLUG).feedback,
await searchParams,
),
);
}