# ElvixLeave

> State-aware soft-delete (leave) wizard with 90-day grace restore and owner-locked pane for admin removals.

<!-- app/account/[appId]/leave/page.tsx -->
```tsx
"use client";

import { ElvixLeave } from "@elvix.is/sdk/react";
import { useRouter } from "next/navigation";

export default function LeavePane({
  appId,
  appName,
  deletedAt,
  deletedBy,
}: {
  appId: string;
  appName: string;
  deletedAt: string | null;
  deletedBy: string | null;
}) {
  const router = useRouter();
  return (
    <ElvixLeave
      appId={appId}
      appName={appName}
      deletedAt={deletedAt}
      deletedBy={deletedBy}
      privacyPolicyUrl="https://yourapp.com/privacy"
      termsOfServiceUrl="https://yourapp.com/terms"
      onSuccess={(state) => {
        // state is "left" (Active -> Leave wizard) or "restored" (in-grace -> Restore wizard).
        // SDK skips its own done pane if you navigate here.
        router.push(state === "left" ? "/account" : "/app");
      }}
      onFail={(error) => console.warn("[ElvixLeave]", error)}
    />
  );
}
```

## Props

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `appId` | `string` | optional | active session app | Scopes the wizard to a specific app membership. Accepts EITHER your public clientId OR the internal Application.id. Defaults to the active session's app. |
| `appName` | `string` | optional | app context | Display name shown in the warn copy. |
| `deletedAt` | `string \| null` | optional | membership context | Drives surface selection. Non-null inside grace renders the Restore wizard. |
| `deletedBy` | `string \| null` | optional | membership context | If set and not the current user, renders the owner-locked pane. |
| `privacyPolicyUrl` | `string \| null` | optional | app context | Surfaced on the warn2 pane so the user sees the app's data policy before OTP. |
| `termsOfServiceUrl` | `string \| null` | optional | app context | Surfaced on the warn2 pane next to the privacy link. |
| `onSuccess` | `(state: "left" \| "restored") => void` | optional | none | Fires before the in-frame done pane. Host navigation here skips the done pane (host wins). |
| `onFail` | `(error: string) => void` | optional | none | Fires alongside the in-frame error pane. Notification hook only. |
| `onResult` | `(r: ElvixLeaveResult) => void` | optional | none | Full discriminated callback. Narrow on `r.ok` before reading `r.state` or `r.error`. |

> **Note:** Leaving never deletes data the app itself stores about the user. elvix only soft-deletes the membership and surfaces the app's privacy and ToS links on the warn2 pane so the user knows where to take that conversation next.

> **Warning:** Owner-initiated removals (`deletedBy` set to someone other than the current user) render the locked pane. The user cannot self-restore in that state. The app owner must reverse the soft-delete from the Console.


## Related

- [ElvixDeactivate](/docs/components/elvix-deactivate.md): State-aware Instagram-style temporary deactivation wizard with OTP gate for deactivate and one-click reactivate.
- [ElvixSessions](/docs/components/elvix-sessions.md): Live session list scoped per-app or per-account, with per-row revoke and a two-CTA mass-revoke confirm pane.
