nextjs-challenge / frontend / src / pages / index.tsx
index.tsx
Raw
// NOTE: the frontend server provides a proxy to the backend on the /api route
// see: next.config.js if you need to change this

import { useForm, SubmitHandler, Controller } from "react-hook-form";
import { NumericFormat } from "react-number-format";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";

const formSchema = z.object({
  amount: z.string(),
  department: z.string(),
  managerApprovalRequired: z.boolean(),
});

type Inputs = z.infer<typeof formSchema>;

export default function Home() {
  const { register, handleSubmit, control, watch } = useForm<Inputs>({
    resolver: zodResolver(formSchema),
  });

  const onSubmit = async (invoiceData: Inputs) => {
    const response = await fetch("/api/invoice", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify(invoiceData),
    });
    const data = await response.json();
    alert(data.result);
  };

  console.log(watch("amount")); // watch input value by passing the name of it

  return (
    <main className="flex min-h-screen w-full p-24">
      <form onSubmit={handleSubmit(onSubmit)} className="mx-auto">
        {/* Tailwind UI CSS Form Stacked */}
        <div className="space-y-12">
          <div className="border-b border-gray-900/10 pb-12 text-gray-900">
            <h2 className="font-semibold">Invoice</h2>
            <div className="mt-10 flex flex-col mt-10 gap-x-6 gap-y-8">
              <div>
                <label
                  htmlFor="amount"
                  className="block text-sm font-medium leading-6"
                >
                  Amount (USD)
                </label>
                <div className="mt-2">
                  <Controller
                    name="amount"
                    control={control}
                    render={({ field: { ref, ...rest } }) => (
                      <NumericFormat
                        className="block w-full rounded-md border-0 p-1.5 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                        thousandSeparator=","
                        decimalSeparator="."
                        prefix="$ "
                        decimalScale={2}
                        getInputRef={ref}
                        {...rest}
                      />
                    )}
                  />
                </div>
              </div>

              <div>
                <fieldset>
                  <legend className="block text-sm font-medium leading-6">
                    Requires Approval
                  </legend>
                  <div className="mt-6 flex gap-x-3">
                    <input
                      // className="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-600"
                      className="h-6"
                      id="requiresManagerApproval"
                      {...register("managerApprovalRequired")}
                      type="checkbox"
                    />
                    <div className="text-sm leading-6">
                      <label
                        htmlFor="managerApprovalRequired"
                        className="font-medium text-gray-900"
                      >
                        Manager
                      </label>
                      <p className="text-gray-500">
                        This invoice requires approval by the Manager.
                      </p>
                    </div>
                  </div>
                </fieldset>
              </div>

              <div>
                <label
                  htmlFor="department"
                  className="block text-sm font-medium leading-6"
                >
                  Department
                </label>
                <div className="mt-2">
                  <select
                    className="block w-full rounded-md border-0 py-1.5 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:max-w-xs sm:text-sm sm:leading-6"
                    id="department"
                    autoComplete="department"
                    {...register("department", { required: true })}
                  >
                    <option value="marketing">Marketing</option>
                    <option value="finance">Finance</option>
                    {/* TODO: Use a dynamic list of departments from the backend */}
                  </select>
                </div>
                <div className="text-sm text-gray-500 mt-2">
                  Select Marketing if the invoice is related to marketing
                  purchases.
                </div>
              </div>
            </div>
          </div>
        </div>
        <button
          type="submit"
          className="rounded-md mt-6 w-full bg-indigo-600 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
        >
          Submit
        </button>
      </form>
    </main>
  );
}