Skip to content
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
01c0e5f
[Chore/#173]: asset 추가
SebellKo Jun 6, 2025
528d6e3
[Style/#173]: non active circle 색상 변경
SebellKo Jun 6, 2025
c2472e0
[Style/#173]: 온보딩 ui 변경
SebellKo Jun 6, 2025
0dcf5a6
[Style/#173]: se 디바이스 ui 디자인 수정
SebellKo Jun 7, 2025
9e08f07
[Style/#185]: 버튼 extraClass props 추가
SebellKo Jun 7, 2025
a914672
[Feat/#185]: 구글 인가 코드 get 구현
SebellKo Jun 7, 2025
346a772
[Chore/#185]: api 패키지 버전 업데이트
SebellKo Jun 10, 2025
1be5606
[Chore/#185]: 구글 로그인 구현중
SebellKo Jun 10, 2025
a31f29b
[Feat/#185]: 회원 가입 완료 페이지 ui 수정
SebellKo Jun 13, 2025
da83e3a
[Feat/#185]: 비밀번호 확인 인풋 삭제
SebellKo Jun 13, 2025
9d7c990
[Style/#185]: 회원 정보 페이지 ui 수정
SebellKo Jun 13, 2025
f543ca0
[Feat/#185]: 회원정보 가입완료 버튼 유효성 검사 추가
SebellKo Jun 13, 2025
0d3338f
[Feat/#185]: 회원가입인 경우 닉네임 인풋 제거
SebellKo Jun 13, 2025
7565528
[Feat/#185]: 비로그인 접근 불가 페이지 경로 추가
SebellKo Jun 13, 2025
4785042
[Chore.#185]: frolog api 패키지 업데이트
SebellKo Jun 19, 2025
3ffa49b
[Feat/#185]: 회원가입 폼 타입 username, passwordCheck 삭제
SebellKo Jun 19, 2025
947abdf
[Feat/#185]: username 삭제, pqssword 값 변경
SebellKo Jun 19, 2025
c358012
[Fix/#185]: 이메일 로그인 클릭시 로그인 페이지로 이동
SebellKo Jun 19, 2025
dfc7757
[Chore/#185]: 목 api 응답값 수정
SebellKo Jun 19, 2025
b8573e3
[Fix/#185]: validation 오류 해결
SebellKo Jun 23, 2025
09c625c
[Chore/#185]: wip
SebellKo Jul 13, 2025
f5ffcec
[Chore/#185]: 회원가입 완료 페이지 protect 제거
SebellKo Jul 20, 2025
4861c5f
[Chore/#185]: 회원가입 완료 페이지 ui 디자인 수정
SebellKo Jul 20, 2025
3ac3e78
[Chore/#185]: api 버전 업데이트
SebellKo Jul 28, 2025
a7e6efc
[Feat/#185]: 구글 회원가입 -> 로그인 구현
SebellKo Jul 28, 2025
f51ad81
[Chore/#185]: 미사용 콘솔 제거
SebellKo Jul 28, 2025
43e628b
[Feat/#185]: 이메일 가입 유저 분기
SebellKo Jul 29, 2025
fea6663
[Fix/#185]: 회원가입후 페이지 전환
SebellKo Jul 29, 2025
305ae66
[Chore/#185]: 미사용 mock 제거
SebellKo Aug 3, 2025
2d342bb
[Chore/#185]: 미사용 주석 제거
SebellKo Aug 3, 2025
fba1da2
[Chore/#185]: 에러 처리 및 미사용 콘솔 제거
SebellKo Aug 3, 2025
15fc895
[Chore/#185]: 빌드에러 해결
SebellKo Aug 4, 2025
b067b27
[Chore/#185]: 미사용 콘솔 제거
SebellKo Aug 4, 2025
3e8b04d
Merge branch 'dev' into feat/#185
SebellKo Aug 4, 2025
15244b9
Merge branch 'dev' into feat/#185
SebellKo Aug 4, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"prepare": "husky"
},
"dependencies": {
"@frolog/frolog-api": "^1.3.1",
"@frolog/frolog-api": "^1.4.0-dev.3",
"@sentry/nextjs": "^8.35.0",
"@svgr/webpack": "^8.1.0",
"@tanstack/react-query": "^5.40.1",
Expand Down
5 changes: 5 additions & 0 deletions public/images/flash/light-bg-onboarding.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
72 changes: 72 additions & 0 deletions public/images/onBoarding/slide-1-se.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
151 changes: 98 additions & 53 deletions public/images/onBoarding/slide-1.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
144 changes: 12 additions & 132 deletions public/images/onBoarding/slide-2.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
295 changes: 132 additions & 163 deletions public/images/onBoarding/slide-3.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 0 additions & 9 deletions public/images/onBoarding/slide-4.svg

This file was deleted.

14 changes: 14 additions & 0 deletions public/logo/sns/google.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion public/sw.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion public/sw.js.map

Large diffs are not rendered by default.

11 changes: 6 additions & 5 deletions src/app/(default)/join/finish/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@ import Image from 'next/image';
import PopperAnimation from '@/components/animation/PopperAnimation';
import QuitButton from '@/components/Button/QuitButton';
import { IMAGES } from '@/constants/images';
import { TestStartButton, FinishLight } from '@/features/Join';
import { FinishLight } from '@/features/Join';
import { PAGES } from '@/constants/page';
import LinkButton from '@/components/Button/LinkButton';

function JoinFinishPage() {
return (
<div className='safe-screen relative flex w-full flex-col justify-between overflow-hidden'>
<FinishLight frog={IMAGES.flash.congrats}>
야호!
<br />
가입이
<br />
완료되었어요
Expand All @@ -21,7 +20,7 @@ function JoinFinishPage() {
route={PAGES.HOME}
classes='absolute left-[24px] top-[24px] z-100 cursor-pointer'
/>
<div className='flex-col-center w-full justify-end gap-[12px]'>
<div>
<Image
src={IMAGES.ground}
alt='ground'
Expand All @@ -30,7 +29,9 @@ function JoinFinishPage() {
className='w-full [@media(max-width:350px)]:h-[200px]'
loading='eager'
/>
<TestStartButton />
<div className='absolute bottom-5 left-0 flex w-full p-page'>
<LinkButton route={PAGES.HOME}>프롤로그 입장하기</LinkButton>
</div>
</div>
<PopperAnimation />
</div>
Expand Down
64 changes: 54 additions & 10 deletions src/app/(default)/onboarding/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,49 @@

/* eslint-disable react/no-array-index-key */

import LinkButton from '@/components/Button/LinkButton';
import Button from '@/components/Button/Button';
import OnBoardingSlide from '@/components/OnBoarding/OnBoardingSlide';
import { PAGES } from '@/constants/page';
import Link from 'next/link';
import React, { useState } from 'react';
import React, { useEffect, useState } from 'react';
import GoogleIcon from 'public/logo/sns/google.svg';
import { useGoogle } from '@/features/Join/hooks/useGoogle';
import { AnimatePresence } from 'framer-motion';
import ErrorToast from '@/components/Toast/ErrorToast';

function OnBoardingPage() {
const [activeSlide, setActiveSlide] = useState<number>(1);
const { handleGoogleSignIn, isRegistered } = useGoogle();

const handleGoogleAuth = async (code: string) => {
handleGoogleSignIn({ authorization_code: code });
};

useEffect(() => {
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get('code');

if (code) {
handleGoogleAuth(code);
}
}, []);
Comment on lines +19 to +30
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기서만 사용되는데 handleGoogleAuth라고 한번 더 감싸야 하는 이유가 있나요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그렇긴 하네요 바로 handleGoogleSignIn 해도 될듯


const handleClickGoogleLogin = () => {
const clientId = process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID;
const redirectUri = process.env.NEXT_PUBLIC_GOOGLE_REDIRECT_URI;

const googleLoginUrl = `https://accounts.google.com/o/oauth2/v2/auth?client_id=${clientId}&redirect_uri=${redirectUri}&response_type=code&scope=email profile`;
window.location.href = googleLoginUrl;
};

return (
<div className='safe-screen safe-bottom safe-header flex h-full min-h-[650px] w-full flex-col bg-gray-900'>
<div className='safe-screen safe-bottom safe-header flex h-[100dvh] w-full flex-col bg-gray-900'>
<OnBoardingSlide setActiveSlide={setActiveSlide} />
<div className='flex w-full shrink-0 flex-col items-center gap-[20px] px-page py-[32px] pt-[12px] transition-all duration-200'>
<div
className={`flex h-[22dvh] w-full flex-col items-center gap-[20px] ${activeSlide === 1 ? 'bg-category-bg-science' : 'bg-gray-300'} px-page py-[32px] pt-[12px] transition-all duration-200 [@media(max-height:750px)]:h-[25dvh]`}
>
<div className='flex gap-[8px]'>
{Array(4)
{Array(3)
.fill(0)
.map((_, i) => (
<div
Expand All @@ -27,14 +55,30 @@ function OnBoardingPage() {
/>
))}
</div>
<LinkButton disabled={false} route={PAGES.LOGIN}>
로그인 하기
</LinkButton>
<Button
disabled={false}
theme='light'
onClick={handleClickGoogleLogin}
extraClass='relative text-gray-800 text-body-lg-bold'
>
<GoogleIcon className='absolute left-5 top-1/2 -translate-y-1/2' />
Google로 로그인
</Button>
<div className='flex justify-center'>
<Link href={PAGES.JOIN} className='text-body-lg-bold text-main'>
30초만에 회원가입 하기
<Link
href={PAGES.LOGIN}
className={`text-body-lg ${activeSlide === 1 ? 'text-white' : 'text-gray-600'}`}
>
이메일로 로그인
</Link>
</div>
<div className='flex-col-center absolute bottom-0 w-full gap-[12px] pb-[24px]'>
<AnimatePresence>
{isRegistered && (
<ErrorToast errorMsg='이메일 로그인으로 가입된 메일이에요' />
)}
</AnimatePresence>
</div>
</div>
</div>
);
Expand Down
7 changes: 5 additions & 2 deletions src/app/(form)/join/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { JoinForm } from '@/features/Join';
import { Metadata } from 'next';
import GoogleJoinForm from '@/features/Join/components/GoogleJoinForm';

export const metadata: Metadata = {
title: '회원가입',
Expand All @@ -12,8 +13,10 @@ export const metadata: Metadata = {
},
};

function JoinPage() {
return <JoinForm />;
function JoinPage({ searchParams }: { searchParams: { type: string } }) {
const { type } = searchParams;

return type === 'google' ? <GoogleJoinForm /> : <JoinForm />;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

구글 로그인은 회원가입 플로우가 단축돼서 별도 컴포넌트로 만들었어요

}

export default JoinPage;
14 changes: 14 additions & 0 deletions src/app/api/mock/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// import { NextRequest } from 'next/server';
// import { NextResponse } from 'next/server';

// export async function POST(request: NextRequest) {
// const { authorization_code } = await request.json();
// return NextResponse.json({
// result: false,
// email: 'test@test.com',
// is_registerd: false,
// login_type: null,
// email_verified_token:
// 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImZ1bGZpbGxlZDc0MThAZ21haWwuY29tIiwidGFyZ2V0Ijoic2lnblVwIiwiaWF0IjoxNzUwMzQzNjI2LCJleHAiOjE3NTA0MzAwMjYsInN1YiI6InZlcmlmeUVtYWlsQ29kZSJ9.WDfsAF3npSC3NKkOSOjmtkKazGIY4gfneFxz6zs2-qE',
// });
// }
4 changes: 3 additions & 1 deletion src/components/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { getButtonColor } from '@/utils/getButtonColor';
interface Props extends HTMLMotionProps<'button'> {
children: React.ReactNode;
theme?: 'normal' | 'error' | 'gray' | 'light' | string;
extraClass?: string;
}

/** 기본 버튼 컴포넌트
Expand All @@ -18,6 +19,7 @@ function Button({
type = 'button',
disabled = false,
theme = 'normal',
extraClass,
...props
}: Props) {
const buttonType = getButtonColor(theme);
Expand All @@ -26,7 +28,7 @@ function Button({
<motion.button
type={type}
disabled={disabled}
className={`${disabled ? 'button-disabled' : ''} ${buttonType}`}
className={`${disabled ? 'button-disabled' : ''} ${buttonType} ${extraClass}`}
variants={tapVariants}
whileTap='tap'
{...props}
Expand Down
24 changes: 0 additions & 24 deletions src/components/Form/Password/PasswordForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ function PasswordForm() {
const {
register,
trigger,
watch,
formState: { errors },
} = useFormContext();

Expand All @@ -31,29 +30,6 @@ function PasswordForm() {
if (errors.password) {
trigger('password');
}
await trigger('passwordCheck');
},
})}
/>
<FormInput
type='password'
placeholder='비밀번호를 재입력하세요'
fieldName='passwordCheck'
errorMessage={
errors.passwordCheck && String(errors.passwordCheck.message)
}
{...register('passwordCheck', {
validate: {
matches: (value: string) =>
value.length === 0 ||
value === watch('password') ||
'비밀번호가 일치하지 않아요.',
},
onChange: async (e) => {
const { value } = e.target;
if (value.length > 0) {
await trigger('passwordCheck');
}
},
})}
/>
Expand Down
82 changes: 30 additions & 52 deletions src/components/OnBoarding/OnBoardingSlide.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Slider, { Settings } from 'react-slick';
import Slide1 from 'public/images/onBoarding/slide-1.svg';
import Slide2 from 'public/images/onBoarding/slide-2.svg';
import Slide3 from 'public/images/onBoarding/slide-3.svg';
import Slide4 from 'public/images/onBoarding/slide-4.svg';
import LightBg from 'public/images/flash/light-bg-onboarding.svg';
import BackButton from '../Button/BackButton';

interface Props {
Expand All @@ -23,73 +23,51 @@ function OnBoardingSlide({ setActiveSlide }: Props) {
slidesToShow: 1,
slidesToScroll: 1,
autoplay: false,
adaptiveHeight: true,
beforeChange: (_, next) => {
setActiveSlide(next + 1);
},
};

return (
<div className='flex flex-1 shrink flex-col gap-[20px] bg-gray-900 pt-[24px] transition-all duration-200 mobile:gap-[12px] [@media(max-height:820px)]:gap-[12px]'>
<div className='flex flex-col gap-[20px] bg-gray-900 pt-[24px] transition-all duration-200'>
<BackButton
fill='#B3B6C4'
onClick={() => router.back()}
extraClass='px-page'
/>
<Slider {...settings} className='flex flex-1 shrink'>
<div className='flex h-full w-full flex-1 shrink flex-col justify-between'>
<div className='flex h-full flex-col pb-[20px]'>
<h1 className='px-page text-heading-md-bold text-main_hightlight mobile:text-title-xl-bold [@media(max-height:700px)]:text-title-xl-bold'>
{onBoarding[1].title()}
</h1>
<div className='flex w-full flex-1 flex-col-reverse'>
<Slide1
className='h-auto w-full self-end'
width={390}
height={302}
/>
</div>
<Slider {...settings} className='w-full'>
<div className='relative !flex h-[calc(80dvh-54px)] flex-col [@media(max-height:750px)]:h-[calc(75dvh-54px)]'>
<h1 className='absolute left-1/2 top-[18%] z-50 -translate-x-1/2 text-center text-title-xl-bold text-gray-900 [@media(max-width:375px)]:text-title-lg-bold'>
{onBoarding[1].title()}
</h1>
<div className='w-full translate-y-[2px] [@media(max-height:670px)]:translate-y-[3px]'>
<LightBg />
</div>
</div>
<div className='flex h-full w-full flex-1 shrink flex-col justify-between px-page'>
<div className='flex h-full w-full flex-1 flex-col gap-[20px] pb-[20px]'>
<h1 className='text-heading-md-bold text-main_hightlight mobile:text-title-xl-bold [@media(max-height:700px)]:text-title-xl-bold'>
{onBoarding[2].title()}
</h1>
<div className='flex flex-1 flex-col-reverse items-center'>
<Slide2
className='h-full max-h-[337px] w-auto max-w-full self-center [@media(max-height:670px)]:w-[90%]'
width={342}
height={337}
/>
</div>
<div className='flex flex-1 translate-y-[1px] flex-col justify-end bg-gray-300 [@media(max-height:670px)]:translate-y-[2px]'>
<Slide1 className='h-auto w-full' />
</div>
</div>
<div className='flex h-full w-full flex-1 shrink flex-col justify-between px-page'>
<div className='flex h-full w-full flex-1 flex-col gap-[20px] pb-[20px]'>
<h1 className='text-heading-md-bold text-main_hightlight mobile:text-title-xl-bold [@media(max-height:700px)]:text-title-xl-bold'>
{onBoarding[3].title()}
</h1>
<div className='flex flex-1 flex-col-reverse items-center'>
<Slide3
className='h-full max-h-[352px] w-auto max-w-full self-center [@media(max-height:670px)]:w-[90%]'
width={342}
height={352}
/>
</div>
<div className='relative !flex h-[calc(80dvh-54px)] flex-col [@media(max-height:750px)]:h-[calc(75dvh-54px)]'>
<h1 className='absolute left-1/2 top-[18%] z-50 -translate-x-1/2 text-center text-title-xl-bold text-gray-900 [@media(max-width:375px)]:text-title-lg-bold'>
{onBoarding[2].title()}
</h1>
<div className='w-full translate-y-[2px]'>
<LightBg />
</div>
<div className='jutify-center flex flex-1 translate-y-[1px] flex-col bg-gray-300 px-page'>
<Slide2 className='my-auto h-auto w-full' />
</div>
</div>
<div className='flex h-full w-full flex-1 shrink flex-col justify-between px-page'>
<div className='flex h-full w-full flex-1 flex-col gap-[20px]'>
<h1 className='text-heading-md-bold text-main_hightlight mobile:text-title-xl-bold [@media(max-height:700px)]:text-title-xl-bold'>
{onBoarding[4].title()}
</h1>
<div className='flex flex-1 flex-col-reverse items-center'>
<Slide4
className='h-full max-h-[389px] w-auto max-w-full self-center [@media(max-height:670px)]:w-[90%]'
width={362}
height={389}
/>
</div>
<div className='relative !flex h-[calc(80dvh-54px)] flex-col [@media(max-height:750px)]:h-[calc(75dvh-54px)]'>
<h1 className='absolute left-1/2 top-[18%] z-50 w-[25dvw] -translate-x-1/2 text-center text-title-xl-bold text-gray-900 mobile:w-[70dvw] [@media(max-width:375px)]:text-title-lg-bold'>
{onBoarding[3].title()}
</h1>
<div className='w-full translate-y-[2px]'>
<LightBg />
</div>
<div className='jutify-center flex flex-1 translate-y-[1px] flex-col bg-gray-300 px-page'>
<Slide3 className='my-auto h-auto w-full [@media(max-height:670px)]:mx-auto [@media(max-height:670px)]:w-[230px]' />
</div>
</div>
</Slider>
Expand Down
Loading