From 24031d93a9854b0a97b6c8d28dae3599b3da4a06 Mon Sep 17 00:00:00 2001 From: ttipo Date: Mon, 22 Jun 2026 13:52:06 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=EB=AF=B8=EC=9D=B8=EC=A6=9D=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=EC=8B=9C=20=EC=97=90=EB=9F=AC=20=ED=86=A0?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=97=86=EC=9D=B4=20=EB=B0=9C=EC=86=A1=20?= =?UTF-8?q?=EC=99=84=EB=A3=8C=20=ED=99=94=EB=A9=B4=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=A0=84=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 로그인 호출에 silent 옵션을 추가해 전역 에러 토스트를 끄고, 로그인 화면에서 에러를 직접 처리. 미인증(403)은 토스트 없이 인증 메일 발송 후 발송 완료 화면으로 이동하고, 그 외 자격 오류만 다이얼로그로 안내. Co-Authored-By: Claude Opus 4.8 (1M context) --- frontend/src/composables/useAuth.ts | 9 ++++--- frontend/src/pages/relay/LoginPage.vue | 33 ++++++++++++++++++-------- frontend/src/stores/auth.store.ts | 9 ++++--- 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/frontend/src/composables/useAuth.ts b/frontend/src/composables/useAuth.ts index b4341a5..6128485 100644 --- a/frontend/src/composables/useAuth.ts +++ b/frontend/src/composables/useAuth.ts @@ -30,9 +30,12 @@ export function useAuth() { await api.post('/auth/reset-password', { token, password }) } - // 로그인 - async function login(payload: LoginPayload): Promise { - return (await api.post('/auth/login', payload)) as unknown as AuthUser + // 로그인 — silent 옵션 시 전역 에러 토스트를 띄우지 않고 호출측이 직접 처리 + async function login( + payload: LoginPayload, + opts?: { silent?: boolean }, + ): Promise { + return (await api.post('/auth/login', payload, opts)) as unknown as AuthUser } // 로그아웃 (쿠키 제거) diff --git a/frontend/src/pages/relay/LoginPage.vue b/frontend/src/pages/relay/LoginPage.vue index d3f5098..67885c6 100644 --- a/frontend/src/pages/relay/LoginPage.vue +++ b/frontend/src/pages/relay/LoginPage.vue @@ -4,10 +4,12 @@ import { computed, ref } from 'vue' import { useRoute, useRouter } from 'vue-router' import RelayMark from '@/components/RelayMark.vue' import { useAuthStore } from '@/stores/auth.store' +import { useDialog } from '@/composables/useDialog' const route = useRoute() const router = useRouter() const authStore = useAuthStore() +const dialog = useDialog() // 폼 상태 const email = ref('') @@ -35,25 +37,36 @@ async function onLogin() { if (submitting.value) return submitting.value = true try { - await authStore.login({ - email: email.value.trim(), - password: password.value, - keepLogin: keepLogin.value, - }) + // silent: 미인증(403)은 토스트 없이 화면 전환으로 처리하므로 전역 에러 알림을 끈다 + await authStore.login( + { + email: email.value.trim(), + password: password.value, + keepLogin: keepLogin.value, + }, + { silent: true }, + ) await router.push('/projects') } catch (err) { - // 미인증 계정(서버 403) → 인증 메일을 즉시 발송하고 '발송 완료' 화면으로 이동 - const status = (err as { response?: { status?: number } })?.response?.status - if (status === 403) { + const res = ( + err as { response?: { status?: number; data?: { error?: { message?: string } } } } + )?.response + // 미인증 계정(서버 403) → 인증 메일을 즉시 발송하고 '발송 완료' 화면으로 조용히 이동 + if (res?.status === 403) { const addr = email.value.trim() try { await authStore.resendVerification(addr) } catch { - // 재발송 실패는 API 인터셉터가 전역 처리 + // 재발송 실패는 무시(화면 전환 우선) } await router.push({ path: '/signup', query: { sent: addr } }) + return } - // 그 외(자격 불일치 등) 에러 메시지는 API 인터셉터에서 전역 처리됨 + // 그 외(자격 불일치 등) — 서버 메시지를 직접 안내 + void dialog.alert( + res?.data?.error?.message ?? '이메일 또는 비밀번호가 올바르지 않습니다.', + { variant: 'danger' }, + ) } finally { submitting.value = false } diff --git a/frontend/src/stores/auth.store.ts b/frontend/src/stores/auth.store.ts index 26f683e..67d52b1 100644 --- a/frontend/src/stores/auth.store.ts +++ b/frontend/src/stores/auth.store.ts @@ -24,9 +24,12 @@ export const useAuthStore = defineStore('auth', () => { fetchMe, } = useAuth() - // 로그인 - async function login(payload: LoginPayload): Promise { - user.value = await loginApi(payload) + // 로그인 — silent 옵션은 그대로 전달(에러 토스트 억제, 호출측 직접 처리) + async function login( + payload: LoginPayload, + opts?: { silent?: boolean }, + ): Promise { + user.value = await loginApi(payload, opts) } // 회원가입 — 인증 메일 발송 후 대기. 자동 로그인하지 않으므로 user 는 갱신하지 않는다.