Vectrum
Sign In
47 lines · 1.7 KB · TypeScript
"use client";

import { useActionState, useEffect, useRef } from "react";
import { Textarea } from "@unlocalhosted/metalui";
import type { FormState } from "@/app/actions/types";
import { CheckIcon, CommentIcon, XIcon } from "@/components/icons";
import { Alert, Button } from "@/components/ui";

/**
 * Answering a pull request: a comment on its conversation, or a review (approve, request changes)
 * of its latest commit, from one box.
 */
export function RespondForm({
  action,
  canReview,
}: {
  action: (prev: FormState, formData: FormData) => Promise<FormState>;
  /** Push access, and not the viewer's own pull request. */
  canReview: boolean;
}) {
  const [state, formAction, pending] = useActionState(action, undefined);
  const form = useRef<HTMLFormElement>(null);
  useEffect(() => {
    if (state?.success) form.current?.reset();
  }, [state]);
  return (
    <form ref={form} action={formAction} className="space-y-3">
      <Textarea name="body" minRows={4} maxRows={16} aria-label="Comment" placeholder="Leave a comment… Markdown is supported." />
      {state?.error && <Alert>{state.error}</Alert>}
      <div className="flex flex-wrap justify-end gap-2">
        {canReview && (
          <>
            <Button name="intent" value="changes_requested" disabled={pending} icon={<XIcon />}>
              Request Changes
            </Button>
            <Button name="intent" value="approved" disabled={pending} icon={<CheckIcon />}>
              Approve
            </Button>
          </>
        )}
        <Button name="intent" value="comment" variant="primary" disabled={pending} icon={<CommentIcon />}>
          Comment
        </Button>
      </div>
    </form>
  );
}