feat(slice-2): Landing + Sign-in screens, entry routing, API client (§5.1/5.2/6.5)

Two-step email + one-time-code sign-in behind both doors; pure entry-routing rule unit-
tested with Vitest (§6.8); storefront routing reaches a SLICE-2 signed-in placeholder with
sign-out (PUC-9). check.sh now runs the frontend unit tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-10 10:38:38 -07:00
parent cfd2b4ecc7
commit b3ffb2d4b6
11 changed files with 750 additions and 13 deletions
+60 -6
View File
@@ -1,10 +1,64 @@
// SLICE-1 shell only — the Landing, Sign-in, Create-storefront, and Admin screens
// (SD-0001 §5) land in SLICE-2/3. This proves the build and dev server work.
// App shell — loads the session, applies the entry-routing rule (SD-0001 §6.5), and renders
// the matching screen. SLICE-2 covers the unauthenticated doors (Landing/SignIn) and a
// signed-in placeholder; the real create-storefront/admin screens land in SLICE-3.
import { useEffect, useState } from "react";
import { getMe, type VerifyResult } from "./api";
import { routeFor, type SessionState } from "./routing";
import Landing from "./screens/Landing";
import SignIn from "./screens/SignIn";
import SignedIn from "./screens/SignedIn";
type Door = "signup" | "login";
export default function App() {
const [session, setSession] = useState<SessionState | null>(null);
const [loading, setLoading] = useState(true);
const [door, setDoor] = useState<Door | null>(null);
const [justCreated, setJustCreated] = useState(false);
async function reload() {
setLoading(true);
setSession(await getMe());
setLoading(false);
}
useEffect(() => {
void reload();
}, []);
if (loading) return <main>Loading</main>;
const route = routeFor(session ?? { account: null, storefront: null });
if (route === "landing") {
if (door) {
return (
<SignIn
door={door}
onBack={() => {
setDoor(null);
}}
onAuthed={(result: VerifyResult) => {
setJustCreated(result.created);
setDoor(null);
void reload();
}}
/>
);
}
return <Landing onGetStarted={() => setDoor("signup")} onLogIn={() => setDoor("login")} />;
}
// route is "create-storefront" or "admin" — both are SLICE-3 screens; SLICE-2 shows the
// signed-in placeholder so sign-out (PUC-9) is reachable.
return (
<main>
<h1>ecomm</h1>
<p>Honest commerce. Your storefront is yours.</p>
</main>
<SignedIn
email={session!.account!.email}
created={justCreated}
onSignedOut={() => {
setJustCreated(false);
void reload();
}}
/>
);
}