- 제출 팝업 페이지 추가 - 조사매물 작성 시 숫자 입력 항목 모바일에서 숫자 키패드만 나오도록 설정 - 제출 필수값 validation 구현
243 lines
7.6 KiB
TypeScript
243 lines
7.6 KiB
TypeScript
import type { SurveyBasicInfo, SurveyDetailRequest, SurveyRegistRequest } from '@/types/Survey'
|
|
import { useMemo } from 'react'
|
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
|
import { useSurveyFilterStore } from '@/store/surveyFilterStore'
|
|
import { useSessionStore } from '@/store/session'
|
|
import { useAxios } from './useAxios'
|
|
import { queryStringFormatter } from '@/utils/common-utils'
|
|
|
|
export const requiredFields = [
|
|
{
|
|
field: 'installationSystem',
|
|
name: '設置希望システム',
|
|
},
|
|
{
|
|
field: 'constructionYear',
|
|
name: '建築年数',
|
|
},
|
|
{
|
|
field: 'rafterSize',
|
|
name: '垂木サイズ',
|
|
},
|
|
{
|
|
field: 'rafterPitch',
|
|
name: '垂木傾斜',
|
|
},
|
|
{
|
|
field: 'waterproofMaterial',
|
|
name: '防水材',
|
|
},
|
|
{
|
|
field: 'insulationPresence',
|
|
name: '断熱材有無',
|
|
},
|
|
{
|
|
field: 'structureOrder',
|
|
name: '屋根構造の順序',
|
|
},
|
|
]
|
|
|
|
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): {
|
|
surveyList: { data: SurveyBasicInfo[]; count: number } | {}
|
|
surveyDetail: SurveyBasicInfo | null
|
|
isLoadingSurveyList: boolean
|
|
isLoadingSurveyDetail: boolean
|
|
isCreatingSurvey: boolean
|
|
isUpdatingSurvey: boolean
|
|
isDeletingSurvey: boolean
|
|
isSubmittingSurvey: boolean
|
|
createSurvey: (survey: SurveyRegistRequest) => Promise<number>
|
|
updateSurvey: ({ survey, isTemporary, storeId }: { survey: SurveyRegistRequest; isTemporary: boolean; storeId?: string }) => void
|
|
deleteSurvey: () => Promise<boolean>
|
|
submitSurvey: (params: { saveId?: number; targetId?: string; storeId?: string; srlNo?: string }) => void
|
|
validateSurveyDetail: (surveyDetail: SurveyDetailRequest) => string
|
|
getZipCode: (zipCode: string) => Promise<ZipCode[] | null>
|
|
refetchSurveyList: () => void
|
|
} {
|
|
const queryClient = useQueryClient()
|
|
const { keyword, searchOption, isMySurvey, sort, offset } = useSurveyFilterStore()
|
|
const { session } = useSessionStore()
|
|
const { axiosInstance } = useAxios()
|
|
|
|
const {
|
|
data: surveyListData,
|
|
isLoading: isLoadingSurveyList,
|
|
refetch: refetchSurveyList,
|
|
} = useQuery({
|
|
queryKey: ['survey', 'list', keyword, searchOption, isMySurvey, sort, offset, session?.storeNm, session?.builderNo, session?.role],
|
|
queryFn: async () => {
|
|
const resp = await axiosInstance(null).get<{ data: SurveyBasicInfo[]; count: number }>('/api/survey-sales', {
|
|
params: {
|
|
keyword,
|
|
searchOption,
|
|
isMySurvey,
|
|
sort,
|
|
offset,
|
|
store: session?.storeId,
|
|
builderNo: session?.builderNo,
|
|
role: session?.role,
|
|
},
|
|
})
|
|
return resp.data
|
|
},
|
|
enabled: session?.isLoggedIn,
|
|
})
|
|
const surveyData = useMemo(() => {
|
|
if (!surveyListData) return { count: 0, data: [] }
|
|
return {
|
|
...surveyListData,
|
|
}
|
|
}, [surveyListData])
|
|
|
|
const { data: surveyDetail, isLoading: isLoadingSurveyDetail } = useQuery({
|
|
queryKey: ['survey', id],
|
|
queryFn: async () => {
|
|
if (id === undefined) throw new Error('id is required')
|
|
if (id === null || isNaN(id)) return null
|
|
const resp = await axiosInstance(null).get<SurveyBasicInfo>(`/api/survey-sales/${id}`)
|
|
return resp.data
|
|
},
|
|
enabled: id !== undefined,
|
|
})
|
|
|
|
const { mutateAsync: createSurvey, isPending: isCreatingSurvey } = useMutation({
|
|
mutationFn: async (survey: SurveyRegistRequest) => {
|
|
const resp = await axiosInstance(null).post<SurveyBasicInfo>('/api/survey-sales', {
|
|
survey: survey,
|
|
storeId: session?.storeId ?? null,
|
|
role: session?.role ?? null,
|
|
})
|
|
return resp.data.id ?? 0
|
|
},
|
|
onSuccess: (data) => {
|
|
queryClient.invalidateQueries({ queryKey: ['survey', 'list'] })
|
|
queryClient.invalidateQueries({ queryKey: ['survey', id] })
|
|
return data
|
|
},
|
|
})
|
|
|
|
const { mutate: updateSurvey, isPending: isUpdatingSurvey } = useMutation({
|
|
mutationFn: async ({ survey, isTemporary, storeId }: { survey: SurveyRegistRequest; isTemporary: boolean; storeId?: string }) => {
|
|
if (id === undefined) throw new Error('id is required')
|
|
const resp = await axiosInstance(null).put<SurveyRegistRequest>(`/api/survey-sales/${id}`, {
|
|
survey: survey,
|
|
isTemporary: isTemporary,
|
|
storeId: storeId,
|
|
role: session?.role ?? null,
|
|
})
|
|
return resp.data
|
|
},
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({ queryKey: ['survey', id] })
|
|
queryClient.invalidateQueries({ queryKey: ['survey', 'list'] })
|
|
},
|
|
})
|
|
|
|
const { mutateAsync: deleteSurvey, isPending: isDeletingSurvey } = useMutation({
|
|
mutationFn: async () => {
|
|
if (id === null) throw new Error('id is required')
|
|
const resp = await axiosInstance(null).delete<boolean>(`/api/survey-sales/${id}`)
|
|
return resp.data
|
|
},
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({ queryKey: ['survey', 'list'] })
|
|
queryClient.invalidateQueries({ queryKey: ['survey', id] })
|
|
},
|
|
})
|
|
|
|
const { mutateAsync: submitSurvey, isPending: isSubmittingSurvey } = useMutation({
|
|
mutationFn: async ({ targetId, storeId, srlNo }: { targetId?: string; storeId?: string; srlNo?: string }) => {
|
|
if (!id) throw new Error('id is required')
|
|
const resp = await axiosInstance(null).patch<boolean>(`/api/survey-sales/${id}`, {
|
|
targetId,
|
|
storeId,
|
|
srlNo,
|
|
role: session?.role ?? null,
|
|
})
|
|
return resp.data
|
|
},
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({ queryKey: ['survey', 'list'] })
|
|
queryClient.invalidateQueries({ queryKey: ['survey', id] })
|
|
},
|
|
})
|
|
|
|
const validateSurveyDetail = (surveyDetail: SurveyDetailRequest) => {
|
|
const etcFields = [
|
|
'installationSystem',
|
|
'constructionYear',
|
|
'rafterSize',
|
|
'rafterPitch',
|
|
'waterproofMaterial',
|
|
'structureOrder',
|
|
'insulationPresence',
|
|
] as const
|
|
|
|
const emptyField = requiredFields.find((field) => {
|
|
if (etcFields.includes(field.field as (typeof etcFields)[number])) {
|
|
return (
|
|
surveyDetail[field.field as keyof SurveyDetailRequest] === null &&
|
|
(surveyDetail[`${field.field}Etc` as keyof SurveyDetailRequest] === null ||
|
|
surveyDetail[`${field.field}Etc` as keyof SurveyDetailRequest]?.toString().trim() === '')
|
|
)
|
|
} else {
|
|
return surveyDetail[field.field as keyof SurveyDetailRequest] === null
|
|
}
|
|
})
|
|
|
|
const contractCapacity = surveyDetail.contractCapacity
|
|
if (contractCapacity && contractCapacity.trim() !== '' && contractCapacity.split(' ')?.length === 1) {
|
|
return 'contractCapacityUnit'
|
|
}
|
|
|
|
return emptyField?.field || ''
|
|
}
|
|
|
|
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 {
|
|
surveyList: surveyData.data,
|
|
surveyDetail: surveyDetail as SurveyBasicInfo | null,
|
|
isLoadingSurveyList,
|
|
isLoadingSurveyDetail,
|
|
isCreatingSurvey,
|
|
isUpdatingSurvey,
|
|
isDeletingSurvey,
|
|
isSubmittingSurvey,
|
|
createSurvey,
|
|
updateSurvey,
|
|
deleteSurvey,
|
|
submitSurvey,
|
|
validateSurveyDetail,
|
|
getZipCode,
|
|
refetchSurveyList,
|
|
}
|
|
}
|