From cf94cbce10bdedee49c987b31e61313bec12e936 Mon Sep 17 00:00:00 2001 From: Jeff Sieu Date: Tue, 25 Oct 2022 01:48:31 +0800 Subject: [PATCH] [questions][feat] add, delete question lists --- .../components/questions/CreatListDialog.tsx | 48 ------------- .../components/questions/CreateListDialog.tsx | 67 +++++++++++++++++++ apps/portal/src/pages/questions/lists.tsx | 62 ++++++++++++----- apps/portal/src/server/router/index.ts | 2 + ...-list-crud.ts => questions-list-router.ts} | 24 +++---- 5 files changed, 126 insertions(+), 77 deletions(-) delete mode 100644 apps/portal/src/components/questions/CreatListDialog.tsx create mode 100644 apps/portal/src/components/questions/CreateListDialog.tsx rename apps/portal/src/server/router/{questions-list-crud.ts => questions-list-router.ts} (94%) diff --git a/apps/portal/src/components/questions/CreatListDialog.tsx b/apps/portal/src/components/questions/CreatListDialog.tsx deleted file mode 100644 index 64af7e2d..00000000 --- a/apps/portal/src/components/questions/CreatListDialog.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { Button, Dialog } from '@tih/ui'; - -export type CreateListDialogProps = { - onCancel: () => void; - onCreate: () => void; - show: boolean; -}; - -export default function CreateListDialog({ - show, - onCancel, - onCreate, -}: CreateListDialogProps) { - return ( - -
-
- -
- - - -
-
- ); -} diff --git a/apps/portal/src/components/questions/CreateListDialog.tsx b/apps/portal/src/components/questions/CreateListDialog.tsx new file mode 100644 index 00000000..d363172c --- /dev/null +++ b/apps/portal/src/components/questions/CreateListDialog.tsx @@ -0,0 +1,67 @@ +import { useForm } from 'react-hook-form'; +import { Button, Dialog, TextInput } from '@tih/ui'; + +import { useFormRegister } from '~/utils/questions/useFormRegister'; + +export type CreateListFormData = { + name: string; +}; + +export type CreateListDialogProps = { + onCancel: () => void; + onSubmit: (data: CreateListFormData) => Promise; + show: boolean; +}; + +export default function CreateListDialog({ + show, + onCancel, + onSubmit, +}: CreateListDialogProps) { + const { + register: formRegister, + handleSubmit, + formState: { isSubmitting }, + } = useForm(); + const register = useFormRegister(formRegister); + + return ( + +
+
+ +
+
+ ); +} diff --git a/apps/portal/src/pages/questions/lists.tsx b/apps/portal/src/pages/questions/lists.tsx index 976701c6..721d5b84 100644 --- a/apps/portal/src/pages/questions/lists.tsx +++ b/apps/portal/src/pages/questions/lists.tsx @@ -8,13 +8,15 @@ import { } from '@heroicons/react/24/outline'; import QuestionListCard from '~/components/questions/card/question/QuestionListCard'; -import CreateListDialog from '~/components/questions/CreatListDialog'; +import type { CreateListFormData } from '~/components/questions/CreateListDialog'; +import CreateListDialog from '~/components/questions/CreateListDialog'; import DeleteListDialog from '~/components/questions/DeleteListDialog'; import { Button } from '~/../../../packages/ui/dist'; import { APP_TITLE } from '~/utils/questions/constants'; import { SAMPLE_QUESTION } from '~/utils/questions/constants'; import createSlug from '~/utils/questions/createSlug'; +import { trpc } from '~/utils/trpc'; export const questions = [ SAMPLE_QUESTION, @@ -34,22 +36,40 @@ export const questions = [ SAMPLE_QUESTION, ]; -export const lists = [ - { id: 1, name: 'list 1', questions }, - { id: 2, name: 'list 2', questions }, - { id: 3, name: 'list 3', questions }, - { id: 4, name: 'list 4', questions }, - { id: 5, name: 'list 5', questions }, -]; - 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 [selectedList, setSelectedList] = useState( - (lists ?? []).length > 0 ? lists[0].id : '', + lists?.length ? lists[0].id : '', ); const [showDeleteListDialog, setShowDeleteListDialog] = useState(false); const [showCreateListDialog, setShowCreateListDialog] = useState(false); - const handleDeleteList = () => { + const [listIdToDelete, setListIdToDelete] = useState(''); + + const handleDeleteList = async (listId: string) => { + await deleteList({ + id: listId, + }); setShowDeleteListDialog(false); }; @@ -57,7 +77,10 @@ export default function ListPage() { setShowDeleteListDialog(false); }; - const handleCreateList = () => { + const handleCreateList = async (data: CreateListFormData) => { + await createList({ + name: data.name, + }); setShowCreateListDialog(false); }; @@ -68,7 +91,7 @@ export default function ListPage() { const listOptions = ( <>
    - {lists.map((list) => ( + {(lists ?? []).map((list) => (
  • setShowDeleteListDialog(true)}> + onClick={() => { + setShowDeleteListDialog(true); + setListIdToDelete(list.id); + }}> Delete )} @@ -134,7 +160,7 @@ export default function ListPage() {
    -
    diff --git a/apps/portal/src/server/router/index.ts b/apps/portal/src/server/router/index.ts index 99e32b83..784137fd 100644 --- a/apps/portal/src/server/router/index.ts +++ b/apps/portal/src/server/router/index.ts @@ -9,6 +9,7 @@ import { offersProfileRouter } from './offers/offers-profile-router'; import { protectedExampleRouter } from './protected-example-router'; import { questionsAnswerCommentRouter } from './questions-answer-comment-router'; import { questionsAnswerRouter } from './questions-answer-router'; +import { questionListRouter } from './questions-list-router'; import { questionsQuestionCommentRouter } from './questions-question-comment-router'; import { questionsQuestionEncounterRouter } from './questions-question-encounter-router'; import { questionsQuestionRouter } from './questions-question-router'; @@ -40,6 +41,7 @@ export const appRouter = createRouter() .merge('resumes.comments.votes.user.', resumesCommentsVotesUserRouter) .merge('questions.answers.comments.', questionsAnswerCommentRouter) .merge('questions.answers.', questionsAnswerRouter) + .merge('questions.lists.', questionListRouter) .merge('questions.questions.comments.', questionsQuestionCommentRouter) .merge('questions.questions.encounters.', questionsQuestionEncounterRouter) .merge('questions.questions.', questionsQuestionRouter) diff --git a/apps/portal/src/server/router/questions-list-crud.ts b/apps/portal/src/server/router/questions-list-router.ts similarity index 94% rename from apps/portal/src/server/router/questions-list-crud.ts rename to apps/portal/src/server/router/questions-list-router.ts index 1f375497..5f189330 100644 --- a/apps/portal/src/server/router/questions-list-crud.ts +++ b/apps/portal/src/server/router/questions-list-router.ts @@ -14,16 +14,16 @@ export const questionListRouter = createProtectedRouter() include: { question: true, }, - } + }, }, orderBy: { createdAt: 'asc', }, where: { - id: userId, + userId, }, }); - } + }, }) .query('getListById', { input: z.object({ @@ -38,7 +38,7 @@ export const questionListRouter = createProtectedRouter() include: { question: true, }, - } + }, }, orderBy: { createdAt: 'asc', @@ -47,7 +47,7 @@ export const questionListRouter = createProtectedRouter() id: userId, }, }); - } + }, }) .mutation('create', { input: z.object({ @@ -111,7 +111,7 @@ export const questionListRouter = createProtectedRouter() }, }); - if (listToDelete?.id !== userId) { + if (listToDelete?.userId !== userId) { throw new TRPCError({ code: 'UNAUTHORIZED', message: 'User have no authorization to record.', @@ -163,11 +163,12 @@ export const questionListRouter = createProtectedRouter() async resolve({ ctx, input }) { const userId = ctx.session?.user?.id; - const entryToDelete = await ctx.prisma.questionsListQuestionEntry.findUnique({ - where: { - id: input.id, - }, - }); + const entryToDelete = + await ctx.prisma.questionsListQuestionEntry.findUnique({ + where: { + id: input.id, + }, + }); if (entryToDelete?.id !== userId) { throw new TRPCError({ @@ -176,7 +177,6 @@ export const questionListRouter = createProtectedRouter() }); } - const listToAugment = await ctx.prisma.questionsList.findUnique({ where: { id: entryToDelete.listId,