diff --git a/package-lock.json b/package-lock.json index bbea71db..fc8a64f9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12420,6 +12420,126 @@ "optional": true } } + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "14.2.18", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.18.tgz", + "integrity": "sha512-tOBlDHCjGdyLf0ube/rDUs6VtwNOajaWV+5FV/ajPgrvHeisllEdymY/oDgv2cx561+gJksfMUtqf8crug7sbA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "14.2.18", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.18.tgz", + "integrity": "sha512-uJCEjutt5VeJ30jjrHV1VIHCsbMYnEqytQgvREx+DjURd/fmKy15NaVK4aR/u98S1LGTnjq35lRTnRyygglxoA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "14.2.18", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.18.tgz", + "integrity": "sha512-IL6rU8vnBB+BAm6YSWZewc+qvdL1EaA+VhLQ6tlUc0xp+kkdxQrVqAnh8Zek1ccKHlTDFRyAft0e60gteYmQ4A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "14.2.18", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.18.tgz", + "integrity": "sha512-RCaENbIZqKKqTlL8KNd+AZV/yAdCsovblOpYFp0OJ7ZxgLNbV5w23CUU1G5On+0fgafrsGcW+GdMKdFjaRwyYA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "14.2.18", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.18.tgz", + "integrity": "sha512-3kmv8DlyhPRCEBM1Vavn8NjyXtMeQ49ID0Olr/Sut7pgzaQTo4h01S7Z8YNE0VtbowyuAL26ibcz0ka6xCTH5g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "14.2.18", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.18.tgz", + "integrity": "sha512-mliTfa8seVSpTbVEcKEXGjC18+TDII8ykW4a36au97spm9XMPqQTpdGPNBJ9RySSFw9/hLuaCMByluQIAnkzlw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "14.2.18", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.18.tgz", + "integrity": "sha512-J5g0UFPbAjKYmqS3Cy7l2fetFmWMY9Oao32eUsBPYohts26BdrMUyfCJnZFQkX9npYaHNDOWqZ6uV9hSDPw9NA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "14.2.18", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.18.tgz", + "integrity": "sha512-Ynxuk4ZgIpdcN7d16ivJdjsDG1+3hTvK24Pp8DiDmIa2+A4CfhJSEHHVndCHok6rnLUzAZD+/UOKESQgTsAZGg==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } } } } diff --git a/src/app/(crew)/_components/hero/hero-crew.tsx b/src/app/(crew)/_components/hero/hero-crew.tsx index dd7ac7fe..969a7db9 100644 --- a/src/app/(crew)/_components/hero/hero-crew.tsx +++ b/src/app/(crew)/_components/hero/hero-crew.tsx @@ -17,7 +17,7 @@ export default function HeroCrew() { 함께할 사람이 없나요? - + 지금 크루에 참여해보세요.

diff --git a/src/app/(crew)/crew/create/_components/create-crew-form/create-crew-form.stories.tsx b/src/app/(crew)/crew/create/_components/create-crew-form/create-crew-form.stories.tsx index acc0aaaa..73e736c9 100644 --- a/src/app/(crew)/crew/create/_components/create-crew-form/create-crew-form.stories.tsx +++ b/src/app/(crew)/crew/create/_components/create-crew-form/create-crew-form.stories.tsx @@ -17,11 +17,27 @@ export default { title: 'crew/create-crew-form', component: CreateCrewForm, tags: ['autodocs'], + argTypes: { + type: { + control: 'radio', + options: ['create', 'edit'], + description: '폼 타입', + table: { type: { summary: 'create | edit' } }, + }, + data: { + control: 'object', + description: '폼 데이터', + table: { type: { summary: 'CreateCrewFormTypes' } }, + }, + isEdit: { control: 'boolean', description: '수정 여부' }, + onSubmit: { + action: 'submit', + table: { type: { summary: '(data: CreateCrewFormTypes) => void' } }, + }, + onEdit: { action: 'edit', table: { type: { summary: '(data: CreateCrewFormTypes) => void' } } }, + }, parameters: { layout: 'fullscreen', - nextjs: { - appDirectory: true, - }, docs: { description: { component: '크루 작성/수정에 사용되는 폼입니다.', diff --git a/src/app/(crew)/crew/create/_components/create-crew-form/index.tsx b/src/app/(crew)/crew/create/_components/create-crew-form/index.tsx index dc17810e..d5fb1a37 100644 --- a/src/app/(crew)/crew/create/_components/create-crew-form/index.tsx +++ b/src/app/(crew)/crew/create/_components/create-crew-form/index.tsx @@ -13,17 +13,26 @@ import DropDown from '@/src/components/common/input/drop-down'; import FileInputWrap from '@/src/components/common/input/file-input-wrap'; import TextInput from '@/src/components/common/input/text-input'; import Textarea from '@/src/components/common/input/textarea'; -import { CreateCrewFormTypes, EditCrewResponseTypes } from '@/src/types/create-crew'; +import { CreateCrewFormTypes } from '@/src/types/create-crew'; import ImgCrewSampleUrls from '@/public/assets/images/crew-sample'; export interface CreateCrewFormProps { type: 'create' | 'edit'; - data: CreateCrewFormTypes | EditCrewResponseTypes; + data: CreateCrewFormTypes; isEdit?: boolean; onEdit?: (data: CreateCrewFormTypes) => void; onSubmit?: (data: CreateCrewFormTypes) => void; } +/** + * 크루 생성/수정 폼 + * @param {'create' | 'edit'} type : form 타입 + * @param {boolean} isEdit : 수정 여부 + * @param {(data: CreateCrewFormTypes) => void} onEdit + * @param {(data: CreateCrewFormTypes) => void} onSubmit + * @param {CreateCrewFormTypes} data + */ + export default function CreateCrewForm({ type, isEdit, @@ -199,7 +208,7 @@ export default function CreateCrewForm({ field.onChange(value); handleMainCategoryChange(value); }} - error={errors.mainCategory?.message} + errorMsg={errors.mainCategory?.message} /> )} /> @@ -218,7 +227,7 @@ export default function CreateCrewForm({ placeholder={isEdit && field.value ? field.value : '세부 카테고리'} data={categoryData[categoryIndex]?.items || []} className="flex-1" - error={errors.subCategory?.message} + errorMsg={errors.subCategory?.message} /> )} /> @@ -277,7 +286,7 @@ export default function CreateCrewForm({ field.onChange(value); handleMainLocationChange(value); }} - error={errors.mainLocation?.message} + errorMsg={errors.mainLocation?.message} /> )} /> @@ -297,7 +306,7 @@ export default function CreateCrewForm({ placeholder={isEdit && field.value ? field.value : '시/군/구'} data={regionData[regionIndex]?.areas || []} className="flex-1" - error={errors.subLocation?.message} + errorMsg={errors.subLocation?.message} /> )} /> diff --git a/src/app/(crew)/crew/detail/[id]/_components/create-gathering/create-gathering-form/index.tsx b/src/app/(crew)/crew/detail/[id]/_components/create-gathering/create-gathering-form/index.tsx index bcdbdf52..a5a2f35e 100644 --- a/src/app/(crew)/crew/detail/[id]/_components/create-gathering/create-gathering-form/index.tsx +++ b/src/app/(crew)/crew/detail/[id]/_components/create-gathering/create-gathering-form/index.tsx @@ -20,6 +20,15 @@ export interface CreateGatheringFormProps { onClose: () => void; } +/** + * 약속 생성/수정 폼 + * @param {CreateGatheringFormTypes} data + * @param {boolean} isEdit + * @param {(data: CreateGatheringFormTypes) => void} onEdit + * @param {(data: CreateGatheringFormTypes) => void} onSubmit + * @param {() => void} onClose + */ + export default function CreateGatheringForm({ isEdit = false, onEdit = () => {}, diff --git a/src/app/(crew)/crew/detail/[id]/_components/crew-review-list.stories.tsx b/src/app/(crew)/crew/detail/[id]/_components/crew-review-list.stories.tsx index 934b43ab..28b97d17 100644 --- a/src/app/(crew)/crew/detail/[id]/_components/crew-review-list.stories.tsx +++ b/src/app/(crew)/crew/detail/[id]/_components/crew-review-list.stories.tsx @@ -10,9 +10,6 @@ const meta: Meta = { component: CrewReviewList, parameters: { layout: 'fulled', - nextjs: { - appDirectory: true, - }, }, tags: ['autodocs'], decorators: [ diff --git a/src/components/common/crew-list/crew-card-list.tsx b/src/components/common/crew-list/crew-card-list.tsx index 50594e7b..e9bce663 100644 --- a/src/components/common/crew-list/crew-card-list.tsx +++ b/src/components/common/crew-list/crew-card-list.tsx @@ -27,9 +27,10 @@ export default function CrewCardList({ data, inWhere }: CrewCardListProps) { if (!crewDataList.length) return ( -
-

데이터가 없습니다.

-
+
+

크루가 아직 없어요

+

크루를 만들어서 함께 운동할 사람을 모집해보세요! 🙌

+
); return ( diff --git a/src/components/common/input/calendar-filter/calendar-filter.stories.tsx b/src/components/common/input/calendar-filter/calendar-filter.stories.tsx index 68f644d7..6656d034 100644 --- a/src/components/common/input/calendar-filter/calendar-filter.stories.tsx +++ b/src/components/common/input/calendar-filter/calendar-filter.stories.tsx @@ -4,12 +4,7 @@ import type { Meta, StoryFn } from '@storybook/react'; import { userEvent, within } from '@storybook/test'; import CalendarFilter, { CalendarFilterProps } from '.'; -const mockData = [ - new Date('2024-10-01'), - new Date('2024-10-05'), - new Date('2024-10-12'), - new Date('2024-10-15'), -]; +const mockData = [new Date()]; const meta: Meta = { title: 'common/calendar/calendar-filter', @@ -20,7 +15,14 @@ const meta: Meta = { type: { name: 'string' }, description: '선택된 날짜', }, - toDoDates: mockData, + toDoDates: { + description: '일정이 있는 날짜', + table: { + type: { + summary: 'Date[] | null', + }, + }, + }, onChange: action('onChange'), }, parameters: { diff --git a/src/components/common/input/calendar-filter/index.tsx b/src/components/common/input/calendar-filter/index.tsx index 26ad4047..874c8a5f 100644 --- a/src/components/common/input/calendar-filter/index.tsx +++ b/src/components/common/input/calendar-filter/index.tsx @@ -12,6 +12,13 @@ export interface CalendarFilterProps { onChange: (date: Date) => void; } +/** + * 달력에서 날짜를 선택하면 값을 변경할 수 있는 컴포넌트 + * @param {Date} value - 선택된 날짜 + * @param {Date[] | null} toDoDates - 일정이 있는 날짜 + * @param {(date: Date) => void} onChange - 값이 변경될 때 실행하는 함수 + */ + export default function CalendarFilter({ value, toDoDates, diff --git a/src/components/common/input/date-time-picker/index.tsx b/src/components/common/input/date-time-picker/index.tsx index e959f59d..990f1a6e 100644 --- a/src/components/common/input/date-time-picker/index.tsx +++ b/src/components/common/input/date-time-picker/index.tsx @@ -12,6 +12,12 @@ export interface DateTimePickerProps { onChange: (date: string) => void; } +/** + * 달력에서 날짜를 선택하고, 드롭다운으로 시간을 선택하면 날짜/시간 값을 변경할 수 있는 컴포넌트 + * @param {Date} fullDate - 선택된 날짜 + * @param {(date: string) => void} onChange - 값이 변경될 때 실행하는 함수 + */ + export default function DateTimePicker({ fullDate, onChange }: DateTimePickerProps) { const [selected, setSelected] = useState(fullDate || new Date()); const [hour, setHour] = useState('시'); diff --git a/src/components/common/input/drop-down/drop-down.stories.tsx b/src/components/common/input/drop-down/drop-down.stories.tsx index e29e98e8..838f0d48 100644 --- a/src/components/common/input/drop-down/drop-down.stories.tsx +++ b/src/components/common/input/drop-down/drop-down.stories.tsx @@ -13,22 +13,57 @@ const meta: Meta = { }, value: { description: '선택된 값', + table: { + type: { + summary: 'string | null', + }, + }, }, data: { description: '옵션 데이터 배열', }, variant: { - description: '`default` | `sort`', + description: '컴포넌트 타입', control: { type: 'radio', option: ['default', 'sort'], }, + table: { + type: { + summary: 'default | sort', + }, + }, }, placeholder: { description: '선택된 값이 없을 때 표시하는 문자열', }, - onChange: { - description: '값이 변경될 때 실행하는 함수', + onChange: action('onChange'), + errorMsg: { + description: '에러 메시지', + table: { + type: { + summary: 'string | null', + }, + }, + }, + inWhere: { + description: '컴포넌트 사용 위치', + control: { + type: 'radio', + option: ['default', 'form'], + }, + table: { + type: { + summary: 'default | form', + }, + }, + }, + }, + parameters: { + docs: { + description: { + component: '필터/정렬에 사용되는 드롭다운입니다.', + }, }, }, }; diff --git a/src/components/common/input/drop-down/index.tsx b/src/components/common/input/drop-down/index.tsx index fcde5af0..113e6bae 100644 --- a/src/components/common/input/drop-down/index.tsx +++ b/src/components/common/input/drop-down/index.tsx @@ -1,4 +1,4 @@ -import { LegacyRef, useEffect, useMemo, useRef, useState } from 'react'; +import { useEffect, useMemo, useRef, useState } from 'react'; import { ComboboxData, Select } from '@mantine/core'; import IconArrow from '@/public/assets/icons/ic-arrow'; @@ -11,11 +11,24 @@ export interface DropDownProps { value: string | null; onChange: (newValue: string | null) => void; className?: string; - inWhere?: string; - error?: string | null; - ref?: LegacyRef; + inWhere?: 'default' | 'form'; + errorMsg?: string | null; } +/** + * 드롭다운 컴포넌트 : 필터, 정렬 등에 사용 + * @param {string} id - 컴포넌트 id + * @param {'default' | 'sort'} variant - 컴포넌트 타입 + * @param {ComboboxData} data - 옵션 데이터 배열 + * @param {string} name - 컴포넌트 name + * @param {string} placeholder - 선택된 값이 없을 때 표시하는 문자열 + * @param {string | null} value - 선택된 값 + * @param {(newValue: string | null) => void} onChange - 값이 변경될 때 실행하는 함수 + * @param {string} className - 컴포넌트 wrapper에 추가하는 클래스명 + * @param {'default' | 'form'} inWhere - 컴포넌트 위치 + * @param {string | null} errorMsg - 에러 메시지 + */ + export default function DropDown({ id, inWhere = 'default', @@ -26,7 +39,7 @@ export default function DropDown({ onChange, placeholder, className, - error, + errorMsg, ...rest }: DropDownProps) { const [currentValue, setCurrentValue] = useState(value); @@ -76,7 +89,7 @@ export default function DropDown({ return (