refactor(routes): move shared pages to global scope
This commit is contained in:
@@ -2,8 +2,6 @@ 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";
|
||||
@@ -13,8 +11,8 @@ const mocks = vi.hoisted(() => ({
|
||||
submitFeedback: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("@/router/use-app-navigator", () => ({
|
||||
useAppNavigator: () => ({ replace: mocks.replace }),
|
||||
vi.mock("@/router/use-global-app-navigator", () => ({
|
||||
useGlobalAppNavigator: () => ({ replace: mocks.replace }),
|
||||
}));
|
||||
|
||||
vi.mock("@/lib/feedback", () => ({
|
||||
@@ -69,6 +67,11 @@ describe("FeedbackScreen", () => {
|
||||
.querySelector("textarea")
|
||||
?.getAttribute("aria-describedby"),
|
||||
).toBe("feedback-content-hint");
|
||||
expect(
|
||||
container.querySelector<HTMLAnchorElement>(
|
||||
'[data-analytics-key="feedback.back_to_sidebar"]',
|
||||
)?.getAttribute("href"),
|
||||
).toBe("/sidebar?returnTo=%2Fcharacters%2Fmaya%2Fchat");
|
||||
});
|
||||
|
||||
it("submits valid text and renders the feedback id", async () => {
|
||||
@@ -103,18 +106,13 @@ describe("FeedbackScreen", () => {
|
||||
});
|
||||
expect(container.textContent).toContain("feedback-123");
|
||||
expect(container.textContent).toContain("Thank you for helping us.");
|
||||
expect(container.textContent).toContain("Back to Sidebar");
|
||||
});
|
||||
});
|
||||
|
||||
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>,
|
||||
),
|
||||
root.render(<FeedbackScreen returnTo="/characters/maya/chat" />),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,8 +17,11 @@ import {
|
||||
import { BackButton } from "@/app/_components";
|
||||
import { MobileShell } from "@/app/_components/core";
|
||||
import type { FeedbackCategory } from "@/data/schemas/feedback";
|
||||
import { useActiveCharacterRoutes } from "@/providers/character-provider";
|
||||
import { useAppNavigator } from "@/router/use-app-navigator";
|
||||
import {
|
||||
resolveGlobalRouteContext,
|
||||
type GlobalReturnToValue,
|
||||
} from "@/router/global-route-context";
|
||||
import { useGlobalAppNavigator } from "@/router/use-global-app-navigator";
|
||||
|
||||
import {
|
||||
FEEDBACK_IMAGE_ACCEPT,
|
||||
@@ -45,9 +48,13 @@ const CATEGORY_OPTIONS: readonly CategoryOption[] = [
|
||||
{ value: "other", label: "Other", icon: MessageCircleMore },
|
||||
];
|
||||
|
||||
export function FeedbackScreen() {
|
||||
const navigator = useAppNavigator();
|
||||
const characterRoutes = useActiveCharacterRoutes();
|
||||
export interface FeedbackScreenProps {
|
||||
returnTo?: GlobalReturnToValue;
|
||||
}
|
||||
|
||||
export function FeedbackScreen({ returnTo }: FeedbackScreenProps) {
|
||||
const navigator = useGlobalAppNavigator();
|
||||
const navigation = resolveGlobalRouteContext(returnTo);
|
||||
const form = useFeedbackSubmission();
|
||||
|
||||
if (form.feedbackId) {
|
||||
@@ -70,11 +77,11 @@ export function FeedbackScreen() {
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
data-analytics-key="feedback.back_to_chat"
|
||||
data-analytics-key="feedback.back_to_sidebar"
|
||||
className={styles.primaryButton}
|
||||
onClick={() => navigator.replace(characterRoutes.chat)}
|
||||
onClick={() => navigator.replace(navigation.sidebarUrl)}
|
||||
>
|
||||
Back to Chat
|
||||
Back to Sidebar
|
||||
</button>
|
||||
</section>
|
||||
</main>
|
||||
@@ -95,10 +102,10 @@ export function FeedbackScreen() {
|
||||
|
||||
<header className={styles.header}>
|
||||
<BackButton
|
||||
href={characterRoutes.chat}
|
||||
href={navigation.sidebarUrl}
|
||||
variant="soft"
|
||||
ariaLabel="Back to chat"
|
||||
analyticsKey="feedback.back_to_chat"
|
||||
ariaLabel="Back to sidebar"
|
||||
analyticsKey="feedback.back_to_sidebar"
|
||||
/>
|
||||
<div className={styles.headingBlock}>
|
||||
<h1 className={styles.title}>Help us improve CozSweet</h1>
|
||||
|
||||
@@ -1,21 +1,12 @@
|
||||
import { redirect } from "next/navigation";
|
||||
import type { RouteSearchParams } from "@/router/routes";
|
||||
|
||||
import { DEFAULT_CHARACTER_SLUG } from "@/data/constants/character";
|
||||
import {
|
||||
appendRouteSearchParams,
|
||||
getCharacterRoutes,
|
||||
type RouteSearchParams,
|
||||
} from "@/router/routes";
|
||||
import { FeedbackScreen } from "./feedback-screen";
|
||||
|
||||
export default async function FeedbackPage({
|
||||
searchParams,
|
||||
}: {
|
||||
searchParams: Promise<RouteSearchParams>;
|
||||
}) {
|
||||
redirect(
|
||||
appendRouteSearchParams(
|
||||
getCharacterRoutes(DEFAULT_CHARACTER_SLUG).feedback,
|
||||
await searchParams,
|
||||
),
|
||||
);
|
||||
const query = await searchParams;
|
||||
return <FeedbackScreen returnTo={query.returnTo} />;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user