diff --git a/src/atoms/userState.tsx b/src/atoms/userState.tsx new file mode 100644 index 0000000..0449e5d --- /dev/null +++ b/src/atoms/userState.tsx @@ -0,0 +1,23 @@ +import { useEffect } from 'react'; +import Cookies from 'js-cookie'; +import { atom, useRecoilState } from 'recoil'; + +const isLoginData = atom({ + key: 'loginState', + default: false, +}); + +const useLoginState = () => { + const [isLogin, setLogin] = useRecoilState(isLoginData); + + useEffect(() => { + const hasAccessToken = Boolean(Cookies.get('AccessToken')); + setLogin(hasAccessToken); + }, []); + + return { + isLogin, + }; +}; + +export { useLoginState }; diff --git a/src/components/authMail/AuthCodeForm.tsx b/src/components/authMail/AuthCodeForm.tsx index 7b0a431..f863f22 100644 --- a/src/components/authMail/AuthCodeForm.tsx +++ b/src/components/authMail/AuthCodeForm.tsx @@ -1,9 +1,10 @@ import React, { useEffect } from 'react'; -import { Input } from '@/components/base'; +import { Input, Modal } from '@/components/base'; import { InputsWrapper, StyledButton, ErrorMessage } from '@/pages/AuthMail'; import useForm, { InitialValues } from '@/hooks/common/useForm'; import useCountdown from '@/hooks/common/useCountdown'; import styled from 'styled-components'; +import { useToggle } from '@/hooks/common'; interface AuthCodeFormProps { email: string; @@ -12,6 +13,7 @@ interface AuthCodeFormProps { const AuthCodeForm = ({ email, onCheckAuthCode }: AuthCodeFormProps) => { const { minutes, seconds, setTarget } = useCountdown(0); + const [isErrorModal, onToggleErrorModal] = useToggle(); const { values, errors, handleSubmit, handleChange } = useForm({ initialValues: { email, @@ -22,7 +24,7 @@ const AuthCodeForm = ({ email, onCheckAuthCode }: AuthCodeFormProps) => { console.log('try submit authCode'); onCheckAuthCode(values.authCode); } catch (e) { - console.error('Modal 띄워야 할 듯'); + onToggleErrorModal(); } }, validate: () => { @@ -45,18 +47,33 @@ const AuthCodeForm = ({ email, onCheckAuthCode }: AuthCodeFormProps) => { }, [email]); return ( -
- - - {errors.email && {errors.email}} - 확인 - {email && ( - - {minutes}:{seconds} - - )} - -
+ <> +
+ + + {errors.email && {errors.email}} + 확인 + {email && ( + + {minutes}:{seconds} + + )} + +
+ {isErrorModal && ( + { + void 0; + }} + /> + )} + ); }; diff --git a/src/components/authMail/EmailForm.tsx b/src/components/authMail/EmailForm.tsx index a8a52b9..12add33 100644 --- a/src/components/authMail/EmailForm.tsx +++ b/src/components/authMail/EmailForm.tsx @@ -1,8 +1,9 @@ import React, { useState } from 'react'; -import { Input } from '@/components/base'; +import { Input, Modal } from '@/components/base'; import { InputsWrapper, StyledButton, ErrorMessage } from '@/pages/AuthMail'; import useForm, { InitialValues } from '@/hooks/common/useForm'; import { checkForm } from '@/utils/validations'; +import { useToggle } from '@/hooks/common'; interface EmailFormProps { onSubmitAuthCode: (email: string) => void; @@ -10,6 +11,7 @@ interface EmailFormProps { const EmailForm = ({ onSubmitAuthCode }: EmailFormProps) => { const [onFocus, setFocus] = useState(true); + const [isErrorModal, onToggleErrorModal] = useToggle(); const { values, errors, handleSubmit, handleChange } = useForm({ initialValues: { email: '', @@ -17,12 +19,11 @@ const EmailForm = ({ onSubmitAuthCode }: EmailFormProps) => { onSubmit: async () => { try { if (values.email) { - console.log('try'); onSubmitAuthCode(values.email); setFocus(false); } } catch (e) { - console.error('Modal 띄워야 할 듯'); + onToggleErrorModal(); } }, validate: ({ email }) => { @@ -37,13 +38,28 @@ const EmailForm = ({ onSubmitAuthCode }: EmailFormProps) => { }); return ( -
- - - {errors.email && {errors.email}} - 인증번호 보내기 - -
+ <> +
+ + + {errors.email && {errors.email}} + 인증번호 보내기 + +
+ {isErrorModal && ( + { + void 0; + }} + /> + )} + ); }; diff --git a/src/components/domain/landing/LandingContainer.tsx b/src/components/domain/landing/LandingContainer.tsx index bf6f490..b53690f 100644 --- a/src/components/domain/landing/LandingContainer.tsx +++ b/src/components/domain/landing/LandingContainer.tsx @@ -1,42 +1,27 @@ +import React from 'react'; import { StringLogo, RadiousLogo } from '@/assets/img'; import { Button, Modal } from '@/components/base'; import useToggle from '@/hooks/common/useToggle'; import { palette } from '@/lib/styles/palette'; -import React, { useState } from 'react'; import styled from 'styled-components'; import { useNavigate } from 'react-router-dom'; +import { useLoginState } from '@/atoms/userState'; function LandingContainer() { - /** - * 로그인 되었는지 안되었는지는 나중에 리코일에서 꺼내기 - */ - const [isLogin, setIsLogin] = useState(false); // FIXME: 임시 콘텐츠 연결을 위한 처리 const [isModal, onToggleModal] = useToggle(); const navigate = useNavigate(); + const { isLogin } = useLoginState(); const handleKakaoLoginClick = () => { const clientId = import.meta.env.VITE_KAKAO_JAVASCRIPT_KEY; const redirectUri = encodeURI(`${window.location.origin}/oauth/kakao`); const loginUrl = import.meta.env.VITE_KAKAO_OPEN_URL.replace('{clientId}', clientId).replace('{redirectUri}', redirectUri); window.location.href = loginUrl; - - // console.log(code); }; return ( - { - setIsLogin((prev) => !prev); - }} - > - 테스트용 로그인 토글버튼 - 유학생을 위한 미팅/소개팅 @@ -47,6 +32,9 @@ function LandingContainer() { 카카오 로그인 + ) : ( @@ -62,7 +50,7 @@ function LandingContainer() { > 시작하기 - setIsLogin((prev) => !prev)}> + console.log('응답 수정')}> 응답 수정하기 diff --git a/src/components/domain/matching/KakaoCopyBox.tsx b/src/components/domain/matching/KakaoCopyBox.tsx index b0d86e6..72eebb0 100644 --- a/src/components/domain/matching/KakaoCopyBox.tsx +++ b/src/components/domain/matching/KakaoCopyBox.tsx @@ -16,7 +16,7 @@ function KakaoCopyBox({ kakaoId }: CopyBoxPorps) { try { onToggleModal(); await navigator.clipboard.writeText(text); - } catch (error) { + } catch (e) { onToggleErrorModal(); } }; diff --git a/src/components/domain/matching/WaitingBox.tsx b/src/components/domain/matching/WaitingBox.tsx index 621fff5..10a50f3 100644 --- a/src/components/domain/matching/WaitingBox.tsx +++ b/src/components/domain/matching/WaitingBox.tsx @@ -7,7 +7,7 @@ function WaitingBox() { <> - 매칭은 매일밤 11시에 이루어집니다. + 매칭은 매일밤 11시에 이루어집니다.
매칭이 되면 카톡과 이메일로 링크를 보내드릴게요.
diff --git a/src/components/header/DatingInfoBox.tsx b/src/components/header/DatingInfoBox.tsx index 68e4104..f3704ef 100644 --- a/src/components/header/DatingInfoBox.tsx +++ b/src/components/header/DatingInfoBox.tsx @@ -1,5 +1,6 @@ +import React, { useEffect } from 'react'; +import { Modal } from '@/components/base'; import { palette } from '@/lib/styles/palette'; -import { Dating } from '@/types/dating'; import { addComma } from '@/utils/addComma'; import { conversionBody, @@ -9,13 +10,13 @@ import { conversionDomesticArea, conversionGender, } from '@/utils/converson'; -import React from 'react'; import styled from 'styled-components'; +import { getDatingSurvey } from '@/lib/api/dating'; +import { useDatingSessionState, useToggle } from '@/hooks/common'; -interface DatingInfoProps { - dating: Dating; -} -const DatingInfoBox = ({ dating }: DatingInfoProps) => { +const DatingInfoBox = () => { + const { initDatingState, setDatingData } = useDatingSessionState(); + const [isErrorModal, onToggleErrorModal] = useToggle(); const { age, myDepartment, @@ -38,70 +39,100 @@ const DatingInfoBox = ({ dating }: DatingInfoProps) => { isAbroad, abroadAreas, //여까지 선호 조건 - } = dating; - console.log(abroadAreas); + } = initDatingState; + + useEffect(() => { + const getDatingData = async () => { + try { + const res = await getDatingSurvey(); + if (res) { + setDatingData(res); + } + } catch (e) { + onToggleErrorModal(); + } + }; + + getDatingData(); + }, []); + return ( -
- Me - 나의 정보 - - {age}살 - {conversionGender(gender)} - {conversionDepartment(myDepartment)} - {mbti} - 연애 횟수 : {conversionDateCount(myDateCount)} - {myHeight}cm - {conversionBody(myBody)} - {mySmoke ? '흡연' : '비흡연'} - {conversionCharacter(characteristic)} - - {domesticAreas?.map((area, index) => ( -
- {addComma(index)} - {conversionDomesticArea(area)} -
- ))} -
- {abroadAreas.length === 0 ? '기피지역 : 없음' : abroadAreas} - 해외여부 : {isAbroad ? '예' : '아니요'} -
- 선호 조건 - - - {preferAge[0]}~{preferAge[1]}살 - - - {preferBodies?.map((body, index) => ( -
- {addComma(index)} - {conversionBody(body)} -
- ))} -
- - {preferCharacteristics?.map((charator, index) => ( -
- {addComma(index)} - {conversionCharacter(charator)} -
- ))} -
- {conversionDateCount(preferDateCount)} - - {preferDepartments?.map((department, index) => ( -
- {addComma(index)} - {conversionDepartment(department)} -
- ))} -
- - {preferHeight[0]}~{preferHeight[1]}cm - - {/* {preferUniversities} */} - 흡연 : {isSmokeOk ? '괜찮아요' : '싫어요'} -
-
+ <> +
+ Me + 나의 정보 + + {age}살 + {conversionGender(gender)} + {conversionDepartment(myDepartment)} + {mbti} + 연애 횟수 : {conversionDateCount(myDateCount)} + {myHeight}cm + {conversionBody(myBody)} + {mySmoke ? '흡연' : '비흡연'} + {conversionCharacter(characteristic)} + + {domesticAreas?.map((area, index) => ( +
+ {addComma(index)} + {conversionDomesticArea(area)} +
+ ))} +
+ {abroadAreas.length === 0 ? '기피지역 : 없음' : abroadAreas} + 해외여부 : {isAbroad ? '예' : '아니요'} +
+ 선호 조건 + + + {preferAge[0]}~{preferAge[1]}살 + + + {preferBodies?.map((body, index) => ( +
+ {addComma(index)} + {conversionBody(body)} +
+ ))} +
+ + {preferCharacteristics?.map((charator, index) => ( +
+ {addComma(index)} + {conversionCharacter(charator)} +
+ ))} +
+ {conversionDateCount(preferDateCount)} + + {preferDepartments?.map((department, index) => ( +
+ {addComma(index)} + {conversionDepartment(department)} +
+ ))} +
+ + {preferHeight[0]}~{preferHeight[1]}cm + + {/* {preferUniversities} */} + 흡연 : {isSmokeOk ? '괜찮아요' : '싫어요'} +
+
+ {isErrorModal && ( + { + void 0; + }} + /> + )} + ); }; export const InfoLabel = styled.div` diff --git a/src/components/header/MeetingInfoBox.tsx b/src/components/header/MeetingInfoBox.tsx index 4aa98a1..8154d14 100644 --- a/src/components/header/MeetingInfoBox.tsx +++ b/src/components/header/MeetingInfoBox.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import { Meeting } from '@/types/meeting'; +import React, { useEffect } from 'react'; +import { Modal } from '@/components/base'; import { conversionDepartment, conversionDomesticArea, @@ -10,11 +10,12 @@ import { } from '@/utils/converson'; import { FlexEle, GroupLabel, InfoBox, InfoEle, InfoLabel } from './DatingInfoBox'; import { addComma } from '@/utils/addComma'; +import { getMeetingSurvey } from '@/lib/api/meeting'; +import { useMeetingSessionState, useToggle } from '@/hooks/common'; -interface MeetingInfoProps { - meeting: Meeting; -} -function MeetingInfoBox({ meeting }: MeetingInfoProps) { +function MeetingInfoBox() { + const { initMeetingState, setMeetingData } = useMeetingSessionState(); + const [isErrorModal, onToggleErrorModal] = useToggle(); const { ourDepartments, domesticAreas, @@ -28,55 +29,86 @@ function MeetingInfoBox({ meeting }: MeetingInfoProps) { preferAge, preferDepartments, preferHeight, - } = meeting; + } = initMeetingState; + + const getMeetingData = async () => { + try { + const res = await getMeetingSurvey(); + if (res) { + setMeetingData(res); + } + } catch (e) { + onToggleErrorModal(); + } + }; + + useEffect(() => { + getMeetingData(); + }, []); + return ( -
- Team - 우리 팀 정보 + <> +
+ Team + 우리 팀 정보 - - {conversionGender(gender)} - {conversionTypeOfMeeting(typeOfMeeting)} - - {ourDepartments?.map((department, index) => ( -
- {addComma(index)} - {conversionDepartment(department)} -
- ))} -
- 평균나이 : {averageAge}살 - 평균 키 : {averageHeight}cm - {conversionPlay(play)} - - {domesticAreas?.map((area, index) => ( -
- {addComma(index)} - {conversionDomesticArea(area)} -
- ))} -
- {conversionMindset(mindset)} -
- 선호 조건 - - - {preferAge[0]}~{preferAge[1]}살 - - - {preferDepartments?.map((department, index) => ( -
- {addComma(index)} - {conversionDepartment(department)} -
- ))} -
- - {preferHeight[0]}~{preferHeight[1]}cm - -
-
+ + {conversionGender(gender)} + {conversionTypeOfMeeting(typeOfMeeting)} + + {ourDepartments?.map((department, index) => ( +
+ {addComma(index)} + {conversionDepartment(department)} +
+ ))} +
+ 평균나이 : {averageAge}살 + 평균 키 : {averageHeight}cm + {conversionPlay(play)} + + {domesticAreas?.map((area, index) => ( +
+ {addComma(index)} + {conversionDomesticArea(area)} +
+ ))} +
+ {conversionMindset(mindset)} +
+ 선호 조건 + + + {preferAge[0]}~{preferAge[1]}살 + + + {preferDepartments?.map((department, index) => ( +
+ {addComma(index)} + {conversionDepartment(department)} +
+ ))} +
+ + {preferHeight[0]}~{preferHeight[1]}cm + +
+
+ {isErrorModal && ( + { + void 0; + }} + /> + )} + ); } -export default MeetingInfoBox; +export default React.memo(MeetingInfoBox); diff --git a/src/components/header/MenuBlock.tsx b/src/components/header/MenuBlock.tsx index a23304b..f835312 100644 --- a/src/components/header/MenuBlock.tsx +++ b/src/components/header/MenuBlock.tsx @@ -1,8 +1,6 @@ +import React from 'react'; import { Logo } from '@/assets/img'; import { palette } from '@/lib/styles/palette'; -import { Dating } from '@/types/dating'; -import { Meeting } from '@/types/meeting'; -import React from 'react'; import styled from 'styled-components'; import DatingInfoBox from './DatingInfoBox'; import MeetingInfoBox from './MeetingInfoBox'; @@ -19,53 +17,6 @@ const TempUserData = { univ: 'Boston University', }; -const TempMeetingData: Meeting = { - typeOfMeeting: 'ONE', - gender: 'FEMALE', - averageAge: 28, - ourUniversities: [1, 21, 3], - ourDepartments: ['LIBERAL', 'SCIENCE'], - averageHeight: 170, - avoidUniversities: [], - preferUniversities: [], - preferAge: [20, 25], - preferHeight: [140, 180], - preferDepartments: ['LIBERAL', 'SCIENCE'], - mindset: 'ALL', - play: 'ALL', - isAbroad: false, - domesticAreas: ['SNW', 'SNE', 'SSW', 'SSE'], - abroadAreas: [], - channel: 'FACEBOOK', - agreement: true, - kakaoId: '', -}; -const TempDatingData: Dating = { - gender: 'FEMALE', - age: 28, - myDepartment: 'LIBERAL', - characteristic: 'A_LITTLE_ACTIVE', - mbti: 'INFP', - myHeight: 0, - myBody: 'SKINNY', - mySmoke: true, - myDateCount: 'ZERO', - isSmokeOk: true, - avoidUniversities: [], - preferUniversities: [], - preferAge: [20, 28], - preferHeight: [140, 180], - preferDepartments: ['LIBERAL', 'SCIENCE'], - preferCharacteristics: ['VERY_QUIET', 'A_LITTLE_QUIET'], - preferBodies: ['SKINNY', 'SLIM'], - preferDateCount: 'ZERO', - isAbroad: false, - domesticAreas: ['SNW', 'SNE', 'SSW', 'SSE'], - abroadAreas: [], - channel: 'FACEBOOK', - agreement: true, - kakaoId: '', -}; function MenuBlock({ isMenu, onToggleMenu }: MenuBlockProps) { return ( <> @@ -77,8 +28,8 @@ function MenuBlock({ isMenu, onToggleMenu }: MenuBlockProps) {
{TempUserData.univ}
- - + + diff --git a/src/components/header/UserHeader.tsx b/src/components/header/UserHeader.tsx index 12f8243..9b9bf0a 100644 --- a/src/components/header/UserHeader.tsx +++ b/src/components/header/UserHeader.tsx @@ -12,7 +12,9 @@ const UserHeader = () => { <> 외딴썸 - 메뉴 이미지 + + 메뉴 이미지 + @@ -27,4 +29,11 @@ const HeaderLayout = styled(HeaderWrapper)` padding: 20px 10px; `; +const Menu = styled.button` + & > img { + width: 20px; + height: 20px; + } +`; + export default UserHeader; diff --git a/src/components/testLogin/LoginForm.tsx b/src/components/testLogin/LoginForm.tsx new file mode 100644 index 0000000..caf65f4 --- /dev/null +++ b/src/components/testLogin/LoginForm.tsx @@ -0,0 +1,93 @@ +import React, { useState } from 'react'; +import { Input, Button, Modal } from '@/components/base'; +import useForm, { InitialValues } from '@/hooks/common/useForm'; +import styled from 'styled-components'; +import { LoginRequest } from '@/types/user'; +import { palette } from '@/lib/styles/palette'; +import { useToggle } from '@/hooks/common'; + +interface LoginFormProps { + onSubmitAuthCode: (values: LoginRequest) => void; +} + +const LoginForm = ({ onSubmitAuthCode }: LoginFormProps) => { + const [onFocus, setFocus] = useState(true); + const [isErrorModal, onToggleErrorModal] = useToggle(); + const { values, errors, handleSubmit, handleChange } = useForm({ + initialValues: { + userName: '', + password: '', + }, + onSubmit: async () => { + try { + if (values.userName) { + onSubmitAuthCode(values as any); + setFocus(false); + } + } catch (e) { + onToggleErrorModal(); + } + }, + validate: ({ userName, password }) => { + const newErrors: InitialValues = { userName: '' }; + if (userName?.length === 0) { + newErrors.userName = '이름을 입력해주세요'; + return newErrors; + } + + if (password?.length === 0) { + newErrors.password = '비밀번호를 입력해주세요'; + return newErrors; + } + return newErrors; + }, + }); + + return ( + <> + + + + {errors.userName && {errors.userName}} + + + + {errors.password && {errors.password}} + + + + {isErrorModal && ( + { + void 0; + }} + /> + )} + + ); +}; + +const FormsWrapper = styled.form` + display: flex; + flex-direction: column; + gap: 30px; +`; + +const InputsWrapper = styled.div` + position: relative; +`; + +export const ErrorMessage = styled.p` + position: absolute; + font-size: 12px; + color: ${palette.warning}; + padding-top: 2px; +`; + +export default LoginForm; diff --git a/src/components/testLogin/index.ts b/src/components/testLogin/index.ts new file mode 100644 index 0000000..5c49358 --- /dev/null +++ b/src/components/testLogin/index.ts @@ -0,0 +1 @@ +export { default as LoginForm } from './LoginForm'; diff --git a/src/hooks/common/useForm.ts b/src/hooks/common/useForm.ts index 5d78180..ff35a75 100644 --- a/src/hooks/common/useForm.ts +++ b/src/hooks/common/useForm.ts @@ -2,29 +2,32 @@ import { useState, useCallback, useEffect } from 'react'; export interface InitialValues { email?: string; + userName?: string; + password?: string; authCode?: string; } -interface UseFormProps { - initialValues: InitialValues; +interface UseFormProps { + initialValues: T; onSubmit: () => void; validate: (arg: InitialValues) => InitialValues; } -const useForm = ({ initialValues, onSubmit, validate }: UseFormProps) => { +const useForm = ({ initialValues, onSubmit, validate }: UseFormProps) => { const [values, setValues] = useState(initialValues); const [errors, setErrors] = useState | InitialValues>({}); const [isLoading, setIsLoading] = useState(false); const handleChange = useCallback((e: React.ChangeEvent) => { const { name, value } = e.target; - setValues({ ...values, [name]: value }); + setValues((prevValues) => { + return { ...prevValues, [name]: value }; + }); }, []); const handleSubmit = async (e: React.FormEvent) => { setIsLoading(true); e.preventDefault(); - console.log(Object.values(errors), 'auth'); await onSubmit(); setIsLoading(false); }; diff --git a/src/lib/api/dating.ts b/src/lib/api/dating.ts new file mode 100644 index 0000000..8b2bdd7 --- /dev/null +++ b/src/lib/api/dating.ts @@ -0,0 +1,18 @@ +import apiClient from './index'; +import { Dating } from '@/types/dating'; +import { AxiosResponse } from 'axios'; + +export const postDatingSurvey = async (payload: Dating) => { + const res = await apiClient.post('/dating/survey', payload); + return res.data; +}; + +export const getDatingSurvey = async () => { + const res = await apiClient.get('/dating/survey'); + return res.data; +}; + +export const postReMatchDatingSurvey = async () => { + const res = await apiClient.post('/dating/survey/rematch'); + return res.data; +}; diff --git a/src/lib/api/index.ts b/src/lib/api/index.ts index 8c8e1c1..d78085e 100644 --- a/src/lib/api/index.ts +++ b/src/lib/api/index.ts @@ -1,13 +1,12 @@ import axios from 'axios'; +import { SERVER_URL } from '@/lib/constants'; import Cookies from 'js-cookie'; -const host = import.meta.env.VITE_SERVER_URL; - const apiClient = axios.create({ - baseURL: host, + baseURL: SERVER_URL, withCredentials: false, headers: { - Authorization: Cookies.get('AccessToken') || '', + Authorization: Cookies.get('AccessToken') ?? '', }, }); diff --git a/src/lib/api/login.ts b/src/lib/api/login.ts new file mode 100644 index 0000000..2820a2e --- /dev/null +++ b/src/lib/api/login.ts @@ -0,0 +1,11 @@ +import apiClient from './index'; +import { LoginResponse, LoginRequest } from '@/types/user'; +/* + @desc + 임시 아이디 비번: test1 +*/ + +export const postLogin = async (payload: LoginRequest): Promise => { + const res = await apiClient.post('/login', payload); + return res.data; +}; diff --git a/src/lib/api/meeting.ts b/src/lib/api/meeting.ts new file mode 100644 index 0000000..e174bc1 --- /dev/null +++ b/src/lib/api/meeting.ts @@ -0,0 +1,18 @@ +import apiClient from './index'; +import { Meeting } from '@/types/meeting'; +import { AxiosResponse } from 'axios'; + +export const postMeetingSurvey = async (payload: Meeting) => { + const res = await apiClient.post('/meeting/survey', payload); + return res.data; +}; + +export const getMeetingSurvey = async () => { + const res = await apiClient.get('/meeting/survey'); + return res.data; +}; + +export const postReMathcingMettingSurvey = async () => { + const res = await apiClient.post('/meeting/survey/rematch'); + return res.data; +}; diff --git a/src/lib/constants/index.ts b/src/lib/constants/index.ts new file mode 100644 index 0000000..9b71a64 --- /dev/null +++ b/src/lib/constants/index.ts @@ -0,0 +1 @@ +export const SERVER_URL = import.meta.env.VITE_SERVER_URL; diff --git a/src/pages/AuthMail.tsx b/src/pages/AuthMail.tsx index ee90cd7..2f37634 100644 --- a/src/pages/AuthMail.tsx +++ b/src/pages/AuthMail.tsx @@ -7,11 +7,12 @@ import { palette } from '@/lib/styles/palette'; import { EmailForm, AuthCodeForm } from '@/components/authMail'; import { Link } from 'react-router-dom'; import client from '@/lib/api'; +import { useToggle } from '@/hooks/common'; const AuthMail = () => { const [cantMoveNext, setCantMoveNext] = useState(true); const [email, setEmail] = useState(''); - // const [state, setState] = useState(initState); + const [isErrorModal, onToggleErrorModal] = useToggle(); const postEmail = async (email: string) => { await client.post(`/api/email`, { email }); @@ -26,8 +27,7 @@ const AuthMail = () => { await postEmail(email); setEmail(email); } catch (e) { - alert(e.message); - console.error('에러 모달'); + onToggleErrorModal(); } }; @@ -36,8 +36,7 @@ const AuthMail = () => { await putEmail(authCode); setCantMoveNext(false); } catch (e) { - alert(e.message); - console.error('에러 모달'); + onToggleErrorModal(); } }; @@ -59,17 +58,19 @@ const AuthMail = () => { - {/*{isModal && (*/} - {/* setConfirm(true)}*/} - {/* />*/} - {/*)}*/} + {isErrorModal && ( + { + void 0; + }} + /> + )} ); }; diff --git a/src/pages/KakaoIdSurvey.tsx b/src/pages/KakaoIdSurvey.tsx index 3fad5bb..db42b01 100644 --- a/src/pages/KakaoIdSurvey.tsx +++ b/src/pages/KakaoIdSurvey.tsx @@ -10,9 +10,8 @@ import Path from '@/router/Path'; import { useMatch, useNavigate } from 'react-router-dom'; import { useDatingNavigate, useMeetingNavigate } from '@/hooks/common/useNavigate'; import { useMeetingSessionState, useDatingSessionState } from '@/hooks/common'; -import apiClient from '@/lib/api'; -// import { useRecoilValue } from 'recoil'; -// import { meetingState } from '@/atoms/meetingState'; +import { postMeetingSurvey } from '@/lib/api/meeting'; +import { postDatingSurvey } from '@/lib/api/dating'; const KakaoIdSurvey = () => { const matchMeeting = useMatch('/meeting/*'); @@ -20,24 +19,29 @@ const KakaoIdSurvey = () => { const { initMeetingState, setMeetingData } = useMeetingSessionState(); const { initDatingState, setDatingData } = useDatingSessionState(); const [isModal, onToggleModal] = useToggle(); + const [isErrorModal, onToggleErrorModal] = useToggle(); const navigate = useNavigate(); const [kakaoId, setkakaoId] = useState(matchMeeting ? initMeetingState.kakaoId : initDatingState.kakaoId); const [isConfirm, setConfirm] = useState(false); - // const meetingData = useRecoilValue(meetingState); 나중에 이걸로 data post const handleNextClick = async () => { - if (initMeetingState) { - matchMeeting ? setMeetingData({ ...initMeetingState, kakaoId }) : setDatingData({ ...initDatingState, kakaoId }); - await postMeetingSurvey(); - navigate(Path.MatchingMeeting); - } - }; - - const postMeetingSurvey = async () => { try { - await apiClient.post('/api/meeting/survey', matchMeeting ? { ...initMeetingState, kakaoId } : { ...initDatingState, kakaoId }); + if (matchMeeting) { + const meetingData = { ...initMeetingState, kakaoId }; + const res = await postMeetingSurvey(meetingData); + if (res.status === 200) { + setMeetingData(meetingData); + } + } else { + const datingData = { ...initDatingState, kakaoId }; + const res = await postDatingSurvey(datingData); + if (res.status === 200) { + setDatingData(datingData); + } + } + navigate(Path.MatchingMeeting); } catch (e) { - console.error(e); + onToggleErrorModal(); } }; @@ -87,6 +91,19 @@ const KakaoIdSurvey = () => { onClick={() => setConfirm(true)} /> )} + {isErrorModal && ( + { + void 0; + }} + /> + )} ); }; @@ -105,4 +122,4 @@ const InputWrapper = styled(FormWrapper)` margin-top: 46px; `; -export default KakaoIdSurvey; +export default React.memo(KakaoIdSurvey); diff --git a/src/pages/MatchingPage.tsx b/src/pages/MatchingPage.tsx index 32486ed..922f4fd 100644 --- a/src/pages/MatchingPage.tsx +++ b/src/pages/MatchingPage.tsx @@ -9,7 +9,7 @@ import React from 'react'; import styled from 'styled-components'; const MatchingPage = () => { - const TempData = { state: 'pay' }; + const TempData = { state: 'waiting' }; return ( <> diff --git a/src/pages/TestLogin.tsx b/src/pages/TestLogin.tsx new file mode 100644 index 0000000..3dcc14e --- /dev/null +++ b/src/pages/TestLogin.tsx @@ -0,0 +1,102 @@ +import { useState } from 'react'; +import styled from 'styled-components'; +import { SurveyTemplate } from '@/components/domain/survey'; +import { Button, Modal } from '@/components/base'; +import { Title } from '@/lib/styles/styledComponents'; +import { palette } from '@/lib/styles/palette'; +import { LoginForm } from '@/components/testLogin'; +import { LoginRequest } from '@/types/user'; +import { postLogin } from '@/lib/api/login'; +import Cookies from 'js-cookie'; +import { useNavigate } from 'react-router-dom'; +import { useToggle } from '@/hooks/common'; + +const TestLogin = () => { + const navigate = useNavigate(); + const [isLogin, setLogin] = useState(false); + const [isErrorModal, onToggleErrorModal] = useToggle(); + const onSubmitAuthCode = async (values: LoginRequest) => { + try { + const response = await postLogin(values); + + if (response) { + const { accessToken } = response; + Cookies.set('AccessToken', accessToken); + alert('로그인 성공'); + setLogin(true); + navigate('/type-of-meeting'); + } + } catch (e) { + alert(e.message); + } + }; + + const handleNextClick = () => { + navigate('/type-of-meeting'); + }; + + const handlePrevClick = () => { + navigate('/'); + }; + + return ( + <> + + + <strong>로그인해주세요.</strong> + + 임시 로그인 계정: test4 + + + + + {isErrorModal && ( + { + void 0; + }} + /> + )} + + ); +}; + +const Description = styled.p` + padding-top: 10px; + font-weight: 300; + font-size: 12px; + line-height: 18px; + letter-spacing: -0.02em; + color: rgba(0, 0, 0, 0.6); +`; + +export const StyledButton = styled(Button)` + margin-top: 16px; +`; + +export const FormWrapper = styled.div` + position: absolute; + width: 100%; + top: 40%; + transform: translateY(-50%); + margin-top: 65px; +`; + +export const InputsWrapper = styled.div` + position: relative; +`; + +export const ErrorMessage = styled.p` + position: absolute; + font-size: 12px; + color: ${palette.warning}; + padding-top: 2px; +`; + +export default TestLogin; diff --git a/src/pages/TypeOfMeetingSurvey.tsx b/src/pages/TypeOfMeetingSurvey.tsx index c281e7a..8991465 100644 --- a/src/pages/TypeOfMeetingSurvey.tsx +++ b/src/pages/TypeOfMeetingSurvey.tsx @@ -41,7 +41,7 @@ const TypeOfMeetingSurvey = () => { disableNext={!checkedOption} currStep={1} totalStep={14} - handlePrevClick={() => navigate(Path.AuthMail)} + handlePrevClick={() => navigate(Path.LandingPage)} handleNextClick={handleNextClick} > diff --git a/src/pages/index.ts b/src/pages/index.ts index 11d8858..0a93ce7 100644 --- a/src/pages/index.ts +++ b/src/pages/index.ts @@ -29,3 +29,5 @@ export { default as PreferBodyDateCountSurvey } from './PreferBodyDateCountSurve export { default as MatchingPage } from './MatchingPage'; export { default as OauthKakao } from './OauthKakao'; + +export { default as TestLogin } from './TestLogin'; diff --git a/src/router/Path.ts b/src/router/Path.ts index d63d738..cbcb5f4 100644 --- a/src/router/Path.ts +++ b/src/router/Path.ts @@ -1,5 +1,6 @@ enum Path { LandingPage = '/', + TestLogin = '/test-login', Component = '/component', // FIXME: 컴포넌트 모아두는 곳 (개발완료 후 삭제) AuthMail = '/auth-mail', TypeOfMeetingSurvey = '/type-of-meeting', diff --git a/src/router/Routing.tsx b/src/router/Routing.tsx index 022c8c0..f36a6b4 100644 --- a/src/router/Routing.tsx +++ b/src/router/Routing.tsx @@ -31,6 +31,7 @@ import { OauthKakao, PreferBodyDateCountSurvey, MatchingPage, + TestLogin, } from '@/pages'; import Test from '@/components/base/Test'; import UserHeader from '@/components/header/UserHeader'; @@ -43,6 +44,7 @@ function Routing() { <PageWrapper> <Routes> <Route path={Path.LandingPage} element={<LandingPage />} /> + <Route path={Path.TestLogin} element={<TestLogin />} /> <Route path={Path.Component} element={<Test />} /> <Route path={Path.AuthMail} element={<AuthMail />} /> <Route path={Path.TypeOfMeetingSurvey} element={<TypeOfMeetingSurvey />} /> diff --git a/src/types/user.ts b/src/types/user.ts new file mode 100644 index 0000000..b3e1cc6 --- /dev/null +++ b/src/types/user.ts @@ -0,0 +1,8 @@ +export interface LoginRequest { + password: 'string' | ''; + userName: 'string' | ''; +} + +export interface LoginResponse { + accessToken: 'string'; +}