Created
October 19, 2021 15:29
-
-
Save samselikoff/c1b2c3d7988ad9fa11046b9bf776047b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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