From 6901e9a618fb088f92a8aa0b21736b74c32ef64e Mon Sep 17 00:00:00 2001 From: sterdsterd Date: Thu, 14 Aug 2025 16:29:41 +0900 Subject: [PATCH 01/17] =?UTF-8?q?feat:=20=EA=B3=BC=EC=99=B8=20=EC=84=A0?= =?UTF-8?q?=EC=83=9D=20=EC=A0=95=EB=B3=B4=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?debounce=20search=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/admin/src/routes/_GNBLayout/teacher/index.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/admin/src/routes/_GNBLayout/teacher/index.tsx b/apps/admin/src/routes/_GNBLayout/teacher/index.tsx index 6472ea8a..464a3d2b 100644 --- a/apps/admin/src/routes/_GNBLayout/teacher/index.tsx +++ b/apps/admin/src/routes/_GNBLayout/teacher/index.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { createFileRoute } from '@tanstack/react-router'; import { Button, FloatingButton, Header, Input, Modal, TwoButtonModalTemplate } from '@components'; import { useForm } from 'react-hook-form'; @@ -31,7 +31,7 @@ function RouteComponent() { openModal: openDeleteModal, closeModal: closeDeleteModal, } = useModal(); - const { register, handleSubmit } = useForm<{ + const { register, handleSubmit, watch } = useForm<{ query: string; }>(); @@ -40,6 +40,15 @@ function RouteComponent() { const { mutateAsync: deleteTeacherMutateAsync } = deleteTeacher(); const queryClient = useQueryClient(); + const watchedQuery = watch('query'); + useEffect(() => { + const debounceTimer = setTimeout(() => { + setSearchQuery((watchedQuery ?? '').trim()); + }, 300); + + return () => clearTimeout(debounceTimer); + }, [watchedQuery]); + const handleClickSearch = (data: { query: string }) => { setSearchQuery(data.query.trim()); }; From 58f474244e99b347ecdab91376f8bb1a5e4a5aca Mon Sep 17 00:00:00 2001 From: sterdsterd Date: Thu, 14 Aug 2025 16:31:44 +0900 Subject: [PATCH 02/17] =?UTF-8?q?feat:=20=EA=B0=9C=EB=85=90=20=ED=83=9C?= =?UTF-8?q?=EA=B7=B8=20=ED=8E=98=EC=9D=B4=EC=A7=80=20debounce=20search=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/routes/_GNBLayout/concept-tags/index.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/admin/src/routes/_GNBLayout/concept-tags/index.tsx b/apps/admin/src/routes/_GNBLayout/concept-tags/index.tsx index 41d6622a..ee502a69 100644 --- a/apps/admin/src/routes/_GNBLayout/concept-tags/index.tsx +++ b/apps/admin/src/routes/_GNBLayout/concept-tags/index.tsx @@ -1,5 +1,5 @@ import { createFileRoute } from '@tanstack/react-router'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { Button, FloatingButton, Header, Input, Modal, TwoButtonModalTemplate } from '@components'; import { useForm } from 'react-hook-form'; import { Divider } from '@repo/pointer-design-system/components'; @@ -46,10 +46,19 @@ function RouteComponent() { ); }; - const { register, handleSubmit } = useForm<{ + const { register, handleSubmit, watch } = useForm<{ query: string; }>(); + const watchedQuery = watch('query'); + useEffect(() => { + const debounceTimer = setTimeout(() => { + setSearchQuery((watchedQuery ?? '').trim()); + }, 300); + + return () => clearTimeout(debounceTimer); + }, [watchedQuery]); + const handleClickSearch = (data: { query: string }) => { setSearchQuery(data.query.trim()); setSelectedTag([]); From 0f85591cdf98d4b19affd0eca636af956b3c0ccd Mon Sep 17 00:00:00 2001 From: sterdsterd Date: Thu, 14 Aug 2025 16:38:08 +0900 Subject: [PATCH 03/17] =?UTF-8?q?feat:=20=EB=AC=B8=EC=A0=9C=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20debounce=20search=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/routes/_GNBLayout/problem/index.tsx | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/apps/admin/src/routes/_GNBLayout/problem/index.tsx b/apps/admin/src/routes/_GNBLayout/problem/index.tsx index 8de49723..3751cfe5 100644 --- a/apps/admin/src/routes/_GNBLayout/problem/index.tsx +++ b/apps/admin/src/routes/_GNBLayout/problem/index.tsx @@ -15,7 +15,7 @@ import { useInvalidate, useModal } from '@hooks'; import { IcDown } from '@svg'; import { createFileRoute, Link } from '@tanstack/react-router'; import { GetProblemsSearchParams } from '@types'; -import { useRef, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { useForm } from 'react-hook-form'; import PulseLoader from 'react-spinners/PulseLoader'; @@ -38,7 +38,7 @@ function RouteComponent() { const [searchQuery, setSearchQuery] = useState({}); const [selectedTagList, setSelectedTagList] = useState([]); - const { register, handleSubmit, reset } = useForm(); + const { register, handleSubmit, reset, watch } = useForm(); const { data: problemList, isLoading } = getProblemsSearch(searchQuery); const { mutate: mutateDeleteProblem } = deleteProblem(); @@ -46,6 +46,33 @@ function RouteComponent() { const allTagList = tagsData?.data || []; const tagsNameMap = Object.fromEntries(allTagList.map((tag) => [tag.id, tag.name])); + const watchedCustomId = watch('customId'); + const watchedTitle = watch('title'); + useEffect(() => { + const debounceTimer = setTimeout(() => { + const trimmedCustomId = (watchedCustomId ?? '').toString().trim(); + const trimmedTitle = (watchedTitle ?? '').toString().trim(); + + setSearchQuery((prev) => { + const nextQuery: GetProblemsSearchParams = { + ...prev, + customId: trimmedCustomId || undefined, + title: trimmedTitle || undefined, + }; + + const cleaned = Object.fromEntries( + Object.entries(nextQuery).filter(([, value]) => + Array.isArray(value) ? value.length > 0 : Boolean(value) + ) + ) as GetProblemsSearchParams; + + return cleaned; + }); + }, 300); + + return () => clearTimeout(debounceTimer); + }, [watchedCustomId, watchedTitle]); + const handleClickDelete = (e: React.MouseEvent, problemId: string) => { e.stopPropagation(); e.preventDefault(); From 8ddf987e18d7399e595fd23c2c2bf67b5cd0bc7c Mon Sep 17 00:00:00 2001 From: sterdsterd Date: Thu, 14 Aug 2025 16:43:37 +0900 Subject: [PATCH 04/17] =?UTF-8?q?feat:=20=EB=AC=B8=EC=A0=9C=20=EC=84=B8?= =?UTF-8?q?=ED=8A=B8=20=ED=8E=98=EC=9D=B4=EC=A7=80=20debounce=20search=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../routes/_GNBLayout/problem-set/index.tsx | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/apps/admin/src/routes/_GNBLayout/problem-set/index.tsx b/apps/admin/src/routes/_GNBLayout/problem-set/index.tsx index 6a8dfdcd..37c2d920 100644 --- a/apps/admin/src/routes/_GNBLayout/problem-set/index.tsx +++ b/apps/admin/src/routes/_GNBLayout/problem-set/index.tsx @@ -13,7 +13,7 @@ import { import { useInvalidate, useModal } from '@hooks'; import { createFileRoute, Link, useRouter } from '@tanstack/react-router'; import { GetProblemSetSearchParams } from '@types'; -import { useRef, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { useForm } from 'react-hook-form'; export const Route = createFileRoute('/_GNBLayout/problem-set/')({ @@ -25,7 +25,7 @@ function RouteComponent() { const { navigate } = useRouter(); const [searchQuery, setSearchQuery] = useState({}); - const { register, handleSubmit, reset } = useForm(); + const { register, handleSubmit, reset, watch } = useForm(); const { isOpen: isDeleteModalOpen, openModal: openDeleteModal, @@ -38,6 +38,33 @@ function RouteComponent() { const { mutate: mutatePostProblemSet } = postProblemSet(); const { mutate: mutateDeleteProblemSet } = deleteProblemSet(); + const watchedSetTitle = watch('setTitle'); + const watchedProblemTitle = watch('problemTitle'); + useEffect(() => { + const debounceTimer = setTimeout(() => { + const trimmedSetTitle = (watchedSetTitle ?? '').toString().trim(); + const trimmedProblemTitle = (watchedProblemTitle ?? '').toString().trim(); + + setSearchQuery((prev) => { + const nextQuery: GetProblemSetSearchParams = { + ...prev, + setTitle: trimmedSetTitle || undefined, + problemTitle: trimmedProblemTitle || undefined, + }; + + const cleaned = Object.fromEntries( + Object.entries(nextQuery).filter(([, value]) => + Array.isArray(value) ? value.length > 0 : Boolean(value) + ) + ) as GetProblemSetSearchParams; + + return cleaned; + }); + }, 300); + + return () => clearTimeout(debounceTimer); + }, [watchedSetTitle, watchedProblemTitle]); + const handleClickSearch = (data: GetProblemSetSearchParams) => { const filteredData = Object.fromEntries( Object.entries(data).filter(([_, value]) => Boolean(value)) From bec85ad46894345501685974ebf60c95924879b9 Mon Sep 17 00:00:00 2001 From: sterdsterd Date: Thu, 14 Aug 2025 16:45:19 +0900 Subject: [PATCH 05/17] =?UTF-8?q?feat:=20ProblemSearchModal=EC=97=90=20deb?= =?UTF-8?q?ounce=20search=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/Modals/ProblemSearchModal.tsx | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/apps/admin/src/components/common/Modals/ProblemSearchModal.tsx b/apps/admin/src/components/common/Modals/ProblemSearchModal.tsx index 4ed7a9b9..51ab3338 100644 --- a/apps/admin/src/components/common/Modals/ProblemSearchModal.tsx +++ b/apps/admin/src/components/common/Modals/ProblemSearchModal.tsx @@ -4,7 +4,7 @@ import { useModal } from '@hooks'; import { components } from '@schema'; import { IcDown } from '@svg'; import { GetProblemsSearchParams } from '@types'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { useForm } from 'react-hook-form'; import PulseLoader from 'react-spinners/PulseLoader'; @@ -20,7 +20,35 @@ const ProblemSearchModal = ({ onClickCard }: ProblemSearchModalProps) => { const [searchQuery, setSearchQuery] = useState({}); const [selectedTagList, setSelectedTagList] = useState([]); - const { register, handleSubmit, reset } = useForm(); + const { register, handleSubmit, reset, watch } = useForm(); + + const watchedCustomId = watch('customId'); + const watchedTitle = watch('title'); + + useEffect(() => { + const debounceTimer = setTimeout(() => { + const trimmedCustomId = (watchedCustomId ?? '').toString().trim(); + const trimmedTitle = (watchedTitle ?? '').toString().trim(); + + setSearchQuery((prev) => { + const nextQuery: GetProblemsSearchParams = { + ...prev, + customId: trimmedCustomId || undefined, + title: trimmedTitle || undefined, + }; + + const cleaned = Object.fromEntries( + Object.entries(nextQuery).filter(([, value]) => + Array.isArray(value) ? value.length > 0 : Boolean(value) + ) + ) as GetProblemsSearchParams; + + return cleaned; + }); + }, 300); + + return () => clearTimeout(debounceTimer); + }, [watchedCustomId, watchedTitle]); const { data: problemList, isLoading } = getProblemsSearch(searchQuery); const { data: tagsData } = getConcept(); From 21f6a3a506c1f44686c860242ba08d1b848bb9a0 Mon Sep 17 00:00:00 2001 From: sterdsterd Date: Thu, 14 Aug 2025 16:48:42 +0900 Subject: [PATCH 06/17] =?UTF-8?q?feat:=20=EB=B0=9C=ED=96=89=20=EC=84=B8?= =?UTF-8?q?=ED=8A=B8=20=EA=B2=80=EC=83=89=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?debounce=20search=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../$publishDate/$studentId/index.tsx | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/apps/admin/src/routes/_GNBLayout/publish/register/$publishDate/$studentId/index.tsx b/apps/admin/src/routes/_GNBLayout/publish/register/$publishDate/$studentId/index.tsx index 780288b5..bf9c6c23 100644 --- a/apps/admin/src/routes/_GNBLayout/publish/register/$publishDate/$studentId/index.tsx +++ b/apps/admin/src/routes/_GNBLayout/publish/register/$publishDate/$studentId/index.tsx @@ -11,7 +11,7 @@ import { import { useInvalidate } from '@hooks'; import { createFileRoute, Link, useRouter } from '@tanstack/react-router'; import { GetProblemSetSearchParams } from '@types'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { useForm } from 'react-hook-form'; import { Slide, toast, ToastContainer } from 'react-toastify'; @@ -36,7 +36,34 @@ function RouteComponent() { const { data: problemSetList } = getProblemSetSearch(searchQuery); const { mutate: mutatePostPublish } = postPublish(); - const { register, handleSubmit, reset } = useForm(); + const { register, handleSubmit, reset, watch } = useForm(); + + const watchedSetTitle = watch('setTitle'); + const watchedProblemTitle = watch('problemTitle'); + useEffect(() => { + const debounceTimer = setTimeout(() => { + const trimmedSetTitle = (watchedSetTitle ?? '').toString().trim(); + const trimmedProblemTitle = (watchedProblemTitle ?? '').toString().trim(); + + setSearchQuery((prev) => { + const nextQuery: GetProblemSetSearchParams = { + ...prev, + setTitle: trimmedSetTitle || undefined, + problemTitle: trimmedProblemTitle || undefined, + }; + + const cleaned = Object.fromEntries( + Object.entries(nextQuery).filter(([, value]) => + Array.isArray(value) ? value.length > 0 : Boolean(value) + ) + ) as GetProblemSetSearchParams; + + return cleaned; + }); + }, 300); + + return () => clearTimeout(debounceTimer); + }, [watchedSetTitle, watchedProblemTitle]); const handleClickSearch = (data: GetProblemSetSearchParams) => { const filteredData = Object.fromEntries( From cee4002f5e7ce743ccafcc61e5edfb2d12d1132d Mon Sep 17 00:00:00 2001 From: sterdsterd Date: Thu, 14 Aug 2025 17:02:58 +0900 Subject: [PATCH 07/17] =?UTF-8?q?refactor:=20@component=20export=20?= =?UTF-8?q?=EA=B5=AC=EC=A1=B0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/common/Modals/index.ts | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/apps/admin/src/components/common/Modals/index.ts b/apps/admin/src/components/common/Modals/index.ts index f4cf8f40..02dd02dc 100644 --- a/apps/admin/src/components/common/Modals/index.ts +++ b/apps/admin/src/components/common/Modals/index.ts @@ -3,11 +3,17 @@ import BaseModalTemplate from './templates/BaseModalTemplate'; import ErrorModalTemplate from './templates/ErrorModalTemplate'; import OneButtonModalTemplate from './templates/OneButtonModalTemplate'; import TwoButtonModalTemplate from './templates/TwoButtonModalTemplate'; -import TagSelectModal from './TagSelectModal'; -import ProblemSearchModal from './ProblemSearchModal'; import CreateNoticeModal from './CreateNoticeModal'; +import CreatePracticeTestModal from './CreatePracticeTestModal'; +import EditCategoryModal from './EditCategoryModal'; +import EditConceptModal from './EditConceptModal'; +import EditTeacherModal from './EditTeacherModal'; import NoticeListModal from './NoticeListModal'; +import ProblemSearchModal from './ProblemSearchModal'; import ProgressModal from './ProgressModal'; +import SelectStudentModal from './SelectStudentModal'; +import StudentSearchModal from './StudentSearchModal'; +import TagSelectModal from './TagSelectModal'; export { Modal, @@ -15,9 +21,15 @@ export { ErrorModalTemplate, OneButtonModalTemplate, TwoButtonModalTemplate, - TagSelectModal, - ProblemSearchModal, CreateNoticeModal, + CreatePracticeTestModal, + EditCategoryModal, + EditConceptModal, + EditTeacherModal, NoticeListModal, + ProblemSearchModal, ProgressModal, + SelectStudentModal, + StudentSearchModal, + TagSelectModal, }; From 6264f1dd8b17cebe43b9fe3a328ad17c64345766 Mon Sep 17 00:00:00 2001 From: sterdsterd Date: Thu, 14 Aug 2025 17:20:16 +0900 Subject: [PATCH 08/17] =?UTF-8?q?feat:=20=EA=B0=9C=EB=85=90=20=ED=83=9C?= =?UTF-8?q?=EA=B7=B8=20=EB=8C=80=EB=B6=84=EB=A5=98=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?Modal=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/Modals/EditCategoryModal.tsx | 37 +++++++++++ .../routes/_GNBLayout/concept-tags/index.tsx | 61 +++++++++++++++++-- 2 files changed, 93 insertions(+), 5 deletions(-) create mode 100644 apps/admin/src/components/common/Modals/EditCategoryModal.tsx diff --git a/apps/admin/src/components/common/Modals/EditCategoryModal.tsx b/apps/admin/src/components/common/Modals/EditCategoryModal.tsx new file mode 100644 index 00000000..33c86338 --- /dev/null +++ b/apps/admin/src/components/common/Modals/EditCategoryModal.tsx @@ -0,0 +1,37 @@ +import { Button, SearchInput } from '@components'; +import { useForm } from 'react-hook-form'; + +interface Props { + onClose: () => void; + onSubmit: (data: { name: string }) => void; + defaultName?: string; +} + +const EditCategoryModal = ({ onClose, onSubmit, defaultName }: Props) => { + const { register, handleSubmit } = useForm<{ name: string }>({ + defaultValues: { name: defaultName ?? '' }, + }); + return ( +
+

대분류 제목 수정

+
+ +
+ + +
+ +
+ ); +}; + +export default EditCategoryModal; diff --git a/apps/admin/src/routes/_GNBLayout/concept-tags/index.tsx b/apps/admin/src/routes/_GNBLayout/concept-tags/index.tsx index ee502a69..a1bceb53 100644 --- a/apps/admin/src/routes/_GNBLayout/concept-tags/index.tsx +++ b/apps/admin/src/routes/_GNBLayout/concept-tags/index.tsx @@ -1,15 +1,23 @@ import { createFileRoute } from '@tanstack/react-router'; import { useEffect, useState } from 'react'; -import { Button, FloatingButton, Header, Input, Modal, TwoButtonModalTemplate } from '@components'; +import { + Button, + EditCategoryModal, + EditConceptModal, + FloatingButton, + Header, + Input, + Modal, + TwoButtonModalTemplate, +} from '@components'; import { useForm } from 'react-hook-form'; import { Divider } from '@repo/pointer-design-system/components'; import { IcPencil } from '@svg'; -import { getConcept, getConceptCategory, deleteConcept } from '@apis'; +import { getConcept, getConceptCategory, deleteConcept, putConceptCategory } from '@apis'; import { useModal, useInvalidate } from '@hooks'; -import type { components } from '@/types/api/schema'; import { ConceptTagCard } from '@/components/conceptTags'; -import EditConceptModal from '@/components/common/Modals/EditConceptModal'; +import type { components } from '@/types/api/schema'; export const Route = createFileRoute('/_GNBLayout/concept-tags/')({ component: RouteComponent, @@ -22,6 +30,9 @@ function RouteComponent() { const [selectedConceptForEdit, setSelectedConceptForEdit] = useState< components['schemas']['ConceptResp'] | null >(null); + const [selectedCategoryForEdit, setSelectedCategoryForEdit] = useState< + components['schemas']['ConceptCategoryResp'] | null + >(null); const [isMultipleDelete, setIsMultipleDelete] = useState(false); const { isOpen: isDeleteModalOpen, @@ -33,10 +44,16 @@ function RouteComponent() { openModal: openEditConceptModal, closeModal: closeEditConceptModal, } = useModal(); + const { + isOpen: isEditCategoryModalOpen, + openModal: openEditCategoryModal, + closeModal: closeEditCategoryModal, + } = useModal(); // api const { data: concepts } = getConcept({ query: searchQuery }); const { data: conceptCategories } = getConceptCategory(); + const { mutateAsync: updateCategoryAsync } = putConceptCategory(); const { invalidateAll } = useInvalidate(); const deleteConceptMutation = deleteConcept(); @@ -139,7 +156,15 @@ function RouteComponent() {

{category.name}

- {}} /> + { + setSelectedCategoryForEdit(category); + openEditCategoryModal(); + }} + />
{concepts?.data @@ -213,6 +238,32 @@ function RouteComponent() { concept={selectedConceptForEdit} /> + { + closeEditCategoryModal(); + setSelectedCategoryForEdit(null); + }}> + { + closeEditCategoryModal(); + setSelectedCategoryForEdit(null); + }} + defaultName={selectedCategoryForEdit ? selectedCategoryForEdit.name : undefined} + onSubmit={async ({ name }) => { + if (!selectedCategoryForEdit) return; + await updateCategoryAsync({ + params: { + path: { categoryId: selectedCategoryForEdit.id }, + }, + body: { name }, + }); + closeEditCategoryModal(); + setSelectedCategoryForEdit(null); + invalidateAll(); + }} + /> + ); } From 50048216ed08186bcd4b2d4773de216aa167b8f6 Mon Sep 17 00:00:00 2001 From: sterdsterd Date: Thu, 14 Aug 2025 18:27:28 +0900 Subject: [PATCH 09/17] =?UTF-8?q?feat:=20=EB=AC=B8=EC=A0=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80/=EC=88=98=EC=A0=95=20=EC=8B=9C=20form=20validation=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/common/Inputs/AnswerInput.tsx | 21 +-- .../src/components/common/Inputs/Input.tsx | 6 +- .../src/components/problem/LevelSelect.tsx | 4 +- .../components/problem/MainProblemSection.tsx | 125 ++++++++++++------ .../_GNBLayout/problem/$problemId/index.tsx | 7 +- .../_GNBLayout/problem/register/index.tsx | 2 - 6 files changed, 107 insertions(+), 58 deletions(-) diff --git a/apps/admin/src/components/common/Inputs/AnswerInput.tsx b/apps/admin/src/components/common/Inputs/AnswerInput.tsx index a616d4d4..8e01c1d8 100644 --- a/apps/admin/src/components/common/Inputs/AnswerInput.tsx +++ b/apps/admin/src/components/common/Inputs/AnswerInput.tsx @@ -1,6 +1,6 @@ import { Input } from '@components'; import { ProblemAnswerType } from '@types'; -import { forwardRef } from 'react'; +import { forwardRef, InputHTMLAttributes } from 'react'; const AnswerTypeList = ['MULTIPLE_CHOICE', 'SHORT_ANSWER']; const AnswerTypeName = { @@ -8,13 +8,14 @@ const AnswerTypeName = { SHORT_ANSWER: '주', }; -interface AnswerTypeSectionProps { +interface AnswerTypeSectionProps extends InputHTMLAttributes { selectedAnswerType: ProblemAnswerType | undefined; } -interface AnswerInputSectionProps { +interface AnswerInputSectionProps extends InputHTMLAttributes { selectedAnswerType: ProblemAnswerType | undefined; selectedAnswer: number | undefined; + isError: boolean; } const AnswerInput = ({ children }: { children: React.ReactNode }) => { @@ -29,8 +30,8 @@ const AnswerTypeSection = forwardRef(