feat(install): /install 페이지 — 안드로이드/아이폰/PC 별 PWA 설치 가이드
Deploy momo-erp / deploy (push) Successful in 4m25s
Deploy momo-erp / deploy (push) Successful in 4m25s
노인 사용자(거래처 사장님 등) 도 따라할 수 있도록 큰 글씨 + 단계별 안내. User-Agent 자동 감지로 해당 기기 가이드 우선 표시, 탭으로 다른 기기 전환 가능. * 안드로이드: Chrome → 앱 설치 배너 → 4단계 * 아이폰: Safari → 공유 → 홈 화면에 추가 → 5단계 (사파리 필수 경고 강조) * PC: QR 코드 (휴대폰 카메라로 즉시 안내 페이지 이동) 모바일 로그인 화면 하단에 "📱 휴대폰 홈 화면에 앱처럼 설치하는 방법" 링크 추가. middleware publicPaths 에 /install 추가 (비로그인 접근 허용). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -218,6 +218,16 @@ export default function MobileLoginPage() {
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{/* 앱 설치 안내 링크 */}
|
||||
<div className="relative z-10 text-center pt-3">
|
||||
<a
|
||||
href="/install"
|
||||
className="inline-flex items-center gap-1.5 text-xs text-emerald-50/90 hover:text-white underline underline-offset-4 decoration-emerald-300/50"
|
||||
>
|
||||
📱 휴대폰 홈 화면에 앱처럼 설치하는 방법
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{/* 푸터 */}
|
||||
<div className="relative z-10 text-center pb-4 pt-2">
|
||||
<p className="text-[10px] text-emerald-100/60 tracking-wide">
|
||||
|
||||
@@ -0,0 +1,259 @@
|
||||
// 앱 설치 안내 페이지 — 노인 사용자도 따라할 수 있도록 큰 글씨 + 단계별 안내.
|
||||
// User-Agent 로 안드로이드/아이폰/PC 감지해서 해당 가이드만 보여줌.
|
||||
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { Smartphone, ChevronRight, Apple, Globe } from "lucide-react";
|
||||
|
||||
type Device = "android" | "ios" | "desktop";
|
||||
|
||||
export default function InstallGuidePage() {
|
||||
const [device, setDevice] = useState<Device>("android");
|
||||
const [autoDetected, setAutoDetected] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const ua = navigator.userAgent.toLowerCase();
|
||||
if (/iphone|ipad|ipod/.test(ua)) setDevice("ios");
|
||||
else if (/android/.test(ua)) setDevice("android");
|
||||
else setDevice("desktop");
|
||||
setAutoDetected(true);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<main className="min-h-screen bg-gradient-to-b from-emerald-50 to-white px-4 py-6 sm:py-10">
|
||||
<div className="max-w-md mx-auto">
|
||||
{/* 헤더 */}
|
||||
<div className="text-center mb-6 sm:mb-8">
|
||||
<div className="w-20 h-20 bg-emerald-700 rounded-2xl mx-auto mb-3 flex items-center justify-center shadow-lg">
|
||||
<span className="text-white text-3xl font-black">M</span>
|
||||
</div>
|
||||
<h1 className="text-2xl sm:text-3xl font-black text-slate-900">모모ERP 앱 설치</h1>
|
||||
<p className="text-base text-slate-600 mt-2">홈 화면에 앱처럼 만들어 사용하세요</p>
|
||||
</div>
|
||||
|
||||
{/* 기종 선택 */}
|
||||
<div className="bg-white border border-slate-200 rounded-2xl p-2 mb-6 shadow-sm">
|
||||
<div className="grid grid-cols-3 gap-1">
|
||||
<TabBtn active={device === "android"} onClick={() => setDevice("android")}>
|
||||
<Smartphone size={20} />
|
||||
<span>안드로이드</span>
|
||||
</TabBtn>
|
||||
<TabBtn active={device === "ios"} onClick={() => setDevice("ios")}>
|
||||
<Apple size={20} />
|
||||
<span>아이폰</span>
|
||||
</TabBtn>
|
||||
<TabBtn active={device === "desktop"} onClick={() => setDevice("desktop")}>
|
||||
<Globe size={20} />
|
||||
<span>컴퓨터</span>
|
||||
</TabBtn>
|
||||
</div>
|
||||
{autoDetected && (
|
||||
<p className="text-[11px] text-center text-slate-400 mt-2">
|
||||
지금 사용 중인 기기에 맞춰 자동 선택됨
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 가이드 본문 */}
|
||||
{device === "android" && <AndroidGuide />}
|
||||
{device === "ios" && <IosGuide />}
|
||||
{device === "desktop" && <DesktopGuide />}
|
||||
|
||||
{/* 하단 — 로그인 바로가기 */}
|
||||
<div className="mt-8 pt-6 border-t border-slate-200 text-center space-y-3">
|
||||
<a
|
||||
href="/m/login"
|
||||
className="inline-flex items-center gap-2 px-6 h-12 rounded-xl bg-emerald-700 text-white text-base font-bold shadow-md active:translate-y-px"
|
||||
>
|
||||
로그인 화면으로 가기 <ChevronRight size={18} />
|
||||
</a>
|
||||
<p className="text-xs text-slate-500">설치 도움이 필요하시면 ☎ 010-6369-8443</p>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
function TabBtn({ active, onClick, children }: { active: boolean; onClick: () => void; children: React.ReactNode }) {
|
||||
return (
|
||||
<button
|
||||
onClick={onClick}
|
||||
className={`flex flex-col items-center gap-1 py-3 rounded-xl text-xs font-bold transition ${
|
||||
active
|
||||
? "bg-emerald-700 text-white shadow"
|
||||
: "bg-transparent text-slate-500 hover:bg-slate-50"
|
||||
}`}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────
|
||||
// 안드로이드 — Chrome 으로 PWA 설치
|
||||
// ─────────────────────────────────────────
|
||||
function AndroidGuide() {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="bg-emerald-50 border border-emerald-200 rounded-2xl p-4 text-center">
|
||||
<p className="text-base font-bold text-emerald-900">
|
||||
📱 안드로이드 휴대폰에 설치하기
|
||||
</p>
|
||||
<p className="text-sm text-emerald-700 mt-1">크롬 브라우저로 따라하세요</p>
|
||||
</div>
|
||||
|
||||
<Step n={1} title="크롬(Chrome) 앱 열기">
|
||||
<p>휴대폰에서 <b className="text-emerald-700">크롬</b> (인터넷) 앱을 열어주세요.</p>
|
||||
<div className="mt-2 flex items-center gap-2 text-sm text-slate-500">
|
||||
<div className="w-10 h-10 rounded-xl bg-gradient-to-br from-blue-500 via-red-500 to-yellow-400 flex items-center justify-center text-white font-black text-sm">C</div>
|
||||
<span>← 이 아이콘</span>
|
||||
</div>
|
||||
</Step>
|
||||
|
||||
<Step n={2} title="momotogether.com 주소 입력">
|
||||
<p>주소창에 <b className="text-emerald-700 text-lg break-all">momotogether.com</b> 을 입력하고 이동.</p>
|
||||
</Step>
|
||||
|
||||
<Step n={3} title='"앱 설치" 누르기'>
|
||||
<p>
|
||||
화면 아래쪽에 <b className="text-emerald-700">"앱 설치"</b> 또는
|
||||
<b className="text-emerald-700"> "홈 화면에 추가"</b> 배너가 자동으로 뜹니다.
|
||||
탭해주세요.
|
||||
</p>
|
||||
<p className="mt-2 text-sm text-slate-500">
|
||||
※ 배너가 안 보이면, 우상단 <b>⋮ 점 세 개</b> 메뉴 → <b>"앱 설치"</b> 직접 선택.
|
||||
</p>
|
||||
</Step>
|
||||
|
||||
<Step n={4} title='"설치" 한 번 더 누르기'>
|
||||
<p>확인 창에서 <b className="text-emerald-700">"설치"</b> 버튼 탭.</p>
|
||||
</Step>
|
||||
|
||||
<FinishBox>
|
||||
홈 화면에 <b>모모ERP</b> 아이콘이 생겼습니다. 탭해서 로그인하세요.
|
||||
</FinishBox>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────
|
||||
// 아이폰 — Safari 로 PWA 설치
|
||||
// ─────────────────────────────────────────
|
||||
function IosGuide() {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="bg-blue-50 border border-blue-200 rounded-2xl p-4 text-center">
|
||||
<p className="text-base font-bold text-blue-900">
|
||||
아이폰(아이패드)에 설치하기
|
||||
</p>
|
||||
<p className="text-sm text-blue-700 mt-1">반드시 사파리(Safari) 로 진행</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-amber-50 border-2 border-amber-300 rounded-2xl p-4">
|
||||
<p className="text-base font-bold text-amber-900">⚠️ 꼭 사파리(Safari) 로 하세요</p>
|
||||
<p className="text-sm text-amber-800 mt-1">크롬·네이버 앱으로 하면 일반 즐겨찾기만 되고 앱처럼 안 됩니다.</p>
|
||||
</div>
|
||||
|
||||
<Step n={1} title="사파리(Safari) 앱 열기">
|
||||
<p>나침반 모양 <b className="text-blue-700">사파리</b> 아이콘 탭.</p>
|
||||
<div className="mt-2 flex items-center gap-2 text-sm text-slate-500">
|
||||
<div className="w-10 h-10 rounded-xl bg-gradient-to-br from-sky-400 to-blue-600 flex items-center justify-center text-white text-lg">🧭</div>
|
||||
<span>← 이 아이콘</span>
|
||||
</div>
|
||||
</Step>
|
||||
|
||||
<Step n={2} title="momotogether.com 주소 입력">
|
||||
<p>주소창에 <b className="text-blue-700 text-lg break-all">momotogether.com</b> 입력 후 이동.</p>
|
||||
</Step>
|
||||
|
||||
<Step n={3} title="공유 버튼 누르기">
|
||||
<p>화면 <b>아래쪽 가운데</b> 의 <b className="text-blue-700">공유 버튼</b> 탭.</p>
|
||||
<div className="mt-2 flex items-center gap-2 text-sm text-slate-500">
|
||||
<div className="w-10 h-10 rounded-xl border-2 border-blue-500 flex items-center justify-center text-blue-600 text-xl">⬆</div>
|
||||
<span>← 사각형 + 위쪽 화살표 모양</span>
|
||||
</div>
|
||||
</Step>
|
||||
|
||||
<Step n={4} title='"홈 화면에 추가" 누르기'>
|
||||
<p>
|
||||
공유 메뉴를 <b>아래로 스크롤</b> 하면
|
||||
<b className="text-blue-700"> "홈 화면에 추가"</b> 항목이 있습니다. 탭.
|
||||
</p>
|
||||
</Step>
|
||||
|
||||
<Step n={5} title='"추가" 한 번 더 누르기'>
|
||||
<p>우측 상단 <b className="text-blue-700">"추가"</b> 탭.</p>
|
||||
</Step>
|
||||
|
||||
<FinishBox>
|
||||
홈 화면에 <b>모모ERP</b> 아이콘 생겼어요. 탭해서 로그인하세요.
|
||||
</FinishBox>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────
|
||||
// PC — QR 안내 + 바로 사용 옵션
|
||||
// ─────────────────────────────────────────
|
||||
function DesktopGuide() {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="bg-slate-50 border border-slate-200 rounded-2xl p-4 text-center">
|
||||
<p className="text-base font-bold text-slate-900">💻 PC 사용자</p>
|
||||
<p className="text-sm text-slate-600 mt-1">휴대폰에서 설치하시거나, 컴퓨터 브라우저로 바로 사용하세요</p>
|
||||
</div>
|
||||
|
||||
<Step n={1} title="휴대폰에서 설치하려면 — QR 코드">
|
||||
<p>아래 QR 코드를 휴대폰 카메라로 찍으면 설치 안내 페이지가 폰에 열립니다.</p>
|
||||
<div className="mt-3 flex justify-center">
|
||||
<img
|
||||
src="https://api.qrserver.com/v1/create-qr-code/?size=220x220&data=https%3A%2F%2Fmomotogether.com%2Finstall"
|
||||
alt="설치 페이지 QR 코드"
|
||||
className="rounded-xl border border-slate-200"
|
||||
width={220}
|
||||
height={220}
|
||||
/>
|
||||
</div>
|
||||
</Step>
|
||||
|
||||
<Step n={2} title="컴퓨터로 바로 사용하기">
|
||||
<p>크롬·엣지에서 momotogether.com 접속 → 로그인 → 그대로 사용 가능합니다.</p>
|
||||
<p className="mt-2 text-sm text-slate-500">
|
||||
크롬 주소창 우측 끝에 <b>⊕</b> 또는 <b>모니터+화살표</b> 모양 아이콘이 보이면 클릭해서 설치할 수도 있어요.
|
||||
</p>
|
||||
</Step>
|
||||
|
||||
<FinishBox>
|
||||
대부분의 기능은 PC 브라우저에서도 동일하게 동작합니다.
|
||||
</FinishBox>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────
|
||||
function Step({ n, title, children }: { n: number; title: string; children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="bg-white border border-slate-200 rounded-2xl p-4 shadow-sm">
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="w-9 h-9 rounded-full bg-emerald-700 text-white flex items-center justify-center font-black text-base shrink-0">
|
||||
{n}
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<h3 className="text-base font-bold text-slate-900 mb-1">{title}</h3>
|
||||
<div className="text-base text-slate-700 leading-relaxed">{children}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function FinishBox({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="bg-emerald-600 text-white rounded-2xl p-5 text-center shadow-md">
|
||||
<p className="text-2xl mb-1">🎉</p>
|
||||
<p className="text-base font-bold">설치 완료!</p>
|
||||
<p className="text-sm mt-1 text-emerald-50">{children}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -11,6 +11,7 @@ export function middleware(request: NextRequest) {
|
||||
"/signup",
|
||||
"/privacy",
|
||||
"/account-deletion",
|
||||
"/install",
|
||||
"/api/auth/login",
|
||||
"/api/auth/signup",
|
||||
"/api/auth/mobile-login",
|
||||
|
||||
Reference in New Issue
Block a user