first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,118 @@
# EmailVerificationView
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
`<EmailVerificationView>` is the pure-UI surface that renders the four states of an email-verification flow — `verifying`, `success`, `expired`, `error` — with the right icon, copy, and CTA per state. It is a status view rather than a form: there are no inputs, no validation, just a deterministic switch from `status` to one of four cards. The page-level host owns the token-extraction, the API call against `useAuth().verifyEmail`, and the status transitions; the view is a dumb renderer that can also be reused inside admin re-verification flows or as a notification banner.
## Features
- Four discrete render branches keyed off the `status` prop, each with its own icon (`Loader2` / `CheckCircle2` / `AlertTriangle` / `XCircle`).
- Each branch ships a CTA wired to one of `onContinueToLogin` / `onRegisterAgain` / `onTryAgain` callbacks supplied by the host.
- The `error` branch additionally renders a destructive `<Alert>` with the same message for screen-reader prominence.
- The `error` retry CTA shows a spinner and is disabled while `isLoading` is true.
- Optional `message` prop overrides the default per-status description copy.
- `translations?: Partial<AuthEmailVerificationStrings>` for full Welsh / zh-CN coverage via Wave 1's translation packs.
- Always renders a "back to login" link except in the `verifying` state (where no action is meaningful yet).
## Usage: Basic
```tsx
import { EmailVerificationView } from "@suaveplan/react-auth";
import { BrowserRouter } from "react-router-dom";
export function VerifyEmailPage() {
return (
<BrowserRouter>
<EmailVerificationView status="verifying" />
</BrowserRouter>
);
}
```
## Usage: Advanced
Drive every transition from URL state + `useAuth().verifyEmail`:
```tsx
import {
EmailVerificationView,
useAuth,
} from "@suaveplan/react-auth";
import {
useEffect,
useState,
} from "react";
import { useNavigate, useSearchParams } from "react-router-dom";
export function VerifyEmail() {
const { verifyEmail } = useAuth();
const navigate = useNavigate();
const [params] = useSearchParams();
const token = params.get("token");
const [status, setStatus] = useState<
"verifying" | "success" | "error" | "expired"
>("verifying");
const [message, setMessage] = useState("");
useEffect(() => {
if (token === null) {
setStatus("expired");
return;
}
verifyEmail({ token })
.then(() => setStatus("success"))
.catch((err: unknown) => {
setStatus("error");
setMessage(
err instanceof Error ? err.message : String(err)
);
});
}, [token, verifyEmail]);
return (
<EmailVerificationView
status={status}
message={message}
onContinueToLogin={() => navigate("/auth/login")}
onRegisterAgain={() => navigate("/auth/register")}
onTryAgain={() => setStatus("verifying")}
/>
);
}
```
## API Reference
### `EmailVerificationView(props: EmailVerificationViewProps): ReactElement`
| Prop | Type | Default | Description |
|---|---|---|---|
| `status` | `"verifying" \| "success" \| "error" \| "expired"` | — required | Which card to render. |
| `message` | `string` | `""` | Override for the default description copy. |
| `onContinueToLogin` | `() => void` | — | Fired by the success-status CTA. |
| `onRegisterAgain` | `() => void` | — | Fired by the expired-status CTA. |
| `onTryAgain` | `() => void` | — | Fired by the error-status retry CTA. |
| `isLoading` | `boolean` | `false` | Disables the error-status retry CTA. |
| `translations` | `Partial<AuthEmailVerificationStrings>` | `enGb.auth.emailVerification` | Override any subset of the 8 copy keys. |
### `EmailVerificationStatus`
```ts
type EmailVerificationStatus =
| "verifying"
| "success"
| "error"
| "expired";
```
## Implementation Notes
- Each card is implemented as a small internal component (`VerifyingCard`, `SuccessCard`, `ExpiredCard`, `ErrorCard`) and dispatched through a `switch`-style helper to keep the public file under the 300-line cap.
- The component intentionally does NOT consume `useTranslation` — Wave 1 dropped the `@suaveplan/react-translate` dependency, and Wave 2 follows that precedent. Translations are injected via the `translations` prop instead.
- The `verifying` card carries `role="status"` on the spinner wrapper for assistive-tech announcements.
- The error card duplicates the message in a destructive `<Alert>` so the failure is announced even when the CTA is off-screen on narrow viewports.
- No OTel instruments emitted from the view; metrics live on the Wave 1 `verifyEmail` action.