10d22938f1
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
93 lines
3.5 KiB
TypeScript
93 lines
3.5 KiB
TypeScript
// Create storefront (SD-0001 §5.3) — a storefront-less Merchant establishes their one
|
|
// storefront (PUC-4/5; PUC-7 defense-in-depth on 409). Visuals per the ui/designs export
|
|
// (hf-storefront). The welcome banner carries PUC-3's honest copy from the verify step.
|
|
import { useState } from "react";
|
|
import { createStorefront, logout, type StorefrontResult } from "../api";
|
|
import { AccountChip, AuthCard, Banner, Eyebrow, Field, Footer, PrimaryButton, Screen, TopBar, Wordmark } from "../ui/kit";
|
|
|
|
interface Props {
|
|
email: string;
|
|
welcome: "new" | "back" | null;
|
|
onCreated: (storefront: StorefrontResult) => void;
|
|
onAlreadyOwns: () => void;
|
|
onSignedOut: () => void;
|
|
}
|
|
|
|
export default function CreateStorefront({ email, welcome, onCreated, onAlreadyOwns, onSignedOut }: Props) {
|
|
const [name, setName] = useState("");
|
|
const [busy, setBusy] = useState(false);
|
|
const [alreadyOwns, setAlreadyOwns] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
async function signOut() {
|
|
await logout();
|
|
onSignedOut();
|
|
}
|
|
|
|
async function submit(e: React.FormEvent) {
|
|
e.preventDefault();
|
|
setBusy(true);
|
|
setError(null);
|
|
const res = await createStorefront(name);
|
|
setBusy(false);
|
|
if (res.ok) {
|
|
onCreated(res.storefront);
|
|
return;
|
|
}
|
|
if (res.error.code === "already_owns_storefront") setAlreadyOwns(true);
|
|
else setError(res.error.message);
|
|
}
|
|
|
|
return (
|
|
<Screen horizon>
|
|
<TopBar left={<Wordmark size={22} />} right={<AccountChip email={email} onSignOut={signOut} />} />
|
|
<main className="screen__main">
|
|
<AuthCard>
|
|
<form onSubmit={submit} style={{ display: "contents" }}>
|
|
<div>
|
|
<Eyebrow>One storefront, fully yours</Eyebrow>
|
|
<h1 style={{ marginTop: 12 }}>Create your storefront</h1>
|
|
<p className="card__sub">
|
|
This is the one thing to do right now. It costs nothing and commits you to nothing.
|
|
</p>
|
|
</div>
|
|
{welcome && (
|
|
<Banner tone="info" title={welcome === "new" ? "Welcome to ecomm" : "Welcome back"}>
|
|
{welcome === "new"
|
|
? "A new account was created for this email."
|
|
: "Signed in to your existing account."}
|
|
</Banner>
|
|
)}
|
|
{alreadyOwns && (
|
|
<Banner title="Your account already has its storefront">
|
|
ecomm is one storefront per account today.{" "}
|
|
<button type="button" className="lk" onClick={onAlreadyOwns}>
|
|
Go to your admin →
|
|
</button>
|
|
</Banner>
|
|
)}
|
|
{error && <Banner title="That didn't work">{error} Try again.</Banner>}
|
|
<Field
|
|
label="Storefront name"
|
|
optional
|
|
helper="You can leave this blank — we'll pick a placeholder name you can change any time."
|
|
inputProps={{
|
|
type: "text",
|
|
value: name,
|
|
placeholder: "e.g. Ben's Bets",
|
|
autoFocus: true,
|
|
onChange: (ev) => setName(ev.target.value),
|
|
}}
|
|
/>
|
|
<div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
|
|
<PrimaryButton busy={busy}>{busy ? "Creating…" : "Create storefront"}</PrimaryButton>
|
|
<p className="note">You can rename, configure, or close your storefront whenever you like.</p>
|
|
</div>
|
|
</form>
|
|
</AuthCard>
|
|
</main>
|
|
<Footer />
|
|
</Screen>
|
|
);
|
|
}
|