- 로또 번호 추천 구독자 전용 페이지 (/services/lotto/recommend) - NAS 몬테카를로 API 연동 + 클라이언트 사이드 폴백 - 무료 미리보기 1개 + 구독자용 프리미엄 번호 추천 - 구독 플랜 변경: 골드(900원)/플래티넘(2,900원)/다이아(9,900원) - 텔레그램 봇 연동: 연결/해제, 웹훅, /start 명령 처리 - 마이페이지 텔레그램 연결 UI + 가이드 모달 - 관리자 페이지 (/admin): 대시보드, 회원, 서비스, 문의 관리 - Supabase 마이그레이션: profiles 텔레그램 컬럼, 신규 상품 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
52 lines
1.8 KiB
TypeScript
52 lines
1.8 KiB
TypeScript
'use client';
|
|
|
|
import { useState } from 'react';
|
|
import { usePathname } from 'next/navigation';
|
|
import Sidebar from './Sidebar';
|
|
|
|
const AUTH_PATHS = ['/login', '/signup', '/admin'];
|
|
|
|
export default function DashboardShell({ children }: { children: React.ReactNode }) {
|
|
const [sidebarOpen, setSidebarOpen] = useState(false);
|
|
const pathname = usePathname();
|
|
|
|
const isAuthPage = AUTH_PATHS.some((p) => pathname.startsWith(p));
|
|
|
|
if (isAuthPage) {
|
|
return <>{children}</>;
|
|
}
|
|
|
|
return (
|
|
<div className="dashboard-layout">
|
|
<Sidebar isOpen={sidebarOpen} onClose={() => setSidebarOpen(false)} />
|
|
|
|
<div className="flex-1 flex flex-col overflow-hidden min-w-0">
|
|
{/* Mobile top bar */}
|
|
<header className="lg:hidden flex items-center justify-between px-4 py-3 bg-[#04102b] border-b border-[#1a3a7a]/50 flex-shrink-0">
|
|
<button
|
|
onClick={() => setSidebarOpen(true)}
|
|
className="p-2 rounded-lg text-slate-400 hover:text-white hover:bg-slate-800 transition"
|
|
aria-label="메뉴 열기"
|
|
>
|
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
|
|
</svg>
|
|
</button>
|
|
<div className="flex items-center gap-2">
|
|
<div className="w-7 h-7 rounded-lg bg-gradient-to-br from-blue-500 to-violet-600 flex items-center justify-center text-white font-bold text-xs">
|
|
쟁
|
|
</div>
|
|
<span className="text-white font-bold text-base">쟁승메이드</span>
|
|
</div>
|
|
<div className="w-9" />
|
|
</header>
|
|
|
|
{/* Main scrollable content */}
|
|
<main className="main-content">
|
|
{children}
|
|
</main>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|