diff --git a/apps/portal/src/components/questions/AddToListDropdown.tsx b/apps/portal/src/components/questions/AddToListDropdown.tsx index 4ae9da46..d19dcf4c 100644 --- a/apps/portal/src/components/questions/AddToListDropdown.tsx +++ b/apps/portal/src/components/questions/AddToListDropdown.tsx @@ -3,22 +3,52 @@ import type { PropsWithChildren } from 'react'; import { useMemo } from 'react'; import { Fragment, useRef, useState } from 'react'; import { Menu, Transition } from '@headlessui/react'; -import { CheckIcon, HeartIcon } from '@heroicons/react/20/solid'; +import { CheckIcon, HeartIcon, PlusIcon } from '@heroicons/react/20/solid'; +import { + useAddQuestionToListAsync, + useCreateListAsync, + useRemoveQuestionFromListAsync, +} from '~/utils/questions/mutations'; import { useProtectedCallback } from '~/utils/questions/useProtectedCallback'; import { trpc } from '~/utils/trpc'; +import CreateListDialog from './CreateListDialog'; + export type AddToListDropdownProps = { questionId: string; }; +export type DropdownButtonProps = PropsWithChildren<{ + onClick: () => void; +}>; + +function DropdownButton({ onClick, children }: DropdownButtonProps) { + return ( + + {({ active }) => ( + + )} + + ); +} + export default function AddToListDropdown({ questionId, }: AddToListDropdownProps) { const [menuOpened, setMenuOpened] = useState(false); const ref = useRef(null); + const [show, setShow] = useState(false); - const utils = trpc.useContext(); + const createListAsync = useCreateListAsync(); const { data: lists } = trpc.useQuery(['questions.lists.getListsByUser']); const listsWithQuestionData = useMemo(() => { @@ -30,25 +60,8 @@ export default function AddToListDropdown({ })); }, [lists, questionId]); - const { mutateAsync: addQuestionToList } = trpc.useMutation( - 'questions.lists.createQuestionEntry', - { - // TODO: Add optimistic update - onSuccess: () => { - utils.invalidateQueries(['questions.lists.getListsByUser']); - }, - }, - ); - - const { mutateAsync: removeQuestionFromList } = trpc.useMutation( - 'questions.lists.deleteQuestionEntry', - { - // TODO: Add optimistic update - onSuccess: () => { - utils.invalidateQueries(['questions.lists.getListsByUser']); - }, - }, - ); + const addQuestionToList = useAddQuestionToListAsync(); + const removeQuestionFromList = useRemoveQuestionFromListAsync(); const addClickOutsideListener = () => { document.addEventListener('click', handleClickOutside, true); @@ -101,63 +114,75 @@ export default function AddToListDropdown({ ); return ( - -
- - -
- - - - {menuOpened && ( - <> - {(listsWithQuestionData ?? []).map((list) => ( -
- - {({ active }) => ( - - )} - -
- ))} - - )} -
-
-
+ + + + ))} + { + setShow(true); + }}> + + + )} + + + + { + setShow(false); + }} + onSubmit={async (data) => { + await createListAsync(data); + setShow(false); + }} + /> + ); } diff --git a/apps/portal/src/pages/questions/lists.tsx b/apps/portal/src/pages/questions/lists.tsx index 9323499c..e64aa41c 100644 --- a/apps/portal/src/pages/questions/lists.tsx +++ b/apps/portal/src/pages/questions/lists.tsx @@ -15,6 +15,10 @@ import DeleteListDialog from '~/components/questions/DeleteListDialog'; import { Button } from '~/../../../packages/ui/dist'; import { APP_TITLE } from '~/utils/questions/constants'; import createSlug from '~/utils/questions/createSlug'; +import { + useCreateListAsync, + useDeleteListAsync, +} from '~/utils/questions/mutations'; import relabelQuestionAggregates from '~/utils/questions/relabelQuestionAggregates'; import { useProtectedCallback } from '~/utils/questions/useProtectedCallback'; import { trpc } from '~/utils/trpc'; @@ -22,24 +26,10 @@ import { trpc } from '~/utils/trpc'; export default function ListPage() { const utils = trpc.useContext(); const { data: lists } = trpc.useQuery(['questions.lists.getListsByUser']); - const { mutateAsync: createList } = trpc.useMutation( - 'questions.lists.create', - { - onSuccess: () => { - // TODO: Add optimistic update - utils.invalidateQueries(['questions.lists.getListsByUser']); - }, - }, - ); - const { mutateAsync: deleteList } = trpc.useMutation( - 'questions.lists.delete', - { - onSuccess: () => { - // TODO: Add optimistic update - utils.invalidateQueries(['questions.lists.getListsByUser']); - }, - }, - ); + + const createListAsync = useCreateListAsync(); + const deleteListAsync = useDeleteListAsync(); + const { mutateAsync: deleteQuestionEntry } = trpc.useMutation( 'questions.lists.deleteQuestionEntry', { @@ -57,7 +47,7 @@ export default function ListPage() { const [listIdToDelete, setListIdToDelete] = useState(''); const handleDeleteList = async (listId: string) => { - await deleteList({ + await deleteListAsync({ id: listId, }); setShowDeleteListDialog(false); @@ -68,7 +58,7 @@ export default function ListPage() { }; const handleCreateList = async (data: CreateListFormData) => { - await createList({ + await createListAsync({ name: data.name, }); setShowCreateListDialog(false); diff --git a/apps/portal/src/utils/questions/mutations.ts b/apps/portal/src/utils/questions/mutations.ts new file mode 100644 index 00000000..7fd1baf6 --- /dev/null +++ b/apps/portal/src/utils/questions/mutations.ts @@ -0,0 +1,60 @@ +import { trpc } from '../trpc'; + +export function useAddQuestionToListAsync() { + const utils = trpc.useContext(); + const { mutateAsync: addQuestionToListAsync } = trpc.useMutation( + 'questions.lists.createQuestionEntry', + { + // TODO: Add optimistic update + onSuccess: () => { + utils.invalidateQueries(['questions.lists.getListsByUser']); + }, + }, + ); + + return addQuestionToListAsync; +} + +export function useRemoveQuestionFromListAsync() { + const utils = trpc.useContext(); + const { mutateAsync: removeQuestionFromListAsync } = trpc.useMutation( + 'questions.lists.deleteQuestionEntry', + { + // TODO: Add optimistic update + onSuccess: () => { + utils.invalidateQueries(['questions.lists.getListsByUser']); + }, + }, + ); + + return removeQuestionFromListAsync; +} + +export function useCreateListAsync() { + const utils = trpc.useContext(); + const { mutateAsync: createListAsync } = trpc.useMutation( + 'questions.lists.create', + { + onSuccess: () => { + // TODO: Add optimistic update + utils.invalidateQueries(['questions.lists.getListsByUser']); + }, + }, + ); + return createListAsync; +} + +export function useDeleteListAsync() { + const utils = trpc.useContext(); + const { mutateAsync: deleteListAsync } = trpc.useMutation( + 'questions.lists.delete', + { + onSuccess: () => { + // TODO: Add optimistic update + utils.invalidateQueries(['questions.lists.getListsByUser']); + }, + }, + ); + + return deleteListAsync; +}