diff --git a/apps/web/src/app/(afterLogin)/vocabulary/[id]/_component/term/Term.tsx b/apps/web/src/app/(afterLogin)/vocabulary/[id]/_component/term/Term.tsx index 847290b..d4d89e3 100644 --- a/apps/web/src/app/(afterLogin)/vocabulary/[id]/_component/term/Term.tsx +++ b/apps/web/src/app/(afterLogin)/vocabulary/[id]/_component/term/Term.tsx @@ -1,6 +1,6 @@ 'use client' -import React, { useEffect, useState } from 'react' +import React, { useEffect, useState, useCallback, useMemo } from 'react' import { Checkbox, Dropbox, Icon, List, Text } from '@vook-client/design-system' import { TermSort, @@ -12,11 +12,15 @@ import { import { useQueryClient } from '@tanstack/react-query' import { usePathname, useSearchParams } from 'next/navigation' import clsx from 'clsx' +import { + GetTermResponse, + TermSortValues, +} from 'node_modules/@vook-client/api/src/services/term/model' -import { useModal } from '@/hooks/useModal' -import { ModalTypes } from '@/hooks/useModal/useModal' import { useToast } from '@/hooks/useToast' import { useVocabularyStore } from '@/store/term' +import { useModal } from '@/hooks/useModal' +import { ModalTypes } from '@/hooks/useModal/useModal' import { LoadingComponent, @@ -35,40 +39,181 @@ import { import { dropboxItem } from 'src/app/(afterLogin)/workspace/VocabularyItem.css' -const TextContainer = ({ length }: { length?: number }) => { +const TextContainer = ({ length }: { length?: number }) => ( +
+ πŸ‘€ μš©μ–΄λͺ©λ‘ + + {length} + +
+) + +const SortableListHeader = ({ + handleSort, + response, +}: { + response: GetTermResponse + handleSort: (sort: TermSort) => void +}) => { + const { checkList, handleCheckList } = useVocabularyStore() + return ( -
- πŸ‘€ μš©μ–΄λͺ©λ‘ - + handleCheckList('all', response)} + > + {}} + checked={checkList.length === response.result.length} + /> + + handleSort(termSort.Term)} > - {length} - + μš©μ–΄ + + handleSort(termSort.Synonym)} + > + λ™μ˜μ–΄ + + handleSort(termSort.Meaning)} + > + 뜻 + + handleSort(termSort.CreatedAt)} + > + μƒμ„±μΌμž + +
) } -interface Term { - sort: 'term' | 'meaning' | 'synonym' | 'createdAt' +const TermItem = ({ + response, + termData, + termUid, + deleteTerm, +}: { + response: GetTermResponse + termData: Terms + termUid: string | null + deleteTerm: (termUid: string) => void +}) => { + const synonymsList = termData.synonyms.join('\n') + const { checkList, handleCheckList } = useVocabularyStore() + + const { setModalData } = useVocabularyStore() + const { toggleModal, setModal } = useModal() + + const handleEdit = (data: Terms) => { + setModalData({ + termUid: data.termUid, + meaning: data.meaning, + name: data.term, + synonym: data.synonyms, + }) + setModal(ModalTypes.EDIT) + toggleModal() + } + + const formatter = useMemo( + () => + new Intl.DateTimeFormat('ko-KR', { + year: 'numeric', + month: 'long', + day: 'numeric', + }), + [], + ) + + return ( +
+ handleCheckList(termData.termUid, response)} + > + {}} + checked={checkList.includes(termData.termUid)} + /> + + + + ', + ``, + )} + /> + ', + ``, + )} + /> + + + + + + + + handleEdit(termData)}> +
+ + μˆ˜μ • +
+
+ deleteTerm(termData.termUid)}> +
+ + μ‚­μ œ +
+
+
+
+
+
+ ) } export const Term = () => { const path = usePathname() const id = path.split('/').pop() ?? '' - const { checkList, setModalData, handleCheckList } = useVocabularyStore() const searchParams = useSearchParams() const termUid = searchParams.get('term-uid') - const { toggleModal, setModal } = useModal() - const [sorts, setSorts] = useState([ - termSort.TermAsc, - termSort.SynonymAsc, - termSort.MeaningAsc, - termSort.CreatedAtAsc, - ]) + const [sorts, setSorts] = useState([]) const [selectedTermUid, setSelectedTermUid] = useState('') const [updated, setUpdated] = useState(false) @@ -79,13 +224,8 @@ export const Term = () => { const deleteTermMutation = useDeleteTermMutation(selectedTermUid, { onSuccess: () => { - queryClient.invalidateQueries({ - queryKey: ['term', id], - }) - addToast({ - message: 'μš©μ–΄κ°€ μ‚­μ œλ˜μ—ˆμŠ΅λ‹ˆλ‹€.', - type: 'success', - }) + queryClient.invalidateQueries({ queryKey: ['term', id] }) + addToast({ message: 'μš©μ–΄κ°€ μ‚­μ œλ˜μ—ˆμŠ΅λ‹ˆλ‹€.', type: 'success' }) }, }) @@ -96,7 +236,6 @@ export const Term = () => { if (termUid) { const offset = document.getElementById(termUid)?.offsetTop - if (offset) { window.scrollTo({ top: offset, behavior: 'smooth' }) } @@ -110,59 +249,42 @@ export const Term = () => { } }, [updated, queryClient, id, sorts]) - if (isLoading || response == null) { - return - } + const handleSort = useCallback( + (sort: TermSort) => { + const checkSort = (sortAsc: TermSortValues, sortDesc: TermSortValues) => { + if (sorts.includes(sortAsc)) { + setSorts([sortDesc]) + } else { + setSorts([sortAsc]) + } + } + switch (sort) { + case termSort.Term: + checkSort(termSort.Term.Asc, termSort.Term.Desc) + break + case termSort.CreatedAt: + checkSort(termSort.CreatedAt.Asc, termSort.CreatedAt.Desc) + break + case termSort.Synonym: + checkSort(termSort.Synonym.Asc, termSort.Synonym.Desc) + break + case termSort.Meaning: + checkSort(termSort.Meaning.Asc, termSort.Meaning.Desc) + break + } - const formatter = new Intl.DateTimeFormat('ko-KR', { - year: 'numeric', - month: 'long', - day: 'numeric', - }) + setUpdated(true) + }, + [sorts], + ) - const updateSort = (sorts: TermSort[], asc: TermSort, desc: TermSort) => { - const ascIndex = sorts.indexOf(asc) - const descIndex = sorts.indexOf(desc) - if (ascIndex !== -1) { - sorts.splice(ascIndex, 1) - sorts.unshift(desc) - } else if (descIndex !== -1) { - sorts.splice(descIndex, 1) - sorts.unshift(asc) - } + const deleteTerm = (termUid: string) => { + setSelectedTermUid(termUid) + deleteTermMutation.mutate() } - const handleSort = ({ sort }: Term) => { - const newSorts = [...sorts] - switch (sort) { - case 'term': - updateSort(newSorts, termSort.TermAsc, termSort.TermDesc) - break - case 'meaning': - updateSort(newSorts, termSort.MeaningAsc, termSort.MeaningDesc) - break - case 'synonym': - updateSort(newSorts, termSort.SynonymAsc, termSort.SynonymDesc) - break - case 'createdAt': - updateSort(newSorts, termSort.CreatedAtAsc, termSort.CreatedAtDesc) - break - default: - return - } - setSorts(newSorts) - setUpdated(true) - } - - const handleEdit = (data: Terms) => { - setModalData({ - termUid: data.termUid, - meaning: data.meaning, - name: data.term, - synonym: data.synonyms, - }) - setModal(ModalTypes.EDIT) - toggleModal() + if (isLoading || response == null) { + return } return ( @@ -171,157 +293,16 @@ export const Term = () => { {response?.result.length ? ( <> -
- { - handleCheckList('all', response) - }} - > - {}} - checked={checkList.length === response.result.length} - /> - - - { - handleSort({ sort: 'term' }) - }} - icon={ - sorts.includes(termSort.TermAsc) - ? 'arrow-down-small' - : 'arrow-up-small' - } - > - μš©μ–΄ - - { - handleSort({ sort: 'synonym' }) - }} - icon={ - sorts.includes(termSort.SynonymAsc) - ? 'arrow-down-small' - : 'arrow-up-small' - } - > - λ™μ˜μ–΄ - - { - handleSort({ sort: 'meaning' }) - }} - icon={ - sorts.includes(termSort.MeaningAsc) - ? 'arrow-down-small' - : 'arrow-up-small' - } - > - 뜻 - - { - handleSort({ sort: 'createdAt' }) - }} - icon={ - sorts.includes(termSort.CreatedAtAsc) - ? 'arrow-down-small' - : 'arrow-up-small' - } - > - μƒμ„±μΌμž - - -
- {response?.result.map((termData, index) => { - const synonymsList = termData.synonyms.join('\n') - - return ( -
- { - handleCheckList(termData.termUid, response) - }} - > - {}} - checked={checkList.includes(termData.termUid)} - /> - - - - ', - ``, - )} - /> - ', - ``, - )} - /> - - - - - - - - { - handleEdit(termData) - }} - > -
- - μˆ˜μ • -
-
- { - setSelectedTermUid(termData.termUid) - deleteTermMutation.mutate() - }} - > -
- - μ‚­μ œ -
-
-
-
-
-
- ) - })} + + {response?.result.map((termData) => ( + + ))} ) : ( diff --git a/apps/web/src/components/common/index.ts b/apps/web/src/components/common/index.ts index 58eed37..65acd40 100644 --- a/apps/web/src/components/common/index.ts +++ b/apps/web/src/components/common/index.ts @@ -1 +1 @@ -export { Hyperlink, Logo } from './Common' +export { Hyperlink, LoadingComponent, Logo, NoneDataComponent } from './Common' diff --git a/packages/api/src/services/term/model.ts b/packages/api/src/services/term/model.ts index b860643..33fc996 100644 --- a/packages/api/src/services/term/model.ts +++ b/packages/api/src/services/term/model.ts @@ -1,16 +1,27 @@ export const termSort = { - TermAsc: 'term%2Casc', - TermDesc: 'term%2Cdesc', - SynonymAsc: 'synonym%2Casc', - SynonymDesc: 'synonym%2Cdesc', - MeaningAsc: 'meaning%2Casc', - MeaningDesc: 'meaning%2Cdesc', - CreatedAtAsc: 'createdAt%2Casc', - CreatedAtDesc: 'createdAt%2Cdesc', + Term: { + Asc: 'term%2Casc', + Desc: 'term%2Cdesc', + }, + Synonym: { + Asc: 'synonym%2Casc', + Desc: 'synonym%2Cdesc', + }, + Meaning: { + Asc: 'meaning%2Casc', + Desc: 'meaning%2Cdesc', + }, + CreatedAt: { + Asc: 'createdAt%2Casc', + Desc: 'createdAt%2Cdesc', + }, } as const export type TermSort = (typeof termSort)[keyof typeof termSort] +export type TermSortValues = + (typeof termSort)[keyof typeof termSort][keyof typeof termSort.Term] + export interface Terms extends TermType { termUid: string createdAt: string diff --git a/packages/api/src/services/term/quries.ts b/packages/api/src/services/term/quries.ts index eb69661..b9eb0c1 100644 --- a/packages/api/src/services/term/quries.ts +++ b/packages/api/src/services/term/quries.ts @@ -14,11 +14,15 @@ import { DeleteAllDTO as DeleteBatchDTO, EditTermDTO, GetTermResponse, - TermSort, + TermSortValues, } from './model' export const termOptions = { - termInfo: (client: QueryClient, vocabularyUid: string, sort: TermSort[]) => ({ + termInfo: ( + client: QueryClient, + vocabularyUid: string, + sort: TermSortValues[], + ) => ({ queryKey: ['term', vocabularyUid, sort], queryFn: () => termService.getTerm(client, vocabularyUid, sort), }), @@ -38,7 +42,7 @@ export const termOptions = { export const useGetTermQuery = ( vocabularyUid: string, - sort: TermSort[], + sort: TermSortValues[], options: QueryOptions = {}, ) => { const queryClient = useQueryClient() diff --git a/packages/api/src/services/term/service.ts b/packages/api/src/services/term/service.ts index 9459350..bfe2daa 100644 --- a/packages/api/src/services/term/service.ts +++ b/packages/api/src/services/term/service.ts @@ -8,11 +8,15 @@ import { DeleteAllDTO as DeleteBatchDTO, EditTermDTO, GetTermResponse, - TermSort, + TermSortValues, } from './model' export const termService = { - async getTerm(client: QueryClient, vocabularyUid: string, sort?: TermSort[]) { + async getTerm( + client: QueryClient, + vocabularyUid: string, + sort?: TermSortValues[], + ) { let url = `/terms?vocabularyUid=${vocabularyUid}` if (sort) { url = url + '&sort=' + sort.join('&sort=')