우편번호 조회 기능 추가

This commit is contained in:
김민식 2025-05-12 14:35:44 +09:00
parent da0d77724d
commit c5db65fc4d
3 changed files with 71 additions and 42 deletions

View File

@ -1,51 +1,55 @@
'use client' 'use client'
import { useServey } from '@/hooks/useSurvey'
import { useAddressStore } from '@/store/addressStore' import { useAddressStore } from '@/store/addressStore'
import { usePopupController } from '@/store/popupController' import { usePopupController } from '@/store/popupController'
import { useState } from 'react' import { useState } from 'react'
const dummyData = [ type Address = {
{ address1: string
post_code: '123-567', address2: string
pref: '東京都', address3: string
city: '千代田区', kana1: string
detail: '永田町ハイツ101号室', kana2: string
}, kana3: string
{ prefcode: string
post_code: '987-654', zipcode: string
pref: '大阪府', }
city: '北区',
detail: '梅田スカイビル23階',
},
{
post_code: '456-789',
pref: '福岡県',
city: '博多区',
detail: '中洲マンション305号',
},
]
export default function ZipCodePopup() { export default function ZipCodePopup() {
const [searchValue, setSearchValue] = useState('') //search 데이터 유무 const [searchValue, setSearchValue] = useState('') //search 데이터 유무
const [selected, setSelected] = useState('') const [selected, setSelected] = useState('')
const { setAddressData } = useAddressStore() const { setAddressData } = useAddressStore()
const { getZipCode } = useServey()
const [addressInfo, setAddressInfo] = useState<Address[] | null>([])
//search 데이터 value 추가 //search 데이터 value 추가
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setSearchValue(e.target.value)
}
const popupController = usePopupController() const popupController = usePopupController()
const handleApply = () => { const handleApply = () => {
const addressData = dummyData.find((item) => item.post_code === selected)
setAddressData({ setAddressData({
post_code: addressData?.post_code || '', post_code: addressInfo?.[0]?.zipcode || '',
address: addressData?.pref || '', address: addressInfo?.[0]?.prefcode || '',
address_detail: addressData?.city + ' ' + addressData?.detail || '', address_detail: addressInfo?.[0]?.address1 + ' ' + addressInfo?.[0]?.address2 + ' ' + addressInfo?.[0]?.address3 || '',
}) })
popupController.setZipCodePopup(false) popupController.setZipCodePopup(false)
} }
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setSearchValue(e.target.value)
}
const handleSearch = () => {
const addressData = getZipCode(searchValue)
addressData.then((address) => {
if (address) {
setAddressInfo(address)
} else {
setAddressInfo([])
}
})
}
return ( return (
<> <>
<div className="modal-popup"> <div className="modal-popup">
@ -66,10 +70,10 @@ export default function ZipCodePopup() {
<div className="zip-code-search-wrap"> <div className="zip-code-search-wrap">
<div className="zip-code-search-input"> <div className="zip-code-search-input">
<div className="search-input"> <div className="search-input">
<input type="text" className="search-frame" value={searchValue} onChange={handleChange} placeholder="Search" /> <input type="text" className="search-frame" value={searchValue} placeholder="Search" onChange={handleChange} />
{/*input에 데이터 있으면 삭제버튼 보임 */} {/*input에 데이터 있으면 삭제버튼 보임 */}
{searchValue && <button className="del-icon" onClick={() => setSearchValue('')}></button>} {searchValue && <button className="del-icon" onClick={() => setSearchValue('')}></button>}
<button className="search-icon"></button> <button className="search-icon" onClick={handleSearch}></button>
</div> </div>
</div> </div>
<div className="zip-code-table-wrap"> <div className="zip-code-table-wrap">
@ -83,11 +87,11 @@ export default function ZipCodePopup() {
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{dummyData.map((item, index) => ( {addressInfo?.map((item, index) => (
<tr key={`${item.post_code}-${index}`} onClick={() => setSelected(item.post_code)}> <tr key={`${item.zipcode}-${index}`} onClick={() => setSelected(item.zipcode)}>
<td>{item.pref}</td> <td>{item.address1}</td>
<td>{item.city}</td> <td>{item.address2}</td>
<td>{item.detail}</td> <td>{item.address3}</td>
</tr> </tr>
))} ))}
</tbody> </tbody>

View File

@ -177,13 +177,7 @@ export default function BasicForm() {
<div className="data-input-form-tit"></div> <div className="data-input-form-tit"></div>
<div className="form-flex"> <div className="form-flex">
<div className="form-bx"> <div className="form-bx">
<input <input type="text" className="input-frame" id="post_code" value={basicInfoData.post_code ?? ''} readOnly />
type="text"
className="input-frame"
id="post_code"
value={basicInfoData.post_code ?? ''}
onChange={(e) => handleChange('post_code', e.target.value)}
/>
</div> </div>
<div className="form-bx"> <div className="form-bx">
<select <select

View File

@ -2,7 +2,23 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import type { SurveyBasicInfo, SurveyBasicRequest, SurveyDetailInfo, SurveyDetailRequest, SurveyDetailCoverRequest } from '@/types/Survey' import type { SurveyBasicInfo, SurveyBasicRequest, SurveyDetailInfo, SurveyDetailRequest, SurveyDetailCoverRequest } from '@/types/Survey'
import { axiosInstance } from '@/libs/axios' import { axiosInstance } from '@/libs/axios'
import { useSurveyFilterStore } from '@/store/surveyFilterStore' import { useSurveyFilterStore } from '@/store/surveyFilterStore'
import { queryStringFormatter } from '@/utils/common-utils'
interface ZipCodeResponse {
status: number
message: string | null
results: ZipCode[] | null
}
type ZipCode = {
zipcode: string
prefcode: string
address1: string
address2: string
address3: string
kana1: string
kana2: string
kana3: string
}
export function useServey(id?: number): { export function useServey(id?: number): {
surveyList: SurveyBasicInfo[] | [] surveyList: SurveyBasicInfo[] | []
surveyDetail: SurveyBasicInfo | null surveyDetail: SurveyBasicInfo | null
@ -18,6 +34,7 @@ export function useServey(id?: number): {
deleteSurvey: () => Promise<boolean> deleteSurvey: () => Promise<boolean>
submitSurvey: () => void submitSurvey: () => void
validateSurveyDetail: (surveyDetail: SurveyDetailRequest) => string validateSurveyDetail: (surveyDetail: SurveyDetailRequest) => string
getZipCode: (zipCode: string) => Promise<ZipCode[] | null>
} { } {
const queryClient = useQueryClient() const queryClient = useQueryClient()
const { keyword, searchOption, isMySurvey, sort, offset } = useSurveyFilterStore() const { keyword, searchOption, isMySurvey, sort, offset } = useSurveyFilterStore()
@ -144,6 +161,19 @@ export function useServey(id?: number): {
return emptyField || '' return emptyField || ''
} }
const getZipCode = async (zipCode: string): Promise<ZipCode[] | null> => {
try {
const { data } = await axiosInstance(null).get<ZipCodeResponse>(
`https://zipcloud.ibsnet.co.jp/api/search?${queryStringFormatter({ zipcode: zipCode.trim() })}`,
)
return data.results
} catch (e) {
console.error('Failed to fetch zipcode data:', e)
throw new Error('Failed to fetch zipcode data')
}
}
return { return {
surveyList: surveyList || [], surveyList: surveyList || [],
surveyDetail: surveyDetail || null, surveyDetail: surveyDetail || null,
@ -159,5 +189,6 @@ export function useServey(id?: number): {
createSurveyDetail, createSurveyDetail,
submitSurvey, submitSurvey,
validateSurveyDetail, validateSurveyDetail,
getZipCode,
} }
} }