refactor: enhance error handling and user feedback in survey components
- API try-catch 구문 함수 구현 - 조사 매물 alert 처리 리팩토링
This commit is contained in:
parent
1a42848ae9
commit
12b9dd4216
@ -3,6 +3,24 @@ import { NextResponse } from 'next/server'
|
||||
import { loggerWrapper } from '@/libs/api-wrapper'
|
||||
import { ERROR_MESSAGES } from '@/utils/common-utils'
|
||||
|
||||
/**
|
||||
* @api {GET} /api/qna/file 문의 첨부 파일 다운로드 API
|
||||
* @apiName GET /api/qna/file
|
||||
* @apiGroup Qna
|
||||
* @apiDescription 문의 첨부 파일 다운로드 API
|
||||
*
|
||||
* @apiParam {String} encodeFileNo 인코딩 파일 번호
|
||||
* @apiParam {String} srcFileNm 소스 파일 이름
|
||||
*
|
||||
* @apiExample {curl} Example usage:
|
||||
* curl -X GET http://localhost:3000/api/qna/file?encodeFileNo=1234567890&srcFileNm=test.pdf
|
||||
*
|
||||
* @apiSuccessExample {octet-stream} Success-Response:
|
||||
* file content
|
||||
*
|
||||
* @apiError {Number} 500 서버 오류
|
||||
* @apiError {Number} 400 잘못된 요청
|
||||
*/
|
||||
async function downloadFile(request: Request): Promise<NextResponse> {
|
||||
const { searchParams } = new URL(request.url)
|
||||
const encodeFileNo = searchParams.get('encodeFileNo')
|
||||
|
||||
@ -41,22 +41,17 @@ import { loggerWrapper } from '@/libs/api-wrapper'
|
||||
* @apiError {String} error.message 에러 메시지
|
||||
*/
|
||||
async function getSubmitTargetData(request: NextRequest): Promise<NextResponse> {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url)
|
||||
const storeId = searchParams.get('storeId')
|
||||
const role = searchParams.get('role')
|
||||
const { searchParams } = new URL(request.url)
|
||||
const storeId = searchParams.get('storeId')
|
||||
const role = searchParams.get('role')
|
||||
|
||||
if (!storeId || !role) {
|
||||
return NextResponse.json({ error: ERROR_MESSAGES.BAD_REQUEST }, { status: HttpStatusCode.BadRequest })
|
||||
}
|
||||
|
||||
const submissionService = new SubmissionService(storeId, role)
|
||||
const data = await submissionService.getSubmissionTarget()
|
||||
return NextResponse.json(data)
|
||||
} catch (error) {
|
||||
console.error('❌ API ROUTE ERROR:', error)
|
||||
return NextResponse.json({ error: ERROR_MESSAGES.FETCH_ERROR }, { status: HttpStatusCode.InternalServerError })
|
||||
if (!storeId || !role) {
|
||||
return NextResponse.json({ error: ERROR_MESSAGES.BAD_REQUEST }, { status: HttpStatusCode.BadRequest })
|
||||
}
|
||||
|
||||
const submissionService = new SubmissionService(storeId, role)
|
||||
const data = await submissionService.tryFunction(() => submissionService.getSubmissionTarget())
|
||||
return NextResponse.json(data)
|
||||
}
|
||||
|
||||
export const GET = loggerWrapper(getSubmitTargetData)
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
import { prisma } from '@/libs/prisma'
|
||||
import { ERROR_MESSAGES } from '@/utils/common-utils'
|
||||
import { SubmitTargetResponse } from '@/types/Survey'
|
||||
import { HttpStatusCode } from 'axios'
|
||||
import { NextResponse } from 'next/server'
|
||||
|
||||
export class SubmissionService {
|
||||
private storeId: string
|
||||
@ -70,4 +73,17 @@ export class SubmissionService {
|
||||
`
|
||||
return await prisma.$queryRawUnsafe(this.BASE_QUERY + query, this.storeId)
|
||||
}
|
||||
|
||||
handleRouteError(error: unknown): NextResponse {
|
||||
console.error('❌ API ROUTE ERROR : ', error)
|
||||
return NextResponse.json({ error: ERROR_MESSAGES.FETCH_ERROR }, { status: HttpStatusCode.InternalServerError })
|
||||
}
|
||||
|
||||
async tryFunction(func: () => Promise<any>): Promise<any> {
|
||||
try {
|
||||
return await func()
|
||||
} catch (error) {
|
||||
return this.handleRouteError(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ import { useEffect, useState } from 'react'
|
||||
import { useParams, useRouter } from 'next/navigation'
|
||||
import { requiredFields, useSurvey } from '@/hooks/useSurvey'
|
||||
import { usePopupController } from '@/store/popupController'
|
||||
import { ALERT_MESSAGES } from '@/types/Survey'
|
||||
|
||||
interface ButtonFormProps {
|
||||
mode: Mode
|
||||
@ -48,7 +49,7 @@ export default function ButtonForm({ mode, setMode, data }: ButtonFormProps) {
|
||||
const isSubmit = data.basic.submissionStatus
|
||||
|
||||
const { deleteSurvey, updateSurvey, isDeletingSurvey, isUpdatingSurvey } = useSurvey(id)
|
||||
const { validateSurveyDetail, createSurvey, isCreatingSurvey } = useSurvey()
|
||||
const { validateSurveyDetail, createSurvey, isCreatingSurvey, showSurveyAlert, showSurveyConfirm } = useSurvey()
|
||||
|
||||
useEffect(() => {
|
||||
if (!session?.isLoggedIn) return
|
||||
@ -116,7 +117,7 @@ export default function ButtonForm({ mode, setMode, data }: ButtonFormProps) {
|
||||
router.push(`/survey-sale/${savedId}`)
|
||||
}
|
||||
}
|
||||
alert('一時保存されました。')
|
||||
showSurveyAlert(ALERT_MESSAGES.TEMP_SAVE_SUCCESS)
|
||||
}
|
||||
|
||||
/** 입력 필드 포커스 처리 */
|
||||
@ -128,7 +129,13 @@ export default function ButtonForm({ mode, setMode, data }: ButtonFormProps) {
|
||||
/** 저장 로직 */
|
||||
const saveProcess = async (emptyField: string | null, isSubmitProcess?: boolean) => {
|
||||
if (emptyField?.trim() === '') {
|
||||
await handleSuccessfulSave(isSubmitProcess)
|
||||
if (!isSubmitProcess) {
|
||||
showSurveyConfirm(ALERT_MESSAGES.SAVE_CONFIRM, async () => {
|
||||
await handleSuccessfulSave(isSubmitProcess)
|
||||
})
|
||||
} else {
|
||||
await handleSuccessfulSave(isSubmitProcess)
|
||||
}
|
||||
} else {
|
||||
handleFailedSave(emptyField)
|
||||
}
|
||||
@ -147,6 +154,8 @@ export default function ButtonForm({ mode, setMode, data }: ButtonFormProps) {
|
||||
setMode('READ')
|
||||
if (isSubmitProcess) {
|
||||
popupController.setSurveySaleSubmitPopup(true)
|
||||
} else {
|
||||
showSurveyAlert(ALERT_MESSAGES.SAVE_SUCCESS)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -156,7 +165,7 @@ export default function ButtonForm({ mode, setMode, data }: ButtonFormProps) {
|
||||
await router.push(`/survey-sale/${savedId}?show=true`)
|
||||
} else {
|
||||
await router.push(`/survey-sale/${savedId}`)
|
||||
alert('保存されました。')
|
||||
showSurveyAlert(ALERT_MESSAGES.SAVE_SUCCESS)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -164,9 +173,10 @@ export default function ButtonForm({ mode, setMode, data }: ButtonFormProps) {
|
||||
/** 필수값 미입력 처리 */
|
||||
const handleFailedSave = (emptyField: string | null) => {
|
||||
if (emptyField?.includes('Unit')) {
|
||||
alert('電気契約容量の単位を入力してください。')
|
||||
showSurveyAlert(ALERT_MESSAGES.UNIT_REQUIRED)
|
||||
} else {
|
||||
alert(requiredFields.find((field) => field.field === emptyField)?.name + ' 項目が空です。')
|
||||
const fieldInfo = requiredFields.find((field) => field.field === emptyField)
|
||||
showSurveyAlert(ALERT_MESSAGES.REQUIRED_FIELD, fieldInfo?.name || '')
|
||||
}
|
||||
focusInput(emptyField as keyof SurveyDetailInfo)
|
||||
}
|
||||
@ -174,10 +184,10 @@ export default function ButtonForm({ mode, setMode, data }: ButtonFormProps) {
|
||||
/** 삭제 로직 */
|
||||
const handleDelete = async () => {
|
||||
if (!Number.isNaN(id)) {
|
||||
window.neoConfirm('削除しますか?', async () => {
|
||||
showSurveyConfirm(ALERT_MESSAGES.DELETE_CONFIRM, async () => {
|
||||
await deleteSurvey()
|
||||
if (!isDeletingSurvey) {
|
||||
alert('削除されました。')
|
||||
showSurveyAlert(ALERT_MESSAGES.DELETE_SUCCESS)
|
||||
router.push('/survey-sale')
|
||||
}
|
||||
})
|
||||
@ -187,16 +197,16 @@ export default function ButtonForm({ mode, setMode, data }: ButtonFormProps) {
|
||||
/** 제출 로직 */
|
||||
const handleSubmit = async () => {
|
||||
if (data.basic.srlNo?.startsWith('一時保存') && Number.isNaN(id)) {
|
||||
alert('一時保存されたデータは提出できません。')
|
||||
showSurveyAlert(ALERT_MESSAGES.TEMP_SAVE_SUBMIT_ERROR)
|
||||
return
|
||||
}
|
||||
|
||||
if (mode === 'READ') {
|
||||
window.neoConfirm('提出しますか?', async () => {
|
||||
showSurveyConfirm(ALERT_MESSAGES.SUBMIT_CONFIRM, async () => {
|
||||
popupController.setSurveySaleSubmitPopup(true)
|
||||
})
|
||||
} else {
|
||||
window.neoConfirm('記入した情報を保存して送信しますか?', async () => {
|
||||
showSurveyConfirm(ALERT_MESSAGES.SAVE_AND_SUBMIT_CONFIRM, async () => {
|
||||
handleSave(false, true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import { useState } from 'react'
|
||||
import type { Mode, SurveyDetailInfo, SurveyDetailRequest } from '@/types/Survey'
|
||||
import { useSurvey } from '@/hooks/useSurvey'
|
||||
import { ALERT_MESSAGES } from '@/types/Survey'
|
||||
|
||||
type RadioEtcKeys =
|
||||
| 'structureOrder'
|
||||
@ -247,6 +249,7 @@ export default function RoofForm(props: {
|
||||
mode: Mode
|
||||
}) {
|
||||
const { roofInfo, setRoofInfo, mode } = props
|
||||
const { showSurveyAlert } = useSurvey()
|
||||
const [isFlip, setIsFlip] = useState<boolean>(true)
|
||||
|
||||
const handleNumberInput = (key: keyof SurveyDetailRequest, value: number | string) => {
|
||||
@ -254,13 +257,13 @@ export default function RoofForm(props: {
|
||||
if (key === 'roofSlope' || key === 'openFieldPlateThickness') {
|
||||
const stringValue = value.toString()
|
||||
if (stringValue.length > 5) {
|
||||
alert('保存できるサイズを超えました。')
|
||||
showSurveyAlert('保存できるサイズを超えました。')
|
||||
return
|
||||
}
|
||||
if (stringValue.includes('.')) {
|
||||
const decimalPlaces = stringValue.split('.')[1].length
|
||||
if (decimalPlaces > 1) {
|
||||
alert('小数点以下1桁までしか許されません。')
|
||||
showSurveyAlert('小数点以下1桁までしか許されません。')
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -732,6 +735,7 @@ const MultiCheck = ({
|
||||
roofInfo: SurveyDetailInfo
|
||||
setRoofInfo: (roofInfo: SurveyDetailRequest) => void
|
||||
}) => {
|
||||
const { showSurveyAlert } = useSurvey()
|
||||
const multiCheckData = column === 'supplementaryFacilities' ? supplementaryFacilities : roofMaterial
|
||||
const etcValue = roofInfo?.[`${column}Etc` as keyof SurveyDetailInfo]
|
||||
const [isOtherCheck, setIsOtherCheck] = useState<boolean>(Boolean(etcValue))
|
||||
@ -751,7 +755,7 @@ const MultiCheck = ({
|
||||
if (isRoofMaterial) {
|
||||
const totalSelected = selectedValues.length + (isOtherSelected || isOtherCheck ? 1 : 0)
|
||||
if (totalSelected >= 2) {
|
||||
alert('屋根材は最大2個まで選択できます。')
|
||||
showSurveyAlert(ALERT_MESSAGES.ROOF_MATERIAL_MAX_SELECT_ERROR)
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -765,7 +769,7 @@ const MultiCheck = ({
|
||||
if (isRoofMaterial) {
|
||||
const currentSelected = selectedValues.length
|
||||
if (!isOtherCheck && currentSelected >= 2) {
|
||||
alert('屋根材は最大2個まで選択できます。')
|
||||
showSurveyAlert(ALERT_MESSAGES.ROOF_MATERIAL_MAX_SELECT_ERROR)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,16 +3,18 @@
|
||||
import { SEARCH_OPTIONS, SEARCH_OPTIONS_ENUM, SEARCH_OPTIONS_PARTNERS, useSurveyFilterStore } from '@/store/surveyFilterStore'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { useState } from 'react'
|
||||
import { useSurvey } from '@/hooks/useSurvey'
|
||||
|
||||
export default function SearchForm({ memberRole, userId }: { memberRole: string; userId: string }) {
|
||||
const router = useRouter()
|
||||
const { showSurveyAlert } = useSurvey()
|
||||
const { setSearchOption, setSort, setIsMySurvey, setKeyword, reset, isMySurvey, keyword, searchOption, sort, setOffset } = useSurveyFilterStore()
|
||||
const [searchKeyword, setSearchKeyword] = useState(keyword)
|
||||
const [option, setOption] = useState(searchOption)
|
||||
|
||||
const handleSearch = () => {
|
||||
if (option !== 'id' && searchKeyword.trim().length < 2) {
|
||||
alert('2文字以上入力してください')
|
||||
showSurveyAlert('2文字以上入力してください')
|
||||
return
|
||||
}
|
||||
setOffset(0)
|
||||
@ -62,7 +64,7 @@ export default function SearchForm({ memberRole, userId }: { memberRole: string;
|
||||
placeholder="タイトルを入力してください. (2文字以上)"
|
||||
onChange={(e) => {
|
||||
if (e.target.value.length > 30) {
|
||||
alert('30文字以内で入力してください')
|
||||
showSurveyAlert('30文字以内で入力してください')
|
||||
return
|
||||
}
|
||||
setSearchKeyword(e.target.value)
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import type { SubmitTargetResponse, SurveyBasicInfo, SurveyDetailRequest, SurveyRegistRequest } from '@/types/Survey'
|
||||
import { ALERT_MESSAGES, type SubmitTargetResponse, type SurveyBasicInfo, type SurveyDetailRequest, type SurveyRegistRequest } from '@/types/Survey'
|
||||
import { useMemo } from 'react'
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import { useSurveyFilterStore } from '@/store/surveyFilterStore'
|
||||
@ -93,6 +93,8 @@ export function useSurvey(
|
||||
refetchSurveyList: () => void
|
||||
refetchSurveyDetail: () => void
|
||||
getSubmitTarget: (params: { storeId: string; role: string }) => Promise<SubmitTargetResponse[] | null>
|
||||
showSurveyAlert: (message: (typeof ALERT_MESSAGES)[keyof typeof ALERT_MESSAGES] | string, requiredField?: string) => void
|
||||
showSurveyConfirm: (message: string, onConfirm: () => void, onCancel?: () => void) => void
|
||||
} {
|
||||
const queryClient = useQueryClient()
|
||||
const { keyword, searchOption, isMySurvey, sort, offset } = useSurveyFilterStore()
|
||||
@ -111,7 +113,7 @@ export function useSurvey(
|
||||
const errorMsg = error.response?.data.error
|
||||
console.error('❌ API ERROR : ', error)
|
||||
if (errorMsg) {
|
||||
alert(errorMsg)
|
||||
showSurveyAlert(errorMsg)
|
||||
}
|
||||
if (isThrow) {
|
||||
throw new Error(error)
|
||||
@ -138,6 +140,19 @@ export function useSurvey(
|
||||
}
|
||||
}
|
||||
|
||||
const tryFunction = async (func: () => Promise<any>, isList?: boolean, isThrow?: boolean): Promise<any> => {
|
||||
try {
|
||||
const resp = await func()
|
||||
return resp.data
|
||||
} catch (error) {
|
||||
handleError(error, isThrow)
|
||||
if (isList) {
|
||||
return { data: [], count: 0 }
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 조사 매물 목록 조회
|
||||
*
|
||||
@ -154,24 +169,23 @@ export function useSurvey(
|
||||
} = useQuery({
|
||||
queryKey: ['survey', 'list', keyword, searchOption, isMySurvey, sort, offset, session?.storeNm, session?.builderId, session?.role],
|
||||
queryFn: async () => {
|
||||
try {
|
||||
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
|
||||
} catch (error: any) {
|
||||
handleError(error, false)
|
||||
return { data: [], count: 0 }
|
||||
}
|
||||
return await tryFunction(
|
||||
() =>
|
||||
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,
|
||||
},
|
||||
}),
|
||||
true,
|
||||
false,
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
@ -205,17 +219,16 @@ export function useSurvey(
|
||||
queryKey: ['survey', id],
|
||||
queryFn: async () => {
|
||||
if (Number.isNaN(id) || id === undefined || id === 0) return null
|
||||
try {
|
||||
const resp = await axiosInstance(null).get<SurveyBasicInfo>(`/api/survey-sales/${id}`, {
|
||||
params: {
|
||||
isPdf: isPdf,
|
||||
},
|
||||
})
|
||||
return resp.data
|
||||
} catch (error: any) {
|
||||
handleError(error, false)
|
||||
return null
|
||||
}
|
||||
return await tryFunction(
|
||||
() =>
|
||||
axiosInstance(null).get<SurveyBasicInfo>(`/api/survey-sales/${id}`, {
|
||||
params: {
|
||||
isPdf: isPdf,
|
||||
},
|
||||
}),
|
||||
false,
|
||||
false,
|
||||
)
|
||||
},
|
||||
enabled: id !== 0 && id !== undefined && id !== null,
|
||||
})
|
||||
@ -294,7 +307,7 @@ export function useSurvey(
|
||||
queryClient.invalidateQueries({ queryKey: ['survey', 'list'] })
|
||||
},
|
||||
onError: (error: any) => {
|
||||
alert(error.response?.data.error)
|
||||
handleError(error, true)
|
||||
},
|
||||
})
|
||||
|
||||
@ -378,15 +391,12 @@ export function useSurvey(
|
||||
* @throws {Error} 우편번호 검색 실패 시 에러 발생
|
||||
*/
|
||||
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 (error: any) {
|
||||
handleError(error, true)
|
||||
return null
|
||||
}
|
||||
const data = await tryFunction(
|
||||
() => axiosInstance(null).get<ZipCodeResponse>(`https://zipcloud.ibsnet.co.jp/api/search?${queryStringFormatter({ zipcode: zipCode.trim() })}`),
|
||||
false,
|
||||
true,
|
||||
)
|
||||
return data ? data.results : null
|
||||
}
|
||||
|
||||
/**
|
||||
@ -398,24 +408,38 @@ export function useSurvey(
|
||||
* @returns {Promise<SubmitTargetResponse[]|null>} 제출 대상 목록
|
||||
*/
|
||||
const getSubmitTarget = async (params: { storeId: string; role: string }): Promise<SubmitTargetResponse[] | null> => {
|
||||
try {
|
||||
if (!params.storeId) {
|
||||
/** 판매점 ID 없는 경우 */
|
||||
alert('販売店IDがありません。')
|
||||
return null
|
||||
}
|
||||
const endpoint = `/api/submission?storeId=${params.storeId}&role=${params.role}`
|
||||
if (!endpoint) {
|
||||
/** 권한 오류 */
|
||||
alert('権限が間違っています。')
|
||||
return null
|
||||
}
|
||||
const { data } = await axiosInstance(null).get<SubmitTargetResponse[]>(endpoint)
|
||||
return data
|
||||
} catch (error: any) {
|
||||
handleError(error, true)
|
||||
if (!params.storeId) {
|
||||
/** 판매점 ID 없는 경우 */
|
||||
showSurveyAlert('販売店IDがありません。')
|
||||
return null
|
||||
}
|
||||
const endpoint = `/api/submission?storeId=${params.storeId}&role=${params.role}`
|
||||
if (!endpoint) {
|
||||
/** 권한 오류 */
|
||||
showSurveyAlert('権限が間違っています。')
|
||||
return null
|
||||
}
|
||||
return await tryFunction(() => axiosInstance(null).get<SubmitTargetResponse[]>(endpoint), false, true)
|
||||
}
|
||||
|
||||
const showSurveyAlert = (message: (typeof ALERT_MESSAGES)[keyof typeof ALERT_MESSAGES] | string, requiredField?: string) => {
|
||||
if (requiredField) {
|
||||
alert(`${requiredField} ${message}`)
|
||||
} else {
|
||||
alert(message)
|
||||
}
|
||||
}
|
||||
const showSurveyConfirm = (message: string, onConfirm: () => void, onCancel?: () => void) => {
|
||||
if (window.neoConfirm) {
|
||||
window.neoConfirm(message, onConfirm)
|
||||
} else {
|
||||
const confirmed = confirm(message)
|
||||
if (confirmed) {
|
||||
onConfirm()
|
||||
} else if (onCancel) {
|
||||
onCancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
@ -436,5 +460,7 @@ export function useSurvey(
|
||||
getSubmitTarget,
|
||||
refetchSurveyList,
|
||||
refetchSurveyDetail,
|
||||
showSurveyAlert,
|
||||
showSurveyConfirm,
|
||||
}
|
||||
}
|
||||
|
||||
@ -323,3 +323,32 @@ export type SurveySearchParams = {
|
||||
/** 시공점 ID */
|
||||
builderId?: string | null
|
||||
}
|
||||
|
||||
|
||||
export const ALERT_MESSAGES = {
|
||||
/** 기본 메세지 */
|
||||
/** 저장 성공 - "저장되었습니다." */
|
||||
SAVE_SUCCESS: '保存されました。',
|
||||
/** 임시 저장 성공 - "임시 저장되었습니다." */
|
||||
TEMP_SAVE_SUCCESS: '一時保存されました。',
|
||||
/** 삭제 성공 - "삭제되었습니다." */
|
||||
DELETE_SUCCESS: '削除されました。',
|
||||
/** 제출 확인 - "제출하시겠습니까?" */
|
||||
SUBMIT_CONFIRM: '提出しますか?',
|
||||
/** 저장 확인 - "저장하시겠습니까?" */
|
||||
SAVE_CONFIRM: '保存しますか?',
|
||||
/** 삭제 확인 - "삭제하시겠습니까?" */
|
||||
DELETE_CONFIRM: '削除しますか?',
|
||||
/** 저장 및 제출 확인 - "입력한 정보를 저장하고 보내시겠습니까?" */
|
||||
SAVE_AND_SUBMIT_CONFIRM: '記入した情報を保存して送信しますか?',
|
||||
/** 임시 저장 제출 오류 - "임시 저장된 데이터는 제출할 수 없습니다." */
|
||||
TEMP_SAVE_SUBMIT_ERROR: '一時保存されたデータは提出できません。',
|
||||
|
||||
/** 입력 오류 메세지 */
|
||||
/* 전기계약 용량 단위 입력 메세지 - "전기 계약 용량의 단위를 입력하세요."*/
|
||||
UNIT_REQUIRED: '電気契約容量の単位を入力してください。',
|
||||
/** 필수 입력 메세지 - "항목이 비어 있습니다."*/
|
||||
REQUIRED_FIELD: '項目が空です。',
|
||||
/** 최대 선택 오류 메세지 - "지붕재는 최대 2개까지 선택할 수 있습니다." */
|
||||
ROOF_MATERIAL_MAX_SELECT_ERROR: '屋根材は最大2個まで選択できます。',
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user