diff --git a/src/app/(auth)/login/LoginForm.tsx b/src/app/(auth)/login/LoginForm.tsx index 59e670e..efe9bba 100644 --- a/src/app/(auth)/login/LoginForm.tsx +++ b/src/app/(auth)/login/LoginForm.tsx @@ -48,10 +48,14 @@ export default function LoginForm() { return; } - const { user } = await response.json(); - // 소속 팀이 있으면 해당 팀 페이지로, 없으면 팀 추가 페이지로 - if (user?.teamId) { - router.push(`/${user.teamId}`); + // 로그인 API는 teamId(프로젝트 식별자 문자열)만 반환하므로 + // 실제 그룹 페이지 경로에 필요한 숫자 groupId를 얻기 위해 + // 유저 정보를 한 번 더 조회한다 + const userRes = await fetch('/api/proxy/user'); + if (userRes.ok) { + const userData = await userRes.json(); + const groupId = userData?.memberships?.[0]?.group?.id; + router.push(groupId !== undefined ? `/${groupId}` : '/addteam'); } else { router.push('/addteam'); } diff --git a/src/app/(auth)/signup/SignupForm.tsx b/src/app/(auth)/signup/SignupForm.tsx index 1bfe186..e08e023 100644 --- a/src/app/(auth)/signup/SignupForm.tsx +++ b/src/app/(auth)/signup/SignupForm.tsx @@ -133,7 +133,9 @@ export default function SignupForm() { type="button" className={styles.kakaoButton} aria-label="카카오톡으로 회원가입" - disabled + onClick={() => { + window.location.href = '/api/auth/kakao'; + }} > 카카오톡 회원가입 diff --git a/src/app/(root)/landing/components/CtaButton.tsx b/src/app/(root)/landing/components/CtaButton.tsx new file mode 100644 index 0000000..3bfbdef --- /dev/null +++ b/src/app/(root)/landing/components/CtaButton.tsx @@ -0,0 +1,41 @@ +'use client'; + +import { useRouter } from 'next/navigation'; +import { useCurrentUserQuery } from '@/shared/queries/user/useCurrentUserQuery'; +import BaseButton from '@/components/Button/base/BaseButton'; + +type CtaButtonProps = { + className?: string; +}; + +/** + * 랜딩페이지 "지금 시작하기" 버튼 + * + * 로그인 상태 분기: + * - 비로그인 → /login + * - 로그인 → /{teamId} (팀이 있는 경우) 또는 /addteam + */ +export default function CtaButton({ className }: CtaButtonProps) { + const router = useRouter(); + const { data: user, isPending } = useCurrentUserQuery({ retry: false }); + + const handleClick = () => { + if (isPending) return; + + if (!user) { + router.push('/login'); + return; + } + + // user.teamId는 프로젝트 식별자 문자열('20-1' 등)이라 팀 페이지 경로에 사용 불가 + // 실제 그룹 페이지 경로는 숫자 group.id를 사용해야 함 + const groupId = user.memberships?.[0]?.group?.id; + router.push(groupId !== undefined ? `/${groupId}` : '/addteam'); + }; + + return ( +
+ 지금 시작하기 +
+ ); +} diff --git a/src/app/(root)/landing/components/CtaSection/CtaSection.tsx b/src/app/(root)/landing/components/CtaSection/CtaSection.tsx index 66279f2..578c14e 100644 --- a/src/app/(root)/landing/components/CtaSection/CtaSection.tsx +++ b/src/app/(root)/landing/components/CtaSection/CtaSection.tsx @@ -1,6 +1,4 @@ -import Link from 'next/link'; - -import BaseButton from '@/components/Button/base/BaseButton'; +import CtaButton from '../CtaButton'; import styles from './CtaSection.module.css'; export default function CtaSection() { @@ -9,9 +7,7 @@ export default function CtaSection() {

지금 바로 시작해보세요

팀원 모두와 같은 방향, 같은 속도로 나아가는 가장 쉬운 방법

- - 지금 시작하기 - +
); diff --git a/src/app/(root)/landing/components/HeroSection/HeroSection.tsx b/src/app/(root)/landing/components/HeroSection/HeroSection.tsx index 7aa8dfb..16d3a5e 100644 --- a/src/app/(root)/landing/components/HeroSection/HeroSection.tsx +++ b/src/app/(root)/landing/components/HeroSection/HeroSection.tsx @@ -1,7 +1,6 @@ import Image from 'next/image'; -import Link from 'next/link'; -import BaseButton from '@/components/Button/base/BaseButton'; +import CtaButton from '../CtaButton'; import gradationLogo from '@/assets/icons/landing/gradation_logo.svg'; import landingPC01 from '@/assets/img/landing/pc/landingPC_01.svg'; import landingTablet01 from '@/assets/img/landing/tablet/landingTablet_01.svg'; @@ -29,9 +28,7 @@ export default function HeroSection() { - - 지금 시작하기 - + {/* diff --git a/src/app/(root)/layout.tsx b/src/app/(root)/layout.tsx index e32fcef..9ce682c 100644 --- a/src/app/(root)/layout.tsx +++ b/src/app/(root)/layout.tsx @@ -2,7 +2,7 @@ import Image from 'next/image'; import { usePathname, useRouter } from 'next/navigation'; -import { useCurrentUser } from '@/hooks/useCurrentUser'; +import { useCurrentUserQuery } from '@/shared/queries/user/useCurrentUserQuery'; import { Sidebar, MobileHeader } from '@/components/sidebar'; import TeamSidebarDropdown from './[teamid]/_domain/components/Team/TeamSidebarDropdown'; import humanBig from '@/assets/buttons/human/humanBig.svg'; @@ -11,12 +11,12 @@ import styles from './layout.module.css'; export default function RootLayout({ children }: { children: React.ReactNode }) { const pathname = usePathname(); const router = useRouter(); - const { data: user, isPending } = useCurrentUser(); + const { data: user, isPending } = useCurrentUserQuery({ retry: false }); - // isPending: 최초 로딩 중 (undefined) - // user === null: 로딩 완료 후 비로그인 - // user !== null: 로그인 - const isLoggedIn = !isPending && user !== null && user !== undefined; + // user가 존재하면 로그인, 없으면 비로그인 + // isPending 중엔도 캐시된 데이터가 있으면 user는 정의되므로 + // isPending으로 차단하지 않아 캐시 히트 시 깨박임 방지 + const isLoggedIn = !!user; const isLanding = pathname === '/'; // 자체 사이드바가 없는 페이지에서만 root layout 사이드바 표시 @@ -46,7 +46,7 @@ export default function RootLayout({ children }: { children: React.ReactNode }) isLoggedIn={isLoggedIn} onProfileClick={handleProfileClick} onLogout={handleLogout} - onLogoClick={() => router.push('/addteam')} + onLogoClick={() => router.push('/')} profileImage={ user?.image ? ( router.push('/mypage')); - const handleLogoClick = onLogoClick ?? (() => router.push('/addteam')); + const handleLogoClick = onLogoClick ?? (() => router.push('/')); useEffect(() => { if (!showProfileMenu) return; diff --git a/src/components/sidebar/Sidebar.tsx b/src/components/sidebar/Sidebar.tsx index 8967b00..dcf27a6 100644 --- a/src/components/sidebar/Sidebar.tsx +++ b/src/components/sidebar/Sidebar.tsx @@ -62,7 +62,7 @@ export default function Sidebar({ const handleLogout = onLogout ?? defaultLogout; const handleProfileClick = onProfileClick ?? (() => router.push('/mypage')); - const handleLogoClick = onLogoClick ?? (() => router.push('/addteam')); + const handleLogoClick = onLogoClick ?? (() => router.push('/')); useEffect(() => { if (!showProfileMenu) return; diff --git a/src/components/sidebar/styles/MobileHeader.module.css b/src/components/sidebar/styles/MobileHeader.module.css index f0cbe71..89eb649 100644 --- a/src/components/sidebar/styles/MobileHeader.module.css +++ b/src/components/sidebar/styles/MobileHeader.module.css @@ -7,13 +7,13 @@ background: var(--color-background-inverse); } -@media (max-width: 1199px) { +@media (max-width: 1200px) { .header { display: flex; } } -@media (min-width: 768px) and (max-width: 1199px) { +@media (min-width: 768px) and (max-width: 1200px) { .header { height: 72px; padding: 0 24px; diff --git a/src/components/sidebar/styles/Sidebar.module.css b/src/components/sidebar/styles/Sidebar.module.css index 1f5795b..47a3681 100644 --- a/src/components/sidebar/styles/Sidebar.module.css +++ b/src/components/sidebar/styles/Sidebar.module.css @@ -11,7 +11,7 @@ z-index: 50; } -@media (max-width: 1199px) { +@media (max-width: 1200px) { .sidebar { display: none; } diff --git a/src/shared/queries/user/useCurrentUserQuery.ts b/src/shared/queries/user/useCurrentUserQuery.ts index eea4b2a..84086f1 100644 --- a/src/shared/queries/user/useCurrentUserQuery.ts +++ b/src/shared/queries/user/useCurrentUserQuery.ts @@ -14,8 +14,8 @@ export function currentUserQueryOptions() { }); } -export function useCurrentUserQuery() { - return useQuery(currentUserQueryOptions()); +export function useCurrentUserQuery(options?: { retry?: boolean | number }) { + return useQuery({ ...currentUserQueryOptions(), ...options }); } export function useSuspenseCurrentUserQuery() {