diff --git a/public/assets/login/white-cheese-logo.svg b/public/assets/login/white-cheese-logo.svg new file mode 100644 index 00000000..8f034014 --- /dev/null +++ b/public/assets/login/white-cheese-logo.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/assets/rending/new-swipe/1.png b/public/assets/rending/new-swipe/1.png new file mode 100644 index 00000000..87167640 Binary files /dev/null and b/public/assets/rending/new-swipe/1.png differ diff --git a/public/assets/rending/new-swipe/2.png b/public/assets/rending/new-swipe/2.png new file mode 100644 index 00000000..b9a0cd06 Binary files /dev/null and b/public/assets/rending/new-swipe/2.png differ diff --git a/public/assets/rending/new-swipe/3.png b/public/assets/rending/new-swipe/3.png new file mode 100644 index 00000000..e285614e Binary files /dev/null and b/public/assets/rending/new-swipe/3.png differ diff --git a/public/assets/rending/new-swipe/4.png b/public/assets/rending/new-swipe/4.png new file mode 100644 index 00000000..373587a9 Binary files /dev/null and b/public/assets/rending/new-swipe/4.png differ diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 88afdd4b..4bfa0971 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -36,6 +36,13 @@ export const metadata: Metadata = { }, }; +export const viewport = { + width: 'device-width', + initialScale: 1, + maximumScale: 1, + userScalable: false, +}; + export default function RootLayout({ children, }: Readonly<{ diff --git a/src/app/page.tsx b/src/app/page.tsx index 33cd9e1a..3457b604 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,5 +1,5 @@ -import ScreenRoot from '@/feature/root/components/ScreenRoot'; +import ScreenNewRoot from '@/feature/root/components/ScreenNewRoot'; export default function Page() { - return ; + return ; } diff --git a/src/feature/root/components/FlashRending.tsx b/src/feature/root/components/FlashRending.tsx new file mode 100644 index 00000000..896b44a3 --- /dev/null +++ b/src/feature/root/components/FlashRending.tsx @@ -0,0 +1,17 @@ +import Image from 'next/image'; + +const FlashRending = () => { + return ( +
+ Cheese Logo +
+ ); +}; + +export default FlashRending; diff --git a/src/feature/root/components/RendingBody.tsx b/src/feature/root/components/RendingBody.tsx new file mode 100644 index 00000000..5841304e --- /dev/null +++ b/src/feature/root/components/RendingBody.tsx @@ -0,0 +1,153 @@ +'use client'; + +import { + Carousel, + CarouselContent, + CarouselItem, + type CarouselApi, +} from '@/components/ui/carousel'; +import { buildQuery } from '@/global/utils/buildQuery'; +import Image from 'next/image'; +import { useSearchParams } from 'next/navigation'; +import { useEffect, useState } from 'react'; + +const KAKAO_AUTH_URL = `https://dev.say-cheese.me/oauth2/authorization/kakao`; + +export const RendingBody = () => { + const [api, setApi] = useState(); + const [current, setCurrent] = useState(0); + const searchParams = useSearchParams(); + const redirect = searchParams.get('redirect'); + + const slides = [ + { + src: '/assets/rending/new-swipe/1.png', + alt: '앨범 목록 화면', + width: 260, + height: 530, + title: '이벤트마다 만드는 공유앨범', + description: '감튀 모임부터 찐친 여행까지', + }, + { + src: '/assets/rending/new-swipe/2.png', + alt: 'QR 코드 공유', + width: 260, + height: 530, + title: '이벤트마다 모인 자리에서 바로 공유', + description: '감튀 모임부터 앨범 만들고 초대까지 딱 10초', + }, + { + src: '/assets/rending/new-swipe/3.png', + alt: '베스트컷', + width: 312.5, + height: 530.3, + title: '이벤트마다 한눈에 보는 베스트컷', + description: '사진 고르는 고민 이제 끝', + }, + { + src: '/assets/rending/new-swipe/4.png', + alt: '네컷추억', + width: 289, + height: 530, + title: '딱 네컷으로 남는 추억', + description: '앨범이 닫히면 사라지는 원본 사진들', + }, + ]; + + // 캐러셀 API를 통해 현재 슬라이드 추적 + useEffect(() => { + if (!api) return; + + api.on('select', () => { + setCurrent(api.selectedScrollSnap()); + }); + }, [api]); + + const handleKakaoLogin = async () => { + try { + const kakaoUrl = redirect + ? `${KAKAO_AUTH_URL}${buildQuery({ redirect })}` + : KAKAO_AUTH_URL; + + window.location.href = kakaoUrl; + } catch (err) { + console.error('카카오 인증 GET 요청 실패:', err); + } + }; + + return ( +
+ {/* 캐러셀 영역 */} +
+ + + {slides.map((slide, index) => ( + +
+ {slide.alt} +
+
+ ))} +
+
+
+ + {/* 하단 흰색 배경 영역 - 이미지 위에 오버레이 */} +
+ {/* 텍스트 영역 */} +
+

+ {slides[current].title} +

+

+ {slides[current].description} +

+
+ + {/* 인디케이터 점들 */} +
+ {slides.map((_, index) => ( +
+ + {/* 카카오 로그인 버튼 */} +
+ 카카오 로고 + + 카카오 로그인 + +
+
+
+ ); +}; diff --git a/src/feature/root/components/ScreenNewRoot.tsx b/src/feature/root/components/ScreenNewRoot.tsx new file mode 100644 index 00000000..a8d9b308 --- /dev/null +++ b/src/feature/root/components/ScreenNewRoot.tsx @@ -0,0 +1,37 @@ +'use client'; + +import { useCheckAuth } from '@/global/hooks/useCheckAuth'; +import { useEffect, useState } from 'react'; +import FlashRending from './FlashRending'; +import { RendingBody } from './RendingBody'; + +const ScreenNewRoot = () => { + const { isAuthed } = useCheckAuth(); + const [showSplash, setShowSplash] = useState(true); + + console.log('ScreenNewRoot - isAuthed:', isAuthed, 'showSplash:', showSplash); + + // 비로그인 상태일 때만 2초 후 스플래시 숨김 + useEffect(() => { + if (isAuthed === false) { + const timer = setTimeout(() => { + setShowSplash(false); + }, 2000); + return () => clearTimeout(timer); + } + }, [isAuthed]); + + // 인증 확인 중이거나 비로그인 상태에서 스플래시 표시 중일 때 + if (isAuthed === null || (isAuthed === false && showSplash)) { + return ; + } + + // 로그인 상태이거나 스플래시 시간이 지난 비로그인 사용자 + return ( +
+ +
+ ); +}; + +export default ScreenNewRoot; diff --git a/src/feature/root/components/ScreenRoot.tsx b/src/feature/root/components/ScreenRoot.tsx deleted file mode 100644 index 6a653ac8..00000000 --- a/src/feature/root/components/ScreenRoot.tsx +++ /dev/null @@ -1,147 +0,0 @@ -'use client'; -import LogoHeader from '@/global/components/header/LogoHeader'; -import LongButton from '@/global/components/LongButton'; -import { GA_EVENTS } from '@/global/constants/gaEvents'; -import { useCheckAuth } from '@/global/hooks/useCheckAuth'; -import { trackGaEvent } from '@/global/utils/trackGaEvent'; -import dynamic from 'next/dynamic'; -import Image from 'next/image'; -import { useRouter } from 'next/navigation'; -import { useCallback, useEffect, useState } from 'react'; -import SelectMenu from './SelectMenu'; - -const RendingFooter = dynamic(() => import('./RendingFooter'), { ssr: false }); -const SelectedList = dynamic(() => import('./SelectedList'), { ssr: false }); -const SwipeList = dynamic(() => import('./SwipeList'), { ssr: false }); - -export default function ScreenRoot() { - const router = useRouter(); - const [selectedMenu, setSelectedMenu] = useState< - 'first' | 'second' | 'third' - >('first'); - const handleCreateAlbumClick = useCallback(() => { - if (typeof document !== 'undefined') { - document.cookie = 'entry=create-album; path=/;'; - } - - trackGaEvent(GA_EVENTS.click_login, { entry_source: 'landing_header' }); - router.push('/login'); - }, [router]); - - useCheckAuth({ onAuthed: () => router.push('/main') }); - - useEffect(() => { - trackGaEvent(GA_EVENTS.view_landing); - }, []); - - return ( -
- - - 딱 7일만 열리는 특별한
- 공유 앨범 서비스 -
- -
- 블러 배경 - 핸드폰 일러스트 -
- - - 92개 모임에서 치이이즈를 사용했어요 - - - - 삼각형 - 소개 텍스트 - 치즈 아이콘 - 치즈 아이콘 - - 일정의 마무리, -
- 사진 주고받기도 가볍고 귀엽게 -
-
- 추억을 더 소중하게 만드는 - 치이이즈의 세 가지 방법 -
-
- -
-
- -
-
- 서비스에 그대로 담긴 - 사진 찍고 나눌 때의 감정 -
- 박스 일러스트 -
- 추억할 일이 있는 모든 곳에서 - 모두 함께 치이이즈 -
- - -
- ); -} diff --git a/src/feature/root/components/RendingFooter.tsx b/src/feature/root/components/_previousRoot/RendingFooter.tsx similarity index 100% rename from src/feature/root/components/RendingFooter.tsx rename to src/feature/root/components/_previousRoot/RendingFooter.tsx diff --git a/src/feature/root/components/_previousRoot/ScreenRoot.tsx b/src/feature/root/components/_previousRoot/ScreenRoot.tsx new file mode 100644 index 00000000..42b6e2b4 --- /dev/null +++ b/src/feature/root/components/_previousRoot/ScreenRoot.tsx @@ -0,0 +1,147 @@ +// 'use client'; +// import LogoHeader from '@/global/components/header/LogoHeader'; +// import LongButton from '@/global/components/LongButton'; +// import { GA_EVENTS } from '@/global/constants/gaEvents'; +// import { useCheckAuth } from '@/global/hooks/useCheckAuth'; +// import { trackGaEvent } from '@/global/utils/trackGaEvent'; +// import dynamic from 'next/dynamic'; +// import Image from 'next/image'; +// import { useRouter } from 'next/navigation'; +// import { useCallback, useEffect, useState } from 'react'; +// import SelectMenu from './SelectMenu'; + +// const RendingFooter = dynamic(() => import('./RendingFooter'), { ssr: false }); +// const SelectedList = dynamic(() => import('./SelectedList'), { ssr: false }); +// const SwipeList = dynamic(() => import('./SwipeList'), { ssr: false }); + +// export default function ScreenRoot() { +// const router = useRouter(); +// const [selectedMenu, setSelectedMenu] = useState< +// 'first' | 'second' | 'third' +// >('first'); +// const handleCreateAlbumClick = useCallback(() => { +// if (typeof document !== 'undefined') { +// document.cookie = 'entry=create-album; path=/;'; +// } + +// trackGaEvent(GA_EVENTS.click_login, { entry_source: 'landing_header' }); +// router.push('/login'); +// }, [router]); + +// useCheckAuth({ onAuthed: () => router.push('/main') }); + +// useEffect(() => { +// trackGaEvent(GA_EVENTS.view_landing); +// }, []); + +// return ( +//
+// +// +// 딱 7일만 열리는 특별한
+// 공유 앨범 서비스 +//
+ +//
+// 블러 배경 +// 핸드폰 일러스트 +//
+ +// +// 92개 모임에서 치이이즈를 사용했어요 +// +// + +// 삼각형 +// 소개 텍스트 +// 치즈 아이콘 +// 치즈 아이콘 +// +// 일정의 마무리, +//
+// 사진 주고받기도 가볍고 귀엽게 +//
+//
+// 추억을 더 소중하게 만드는 +// 치이이즈의 세 가지 방법 +//
+//
+// +//
+//
+// +//
+//
+// 서비스에 그대로 담긴 +// 사진 찍고 나눌 때의 감정 +//
+// 박스 일러스트 +//
+// 추억할 일이 있는 모든 곳에서 +// 모두 함께 치이이즈 +//
+// +// +//
+// ); +// } diff --git a/src/feature/root/components/SelectMenu.tsx b/src/feature/root/components/_previousRoot/SelectMenu.tsx similarity index 100% rename from src/feature/root/components/SelectMenu.tsx rename to src/feature/root/components/_previousRoot/SelectMenu.tsx diff --git a/src/feature/root/components/SelectedList.tsx b/src/feature/root/components/_previousRoot/SelectedList.tsx similarity index 100% rename from src/feature/root/components/SelectedList.tsx rename to src/feature/root/components/_previousRoot/SelectedList.tsx diff --git a/src/feature/root/components/SwipeList.tsx b/src/feature/root/components/_previousRoot/SwipeList.tsx similarity index 100% rename from src/feature/root/components/SwipeList.tsx rename to src/feature/root/components/_previousRoot/SwipeList.tsx diff --git a/src/global/hooks/useCheckAuth.ts b/src/global/hooks/useCheckAuth.ts index 4c4b1541..546006b4 100644 --- a/src/global/hooks/useCheckAuth.ts +++ b/src/global/hooks/useCheckAuth.ts @@ -47,11 +47,18 @@ export function useCheckAuth({ } // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (err: any) { + console.log('err 타입', err); if (cancelled) return; const status = err?.response?.status; + const code = err?.code; - if (status === 401) { + // 401 에러 또는 refresh token 없음 에러 처리 + if ( + status === 401 || + code === 401 || + err?.message?.includes('No refresh token') + ) { setIsAuthed(false); setUserId(null); onUnauthed?.();