"use client";
import { useActionState, useState } from "react";
import { FormField, Select } from "@unlocalhosted/metalui";
import type { FormState } from "@/app/actions/types";
import { BranchIcon, PencilIcon } from "@/components/icons";
import { TextareaField, TextField } from "@/components/settings-fields";
import { Alert, Button } from "@/components/ui";
/** Editing a pull request's title, description and (while it's open) the branch it merges into, behind an Edit button. */
export function EditPullForm({
action,
title,
body,
base,
branches,
}: {
action: (prev: FormState, formData: FormData) => Promise<FormState>;
title: string;
body: string;
base: string;
/** Branches it could merge into instead; empty when the base can't change. */
branches: string[];
}) {
const [open, setOpen] = useState(false);
const [state, formAction, pending] = useActionState(async (prev: FormState, formData: FormData) => {
const result = await action(prev, formData);
if (result?.success) setOpen(false);
return result;
}, undefined);
if (!open) {
return (
<Button type="button" variant="invisible" icon={<PencilIcon />} onClick={() => setOpen(true)}>
Edit
</Button>
);
}
return (
<form action={formAction} className="flex w-full flex-col gap-4">
<TextField label="Title" name="title" required maxLength={256} defaultValue={title} />
<TextareaField label="Description" name="body" minRows={5} maxRows={20} defaultValue={body} description="“Fixes #12” links an issue." />
{branches.length > 1 && (
<FormField>
<FormField.Label>Base branch</FormField.Label>
<Select name="base" aria-label="Base branch" defaultValue={base} options={branches.map((b) => ({ value: b, label: b, lead: <BranchIcon /> }))} className="max-w-72" />
<FormField.Description>The branch the changes are merged into.</FormField.Description>
</FormField>
)}
{state?.error && <Alert>{state.error}</Alert>}
<div className="flex justify-end gap-2">
<Button type="button" onClick={() => setOpen(false)}>
Cancel
</Button>
<Button variant="primary" disabled={pending}>
{pending ? "Saving…" : "Save"}
</Button>
</div>
</form>
);
}