first commit
This commit is contained in:
@@ -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.
|
||||
Reference in New Issue
Block a user