300 lines
9.3 KiB
TypeScript
300 lines
9.3 KiB
TypeScript
import type { SurveyBasicInfo, SurveyDetailRequest, SurveyRegistRequest } from '@/types/Survey'
|
|
import { useMemo, useEffect } 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'
|
|
import { useRouter } from 'next/navigation'
|
|
|
|
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 useSurvey(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: { targetId?: string | null; targetNm?: string | null }) => 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 router = useRouter()
|
|
|
|
const checkSession = () => {
|
|
if (session?.isLoggedIn) {
|
|
switch (session?.role) {
|
|
case 'T01':
|
|
case 'Admin':
|
|
case 'Admin_Sub':
|
|
if (session?.storeId === null) {
|
|
alert('販売店IDがありません。')
|
|
return false
|
|
}
|
|
return true
|
|
case 'Builder':
|
|
case 'Partner':
|
|
if (session?.builderId === null) {
|
|
alert('施工店IDがありません。')
|
|
return false
|
|
}
|
|
return true
|
|
default:
|
|
alert('権限が間違っています。')
|
|
return false
|
|
}
|
|
}
|
|
alert('ログインしていません。')
|
|
return false
|
|
}
|
|
|
|
const {
|
|
data: surveyListData,
|
|
isLoading: isLoadingSurveyList,
|
|
refetch: refetchSurveyList,
|
|
} = useQuery({
|
|
queryKey: ['survey', 'list', keyword, searchOption, isMySurvey, sort, offset, session?.storeNm, session?.builderId, session?.role],
|
|
queryFn: async () => {
|
|
if (!checkSession()) {
|
|
router.replace('/')
|
|
return { data: [], count: 0 }
|
|
}
|
|
const resp = await axiosInstance(null).get<{ data: SurveyBasicInfo[]; count: number }>('/api/survey-sales', {
|
|
params: {
|
|
keyword,
|
|
searchOption,
|
|
isMySurvey,
|
|
sort,
|
|
offset,
|
|
storeId: session?.storeId,
|
|
builderId: session?.builderId,
|
|
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 (!checkSession()) {
|
|
router.replace('/survey-sale')
|
|
return null
|
|
}
|
|
if (id === 0 || id === undefined) return null
|
|
try {
|
|
const resp = await axiosInstance(null).get<SurveyBasicInfo>(`/api/survey-sales/${id}`, {
|
|
params: {
|
|
role: session?.role,
|
|
storeId: session?.storeId,
|
|
builderId: session?.builderId,
|
|
isLoggedIn: session?.isLoggedIn,
|
|
},
|
|
})
|
|
return resp.data
|
|
} catch (error: any) {
|
|
alert(error.response?.data.error)
|
|
router.replace('/survey-sale')
|
|
return null
|
|
}
|
|
},
|
|
enabled: id !== 0 && id !== undefined && session?.isLoggedIn,
|
|
})
|
|
|
|
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, targetNm }: { targetId?: string | null; targetNm?: string | null }) => {
|
|
if (!id) throw new Error('id is required')
|
|
const resp = await axiosInstance(null).patch<boolean>(`/api/survey-sales/${id}`, {
|
|
targetId,
|
|
targetNm,
|
|
})
|
|
return resp.data
|
|
},
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({ queryKey: ['survey', 'list'] })
|
|
queryClient.invalidateQueries({ queryKey: ['survey', id] })
|
|
},
|
|
})
|
|
|
|
const validateSurveyDetail = (surveyDetail: SurveyDetailRequest) => {
|
|
// 상수 정의
|
|
const ETC_FIELDS = ['installationSystem', 'rafterSize', 'rafterPitch', 'waterproofMaterial', 'structureOrder'] as const
|
|
|
|
const SPECIAL_CONDITIONS = ['constructionYear', 'insulationPresence'] as const
|
|
|
|
// 유틸리티 함수들
|
|
const isEmptyValue = (value: any): boolean => {
|
|
return value === null || value?.toString().trim() === ''
|
|
}
|
|
|
|
const checkRequiredField = (field: string): string => {
|
|
if (ETC_FIELDS.includes(field as (typeof ETC_FIELDS)[number])) {
|
|
if (
|
|
isEmptyValue(surveyDetail[field as keyof SurveyDetailRequest]) &&
|
|
isEmptyValue(surveyDetail[`${field}Etc` as keyof SurveyDetailRequest])
|
|
) {
|
|
return field
|
|
}
|
|
} else if (SPECIAL_CONDITIONS.includes(field as (typeof SPECIAL_CONDITIONS)[number])) {
|
|
if (surveyDetail[field as keyof SurveyDetailRequest] === '2' && isEmptyValue(surveyDetail[`${field}Etc` as keyof SurveyDetailRequest])) {
|
|
return `${field}Etc`
|
|
} else if (isEmptyValue(surveyDetail[field as keyof SurveyDetailRequest])) {
|
|
return field
|
|
}
|
|
}
|
|
return ''
|
|
}
|
|
|
|
// 필수 필드 체크
|
|
const emptyField = requiredFields.find((field) => checkRequiredField(field.field))
|
|
if (emptyField) return emptyField.field
|
|
|
|
// 계약 용량 단위 체크
|
|
const contractCapacity = surveyDetail.contractCapacity
|
|
if (contractCapacity?.trim() && contractCapacity.split(' ').length === 1) {
|
|
return 'contractCapacityUnit'
|
|
}
|
|
return ''
|
|
}
|
|
|
|
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,
|
|
}
|
|
}
|