- OWNER 권한 신설, 최고관리자가 자기 회사 소속 직원(USER) 계정 생성·수정·삭제 관리 - 회사 사용자 API(/v1/company/user/*), 회원관리 페이지·폼 - 로그인/프로필 흐름 정비, 무인증 계정생성(/auth/create) 제거 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
109 lines
3.9 KiB
TypeScript
109 lines
3.9 KiB
TypeScript
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<T extends {result?: ErrorInfo}>(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<void> {
|
|
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<void> | null = null;
|
|
export function initAuth(): Promise<void> {
|
|
if (!restorePromise) restorePromise = restore();
|
|
return restorePromise;
|
|
}
|
|
|
|
export async function login(loginId: string, password: string): Promise<ResMe> {
|
|
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<ResMe> {
|
|
let me: ResMe;
|
|
try {
|
|
me = await customFetch<ResMe>({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<void> {
|
|
localStorage.removeItem(ACCESS_KEY);
|
|
localStorage.removeItem(REFRESH_KEY);
|
|
setAccessToken(null);
|
|
useAuthStore.getState().setUser(null);
|
|
}
|