diff --git a/public/manifest.json b/public/manifest.json index f752f7b..fc44935 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -2,7 +2,7 @@ "name": "모모유통 ERP", "short_name": "모모ERP", "description": "모모유통 유통관리 ERP", - "start_url": "/", + "start_url": "/m/login", "scope": "/", "display": "standalone", "orientation": "portrait", diff --git a/src/app/(auth)/m/login/page.tsx b/src/app/(auth)/m/login/page.tsx new file mode 100644 index 0000000..2e55d4f --- /dev/null +++ b/src/app/(auth)/m/login/page.tsx @@ -0,0 +1,197 @@ +"use client"; + +import { useState, useEffect, FormEvent } from "react"; +import { useRouter } from "next/navigation"; +import { User, Lock, Eye, EyeOff } from "lucide-react"; +import Swal from "sweetalert2"; + +const SAVE_KEY = "momo_saved_credentials"; + +export default function MobileLoginPage() { + const router = useRouter(); + const [userId, setUserId] = useState(""); + const [password, setPassword] = useState(""); + const [showPw, setShowPw] = useState(false); + const [loading, setLoading] = useState(false); + const [remember, setRemember] = useState(true); + const [saveCreds, setSaveCreds] = useState(false); + + useEffect(() => { + try { + const raw = localStorage.getItem(SAVE_KEY); + if (!raw) return; + const saved = JSON.parse(raw) as { userId?: string; password?: string }; + if (saved.userId) setUserId(saved.userId); + if (saved.password) setPassword(saved.password); + setSaveCreds(true); + } catch { + /* ignore */ + } + }, []); + + const handleSubmit = async (e: FormEvent) => { + e.preventDefault(); + if (!userId || !password) { + Swal.fire({ icon: "warning", title: "아이디와 비밀번호를 입력하세요." }); + return; + } + setLoading(true); + try { + const res = await fetch("/api/auth/login", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ userId, password, remember }), + }); + const data = await res.json(); + if (data.success) { + try { + if (saveCreds) { + localStorage.setItem(SAVE_KEY, JSON.stringify({ userId, password })); + } else { + localStorage.removeItem(SAVE_KEY); + } + } catch { + /* ignore */ + } + // 모바일은 항상 /m/dashboard 로 + router.push("/m/dashboard"); + } else { + Swal.fire({ + icon: "error", + title: "로그인 실패", + text: data.message || "아이디 또는 비밀번호를 확인하세요.", + }); + } + } catch { + Swal.fire({ icon: "error", title: "서버 오류", text: "잠시 후 다시 시도하세요." }); + } finally { + setLoading(false); + } + }; + + return ( +
+ {/* 배경 패턴 */} +
+ + {/* 헤더: 로고 + 타이틀 */} +
+ MOMO +

모모유통 ERP

+

유통 업무 통합 관리

+
+ + {/* 폼 카드 */} +
+
+
+ +
+ + setUserId(e.target.value)} + placeholder="아이디" + autoFocus + autoComplete="username" + inputMode="text" + className="w-full h-11 pl-10 pr-3 rounded-xl border border-slate-200 bg-white text-sm text-slate-900 placeholder-slate-400 focus:outline-none focus:border-emerald-500 focus:ring-2 focus:ring-emerald-500/20 transition" + /> +
+
+ +
+ +
+ + setPassword(e.target.value)} + placeholder="비밀번호" + autoComplete="current-password" + className="w-full h-11 pl-10 pr-10 rounded-xl border border-slate-200 bg-white text-sm text-slate-900 placeholder-slate-400 focus:outline-none focus:border-emerald-500 focus:ring-2 focus:ring-emerald-500/20 transition" + /> + +
+
+ +
+ + +
+ + +
+
+ + {/* 푸터 */} +
+

+ © 2026 MOMO DISTRIBUTION +

+
+
+ ); +} diff --git a/src/middleware.ts b/src/middleware.ts index c54110f..79633ef 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -7,6 +7,7 @@ export function middleware(request: NextRequest) { // 인증 불필요 경로 const publicPaths = [ "/login", + "/m/login", "/signup", "/api/auth/login", "/api/auth/signup", @@ -17,6 +18,12 @@ export function middleware(request: NextRequest) { "/icon.svg", "/momo-logo.svg", "/momo-icon.svg", + "/icon-192.png", + "/icon-512.png", + "/icon-180.png", + "/manifest.json", + "/sw.js", + "/.well-known", ]; // 랜딩 페이지: 세션이 살아있으면 대시보드로 직행 (이미 로그인된 사용자가 /로 들어와도 마케팅 화면 안 보이게) if (pathname === "/") { @@ -26,7 +33,7 @@ export function middleware(request: NextRequest) { return NextResponse.next(); } // 로그인/가입 페이지도 세션 있으면 대시보드로 - if (pathname === "/login" || pathname === "/signup") { + if (pathname === "/login" || pathname === "/m/login" || pathname === "/signup") { if (request.cookies.get("plm-session")) { return NextResponse.redirect(new URL("/m/dashboard", request.url)); }