feat(mobile): 로그아웃 모바일 분기 + 뒤로가기 토스트 활성화 조건 완화
Deploy momo-erp / deploy (push) Failing after 3s

- middleware: User-Agent 가 모바일이면 /login → /m/login 으로 redirect (서버 측 분기)
- auth-store.logout: window 가 모바일이면 /m/login, 아니면 /login (클라이언트 측 분기)
- BackButtonGuard: TWA 일부 환경에서 display-mode 가 standalone 으로 보고되지 않는 케이스 대응 — fullscreen/minimal-ui 도 포함, 모바일 UA 면 무조건 활성화

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
chpark
2026-05-13 00:34:26 +09:00
parent 0e9378a638
commit 1e0a2640e9
3 changed files with 20 additions and 4 deletions
+6 -3
View File
@@ -12,13 +12,16 @@ import Swal from "sweetalert2";
*/
export default function BackButtonGuard() {
useEffect(() => {
// standalone 모드 (PWA 설치 또는 TWA) 인지 확인
// standalone(PWA/TWA) 이거나 모바일 UA 면 활성화
// (TWA 일부 환경에서 display-mode 가 standalone 으로 보고되지 않는 케이스 대응)
const isStandalone =
window.matchMedia("(display-mode: standalone)").matches ||
// iOS Safari
window.matchMedia("(display-mode: fullscreen)").matches ||
window.matchMedia("(display-mode: minimal-ui)").matches ||
(window.navigator as Navigator & { standalone?: boolean }).standalone === true;
const isMobileUA = /Mobile|Android|iPhone|iPad|iPod/i.test(window.navigator.userAgent);
if (!isStandalone) return;
if (!isStandalone && !isMobileUA) return;
let lastBackPress = 0;
let toastTimer: ReturnType<typeof setTimeout> | null = null;
+8
View File
@@ -38,6 +38,14 @@ export function middleware(request: NextRequest) {
return NextResponse.redirect(new URL("/m/dashboard", request.url));
}
}
// 모바일(앱/모바일브라우저)에서 /login 접근 시 /m/login 으로 전환
if (pathname === "/login") {
const ua = request.headers.get("user-agent") || "";
const isMobile = /Mobile|Android|iPhone|iPad|iPod/i.test(ua);
if (isMobile) {
return NextResponse.redirect(new URL("/m/login", request.url));
}
}
if (publicPaths.some((p) => pathname.startsWith(p))) {
return NextResponse.next();
}
+6 -1
View File
@@ -20,7 +20,12 @@ export const useAuthStore = create<AuthState>((set) => ({
logout: async () => {
await fetch("/api/auth/logout", { method: "POST" });
set({ user: null });
window.location.href = "/login";
// 모바일(앱/모바일브라우저) → /m/login, 데스크톱 → /login
const isMobile =
typeof window !== "undefined" &&
(window.matchMedia("(max-width: 768px)").matches ||
/Mobile|Android|iPhone|iPad|iPod/i.test(window.navigator.userAgent));
window.location.href = isMobile ? "/m/login" : "/login";
},
fetchUser: async () => {