import {setAccessToken, customFetch} from '../../api/mutator/custom-fetch'; import { login as loginRequest, refreshToken as refreshRequest, me as fetchMe, } from '../../api/generated/auth/auth'; import type {ResMe} from '../../api/generated/model/resMe'; import type {ErrorInfo} from '../../api/generated/model/errorInfo'; import {useAuthStore, type AuthUser, type UserRole} from '../../stores/auth'; import {UserRole as UserRoleCode} from '../../api/generated/model'; import {USER_ROLE_LABEL} from '../../lib/enumLabels'; import {toMessage, resultMessage} from '../../lib/apiError'; const ACCESS_KEY = 'negodata.accessToken'; const REFRESH_KEY = 'negodata.refreshToken'; // 백엔드 공통 응답: { result: {success, code, desc}, ...payload }. // result.success 가 false 면 desc 로 throw (HTTP 4xx 는 customFetch 가 ApiError 로 던짐). function ensureOk(res: T): T { const r = res.result; if (r && r.success === false) throw new Error(r.desc || String(r.code ?? '') || 'request failed'); return res; } function toAuthUser(me: ResMe): AuthUser { return { userId: me.user_id ?? '', company: me.company?.name ?? '', name: me.name ?? me.id ?? '', loginId: me.id ?? '', email: me.email ?? '', contact: me.contact_number ?? '', role: (USER_ROLE_LABEL[me.role ?? UserRoleCode.USER] ?? '일반') as UserRole, }; } async function restore(): Promise { const access = localStorage.getItem(ACCESS_KEY); const refresh = localStorage.getItem(REFRESH_KEY); if (!access && !refresh) return; if (access) setAccessToken(access); try { const me = ensureOk(await fetchMe()); useAuthStore.getState().setUser(toAuthUser(me)); } catch { try { if (!refresh) throw new Error('no refresh token'); // refresh 토큰은 Authorization 헤더(Bearer)로 보낸다 → accessToken 슬롯에 잠시 실어 보냄. setAccessToken(refresh); const {access_token = ''} = ensureOk(await refreshRequest()); localStorage.setItem(ACCESS_KEY, access_token); setAccessToken(access_token); const me = ensureOk(await fetchMe()); useAuthStore.getState().setUser(toAuthUser(me)); } catch { localStorage.removeItem(ACCESS_KEY); localStorage.removeItem(REFRESH_KEY); setAccessToken(null); } } } let restorePromise: Promise | null = null; export function initAuth(): Promise { if (!restorePromise) restorePromise = restore(); return restorePromise; } export async function login(loginId: string, password: string): Promise { const tokens = ensureOk(await loginRequest({id: loginId, password})); localStorage.setItem(ACCESS_KEY, tokens.access_token ?? ''); localStorage.setItem(REFRESH_KEY, tokens.refresh_token ?? ''); setAccessToken(tokens.access_token ?? null); const me = ensureOk(await fetchMe()); useAuthStore.getState().setUser(toAuthUser(me)); return me; } export interface UpdateMePayload { name?: string | null; email?: string | null; contact_number?: string | null; password?: string | null; } // 본인 정보 수정(PATCH /v1/auth/me). 성공 시 최신 정보로 스토어 갱신. // HTTP 에러(ApiError)·응답봉투 모두 toMessage/resultMessage 로 한글 통일. export async function updateMe(payload: UpdateMePayload): Promise { let me: ResMe; try { me = await customFetch({url: '/v1/auth/me', method: 'PATCH', data: payload}); } catch (err) { throw new Error(toMessage(err)); } const msg = resultMessage(me.result); if (msg) throw new Error(msg); useAuthStore.getState().setUser(toAuthUser(me)); return me; } // 백엔드에 logout 엔드포인트가 없으므로 클라이언트 상태만 비운다. export async function logout(): Promise { localStorage.removeItem(ACCESS_KEY); localStorage.removeItem(REFRESH_KEY); setAccessToken(null); useAuthStore.getState().setUser(null); }