"use client";
import { useActionState, useState } from "react";
import { Fieldset, FormField, Select } from "@unlocalhosted/metalui";
import { createTokenAction } from "@/app/actions/settings";
import { PlusIcon } from "@/components/icons";
import { RepoChecklist, type RepoOption } from "@/components/repo-checklist";
import { ChoiceCards, CopyIconButton, TextField } from "@/components/settings-fields";
import { PlateBody, PlateFooter } from "@/components/settings-plate";
import { Alert, Button } from "@/components/ui";
const expiries = [
{ value: "7", label: "7 days" },
{ value: "30", label: "30 days" },
{ value: "90", label: "90 days" },
{ value: "365", label: "1 year" },
{ value: "never", label: "No expiration" },
];
export function NewTokenForm({ repos, origin, username }: { repos: RepoOption[]; origin: string; username: string }) {
const [state, action, pending] = useActionState(createTokenAction, undefined);
const [scope, setScope] = useState<"all" | "selected">("all");
const [permission, setPermission] = useState<"read" | "write">("write");
const example = repos[0]?.fullName ?? `${username}/repo`;
if (state?.token) {
return (
<>
<PlateBody className="max-w-2xl">
<Alert kind="success">Token created. Copy it now — you won’t be able to see it again.</Alert>
<div className="flex items-center gap-2 rounded-row recipe-well-field py-1.5 pr-1.5 pl-3.5">
<code className="flex-1 font-mono text-[12.5px] leading-5 break-all text-ink">{state.token}</code>
<CopyIconButton text={state.token} label="Copy token" toast="Copied token" />
</div>
<div className="flex flex-col gap-1.5">
<p className="type-title text-ink">Use it with git</p>
<p className="type-body text-ink2">When git asks for a password, paste the token. Or put it in the remote URL:</p>
<pre className="well mt-1 overflow-x-auto rounded-row px-3.5 py-3 font-mono text-[12px] leading-5 text-ink">
git clone {origin.replace("://", `://${username}:${state.token}@`)}/{example}.git
</pre>
</div>
</PlateBody>
<PlateFooter>
<Button type="button" onClick={() => window.location.reload()}>
Done
</Button>
</PlateFooter>
</>
);
}
return (
<form action={action}>
<PlateBody className="max-w-2xl gap-6">
<TextField
label="Token name"
description="What’s this token for? e.g. “CI deploy” or “Laptop”."
name="name"
required
maxLength={100}
/>
<FormField>
<FormField.Label>Expiration</FormField.Label>
<Select name="expiry" defaultValue="30" options={expiries} aria-label="Expiration" className="w-44" />
</FormField>
<Fieldset>
<Fieldset.Legend>Permissions</Fieldset.Legend>
<ChoiceCards
name="permission"
aria-label="Permissions"
value={permission}
onValueChange={setPermission}
choices={[
{ value: "write", title: "Read & write", description: "Clone, fetch and push." },
{ value: "read", title: "Read-only", description: "Clone and fetch only." },
]}
/>
</Fieldset>
<Fieldset>
<Fieldset.Legend>Repository access</Fieldset.Legend>
<ChoiceCards
name="scope"
aria-label="Repository access"
value={scope}
onValueChange={setScope}
choices={[
{ value: "all", title: "All repositories", description: "Including ones you get access to later." },
{ value: "selected", title: "Only select repositories" },
]}
/>
{scope === "selected" && <RepoChecklist repos={repos} needWrite={permission === "write"} />}
</Fieldset>
{state?.error && <Alert>{state.error}</Alert>}
</PlateBody>
<PlateFooter>
<Button variant="primary" icon={<PlusIcon />} disabled={pending}>
{pending ? "Generating…" : "Generate Token"}
</Button>
</PlateFooter>
</form>
);
}