Files
web-temp/layers/composables/usePreregist.ts
2025-11-07 16:29:44 +09:00

263 lines
7.8 KiB
TypeScript

import type {
ReqPreorderSelectEvent,
ResPreorderSelectEvent,
ReqPreorderReserveDataUpdate,
ResPreorderReserveDataUpdate,
} from '#layers/types/PreregistType'
import { DEFAULT_LOCALE_CODE } from '@/i18n.config'
import { countryDialingCodes } from '#layers/assets/data/countryData'
/**
* 프로모션 - 사전등록
*/
const PREREGIST_ERROR_CODE = {
SUCCESS: 0,
NO_DATA: -1, // 조회된 데이터가 없습니다 (최초)
NOT_PERIOD: -90002, // 사전 등록 기간이 아닙니다
REQUIRED_TERMS: -90000, // 필수 약관을 모두 선택해 주세요
// BIRTH_DATE_REQUIRED: -90018, // 생년 월일을 입력해 주세요
AGE_RESTRICTION: -90022, // 사전 등록 가능한 연령이 아닙니다
ALREADY_REGISTERED: -90023, // 이미 사전 등록이 완료된 계정입니다
LOGIN_REQUIRED: -90028, // 로그인 후 이용하실 수 있습니다
// MAINTENANCE: -90003, // 점검 진행 중
UNKNOWN: -99999, // 알 수 없는 오류
} as const
const usePreregist = () => {
const preregistDate = ref(Date.now())
// GDS composable
const {
isKorea,
isTaiwanHongKongMacau,
isNorthAmerica,
countryCode,
checkCountryByIp,
} = useGds()
// 국가 번호 조회
const countryDialingCode = computed(() => {
const code = countryCode.value?.toUpperCase()
return code ? countryDialingCodes[code] : undefined
})
/**
* 사전 등록일 세팅 (숫자 검증)
*/
const setPreregistDate = (dateValue: number | string | undefined) => {
if (dateValue && isNumeric(String(dateValue))) {
preregistDate.value = Number(dateValue)
} else {
preregistDate.value = Date.now()
}
}
/**
* 에러 응답 생성
*/
const createErrorResponse = <T extends { code: number; message: string }>(
code: number,
message: string = ''
): T => {
return { code, message } as T
}
/**
* 401 에러를 LOGIN_REQUIRED로 정규화
*/
const normalizeAuthError = (code: number): number => {
return String(code).startsWith('401')
? PREREGIST_ERROR_CODE.LOGIN_REQUIRED
: code
}
/**
* 사전 등록 - 조회 (등록 여부)
*/
const getPreregist = async (
req: ReqPreorderSelectEvent
): Promise<ResPreorderSelectEvent> => {
try {
const runtimeConfig = useRuntimeConfig()
const stoveApiBaseUrl = runtimeConfig.public.stoveApiUrl
const url = `${stoveApiBaseUrl}/pub-comm/v1.0/Preorder/SelectEvent`
const headers = {
Authorization: `Bearer ${req.accessToken}`,
}
const body = {
event_code: req.event_code,
lang: req.lang || DEFAULT_LOCALE_CODE,
terms_type: req.terms_type,
}
const res = (await commonFetch('POST', url, {
headers,
body,
})) as ResPreorderSelectEvent
// 응답 검증
if (!res) {
// eslint-disable-next-line no-console
console.error('[usePreregist].getPreregist: Empty response')
return createErrorResponse(PREREGIST_ERROR_CODE.UNKNOWN)
}
// 정규화된 에러 코드
const normalizedCode = normalizeAuthError(res.code)
// 성공 케이스
if (normalizedCode === PREREGIST_ERROR_CODE.SUCCESS) {
setPreregistDate(res.value?.terms_time_long ?? Date.now())
return res
}
// 예상된 에러 케이스 (NO_DATA, NOT_PERIOD, LOGIN_REQUIRED)
const expectedErrors: number[] = [
PREREGIST_ERROR_CODE.NO_DATA,
PREREGIST_ERROR_CODE.NOT_PERIOD,
PREREGIST_ERROR_CODE.LOGIN_REQUIRED,
]
if (expectedErrors.includes(normalizedCode)) {
return createErrorResponse(normalizedCode, res.message)
}
// 예상치 못한 에러
if (import.meta.dev) {
// eslint-disable-next-line no-console
console.error('[usePreregist].getPreregist: Unexpected error', res)
}
return createErrorResponse(PREREGIST_ERROR_CODE.UNKNOWN, res.message)
} catch (error) {
// eslint-disable-next-line no-console
console.error('[usePreregist].getPreregist: Exception', error)
return createErrorResponse(
PREREGIST_ERROR_CODE.UNKNOWN,
error instanceof Error ? error.message : String(error)
)
}
}
/**
* 사전 등록 - 저장
*/
const setPreregist = async (
req: ReqPreorderReserveDataUpdate
): Promise<ResPreorderReserveDataUpdate> => {
try {
const runtimeConfig = useRuntimeConfig()
const stoveApiBaseUrl = runtimeConfig.public.stoveApiUrl
if (!stoveApiBaseUrl) {
throw new Error('stoveApiUrl is not configured')
}
const url = `${stoveApiBaseUrl}/pub-comm/v1.0/Preorder/ReserveDataUpdate`
const headers = {
Authorization: `Bearer ${req.accessToken}`,
}
const body = {
necessary_consent1: req.necessary_consent1,
necessary_consent2: req.necessary_consent2,
necessary_consent3: req.necessary_consent3,
event_code: req.event_code,
terms_type: req.terms_type,
c_num: req.c_num,
lang_code: req.lang_code,
hp: req.hp,
email: req.email,
metric_seq: req.metric_seq,
g_server: req.g_server,
world_id: req.world_id,
game_unique_num: req.game_unique_num,
event_info1: req.event_info1,
event_info2: req.event_info2,
event_info3: req.event_info3,
event_info4: req.event_info4,
under14_terms: req.under14_terms,
device_type: req.device_type,
country_code: req.country_code,
country_dialing_code: req.country_dialing_code,
birth_date: req.birth_date,
}
const res = (await commonFetch('POST', url, {
headers,
body,
})) as ResPreorderReserveDataUpdate
// 응답 검증
if (!res) {
// eslint-disable-next-line no-console
console.error('[usePreregist].setPreregist: Empty response')
return createErrorResponse(PREREGIST_ERROR_CODE.UNKNOWN)
}
// 정규화된 에러 코드
const normalizedCode = normalizeAuthError(res.code)
// 성공 케이스
if (normalizedCode === PREREGIST_ERROR_CODE.SUCCESS) {
setPreregistDate(res.message ? Number(res.message) : Date.now())
return res
}
// 이미 등록된 경우 (날짜 업데이트)
if (normalizedCode === PREREGIST_ERROR_CODE.ALREADY_REGISTERED) {
setPreregistDate(res.message ? Number(res.message) : Date.now())
return createErrorResponse(normalizedCode, res.message)
}
// 예상된 에러 케이스
const expectedErrors: number[] = [
PREREGIST_ERROR_CODE.LOGIN_REQUIRED,
PREREGIST_ERROR_CODE.NOT_PERIOD,
// PREREGIST_ERROR_CODE.BIRTH_DATE_REQUIRED,
PREREGIST_ERROR_CODE.AGE_RESTRICTION,
PREREGIST_ERROR_CODE.REQUIRED_TERMS,
]
if (expectedErrors.includes(normalizedCode)) {
return createErrorResponse(normalizedCode, res.message)
}
// 예상치 못한 에러
if (import.meta.dev) {
// eslint-disable-next-line no-console
console.error('[usePreregist].setPreregist: Unexpected error', res)
}
return createErrorResponse(PREREGIST_ERROR_CODE.UNKNOWN, res.message)
} catch (error) {
// eslint-disable-next-line no-console
console.error('[usePreregist].setPreregist: Exception', error)
return createErrorResponse(
PREREGIST_ERROR_CODE.UNKNOWN,
error instanceof Error ? error.message : String(error)
)
}
}
return {
// GDS state & methods
isKorea,
isTaiwanHongKongMacau,
isNorthAmerica,
countryCode,
checkCountryByIp,
// Preregist state & computed
countryDialingCode,
preregistDate: readonly(preregistDate),
// Preregist methods
getPreregist,
setPreregist,
}
}
export { usePreregist, PREREGIST_ERROR_CODE }