From 4bcef1ee1ef26b56b47204d9de1d990dd6ab0ae4 Mon Sep 17 00:00:00 2001 From: Seoyoung Date: Wed, 18 Sep 2024 20:20:14 +0900 Subject: [PATCH 01/36] =?UTF-8?q?Refactor:=20ver3.0=20=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=EC=83=9D=EC=84=B1=20=ED=8F=B4=EB=8D=94=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EB=B0=8F=20=EA=B3=B5=EC=9A=A9=ED=97=A4=EB=8D=94=20?= =?UTF-8?q?ver3.0=20=EB=94=94=EC=9E=90=EC=9D=B8=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_components/CreateItem.css.ts | 0 .../_components/CreateItem.tsx | 0 .../_components/CreateList.css.ts | 0 .../_components/CreateList.tsx | 0 .../_components/item/AddItemButton.css.ts | 0 .../_components/item/AddItemButton.tsx | 0 .../_components/item/Header.css.ts | 0 .../_components/item/Header.tsx | 0 .../_components/item/ImagePreview.tsx | 0 .../_components/item/ImageUploader.css.ts | 0 .../_components/item/ImageUploader.tsx | 0 .../_components/item/ItemLayout.css.ts | 0 .../_components/item/ItemLayout.tsx | 0 .../_components/item/Items.css.ts | 0 .../_components/item/Items.tsx | 0 .../_components/item/LinkModal.css.ts | 0 .../_components/item/LinkModal.tsx | 0 .../_components/item/LinkPreview.tsx | 0 .../_components/item/Preview.css.ts | 0 .../_components/list/ButtonSelector.css.ts | 0 .../_components/list/ButtonSelector.tsx | 0 .../_components/list/ColorSelector.css.ts | 0 .../_components/list/ColorSelector.tsx | 0 .../_components/list/CreateListMock.ts | 0 .../_components/list/Header.css.ts | 0 .../_components/list/Header.tsx | 0 .../_components/list/LabelInput.css.ts | 0 .../_components/list/LabelInput.tsx | 0 .../_components/list/MemberSelector.css.ts | 0 .../_components/list/MemberSelector.tsx | 0 .../_components/list/PaletteSelector.css.ts | 0 .../_components/list/PaletteSelector.tsx | 0 .../_components/list/RadioInput.css.ts | 0 .../_components/list/RadioInput.tsx | 0 .../_components/list/Section.css.ts | 0 .../_components/list/Section.tsx | 0 .../_components/list/SimpleInput.css.ts | 0 .../_components/list/SimpleInput.tsx | 0 src/app/list/_create/locale.ts | 99 +++++++++ src/app/list/_create/page.tsx | 187 +++++++++++++++++ src/app/list/create/locale.ts | 99 --------- src/app/list/create/page.tsx | 188 +----------------- src/components/Header/Header.tsx | 2 +- src/styles/GlobalStyles.css.ts | 4 +- 44 files changed, 299 insertions(+), 280 deletions(-) rename src/app/list/{create => _create}/_components/CreateItem.css.ts (100%) rename src/app/list/{create => _create}/_components/CreateItem.tsx (100%) rename src/app/list/{create => _create}/_components/CreateList.css.ts (100%) rename src/app/list/{create => _create}/_components/CreateList.tsx (100%) rename src/app/list/{create => _create}/_components/item/AddItemButton.css.ts (100%) rename src/app/list/{create => _create}/_components/item/AddItemButton.tsx (100%) rename src/app/list/{create => _create}/_components/item/Header.css.ts (100%) rename src/app/list/{create => _create}/_components/item/Header.tsx (100%) rename src/app/list/{create => _create}/_components/item/ImagePreview.tsx (100%) rename src/app/list/{create => _create}/_components/item/ImageUploader.css.ts (100%) rename src/app/list/{create => _create}/_components/item/ImageUploader.tsx (100%) rename src/app/list/{create => _create}/_components/item/ItemLayout.css.ts (100%) rename src/app/list/{create => _create}/_components/item/ItemLayout.tsx (100%) rename src/app/list/{create => _create}/_components/item/Items.css.ts (100%) rename src/app/list/{create => _create}/_components/item/Items.tsx (100%) rename src/app/list/{create => _create}/_components/item/LinkModal.css.ts (100%) rename src/app/list/{create => _create}/_components/item/LinkModal.tsx (100%) rename src/app/list/{create => _create}/_components/item/LinkPreview.tsx (100%) rename src/app/list/{create => _create}/_components/item/Preview.css.ts (100%) rename src/app/list/{create => _create}/_components/list/ButtonSelector.css.ts (100%) rename src/app/list/{create => _create}/_components/list/ButtonSelector.tsx (100%) rename src/app/list/{create => _create}/_components/list/ColorSelector.css.ts (100%) rename src/app/list/{create => _create}/_components/list/ColorSelector.tsx (100%) rename src/app/list/{create => _create}/_components/list/CreateListMock.ts (100%) rename src/app/list/{create => _create}/_components/list/Header.css.ts (100%) rename src/app/list/{create => _create}/_components/list/Header.tsx (100%) rename src/app/list/{create => _create}/_components/list/LabelInput.css.ts (100%) rename src/app/list/{create => _create}/_components/list/LabelInput.tsx (100%) rename src/app/list/{create => _create}/_components/list/MemberSelector.css.ts (100%) rename src/app/list/{create => _create}/_components/list/MemberSelector.tsx (100%) rename src/app/list/{create => _create}/_components/list/PaletteSelector.css.ts (100%) rename src/app/list/{create => _create}/_components/list/PaletteSelector.tsx (100%) rename src/app/list/{create => _create}/_components/list/RadioInput.css.ts (100%) rename src/app/list/{create => _create}/_components/list/RadioInput.tsx (100%) rename src/app/list/{create => _create}/_components/list/Section.css.ts (100%) rename src/app/list/{create => _create}/_components/list/Section.tsx (100%) rename src/app/list/{create => _create}/_components/list/SimpleInput.css.ts (100%) rename src/app/list/{create => _create}/_components/list/SimpleInput.tsx (100%) create mode 100644 src/app/list/_create/locale.ts create mode 100644 src/app/list/_create/page.tsx diff --git a/src/app/list/create/_components/CreateItem.css.ts b/src/app/list/_create/_components/CreateItem.css.ts similarity index 100% rename from src/app/list/create/_components/CreateItem.css.ts rename to src/app/list/_create/_components/CreateItem.css.ts diff --git a/src/app/list/create/_components/CreateItem.tsx b/src/app/list/_create/_components/CreateItem.tsx similarity index 100% rename from src/app/list/create/_components/CreateItem.tsx rename to src/app/list/_create/_components/CreateItem.tsx diff --git a/src/app/list/create/_components/CreateList.css.ts b/src/app/list/_create/_components/CreateList.css.ts similarity index 100% rename from src/app/list/create/_components/CreateList.css.ts rename to src/app/list/_create/_components/CreateList.css.ts diff --git a/src/app/list/create/_components/CreateList.tsx b/src/app/list/_create/_components/CreateList.tsx similarity index 100% rename from src/app/list/create/_components/CreateList.tsx rename to src/app/list/_create/_components/CreateList.tsx diff --git a/src/app/list/create/_components/item/AddItemButton.css.ts b/src/app/list/_create/_components/item/AddItemButton.css.ts similarity index 100% rename from src/app/list/create/_components/item/AddItemButton.css.ts rename to src/app/list/_create/_components/item/AddItemButton.css.ts diff --git a/src/app/list/create/_components/item/AddItemButton.tsx b/src/app/list/_create/_components/item/AddItemButton.tsx similarity index 100% rename from src/app/list/create/_components/item/AddItemButton.tsx rename to src/app/list/_create/_components/item/AddItemButton.tsx diff --git a/src/app/list/create/_components/item/Header.css.ts b/src/app/list/_create/_components/item/Header.css.ts similarity index 100% rename from src/app/list/create/_components/item/Header.css.ts rename to src/app/list/_create/_components/item/Header.css.ts diff --git a/src/app/list/create/_components/item/Header.tsx b/src/app/list/_create/_components/item/Header.tsx similarity index 100% rename from src/app/list/create/_components/item/Header.tsx rename to src/app/list/_create/_components/item/Header.tsx diff --git a/src/app/list/create/_components/item/ImagePreview.tsx b/src/app/list/_create/_components/item/ImagePreview.tsx similarity index 100% rename from src/app/list/create/_components/item/ImagePreview.tsx rename to src/app/list/_create/_components/item/ImagePreview.tsx diff --git a/src/app/list/create/_components/item/ImageUploader.css.ts b/src/app/list/_create/_components/item/ImageUploader.css.ts similarity index 100% rename from src/app/list/create/_components/item/ImageUploader.css.ts rename to src/app/list/_create/_components/item/ImageUploader.css.ts diff --git a/src/app/list/create/_components/item/ImageUploader.tsx b/src/app/list/_create/_components/item/ImageUploader.tsx similarity index 100% rename from src/app/list/create/_components/item/ImageUploader.tsx rename to src/app/list/_create/_components/item/ImageUploader.tsx diff --git a/src/app/list/create/_components/item/ItemLayout.css.ts b/src/app/list/_create/_components/item/ItemLayout.css.ts similarity index 100% rename from src/app/list/create/_components/item/ItemLayout.css.ts rename to src/app/list/_create/_components/item/ItemLayout.css.ts diff --git a/src/app/list/create/_components/item/ItemLayout.tsx b/src/app/list/_create/_components/item/ItemLayout.tsx similarity index 100% rename from src/app/list/create/_components/item/ItemLayout.tsx rename to src/app/list/_create/_components/item/ItemLayout.tsx diff --git a/src/app/list/create/_components/item/Items.css.ts b/src/app/list/_create/_components/item/Items.css.ts similarity index 100% rename from src/app/list/create/_components/item/Items.css.ts rename to src/app/list/_create/_components/item/Items.css.ts diff --git a/src/app/list/create/_components/item/Items.tsx b/src/app/list/_create/_components/item/Items.tsx similarity index 100% rename from src/app/list/create/_components/item/Items.tsx rename to src/app/list/_create/_components/item/Items.tsx diff --git a/src/app/list/create/_components/item/LinkModal.css.ts b/src/app/list/_create/_components/item/LinkModal.css.ts similarity index 100% rename from src/app/list/create/_components/item/LinkModal.css.ts rename to src/app/list/_create/_components/item/LinkModal.css.ts diff --git a/src/app/list/create/_components/item/LinkModal.tsx b/src/app/list/_create/_components/item/LinkModal.tsx similarity index 100% rename from src/app/list/create/_components/item/LinkModal.tsx rename to src/app/list/_create/_components/item/LinkModal.tsx diff --git a/src/app/list/create/_components/item/LinkPreview.tsx b/src/app/list/_create/_components/item/LinkPreview.tsx similarity index 100% rename from src/app/list/create/_components/item/LinkPreview.tsx rename to src/app/list/_create/_components/item/LinkPreview.tsx diff --git a/src/app/list/create/_components/item/Preview.css.ts b/src/app/list/_create/_components/item/Preview.css.ts similarity index 100% rename from src/app/list/create/_components/item/Preview.css.ts rename to src/app/list/_create/_components/item/Preview.css.ts diff --git a/src/app/list/create/_components/list/ButtonSelector.css.ts b/src/app/list/_create/_components/list/ButtonSelector.css.ts similarity index 100% rename from src/app/list/create/_components/list/ButtonSelector.css.ts rename to src/app/list/_create/_components/list/ButtonSelector.css.ts diff --git a/src/app/list/create/_components/list/ButtonSelector.tsx b/src/app/list/_create/_components/list/ButtonSelector.tsx similarity index 100% rename from src/app/list/create/_components/list/ButtonSelector.tsx rename to src/app/list/_create/_components/list/ButtonSelector.tsx diff --git a/src/app/list/create/_components/list/ColorSelector.css.ts b/src/app/list/_create/_components/list/ColorSelector.css.ts similarity index 100% rename from src/app/list/create/_components/list/ColorSelector.css.ts rename to src/app/list/_create/_components/list/ColorSelector.css.ts diff --git a/src/app/list/create/_components/list/ColorSelector.tsx b/src/app/list/_create/_components/list/ColorSelector.tsx similarity index 100% rename from src/app/list/create/_components/list/ColorSelector.tsx rename to src/app/list/_create/_components/list/ColorSelector.tsx diff --git a/src/app/list/create/_components/list/CreateListMock.ts b/src/app/list/_create/_components/list/CreateListMock.ts similarity index 100% rename from src/app/list/create/_components/list/CreateListMock.ts rename to src/app/list/_create/_components/list/CreateListMock.ts diff --git a/src/app/list/create/_components/list/Header.css.ts b/src/app/list/_create/_components/list/Header.css.ts similarity index 100% rename from src/app/list/create/_components/list/Header.css.ts rename to src/app/list/_create/_components/list/Header.css.ts diff --git a/src/app/list/create/_components/list/Header.tsx b/src/app/list/_create/_components/list/Header.tsx similarity index 100% rename from src/app/list/create/_components/list/Header.tsx rename to src/app/list/_create/_components/list/Header.tsx diff --git a/src/app/list/create/_components/list/LabelInput.css.ts b/src/app/list/_create/_components/list/LabelInput.css.ts similarity index 100% rename from src/app/list/create/_components/list/LabelInput.css.ts rename to src/app/list/_create/_components/list/LabelInput.css.ts diff --git a/src/app/list/create/_components/list/LabelInput.tsx b/src/app/list/_create/_components/list/LabelInput.tsx similarity index 100% rename from src/app/list/create/_components/list/LabelInput.tsx rename to src/app/list/_create/_components/list/LabelInput.tsx diff --git a/src/app/list/create/_components/list/MemberSelector.css.ts b/src/app/list/_create/_components/list/MemberSelector.css.ts similarity index 100% rename from src/app/list/create/_components/list/MemberSelector.css.ts rename to src/app/list/_create/_components/list/MemberSelector.css.ts diff --git a/src/app/list/create/_components/list/MemberSelector.tsx b/src/app/list/_create/_components/list/MemberSelector.tsx similarity index 100% rename from src/app/list/create/_components/list/MemberSelector.tsx rename to src/app/list/_create/_components/list/MemberSelector.tsx diff --git a/src/app/list/create/_components/list/PaletteSelector.css.ts b/src/app/list/_create/_components/list/PaletteSelector.css.ts similarity index 100% rename from src/app/list/create/_components/list/PaletteSelector.css.ts rename to src/app/list/_create/_components/list/PaletteSelector.css.ts diff --git a/src/app/list/create/_components/list/PaletteSelector.tsx b/src/app/list/_create/_components/list/PaletteSelector.tsx similarity index 100% rename from src/app/list/create/_components/list/PaletteSelector.tsx rename to src/app/list/_create/_components/list/PaletteSelector.tsx diff --git a/src/app/list/create/_components/list/RadioInput.css.ts b/src/app/list/_create/_components/list/RadioInput.css.ts similarity index 100% rename from src/app/list/create/_components/list/RadioInput.css.ts rename to src/app/list/_create/_components/list/RadioInput.css.ts diff --git a/src/app/list/create/_components/list/RadioInput.tsx b/src/app/list/_create/_components/list/RadioInput.tsx similarity index 100% rename from src/app/list/create/_components/list/RadioInput.tsx rename to src/app/list/_create/_components/list/RadioInput.tsx diff --git a/src/app/list/create/_components/list/Section.css.ts b/src/app/list/_create/_components/list/Section.css.ts similarity index 100% rename from src/app/list/create/_components/list/Section.css.ts rename to src/app/list/_create/_components/list/Section.css.ts diff --git a/src/app/list/create/_components/list/Section.tsx b/src/app/list/_create/_components/list/Section.tsx similarity index 100% rename from src/app/list/create/_components/list/Section.tsx rename to src/app/list/_create/_components/list/Section.tsx diff --git a/src/app/list/create/_components/list/SimpleInput.css.ts b/src/app/list/_create/_components/list/SimpleInput.css.ts similarity index 100% rename from src/app/list/create/_components/list/SimpleInput.css.ts rename to src/app/list/_create/_components/list/SimpleInput.css.ts diff --git a/src/app/list/create/_components/list/SimpleInput.tsx b/src/app/list/_create/_components/list/SimpleInput.tsx similarity index 100% rename from src/app/list/create/_components/list/SimpleInput.tsx rename to src/app/list/_create/_components/list/SimpleInput.tsx diff --git a/src/app/list/_create/locale.ts b/src/app/list/_create/locale.ts new file mode 100644 index 00000000..95a75a29 --- /dev/null +++ b/src/app/list/_create/locale.ts @@ -0,0 +1,99 @@ +export const itemLocale = { + ko: { + addItem: '아이템 추가', + backIconAlt: '뒤로가기 버튼', + createList: '리스트 생성', + editList: '리스트 수정', + complete: '완료', + imageAlt: '첨부 이미지', + deleteLinkAlt: '링크 삭제 버튼', + dragAndDrop: '드래그앤드롭', + deleteItem: '아이템 삭제', + rank: '위', + addLink: '링크 추가', + confirm: '확인', + itemCreateMessage1: '최소 3개, 최대 10개까지 아이템을 추가할 수 있어요.', + itemCreateMessage2: '아이템의 순서대로 순위가 정해져요.', + }, + en: { + addItem: 'Add Item', + backIconAlt: 'Back button', + createList: 'Create list', + editList: 'Edit list', + complete: 'Complete', + imageAlt: 'Attached image', + deleteLinkAlt: 'Delete link button', + dragAndDrop: 'Drag and drop', + deleteItem: 'Delete item', + rank: 'No.', + addLink: 'Add link', + confirm: 'Confirm', + itemCreateMessage1: 'You can add a minimum of 3 and a maximum of 10 items.', + itemCreateMessage2: 'The ranking is determined in the order of the items.', + }, +}; + +export const listLocale = { + ko: { + closeButtonAlt: '닫기버튼', + createList: '리스트 생성', + editList: '리스트 수정', + next: '다음', + noData: '검색결과가 없어요.', + public: '공개', + private: '비공개', + title: '타이틀', + description: '소개', + category: '카테고리', + label: '라벨', + addCollaborator: '콜라보레이터 추가', + addCollaboratorError: '콜라보레이터는 최대 20명까지 지정할 수 있어요.', + backgroundcolor: '배경 색상', + publicSetting: '공개 설정', + publicMessage: '모든 사람이 이 리스트를 볼 수 있어요.', + privateMessage: '이 리스트는 나만 볼 수 있어요.', + }, + en: { + closeButtonAlt: 'Close button', + createList: 'Create list', + editList: 'Edit list', + next: 'Next', + noData: 'There are no search results.', + public: 'Public', + private: 'Private', + title: 'Title', + description: 'Introduction', + category: 'Category', + label: 'Label', + addCollaborator: 'Add collaborator', + addCollaboratorError: 'You can designate up to 20 collaborators.', + backgroundcolor: 'Background color', + publicSetting: 'Public Settings', + publicMessage: 'Everyone can see this list.', + privateMessage: 'Only I can see this list.', + }, +}; + +type PaletteLocale = { + ko: { + [key: string]: string; + }; + en: { + [key: string]: string; + }; +}; + +export const paletteLocale: PaletteLocale = { + ko: { + PASTEL: '파스텔', + VIVID: '비비드', + GRAY: '그레이', + LISTY: '리스티', + }, + en: { + PASTEL: 'Pastel', + VIVID: 'Vivid', + GRAY: 'Gray', + LISTY: 'Listy', + }, +}; diff --git a/src/app/list/_create/page.tsx b/src/app/list/_create/page.tsx new file mode 100644 index 00000000..6da9557d --- /dev/null +++ b/src/app/list/_create/page.tsx @@ -0,0 +1,187 @@ +'use client'; + +import { useState } from 'react'; +import { FieldErrors, FormProvider, useForm } from 'react-hook-form'; +import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { useRouter } from 'next/navigation'; + +import CreateItem from '@/app/list/create/_components/CreateItem'; +import CreateList from '@/app/list/create/_components/CreateList'; +import { ItemImagesType, ListCreateType } from '@/lib/types/listType'; +import toasting from '@/lib/utils/toasting'; +import toastMessage from '@/lib/constants/toastMessage'; +import { QUERY_KEYS } from '@/lib/constants/queryKeys'; +import createList from '@/app/_api/list/createList'; +import uploadItemImages from '@/app/_api/list/uploadItemImages'; +import { useLanguage } from '@/store/useLanguage'; +import { useUser } from '@/store/useUser'; + +export type FormErrors = FieldErrors; + +export default function CreatePage() { + const { language } = useLanguage(); + const { user: userMeData } = useUser(); + const queryClient = useQueryClient(); + const [step, setStep] = useState<'list' | 'item'>('list'); + const router = useRouter(); + + const methods = useForm({ + mode: 'onChange', + defaultValues: { + category: 'culture', + labels: [], + collaboratorIds: [], + title: '', + description: '', + isPublic: true, + backgroundPalette: 'PASTEL', + backgroundColor: 'PASTEL_PINK', + items: [ + { + rank: 0, + title: '', + comment: '', + link: '', + imageUrl: '', + }, + { + rank: 0, + title: '', + comment: '', + link: '', + imageUrl: '', + }, + { + rank: 0, + title: '', + comment: '', + link: '', + imageUrl: '', + }, + ], + }, + }); + + const handleStepChange = (step: 'list' | 'item') => { + setStep(step); + }; + + //request용 데이터 만드는 함수. + const formatData = () => { + const originData = methods.getValues(); + + //rank 정리 + originData.items.forEach((item, index) => { + item.rank = index + 1; + }); + + //데이터 쪼개기 + const listData: ListCreateType = { + ...originData, + items: originData.items.map(({ imageUrl, ...rest }) => { + return { + ...rest, + imageUrl: '', + }; + }), + }; + + const imageData: ItemImagesType = { + listId: 0, //temp + extensionRanks: originData.items + .filter(({ imageUrl }) => imageUrl !== '') + .map(({ rank, imageUrl }) => { + return { + rank: rank, + extension: + typeof imageUrl === 'object' ? (imageUrl?.[0]?.type.split('/')[1] as 'jpg' | 'jpeg' | 'png') : '', + }; + }), + }; + + const imageFileList: File[] = originData.items + .filter(({ imageUrl }) => imageUrl !== '') + .map(({ imageUrl }) => imageUrl?.[0] as File); + + return { listData, imageData, imageFileList }; + }; + + const { mutate: uploadImageMutate, isPending: isUploadingImage } = useMutation({ + mutationFn: uploadItemImages, + retry: 3, + retryDelay: 1000, + onError: () => { + toasting({ type: 'error', txt: toastMessage[language].uploadImageError }); + }, + }); + + const { + mutate: createListMutate, + isPending: isCreatingList, + isSuccess, + } = useMutation({ + mutationFn: createList, + onSuccess: (data) => { + if (formatData().imageData.extensionRanks.length !== 0) { + uploadImageMutate({ + listId: data.listId, + imageData: formatData().imageData, + imageFileList: formatData().imageFileList, + }); + } + queryClient.invalidateQueries({ + queryKey: [ + QUERY_KEYS.getAllList, + userMeData.id + '', + formatData().listData.collaboratorIds.length === 0 ? 'my' : 'collabo', + ], + }); + router.replace(`/list/${data.listId}`); + }, + onError: () => { + toasting({ type: 'error', txt: toastMessage[language].createListError }); + }, + }); + + //아이템 중복 확인 + const getIsAllUnique = () => { + const allTitles = methods.getValues().items.map((item, itemIndex) => { + return item.title === '' ? itemIndex : item.title; + }); + const isAllUnique = new Set(allTitles).size === allTitles.length; + return isAllUnique; + }; + + const handleSubmit = () => { + if (getIsAllUnique()) { + const { listData } = formatData(); + createListMutate(listData); + } else { + toasting({ type: 'error', txt: toastMessage[language].duplicatedItemError }); + } + }; + + return ( + <> + + {step === 'list' ? ( + { + handleStepChange('item'); + }} + type="create" + /> + ) : ( + { + handleStepChange('list'); + }} + onSubmitClick={handleSubmit} + isSubmitting={isUploadingImage || isCreatingList || isSuccess} + type="create" + /> + )} + + + ); +} diff --git a/src/app/list/create/locale.ts b/src/app/list/create/locale.ts index 1c523af2..e69de29b 100644 --- a/src/app/list/create/locale.ts +++ b/src/app/list/create/locale.ts @@ -1,99 +0,0 @@ -export const itemLocale = { - ko: { - addItem: '아이템 추가', - backIconAlt: '뒤로가기 버튼', - createList: '리스트 생성', - editList: '리스트 수정', - complete: '완료', - imageAlt: '첨부 이미지', - deleteLinkAlt: '링크 삭제 버튼', - dragAndDrop: '드래그앤드롭', - deleteItem: '아이템 삭제', - rank: '위', - addLink: '링크 추가', - confirm: '확인', - itemCreateMessage1: '최소 3개, 최대 10개까지 아이템을 추가할 수 있어요.', - itemCreateMessage2: '아이템의 순서대로 순위가 정해져요.', - }, - en: { - addItem: 'Add Item', - backIconAlt: 'Back button', - createList: 'Create list', - editList: 'Edit list', - complete: 'Complete', - imageAlt: 'Attached image', - deleteLinkAlt: 'Delete link button', - dragAndDrop: 'Drag and drop', - deleteItem: 'Delete item', - rank: 'No.', - addLink: 'Add link', - confirm: 'confirm', - itemCreateMessage1: 'You can add a minimum of 3 and a maximum of 10 items.', - itemCreateMessage2: 'The ranking is determined in the order of the items.', - }, -}; - -export const listLocale = { - ko: { - closeButtonAlt: '닫기버튼', - createList: '리스트 생성', - editList: '리스트 수정', - next: '다음', - noData: '검색결과가 없어요.', - public: '공개', - private: '비공개', - title: '타이틀', - description: '소개', - category: '카테고리', - label: '라벨', - addCollaborator: '콜라보레이터 추가', - addCollaboratorError: '콜라보레이터는 최대 20명까지 지정할 수 있어요.', - backgroundcolor: '배경 색상', - publicSetting: '공개 설정', - publicMessage: '모든 사람이 이 리스트를 볼 수 있어요.', - privateMessage: '이 리스트는 나만 볼 수 있어요.', - }, - en: { - closeButtonAlt: 'Close button', - createList: 'Create list', - editList: 'Edit list', - next: 'Next', - noData: 'There are no search results.', - public: 'Public', - private: 'Private', - title: 'Title', - description: 'Introduction', - category: 'Category', - label: 'Label', - addCollaborator: 'Add collaborator', - addCollaboratorError: 'You can designate up to 20 collaborators.', - backgroundcolor: 'Background color', - publicSetting: 'Public Settings', - publicMessage: 'Everyone can see this list.', - privateMessage: 'Only I can see this list.', - }, -}; - -type PaletteLocale = { - ko: { - [key: string]: string; - }; - en: { - [key: string]: string; - }; -}; - -export const paletteLocale: PaletteLocale = { - ko: { - PASTEL: '파스텔', - VIVID: '비비드', - GRAY: '그레이', - LISTY: '리스티', - }, - en: { - PASTEL: 'Pastel', - VIVID: 'Vivid', - GRAY: 'Gray', - LISTY: 'Listy', - }, -}; diff --git a/src/app/list/create/page.tsx b/src/app/list/create/page.tsx index 6da9557d..6a72bc07 100644 --- a/src/app/list/create/page.tsx +++ b/src/app/list/create/page.tsx @@ -1,187 +1,19 @@ 'use client'; -import { useState } from 'react'; -import { FieldErrors, FormProvider, useForm } from 'react-hook-form'; -import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { useRouter } from 'next/navigation'; - -import CreateItem from '@/app/list/create/_components/CreateItem'; -import CreateList from '@/app/list/create/_components/CreateList'; -import { ItemImagesType, ListCreateType } from '@/lib/types/listType'; -import toasting from '@/lib/utils/toasting'; -import toastMessage from '@/lib/constants/toastMessage'; -import { QUERY_KEYS } from '@/lib/constants/queryKeys'; -import createList from '@/app/_api/list/createList'; -import uploadItemImages from '@/app/_api/list/uploadItemImages'; -import { useLanguage } from '@/store/useLanguage'; -import { useUser } from '@/store/useUser'; - -export type FormErrors = FieldErrors; +import Header from '@/components/Header/Header'; export default function CreatePage() { - const { language } = useLanguage(); - const { user: userMeData } = useUser(); - const queryClient = useQueryClient(); - const [step, setStep] = useState<'list' | 'item'>('list'); - const router = useRouter(); - - const methods = useForm({ - mode: 'onChange', - defaultValues: { - category: 'culture', - labels: [], - collaboratorIds: [], - title: '', - description: '', - isPublic: true, - backgroundPalette: 'PASTEL', - backgroundColor: 'PASTEL_PINK', - items: [ - { - rank: 0, - title: '', - comment: '', - link: '', - imageUrl: '', - }, - { - rank: 0, - title: '', - comment: '', - link: '', - imageUrl: '', - }, - { - rank: 0, - title: '', - comment: '', - link: '', - imageUrl: '', - }, - ], - }, - }); - - const handleStepChange = (step: 'list' | 'item') => { - setStep(step); - }; - - //request용 데이터 만드는 함수. - const formatData = () => { - const originData = methods.getValues(); - - //rank 정리 - originData.items.forEach((item, index) => { - item.rank = index + 1; - }); - - //데이터 쪼개기 - const listData: ListCreateType = { - ...originData, - items: originData.items.map(({ imageUrl, ...rest }) => { - return { - ...rest, - imageUrl: '', - }; - }), - }; - - const imageData: ItemImagesType = { - listId: 0, //temp - extensionRanks: originData.items - .filter(({ imageUrl }) => imageUrl !== '') - .map(({ rank, imageUrl }) => { - return { - rank: rank, - extension: - typeof imageUrl === 'object' ? (imageUrl?.[0]?.type.split('/')[1] as 'jpg' | 'jpeg' | 'png') : '', - }; - }), - }; - - const imageFileList: File[] = originData.items - .filter(({ imageUrl }) => imageUrl !== '') - .map(({ imageUrl }) => imageUrl?.[0] as File); - - return { listData, imageData, imageFileList }; - }; - - const { mutate: uploadImageMutate, isPending: isUploadingImage } = useMutation({ - mutationFn: uploadItemImages, - retry: 3, - retryDelay: 1000, - onError: () => { - toasting({ type: 'error', txt: toastMessage[language].uploadImageError }); - }, - }); - - const { - mutate: createListMutate, - isPending: isCreatingList, - isSuccess, - } = useMutation({ - mutationFn: createList, - onSuccess: (data) => { - if (formatData().imageData.extensionRanks.length !== 0) { - uploadImageMutate({ - listId: data.listId, - imageData: formatData().imageData, - imageFileList: formatData().imageFileList, - }); - } - queryClient.invalidateQueries({ - queryKey: [ - QUERY_KEYS.getAllList, - userMeData.id + '', - formatData().listData.collaboratorIds.length === 0 ? 'my' : 'collabo', - ], - }); - router.replace(`/list/${data.listId}`); - }, - onError: () => { - toasting({ type: 'error', txt: toastMessage[language].createListError }); - }, - }); - - //아이템 중복 확인 - const getIsAllUnique = () => { - const allTitles = methods.getValues().items.map((item, itemIndex) => { - return item.title === '' ? itemIndex : item.title; - }); - const isAllUnique = new Set(allTitles).size === allTitles.length; - return isAllUnique; - }; - - const handleSubmit = () => { - if (getIsAllUnique()) { - const { listData } = formatData(); - createListMutate(listData); - } else { - toasting({ type: 'error', txt: toastMessage[language].duplicatedItemError }); - } - }; - return ( <> - - {step === 'list' ? ( - { - handleStepChange('item'); - }} - type="create" - /> - ) : ( - { - handleStepChange('list'); - }} - onSubmitClick={handleSubmit} - isSubmitting={isUploadingImage || isCreatingList || isSuccess} - type="create" - /> - )} - +

리스트 생성 페이지

+
{ + console.log('뒤로가기'); + }} + right={'다음'} + /> ); } diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index c8ca69f6..859be6df 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -26,7 +26,7 @@ function Header({ title, left, leftClick, right }: HeaderProps) {

{title}

-
{right}
+ {right === null ? <> :
{right}
} ); } diff --git a/src/styles/GlobalStyles.css.ts b/src/styles/GlobalStyles.css.ts index 95fbaa1b..a7465333 100644 --- a/src/styles/GlobalStyles.css.ts +++ b/src/styles/GlobalStyles.css.ts @@ -1,11 +1,11 @@ import { globalStyle } from '@vanilla-extract/css'; import { Pretendard } from './pretendardFont.css'; -import { vars } from './__theme.css'; +import { vars } from './theme.css'; globalStyle('html', { fontSize: '62.5%', color: vars.color.black, - backgroundColor: vars.color.gray3, + backgroundColor: vars.color.white, }); globalStyle('body', { From 0c91ca5dfd7ccf8480bf0a10f038b8c444077e17 Mon Sep 17 00:00:00 2001 From: Seoyoung Date: Thu, 3 Oct 2024 18:11:52 +0900 Subject: [PATCH 02/36] =?UTF-8?q?Feat:=20=EB=A6=AC=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EC=83=9D=EC=84=B1=201=EB=8B=A8=EA=B3=84=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/list/create/_components/StepOne.tsx | 23 ++++++++ src/app/list/create/locale.ts | 8 +++ src/app/list/create/page.tsx | 63 ++++++++++++++++----- 3 files changed, 81 insertions(+), 13 deletions(-) create mode 100644 src/app/list/create/_components/StepOne.tsx diff --git a/src/app/list/create/_components/StepOne.tsx b/src/app/list/create/_components/StepOne.tsx new file mode 100644 index 00000000..ad0b393b --- /dev/null +++ b/src/app/list/create/_components/StepOne.tsx @@ -0,0 +1,23 @@ +'use client'; + +import router from 'next/router'; +import { useLanguage } from '@/store/useLanguage'; +import Header from '@/components/Header/Header'; +import { listLocale } from '../locale'; + +export default function StepOne() { + const { language } = useLanguage(); + + return ( + <> +
{ + router.back(); + }} + right={listLocale[language].next} + /> + + ); +} diff --git a/src/app/list/create/locale.ts b/src/app/list/create/locale.ts index e69de29b..dfd356a3 100644 --- a/src/app/list/create/locale.ts +++ b/src/app/list/create/locale.ts @@ -0,0 +1,8 @@ +export const listLocale = { + ko: { + next: '다음', + }, + en: { + next: 'next', + }, +}; diff --git a/src/app/list/create/page.tsx b/src/app/list/create/page.tsx index 6a72bc07..05363ecd 100644 --- a/src/app/list/create/page.tsx +++ b/src/app/list/create/page.tsx @@ -1,19 +1,56 @@ 'use client'; import Header from '@/components/Header/Header'; +import { listLocale } from './locale'; +import { useLanguage } from '@/store/useLanguage'; +import router from 'next/router'; +import { useState } from 'react'; +import { FormProvider, useForm } from 'react-hook-form'; +import { ListCreateType } from '@/lib/types/listType'; +import StepOne from './_components/StepOne'; + +//TODO: Yup 스키마 사용해보기 export default function CreatePage() { - return ( - <> -

리스트 생성 페이지

-
{ - console.log('뒤로가기'); - }} - right={'다음'} - /> - - ); + const { language } = useLanguage(); + const [step, setStep] = useState<1 | 2 | 3>(1); + + const methods = useForm({ + mode: 'onChange', + defaultValues: { + category: 'culture', + labels: [], + collaboratorIds: [], + title: '', + description: '', + isPublic: true, + backgroundPalette: 'PASTEL', + backgroundColor: 'PASTEL_PINK', + items: [ + { + rank: 0, + title: '', + comment: '', + link: '', + imageUrl: '', + }, + { + rank: 0, + title: '', + comment: '', + link: '', + imageUrl: '', + }, + { + rank: 0, + title: '', + comment: '', + link: '', + imageUrl: '', + }, + ], + }, + }); + + return {step === 1 && }; } From d8866ea62f58b17e20a98e9dfd7bf0f7f1f55542 Mon Sep 17 00:00:00 2001 From: Seoyoung Date: Fri, 4 Oct 2024 02:01:22 +0900 Subject: [PATCH 03/36] =?UTF-8?q?design:=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20step1=20=EB=94=94=EC=9E=90=EC=9D=B8=20?= =?UTF-8?q?=EC=9E=85=ED=9E=88=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../list/create/_components/StepOne.css.ts | 80 +++++++++++++++++++ src/app/list/create/_components/StepOne.tsx | 74 ++++++++++++++++- src/app/list/create/page.tsx | 12 ++- src/lib/constants/formInputValidationRules.ts | 29 +++---- 4 files changed, 178 insertions(+), 17 deletions(-) create mode 100644 src/app/list/create/_components/StepOne.css.ts diff --git a/src/app/list/create/_components/StepOne.css.ts b/src/app/list/create/_components/StepOne.css.ts new file mode 100644 index 00000000..8d2df4c6 --- /dev/null +++ b/src/app/list/create/_components/StepOne.css.ts @@ -0,0 +1,80 @@ +import { style } from '@vanilla-extract/css'; +import { vars } from '@/styles/theme.css'; +import * as fonts from '@/styles/font.css'; + +export const section = style({ + padding: '1.2rem 1.6rem', + + display: 'flex', + flexDirection: 'column', + justifyContent: 'space-between', + rowGap: '32px', +}); + +export const description = style([ + fonts.Label, + { + color: vars.color.bluegray8, + lineHeight: '2rem', + }, +]); + +export const field = style({ + display: 'flex', + flexDirection: 'column', + justifyContent: 'space-between', + rowGap: '1.6rem', +}); + +export const label = style([fonts.Subtitle]); + +export const requiredIcon = style({ + color: vars.color.blue, +}); + +export const input = style([ + fonts.BodyRegular, + { + width: '100%', + height: '4.8rem', + padding: '1.2rem 1.6rem', + borderRadius: '1.2rem', + color: vars.color.bluegray10, + + '::placeholder': { color: vars.color.bluegray6 }, + }, +]); + +export const chipGroup = style({ + display: 'flex', + flexWrap: 'wrap', + gap: '0.8rem', +}); + +export const chip = style([ + fonts.Label, + { + width: 'auto', + padding: '0.6rem 1.2rem', + borderRadius: '2rem', + + color: vars.color.bluegray8, + backgroundColor: vars.color.white, + + whiteSpace: 'nowrap', + }, +]); + +export const selectedChip = style([ + fonts.Label, + chip, + { + color: vars.color.blue, + backgroundColor: vars.color.lightblue, + }, +]); + +export const temp = style({ + all: 'inherit', + cursor: 'pointer', +}); diff --git a/src/app/list/create/_components/StepOne.tsx b/src/app/list/create/_components/StepOne.tsx index ad0b393b..5ddf4050 100644 --- a/src/app/list/create/_components/StepOne.tsx +++ b/src/app/list/create/_components/StepOne.tsx @@ -2,11 +2,38 @@ import router from 'next/router'; import { useLanguage } from '@/store/useLanguage'; +import { useUser } from '@/store/useUser'; import Header from '@/components/Header/Header'; + import { listLocale } from '../locale'; +import * as styles from './StepOne.css'; +import { useFormContext } from 'react-hook-form'; +import { useQuery } from '@tanstack/react-query'; +import { CategoryType } from '@/lib/types/categoriesType'; +import { QUERY_KEYS } from '@/lib/constants/queryKeys'; +import getCategories from '@/app/_api/category/getCategories'; +import { listTitleRules } from '@/lib/constants/formInputValidationRules'; + +interface StepOneProps { + onNextClick: () => void; +} -export default function StepOne() { +export default function StepOne({ onNextClick }: StepOneProps) { const { language } = useLanguage(); + const { user: me } = useUser(); + + const { + register, + setValue, + getValues, + control, + formState: { errors }, + } = useFormContext(); + + const { data: categories } = useQuery({ + queryKey: [QUERY_KEYS.getCategories], + queryFn: getCategories, + }); return ( <> @@ -16,8 +43,51 @@ export default function StepOne() { leftClick={() => { router.back(); }} - right={listLocale[language].next} + right={ + + } /> +
+

+ 기록하고 싶은 것들을 리스트로 남겨 봐요.
+ 나만의 기준으로 순위를 매겨도 좋고, 하나의 주제의 정보를 정리해도 좋아요. +

+
+ + +
+ {/** end-타이틀field*/} +
+ + +
+ {/** end-소개field*/} +
+ +
+ {/**TODO: 선택된 chip 스타일 변경 */} + {categories?.map((item) => ( + + ))} +
+
+ {/** end-카테고리field*/} +
+ {/** end-section*/} ); } diff --git a/src/app/list/create/page.tsx b/src/app/list/create/page.tsx index 05363ecd..9cd272ba 100644 --- a/src/app/list/create/page.tsx +++ b/src/app/list/create/page.tsx @@ -52,5 +52,15 @@ export default function CreatePage() { }, }); - return {step === 1 && }; + return ( + + {step === 1 && ( + { + console.log('next'); + }} + /> + )} + + ); } diff --git a/src/lib/constants/formInputValidationRules.ts b/src/lib/constants/formInputValidationRules.ts index 21ef057f..1df2dc7c 100644 --- a/src/lib/constants/formInputValidationRules.ts +++ b/src/lib/constants/formInputValidationRules.ts @@ -1,4 +1,17 @@ -//item +//list-step1 +export const listTitleRules = { + required: '타이틀을 입력해주세요', + maxLength: { + value: 30, + message: '리스트 타이틀은 최대 30자까지 입력할 수 있어요.', + }, +}; + +export const listDescriptionRules = { + maxLength: { value: 200, message: '리스트 소개는 최대 200자까지 입력할 수 있어요.' }, +}; + +//list-step2 export const itemTitleRules = { required: '아이템을 입력해주세요.', maxLength: { @@ -18,19 +31,7 @@ export const itemLinkRules = { }, }; -//list -export const listTitleRules = { - required: { errorMessage: '제목을 입력해주세요' }, - maxLength: { - length: 30, - errorMessage: '리스트 제목은 최대 30자까지 입력할 수 있어요.', - }, -}; - -export const listDescriptionRules = { - maxLength: { length: 200, errorMessage: '리스트 소개는 최대 200자까지 입력할 수 있어요.' }, -}; - +//list-step3 export const listLabelRules = { maxNumRule: { num: 3, errorMessage: '라벨은 최대 3개까지 등록할 수 있어요.' }, maxLengthRule: { length: 10, errorMessage: '라벨은 최대 10자까지 입력할 수 있어요.' }, From 0762da40b3246313e3a9bf4b07215bdb1a2e8a6b Mon Sep 17 00:00:00 2001 From: Seoyoung Date: Fri, 25 Oct 2024 16:45:23 +0900 Subject: [PATCH 04/36] =?UTF-8?q?Feat:=20step1=20=EA=B8=80=EC=9E=90?= =?UTF-8?q?=EC=88=98=EC=84=B8=EA=B8=B0=20=EB=B0=8F=20=EC=A1=B0=EA=B1=B4=20?= =?UTF-8?q?=EA=B2=80=EC=82=AC=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../list/create/_components/StepOne.css.ts | 29 ++++- src/app/list/create/_components/StepOne.tsx | 120 ++++++++++++++---- src/app/list/create/locale.ts | 9 ++ src/app/list/create/page.tsx | 9 +- 4 files changed, 133 insertions(+), 34 deletions(-) diff --git a/src/app/list/create/_components/StepOne.css.ts b/src/app/list/create/_components/StepOne.css.ts index 8d2df4c6..112cb904 100644 --- a/src/app/list/create/_components/StepOne.css.ts +++ b/src/app/list/create/_components/StepOne.css.ts @@ -8,7 +8,7 @@ export const section = style({ display: 'flex', flexDirection: 'column', justifyContent: 'space-between', - rowGap: '32px', + rowGap: '3.2rem', }); export const description = style([ @@ -32,19 +32,36 @@ export const requiredIcon = style({ color: vars.color.blue, }); +export const inputDiv = style({ + display: 'flex', + padding: '1.2rem 1.6rem', + borderRadius: '1.2rem', + color: vars.color.bluegray10, + background: vars.color.white, +}); + export const input = style([ fonts.BodyRegular, { width: '100%', - height: '4.8rem', - padding: '1.2rem 1.6rem', - borderRadius: '1.2rem', - color: vars.color.bluegray10, - '::placeholder': { color: vars.color.bluegray6 }, }, ]); +export const length = style([fonts.BodyRegular, { color: vars.color.bluegray6 }]); + +export const textarea = style([ + input, + inputDiv, + { + resize: 'none', + border: 'none', + outline: 'none', + }, +]); + +export const errorMessage = style([fonts.BodyRegular, { color: vars.color.red }]); + export const chipGroup = style({ display: 'flex', flexWrap: 'wrap', diff --git a/src/app/list/create/_components/StepOne.tsx b/src/app/list/create/_components/StepOne.tsx index 5ddf4050..a96fa388 100644 --- a/src/app/list/create/_components/StepOne.tsx +++ b/src/app/list/create/_components/StepOne.tsx @@ -1,27 +1,61 @@ 'use client'; +import { useState } from 'react'; import router from 'next/router'; +import { useParams } from 'next/navigation'; +import { useFormContext, useWatch } from 'react-hook-form'; +import { useQuery } from '@tanstack/react-query'; + +import { CategoryType } from '@/lib/types/categoriesType'; +import { ListDetailType } from '@/lib/types/listType'; +import { QUERY_KEYS } from '@/lib/constants/queryKeys'; +import { listDescriptionRules, listTitleRules } from '@/lib/constants/formInputValidationRules'; import { useLanguage } from '@/store/useLanguage'; import { useUser } from '@/store/useUser'; import Header from '@/components/Header/Header'; -import { listLocale } from '../locale'; -import * as styles from './StepOne.css'; -import { useFormContext } from 'react-hook-form'; -import { useQuery } from '@tanstack/react-query'; -import { CategoryType } from '@/lib/types/categoriesType'; -import { QUERY_KEYS } from '@/lib/constants/queryKeys'; +import { getListDetail } from '@/app/_api/list/getLists'; import getCategories from '@/app/_api/category/getCategories'; -import { listTitleRules } from '@/lib/constants/formInputValidationRules'; + +import { listError, listLocale } from '../locale'; +import * as styles from './StepOne.css'; interface StepOneProps { onNextClick: () => void; + type: 'create' | 'edit'; } -export default function StepOne({ onNextClick }: StepOneProps) { +/** + * StepOne 컴포넌트: + * 리스트 생성/수정 과정 1단계 + * + * @param props.onNextClick - 헤더의 '다음'버튼을 클릭했을때 동작시킬 함수 + * @param props.type - 생성과 수정 중 택1 + */ +export default function StepOne({ onNextClick, type }: StepOneProps) { const { language } = useLanguage(); const { user: me } = useUser(); + const param = useParams<{ listId: string }>(); + const listId = param?.listId; + + /** state */ + const [selectedCategory, setSelectedCategory] = useState(''); + + /** 데이터 가져오기 */ + //--- (수정)기존 데이터 가져오기 + const { data: listDetailData } = useQuery({ + queryKey: [QUERY_KEYS.getListDetail, listId], + queryFn: () => getListDetail(listId), + enabled: type === 'edit', + }); + + //--- 카테고리 가져오기 + const { data: categories } = useQuery({ + queryKey: [QUERY_KEYS.getCategories], + queryFn: getCategories, + }); + /** React Hook Form */ const { register, setValue, @@ -30,10 +64,23 @@ export default function StepOne({ onNextClick }: StepOneProps) { formState: { errors }, } = useFormContext(); - const { data: categories } = useQuery({ - queryKey: [QUERY_KEYS.getCategories], - queryFn: getCategories, - }); + //--- 글자수 세기 + const watchTitle = useWatch({ control, name: 'title' }); + + /** 카테고리 선택 */ + const handleSelectCategory = (name: string) => { + setSelectedCategory(name); + setValue('category', name); + }; + + const isValid = !errors.title && !errors.category && !errors.description; + + const handleClick = () => { + console.log(`title: ${getValues().title}`); + console.log(`description: ${getValues().description}`); + console.log(`category: ${getValues().category}`); + console.log(errors.title); + }; return ( <> @@ -44,7 +91,7 @@ export default function StepOne({ onNextClick }: StepOneProps) { router.back(); }} right={ - } @@ -58,18 +105,31 @@ export default function StepOne({ onNextClick }: StepOneProps) { - +
+ +

+ {watchTitle?.length}/30 +

+
+ {/** end-input과 length 묶은 div */} {/** end-타이틀field*/}
- +