diff --git a/public/sign/LeftArrowIcon.svg b/public/sign/LeftArrowIcon.svg new file mode 100644 index 0000000..bb90905 --- /dev/null +++ b/public/sign/LeftArrowIcon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/app/find/page.tsx b/src/app/find/page.tsx index 0ac763e..995965e 100644 --- a/src/app/find/page.tsx +++ b/src/app/find/page.tsx @@ -8,9 +8,6 @@ import { Suspense } from "react"; const FindPage = () => { return (
- - -
); diff --git a/src/app/globals.css b/src/app/globals.css index d7a834e..dd1aa32 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -34,3 +34,39 @@ .mySwiper .swiper-pagination-bullet-active { background-color: black; } + +.custom-container { + display: flex; + width: 100%; + flex-direction: column; + align-items: center; + min-height: calc(100vh - 100px); + overflow-y: auto; +} + +@media (max-width: 640px) { + .custom-container { + justify-content: space-between; + } +} + + +.find-container { + display: flex; + width: 100%; + flex-direction: column; + align-items: center; + overflow-y: auto; +} + +.find-inner-container { + display: flex; + flex-direction: column; +} + + +@media (max-width: 640px) { + .find-inner-container { + justify-content: space-between; + } +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 3f25e92..1d52dc8 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,19 +1,19 @@ import { Metadata } from 'next'; import './globals.css'; import localFont from 'next/font/local'; -import Gnb from '@/components/common/Gnb'; import QueryProvider from '@/providers/QueryProvider'; import IntegrateMSW from '@/mocks/IntegrateMsw'; - import Script from 'next/script'; import ModalProvider from '@/providers/ModalProvider'; import MobileFooter from '@/components/common/MobileFooter'; +import GnbWrapper from '@/components/common/GnbWrapper'; declare global { interface Window { kakao: any; } } + const pretendard = localFont({ src: '../static/fonts/PretendardVariable.woff2', display: 'swap', @@ -51,7 +51,7 @@ export default function RootLayout({ strategy="beforeInteractive" src={`//dapi.kakao.com/v2/maps/sdk.js?appkey=${process.env.NEXT_PUBLIC_MAP_KEY}&autoload=false`} /> - + {children} diff --git a/src/app/mypage/page.tsx b/src/app/mypage/page.tsx index a32166a..ef1fc56 100644 --- a/src/app/mypage/page.tsx +++ b/src/app/mypage/page.tsx @@ -14,11 +14,11 @@ const Mypage = () => { useEffect(() => { const checkLoginStatus = async () => { - const isLoggedIn = !!localStorage.getItem('access_token'); - if (!isLoggedIn) { + const accessToken = localStorage.getItem('access_token'); + if (!accessToken || accessToken === 'undefined') { router.push('/sign'); } else { - setLoading(false); + setLoading(false); } }; @@ -28,6 +28,7 @@ const Mypage = () => { const handleLogout = async () => { await logout(); setIsLoggedIn(false); + localStorage.removeItem('access_token'); // Remove access token from local storage router.push('/sign'); }; diff --git a/src/app/sign/page.tsx b/src/app/sign/page.tsx index e10f643..2a42152 100644 --- a/src/app/sign/page.tsx +++ b/src/app/sign/page.tsx @@ -8,9 +8,6 @@ import { Suspense } from "react"; const SignPage = () => { return (
- - -
); diff --git a/src/app/signup/page.tsx b/src/app/signup/page.tsx index 4d4eeb1..e40289d 100644 --- a/src/app/signup/page.tsx +++ b/src/app/signup/page.tsx @@ -1,21 +1,11 @@ 'use client'; import React, { useEffect, useState } from 'react'; -import dynamic from 'next/dynamic'; -import { finalSignup } from '@/service/auth'; - -// Step 컴포넌트들을 동적 로딩으로 사용할 경우 (필요시 사용) -// const Step1 = dynamic(() => import('@/components/signup/Step1')); -// const Step2 = dynamic(() => import('@/components/signup/Step2')); -// const Step3 = dynamic(() => import('@/components/signup/Step3')); -// const Step4 = dynamic(() => import('@/components/signup/Step4')); - import Step1 from '@/components/signup/Step1'; import Step2 from '@/components/signup/Step2'; import Step3 from '@/components/signup/Step3'; import Step4 from '@/components/signup/Step4'; -import Navbar from '@/components/common/Navbar'; -import { Suspense } from "react"; +import { finalSignup } from '@/service/auth'; const SignupPage: React.FC = () => { const [currentStep, setCurrentStep] = useState(1); @@ -32,6 +22,24 @@ const SignupPage: React.FC = () => { }>({ loginType: 'local' }); + + const [maxHeightClass, setmaxHeightClass] = useState('max-h-screen'); + + useEffect(() => { + const handleResize = () => { + if (window.innerWidth < 640) { + setmaxHeightClass('max-h-[calc(100vh-75.5px)]'); + } else { + setmaxHeightClass('max-h-screen'); + } + }; + handleResize(); + window.addEventListener('resize', handleResize); + + return () => { + window.removeEventListener('resize', handleResize); + }; + }, []); const handleNext = () => { setCurrentStep((prev) => prev + 1); @@ -41,7 +49,6 @@ const SignupPage: React.FC = () => { setFormData((prev) => { const updatedFormData = { ...prev, ...data }; - // 새로운 상태와 기존 상태를 비교해 변경 사항이 없으면 업데이트를 생략합니다. if (JSON.stringify(prev) === JSON.stringify(updatedFormData)) { return prev; } @@ -49,17 +56,11 @@ const SignupPage: React.FC = () => { return updatedFormData; }); }; - - - useEffect(() => { - console.log(formData); - }, [formData]); const handleSubmit = async () => { try { console.log('최종 제출 데이터:', formData); - // 로컬스토리지에서 access_token 가져오기 const accessToken = localStorage.getItem('access_token'); if (!accessToken) { throw new Error('Access token이 없습니다.'); @@ -78,11 +79,7 @@ const SignupPage: React.FC = () => { }; return ( -
- - - -
+
{currentStep === 1 && ( handleUpdate(data)} /> )} @@ -96,7 +93,6 @@ const SignupPage: React.FC = () => { handleUpdate(data)} /> )}
-
); }; diff --git a/src/components/common/Gnb.tsx b/src/components/common/Gnb.tsx index fd10682..20717f3 100644 --- a/src/components/common/Gnb.tsx +++ b/src/components/common/Gnb.tsx @@ -13,7 +13,8 @@ const Gnb = () => { useEffect(() => { const accessToken = localStorage.getItem('access_token'); - if (accessToken) { + + if (accessToken && accessToken !== 'undefined') { setIsLoggedIn(true); } else { setIsLoggedIn(false); @@ -53,7 +54,7 @@ const Gnb = () => { className="cursor-pointer"> alert
-
+
{isLoggedIn ? ( mypage diff --git a/src/components/common/GnbWrapper.tsx b/src/components/common/GnbWrapper.tsx new file mode 100644 index 0000000..f669e6d --- /dev/null +++ b/src/components/common/GnbWrapper.tsx @@ -0,0 +1,26 @@ +'use client'; + +import { useEffect, useState } from 'react'; +import { usePathname } from 'next/navigation'; +import Gnb from '@/components/common/Gnb'; + +const GnbWrapper = () => { + const pathname = usePathname(); + const [isGnbHidden, setIsGnbHidden] = useState(false); + + useEffect(() => { + const checkIfGnbShouldBeHidden = () => { + if (pathname === '/signup' || pathname === '/sign' || pathname === '/find' || pathname === '/login') { + setIsGnbHidden(true); + } else { + setIsGnbHidden(false); + } + }; + + checkIfGnbShouldBeHidden(); + }, [pathname]); + + return !isGnbHidden ? : null; +}; + +export default GnbWrapper; diff --git a/src/components/find/FindEmail.tsx b/src/components/find/FindEmail.tsx index 016152f..dc95027 100644 --- a/src/components/find/FindEmail.tsx +++ b/src/components/find/FindEmail.tsx @@ -121,8 +121,8 @@ const FindEmail = ({ onEmailFound }: { onEmailFound: () => void }) => { }, [isError]); return ( -
-
+
+

휴대폰 번호를
@@ -220,19 +220,21 @@ const FindEmail = ({ onEmailFound }: { onEmailFound: () => void }) => {

)}
+
+
{isComplete ? (
다음으로
) : ( -
+
다음으로
)} - +
); }; diff --git a/src/components/find/FindPassword.tsx b/src/components/find/FindPassword.tsx index b3c69ca..2220e3b 100644 --- a/src/components/find/FindPassword.tsx +++ b/src/components/find/FindPassword.tsx @@ -5,8 +5,8 @@ const FindPassword = () => { const [email, setEmail] = useState(''); return ( -
-
+
+

가입하신
@@ -25,16 +25,17 @@ const FindPassword = () => { className="w-full mt-2 px-4 py-[14px] bg-bg rounded-[12px] outline-none text-body2 " />

- +
+
-
+
); }; -export default FindPassword; +export default FindPassword; \ No newline at end of file diff --git a/src/components/find/FindTabs.tsx b/src/components/find/FindTabs.tsx index 5a25fd5..7b28d17 100644 --- a/src/components/find/FindTabs.tsx +++ b/src/components/find/FindTabs.tsx @@ -1,9 +1,10 @@ 'use client'; -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import FindEmail from './FindEmail'; import ShowEmailInfo from './ShowEmailInfo'; import FindPassword from './FindPassword'; +import Image from 'next/image'; const FindTabs = () => { const [activeTab, setActiveTab] = useState('email'); @@ -17,11 +18,40 @@ const FindTabs = () => { setShowEmailInfo(true); }; + const [maxHeightClass, setmaxHeightClass] = useState('max-h-screen'); + + useEffect(() => { + const handleResize = () => { + if (window.innerWidth < 640) { + setmaxHeightClass('max-h-[calc(100vh-75.5px)]'); + } else { + setmaxHeightClass('max-h-screen'); + } + }; + handleResize(); + window.addEventListener('resize', handleResize); + + return () => { + window.removeEventListener('resize', handleResize); + }; + }, []); + return ( -
+
{!showEmailInfo ? ( <> -
+
+
+
+ 뒤로가기 +
+
+
handleTabClick('email')} @@ -40,6 +70,7 @@ const FindTabs = () => { {activeTab === 'email' && } {activeTab === 'password' && }
+
) : ( diff --git a/src/components/find/ShowEmailInfo.tsx b/src/components/find/ShowEmailInfo.tsx index 6326332..47bd940 100644 --- a/src/components/find/ShowEmailInfo.tsx +++ b/src/components/find/ShowEmailInfo.tsx @@ -3,18 +3,18 @@ import React from 'react'; const ShowEmailInfo = () => { return ( -
-
-

- 가입하신
- 이메일 정보입니다 -

-
-
Moaguide@gmail.com
- - +
+
+

+ 가입하신
+ 이메일 정보입니다 +

+
+
Moaguide@gmail.com
+ +
); diff --git a/src/components/sign/SignLayout.tsx b/src/components/sign/SignLayout.tsx index a68c6ad..79415d5 100644 --- a/src/components/sign/SignLayout.tsx +++ b/src/components/sign/SignLayout.tsx @@ -22,11 +22,11 @@ const SignLayout = () => { }; return ( -
- -
- logo +
+
+ + logo +
@@ -61,13 +61,13 @@ const SignLayout = () => {
{errorMessage && ( -
+
{errorMessage}
)}
+ + {activePage === 'privacy' && } {activePage === 'service' && } {activePage === 'age' && } diff --git a/src/components/signup/Step3.tsx b/src/components/signup/Step3.tsx index 128cd99..362c725 100644 --- a/src/components/signup/Step3.tsx +++ b/src/components/signup/Step3.tsx @@ -1,4 +1,5 @@ import Image from 'next/image'; +import { useRouter } from 'next/navigation'; import React, { useState } from 'react'; interface StepProps { @@ -13,6 +14,8 @@ const Step3: React.FC = ({ onNext, onUpdate }) => { const [passwordValid, setPasswordValid] = useState(null); const [passwordMatch, setPasswordMatch] = useState(null); + const router = useRouter(); + const validatePassword = (password: string) => { const isValid = /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[!@#$%^&*])[A-Za-z\d!@#$%^&*]{8,20}$/.test(password); setPasswordValid(isValid); @@ -37,10 +40,18 @@ const Step3: React.FC = ({ onNext, onUpdate }) => { const isFormValid = email && passwordValid && passwordMatch; return ( -
-
+
+
+ 뒤로가기 router.back()} + /> ProgressBar = ({ onNext, onUpdate }) => { )}
-
+
비밀번호 확인
= ({ onNext, onUpdate }) => { )}
+
-
); }; diff --git a/src/components/signup/Step4.tsx b/src/components/signup/Step4.tsx index ac3206a..51d5d77 100644 --- a/src/components/signup/Step4.tsx +++ b/src/components/signup/Step4.tsx @@ -2,6 +2,7 @@ import React, { useState, useEffect, useCallback } from 'react'; import { useRouter } from 'next/navigation'; import { checkNicknameAvailability } from '@/service/auth'; import { formatBirthDate } from '@/utils/dateUtils'; +import Image from 'next/image'; interface StepProps { onNext: () => void; @@ -91,13 +92,27 @@ const Step4: React.FC = ({ onNext, onUpdate }) => { }; return ( -
-
- ProgressBar +
+
+ 뒤로가기 router.back()} + /> + ProgressBar

모아가이드에서 사용할
상세정보를 입력해주세요

-
+
닉네임
= ({ onNext, onUpdate }) => { />
-
+
생년월일
= ({ onNext, onUpdate }) => {
)} +
-
+
); }; diff --git a/src/components/signup/modal/PhoneVerification.tsx b/src/components/signup/modal/PhoneVerification.tsx index e324699..2a40de2 100644 --- a/src/components/signup/modal/PhoneVerification.tsx +++ b/src/components/signup/modal/PhoneVerification.tsx @@ -2,6 +2,7 @@ import React, { ChangeEvent, useEffect, useRef, useState } from 'react'; import { sendVerificationCode, verifyCode } from '@/service/auth'; import Image from 'next/image'; import { validNumberToTime } from '@/utils/validNumberToTime'; +import { useRouter } from 'next/navigation'; interface PhoneVerificationProps { onNext: () => void; @@ -19,6 +20,8 @@ const PhoneVerification: React.FC = ({ onNext, onPhoneNu const [validTime, setValidTime] = useState(300); // 인증 시간 const inputRef = useRef(null); + const router = useRouter(); + const handlePhoneNumberChange = (e: ChangeEvent) => { const regex = e.target.value .replace(/[^0-9]/g, '') @@ -35,7 +38,8 @@ const PhoneVerification: React.FC = ({ onNext, onPhoneNu const handleRequest = async () => { try { - const data = await sendVerificationCode(phoneNumber); + const plainPhoneNumber = phoneNumber.replace(/-/g, ''); + const data = await sendVerificationCode(plainPhoneNumber); console.log('인증 요청 성공:', data); setIsRequest(true); // 요청 상태 true setValidTime(300); // 인증 요청 시 타이머 초기화 @@ -48,7 +52,8 @@ const PhoneVerification: React.FC = ({ onNext, onPhoneNu const handleResending = async () => { if (isComplete) return; try { - const data = await sendVerificationCode(phoneNumber); + const plainPhoneNumber = phoneNumber.replace(/-/g, ''); + const data = await sendVerificationCode(plainPhoneNumber); console.log('인증 재요청 성공:', data); setValidNumber(''); inputRef.current?.focus(); @@ -62,7 +67,8 @@ const PhoneVerification: React.FC = ({ onNext, onPhoneNu const handleCertify = async () => { if (isComplete) return; // 이미 인증 완료된 상태면 return try { - const data = await verifyCode(phoneNumber, validNumber); + const plainPhoneNumber = phoneNumber.replace(/-/g, ''); + const data = await verifyCode(plainPhoneNumber, validNumber); console.log('인증 완료:', data); setIsComplete(true); // 인증 검사 통과 setIsError(false); @@ -127,10 +133,18 @@ const PhoneVerification: React.FC = ({ onNext, onPhoneNu }, [isError]); return ( -
-
+
+
+ 뒤로가기 router.back()} + /> ProgressBar = ({ onNext, onPhoneNu
)}
+
{isComplete ? (
다음으로
) : ( -
+
다음으로
)} -
); }; diff --git a/src/service/auth.ts b/src/service/auth.ts index fdf85e8..bfe293c 100644 --- a/src/service/auth.ts +++ b/src/service/auth.ts @@ -15,8 +15,7 @@ export const verifyCode = async (phone: string, code: string): Promise