Skip to content

Instantly share code, notes, and snippets.

@samselikoff
Created October 19, 2021 15:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save samselikoff/c1b2c3d7988ad9fa11046b9bf776047b to your computer and use it in GitHub Desktop.
Save samselikoff/c1b2c3d7988ad9fa11046b9bf776047b to your computer and use it in GitHub Desktop.
import Spinner from "@/components/Spinner";
import useCurrentUser from "@/hooks/use-current-user";
import useMutation from "@/hooks/use-mutation";
import { Dialog, Switch } from "@headlessui/react";
import { CheckIcon } from "@heroicons/react/solid";
import { format, startOfWeek } from "date-fns";
import { Field, Formik } from "formik";
import { motion } from "framer-motion";
import { gql } from "graphql-request";
import { useRef } from "react";
import { Controller, useFieldArray, useForm } from "react-hook-form";
let isTest = typeof window !== "undefined" && window.Cypress;
const DURATIONS = {
in: !isTest ? 0.4 : 0,
out: !isTest ? 0.45 : 0,
};
const EASE = [0.36, 0.66, 0.04, 1];
let startDate = startOfWeek(new Date());
let startDateString = format(startDate, "yyyy-MM-dd");
let createWeeklyGoalMutation = gql`
mutation InsertWeeklyGoalOne($attrs: weeklyGoals_insert_input!) {
insert_weeklyGoals_one(object: $attrs) {
id
}
}
`;
let createWeeklyGoalsMutation = gql`
mutation InsertWeeklyGoals($attrs: weeklyGoals_insert_input!) {
insert_weeklyGoals(objects: $weeklyGoals) {
id
}
}
`;
export default function GoalsForm({
availableCategories,
weeklyGoals,
onClose,
}) {
let availableCategoriesDraftRef = useRef();
if (!availableCategoriesDraftRef.current) {
availableCategoriesDraftRef.current = JSON.parse(
JSON.stringify(availableCategories)
);
}
let weeklyGoalsDraftRef = useRef();
if (!weeklyGoalsDraftRef.current) {
weeklyGoalsDraftRef.current = JSON.parse(JSON.stringify(weeklyGoals));
}
let currentUser = useCurrentUser();
let [createWeeklyGoals] = useMutation(createWeeklyGoals);
let doneButtonRef = useRef();
const { control, register, handleSubmit, formState, getValues } = useForm({
defaultValues: {
categories: availableCategoriesDraftRef.current.map((c) => ({
id: c.id,
label: c.label,
selected: false,
total: 1,
})),
},
});
const { fields, swap } = useFieldArray({
control,
name: "categories",
});
async function onSubmit(values) {
console.log({ values });
// await createWeeklyGoals({
// attrs: {
// categoryId: values.categoryId,
// total: values.total,
// userId: currentUser.id,
// weekBeginning: startDateString,
// },
// });
// onClose();
}
// console.log(getValues());
return (
<Dialog
open={true}
as="div"
static
className="fixed inset-0 z-10"
onClose={onClose}
initialFocus={doneButtonRef}
>
<div className="flex flex-col items-end justify-center min-h-screen text-center">
<Dialog.Overlay
as={motion.div}
initial={{ opacity: 0 }}
animate={{
opacity: 1,
transition: { ease: EASE, duration: DURATIONS.in },
}}
exit={{
opacity: 0,
transition: { ease: EASE, duration: DURATIONS.out },
}}
className="fixed inset-0 bg-black/40"
/>
{/* Modal window */}
<motion.div
initial={{ y: "100%" }}
animate={{
y: 0,
transition: { ease: EASE, duration: DURATIONS.in },
}}
exit={{
y: "100%",
transition: { ease: EASE, duration: DURATIONS.out },
}}
className="relative flex flex-col flex-1 w-full p-3 pointer-events-none "
>
<div className="flex-1 w-full px-4 pt-5 pb-8 text-left align-bottom bg-white shadow-xl pointer-events-auto rounded-2xl mb-safe-bottom">
<form className="my-2" onSubmit={handleSubmit(onSubmit)}>
<div className="relative">
<button
onClick={onClose}
type="button"
className="absolute inset-y-0 left-0 text-blue-500"
>
Cancel
</button>
<Dialog.Title
as="h3"
className="text-lg font-medium text-center text-gray-900"
>
Add goals
</Dialog.Title>
<div className="absolute inset-y-0 right-0 flex items-center">
<button
type="submit"
className={`relative font-semibold text-blue-500 ${
formState.isSubmitting ? "pointer-events-none" : ""
}`}
disabled={formState.isSubmitting}
ref={doneButtonRef}
>
<span
className={`${formState.isSubmitting ? "invisible" : ""}`}
>
Done
</span>
{formState.isSubmitting && (
<span className="absolute inset-0 flex items-center justify-center">
<Spinner style="plain" />
</span>
)}
</button>
</div>
</div>
<div className="mt-8 border-t divide-y">
{fields.map((category, index) => (
<div key={category.id} className="py-4">
<label className="flex items-center text-lg">
<span>{category.label}</span>
<Controller
control={control}
name={`categories.${index}.selected`}
render={({ field: { onChange, value } }) => (
<Switch
checked={value}
onChange={onChange}
className={`${
value ? "bg-blue-600" : ""
} w-6 h-6 ml-auto border-blue-600 border-2 rounded-full flex items-center justify-center`}
>
{value && (
<CheckIcon className="w-4 h-4 text-white" />
)}
</Switch>
)}
/>
</label>
{console.log({ category, fields })}
</div>
))}
</div>
{/* <div className="mt-10">
{!availableCategories
.map((c) => +c.id)
.includes(+values.categoryId) && console.log("setting")}
<div className="mt-4">
<div className="max-w-lg rounded-md shadow-sm">
<Field
as="select"
className="block w-full transition duration-150 ease-in-out form-select"
name="categoryId"
id="categoryId"
>
{availableCategories.map((category) => (
<option key={category.id} value={category.id}>
{category.label}
</option>
))}
</Field>
</div>
</div>
<div className="mt-6">
<div className="flex items-center mt-2">
<p>
{values.total} {values.total > 1 ? "times" : "time"}{" "}
per week
</p>
<div className="ml-auto">
<span className="inline-flex rounded-md shadow-sm">
<button
type="button"
className={`
${
values.total === 1
? "opacity-50 pointer-events-none"
: ""
}
flex justify-center items-center w-10 h-10 border border-gray-300 text-sm leading-5 font-medium rounded-md text-gray-700 bg-white hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:ring-1 ring-opacity-5 active:text-gray-800 active:bg-gray-50 transition ease-in-out duration-150`}
onClick={() => {
if (values.total > 1) {
setFieldValue("total", values.total - 1);
}
}}
disabled={values.total === 1}
data-test="subtract"
>
<svg
className="w-4 h-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M20 12H4"
/>
</svg>
</button>
</span>
<span className="inline-flex ml-3 rounded-md shadow-sm">
<button
type="button"
className={`
${
values.total === 7
? "opacity-50 pointer-events-none"
: ""
}
flex justify-center items-center w-10 h-10 border border-gray-300 text-sm leading-5 font-medium rounded-md text-gray-700 bg-white hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:ring-1 ring-opacity-5 active:text-gray-800 active:bg-gray-50 transition ease-in-out duration-150`}
onClick={() => {
if (values.total < 7) {
setFieldValue("total", values.total + 1);
}
}}
disabled={values.total === 7}
data-test="add"
>
<svg
className="w-4 h-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M12 6v6m0 0v6m0-6h6m-6 0H6"
/>
</svg>
</button>
</span>
</div>
</div>
</div>
</div> */}
</form>
</div>
</motion.div>
</div>
</Dialog>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment