diff --git a/package.json b/package.json index 4ed30cd7..6bf938e2 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "motion": "^12.23.24", "next": "16.0.7", "react": "19.2.1", + "react-daum-postcode": "^3.2.0", "react-dom": "19.2.1", "swiper": "^12.0.3", "tailwind-merge": "^3.3.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 97614f8c..05f5b2a3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -41,6 +41,9 @@ importers: react: specifier: 19.2.1 version: 19.2.1 + react-daum-postcode: + specifier: ^3.2.0 + version: 3.2.0(react@19.2.1) react-dom: specifier: 19.2.1 version: 19.2.1(react@19.2.1) @@ -5821,6 +5824,11 @@ packages: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} + react-daum-postcode@3.2.0: + resolution: {integrity: sha512-NHY8TUicZXMqykbKYT8kUo2PEU7xu1DFsdRmyWJrLEUY93Xhd3rEdoJ7vFqrvs+Grl9wIm9Byxh3bI+eZxepMQ==} + peerDependencies: + react: '>=16.8.0' + react-docgen-typescript@2.4.0: resolution: {integrity: sha512-ZtAp5XTO5HRzQctjPU0ybY0RRCQO19X/8fxn3w7y2VVTUbGHDKULPTL4ky3vB05euSgG5NpALhEhDPvQ56wvXg==} peerDependencies: @@ -14115,6 +14123,10 @@ snapshots: range-parser@1.2.1: {} + react-daum-postcode@3.2.0(react@19.2.1): + dependencies: + react: 19.2.1 + react-docgen-typescript@2.4.0(typescript@5.9.3): dependencies: typescript: 5.9.3 diff --git a/src/components/pages/post-meetup/fields/date-field/index.tsx b/src/components/pages/post-meetup/fields/date-field/index.tsx index 18f5e226..b62a188f 100644 --- a/src/components/pages/post-meetup/fields/date-field/index.tsx +++ b/src/components/pages/post-meetup/fields/date-field/index.tsx @@ -17,7 +17,7 @@ export const MeetupDateField = ({ field }: Props) => { const formattedDate = formatDate(new Date(field.state.value), 'YY.MM.DD - HH:mm'); const onInputClick = () => { - open(); + open(); }; return ( diff --git a/src/components/pages/post-meetup/fields/images-field/index.tsx b/src/components/pages/post-meetup/fields/images-field/index.tsx index c1020aa2..806fe3a4 100644 --- a/src/components/pages/post-meetup/fields/images-field/index.tsx +++ b/src/components/pages/post-meetup/fields/images-field/index.tsx @@ -25,47 +25,50 @@ export const MeetupImagesField = ({ field, initialImages }: Props) => { onChange={field.handleChange} > {(images, onRemoveImageClick, onFileSelectClick) => ( -
- - {Object.entries(images).map(([url, _file]) => ( -
- 팀 이미지 - -
- ))} + /> + + {Object.entries(images).map(([url, _file]) => ( +
+ 팀 이미지 + +
+ ))} +
+

최대 3개까지 업로드할 수 있어요.

)} diff --git a/src/components/pages/post-meetup/fields/location-field/index.tsx b/src/components/pages/post-meetup/fields/location-field/index.tsx index 733237fb..c8505e11 100644 --- a/src/components/pages/post-meetup/fields/location-field/index.tsx +++ b/src/components/pages/post-meetup/fields/location-field/index.tsx @@ -1,38 +1,49 @@ 'use client'; import { AnyFieldApi } from '@tanstack/react-form'; +import clsx from 'clsx'; import { Icon } from '@/components/icon'; -import { Input, Label } from '@/components/ui'; +import { LocationSearchModal } from '@/components/pages/post-meetup/modals/location-search-modal'; +import { Label } from '@/components/ui'; +import { useModal } from '@/components/ui'; interface Props { field: AnyFieldApi; } export const MeetupLocationField = ({ field }: Props) => { + const { open } = useModal(); + + const onInputClick = () => { + open(); + }; + return (
-
); }; diff --git a/src/components/pages/post-meetup/fields/tags-field/index.tsx b/src/components/pages/post-meetup/fields/tags-field/index.tsx index 176f85d3..dfd4ea75 100644 --- a/src/components/pages/post-meetup/fields/tags-field/index.tsx +++ b/src/components/pages/post-meetup/fields/tags-field/index.tsx @@ -3,6 +3,7 @@ import { useState } from 'react'; import { AnyFieldApi } from '@tanstack/react-form'; +import clsx from 'clsx'; import { Icon } from '@/components/icon'; import { Input, Label } from '@/components/ui'; @@ -16,10 +17,13 @@ export const MeetupTagsField = ({ field }: Props) => { const onEnter = (e: React.KeyboardEvent) => { if (e.code !== 'Enter' && e.code !== 'NumpadEnter') return; + if (e.nativeEvent.isComposing) return; const hasDupe = field.state.value.includes(inputValue); - if (!hasDupe && inputValue.trim()) field.pushValue(inputValue); + if (!hasDupe && inputValue.trim()) { + field.pushValue(inputValue); + } setInputValue(''); }; @@ -44,7 +48,13 @@ export const MeetupTagsField = ({ field }: Props) => { onChange={(e) => setInputValue(e.target.value)} onKeyDown={onEnter} /> -
    + +
      {field.state.value.map((tag: string, idx: number) => (
    • {
    • ))}
    + +

    최대 10개까지 업로드할 수 있어요.

    ); }; diff --git a/src/components/pages/post-meetup/modals/date-picker-modal/index.tsx b/src/components/pages/post-meetup/modals/date-picker-modal/index.tsx index eb433c26..fc2612f3 100644 --- a/src/components/pages/post-meetup/modals/date-picker-modal/index.tsx +++ b/src/components/pages/post-meetup/modals/date-picker-modal/index.tsx @@ -10,10 +10,10 @@ import { Calendar } from '@/components/pages/post-meetup/modals/date-picker-moda import { ModalContent, ModalTitle } from '@/components/ui'; interface Props { - field: AnyFieldApi; + dateField: AnyFieldApi; } -export const DatePickerModal = ({ field }: Props) => { +export const DatePickerModal = ({ dateField }: Props) => { const [tabMenu, setTabMenu] = useState<'date' | 'time'>('date'); return ( @@ -41,8 +41,8 @@ export const DatePickerModal = ({ field }: Props) => { field.handleChange(selectedDate)} + dateFieldValue={dateField.state.value} + updateDateField={(selectedDate: string) => dateField.handleChange(selectedDate)} />
    diff --git a/src/components/pages/post-meetup/modals/location-search-modal/index.tsx b/src/components/pages/post-meetup/modals/location-search-modal/index.tsx new file mode 100644 index 00000000..dead6efe --- /dev/null +++ b/src/components/pages/post-meetup/modals/location-search-modal/index.tsx @@ -0,0 +1,35 @@ +'use client'; + +import DaumPostcodeEmbed, { Address } from 'react-daum-postcode'; + +import { AnyFieldApi } from '@tanstack/react-form'; + +import { ModalContent, ModalTitle, useModal } from '@/components/ui'; + +interface Props { + LocationField: AnyFieldApi; +} + +export const LocationSearchModal = ({ LocationField }: Props) => { + const { close } = useModal(); + + const handleComplete = (data: Address) => { + const fullAddress = `${data.sido} ${data.sigungu} ${data.bname}`; + LocationField.handleChange(fullAddress); + close(); + }; + + return ( + + 모임 장소 +
    + +
    +
    + ); +};