Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature 006,007.008: 이메일 찾기 페이지 & 닉네임 모달 추가 #91

Merged
merged 2 commits into from
Feb 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 15 additions & 0 deletions src/apis/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ import {
MyInfoResponse,
UpdateMyInfoRequest,
UpdatePasswordRequest,
NickNameRequest,
NickNameResponse,
FindEmailResponse,
FindEmailRequest
} from '@/models/user';
import {
AlarmResponse,
Expand Down Expand Up @@ -67,3 +71,14 @@ export const updateMyInfoAPI = (data: UpdateMyInfoRequest) => {
export const updatePasswordAPI = (data: UpdatePasswordRequest) => {
return axios.put<APIBaseResponse>(PREFIX + '/myPage/updatePassword', data);
};

export const nickNameAPI = (data: NickNameRequest) => {
return axios.put<NickNameResponse>(PREFIX + '/nickname', data);
};

export const findEmailAPI = (data : FindEmailRequest) => {
return axios.post<FindEmailResponse>(
PREFIX + '/findEmail',
data
);
}
37 changes: 37 additions & 0 deletions src/components/FindEmail.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from "react"
import MailPng from '@/assets/mail.png';
import Container from "@/styles/FindEmail";
import { useNavigate } from "react-router-dom";

interface FindEmailProp {
userName : string;
email : string;
}

const FindEmail : React.FC<FindEmailProp> = ({userName, email}) => {
const navigate = useNavigate();

const handleLoginBtn = () => {
navigate('/sign-in');
}
const handlePwdBtn = () => {
navigate('/find-password');
}
return(
<Container>
<div className="wrapper">
<div style={{gap : '15px'}}>
<img src={MailPng}/>
<span className="result">{userName}님의 이메일은 {email}입니다!</span>
<span className="tool">로그인하고 나만의 영상 아카이빙을 시작해요</span>
</div>
<div style={{gap : '10px'}}>
<button style={{backgroundColor : '#1E1E1E', color : '#FFFFFF'}} onClick={handleLoginBtn}>로그인 하러가기</button>
<button style={{backgroundColor : '#FFFFFF', color : '#787878', border : '1.5px solid #E8E8E8'}} onClick={handlePwdBtn}>비밀번호 찾기</button>
</div>
</div>
</Container>
);
}

export default FindEmail;
193 changes: 193 additions & 0 deletions src/components/NicknameModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
import styled from 'styled-components';
import theme from '@/styles/theme';
import React, { useState } from 'react';
import { nickNameAPI } from '@/apis/user';
import nameImg from '@/assets/name.png';
import { BlurBackground } from '@/styles/modals/common.style';

const NicknameModal = () => {
const [inputCount, setInputCount] = useState(0);
const [name, setName] = useState<string>("");

const onChangeName = (e: React.ChangeEvent<HTMLInputElement>) => {
const target = e.currentTarget;
if (target.value.length > 7) {
target.value = target.value.slice(0, 7);
}
setName(target.value);
console.log(name);
setInputCount(
target.value.replace(/[\0-\x7f]|([0-\u07ff]|(.))/g, "$&$1$2").length
);
setInputCount(target.value.length);
};

const onApply = () => {
if (name) {
// 서버에 데이터 전송
onRegisterNicknameInfo();
} else {
alert('입력값을 확인해주세요.');
}
};

const onRegisterNicknameInfo = async () => {
try {
const response = (await nickNameAPI({
nick_name : name,
})).data
console.log(response);
} catch (err) {
console.log(err);
}
};

return (
<BlurBackground>
<ModalDiv>

<div
style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: 12
}}
>
<img src={nameImg} alt="signup" width={56} height={56} />
<h1 className="title">어떤 이름으로 불러드릴까요?</h1>
<span className="description">
vino에 오신걸 환영합니다! 원하시는 이름으로 불러드릴게요
</span>
</div>

<TextDiv
className="text_box">
<InputBox
type="text"
id="name"
name="name"
value={name}
placeholder="원하시는 닉네임을 작성해주세요"
onChange={onChangeName}
maxLength={7}
>
</InputBox>
<InputNickNameMessage>
<InputNickNameLength>
{inputCount}
</InputNickNameLength>
/7(공백포함)
</InputNickNameMessage>
</TextDiv>
{name ? (
<SucButton
type="submit"
onClick={onApply}
style={{ marginTop: 12 }}
>
등록하기
</SucButton>) : (
<Button
style={{ marginTop: 12 }}>
등록하기
</Button>)
}
</ModalDiv>
</BlurBackground>
);
};

export default NicknameModal;

const ModalDiv = styled.div`
padding: 40px 50px;
display: flex;
flex-direction: column;
align-items: center;
width: 700px;
border-radius: 20px;
background: ${(props) => props.theme.color.white};
box-shadow: 0px 4px 40px 0px rgba(0, 0, 0, 0.1);

& h1.title {
color: ${(props) => props.theme.color.gray500};
${(props) => props.theme.typography.Header6};
}

& span.description {
color: ${(props) => props.theme.color.gray300};
${(props) => props.theme.typography.Body1};
}
`;

const InputBox = styled.input`
width: 202px;
height: 56px;
background-color: #F3F3F3;
padding: 0px 0px 0px 20px;
display: flex;
align-items: center;
justify-content: center;
gap: 20px;
flex: 1 0 0;
font-style: normal;
border: none;
border-radius: 12px;
color: var(--Main, #1E1E1E);
font-family: Pretendard;
${theme.typography.Body1};
&:focus {
outline: none;
}

&::placeholder {
color: #bbb;
${theme.typography.Body1};
}
`;

const SucButton = styled.button`
width: 100%;
height: 56px;
border: none;
border-radius: 12px;
background-color : #1E1E1E;
color: #fff;
text-align: center;
${theme.typography.Body1};
`;

const Button = styled.button`
width: 100%;
height: 56px;
border: none;
border-radius: 12px;
background-color : #F3F3F3;
color: #BBBBBB;
text-align: center;
${theme.typography.Body1};
`;

const InputNickNameMessage = styled.span`
${theme.typography.Caption1};
color: ${theme.color.gray300};
padding: 0px 20px 0px 0px;
`;

const InputNickNameLength = styled.span`
color: ${({ theme }) => theme.color.gray300};
`;

const TextDiv = styled.div`
position : relative;
width : 600px;
height : 56px;
align-items: center;
justify-content: center;
background-color: #F3F3F3;
display: flex;
flex-direction: row;
border-radius: 12px;
margin-top: 48px;
`
6 changes: 5 additions & 1 deletion src/components/layout/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import { isSideBarOpenState } from '@/stores/ui';
import Footer from './footer/Footer';
import Header from './header';
import SideBar from './sideBar';
import { useEffect, useMemo } from 'react';
import NicknameModal from '@/components/NicknameModal';
import { useMemo, useEffect } from 'react';
import { userInfoState } from '@/stores/user';

const Layout = () => {
const { pathname } = useLocation();
const isSideBarOpen = useRecoilValue(isSideBarOpenState);
const userInfo = useRecoilValue(userInfoState);

const isShowFooter = useMemo(
() => pathname === '/' || /^(\/category)/g.test(pathname),
Expand All @@ -34,6 +37,7 @@ const Layout = () => {
</div>

{isShowFooter && <Footer />}
{userInfo && userInfo.nick_name === '' && <NicknameModal />}
</>
);
};
Expand Down
53 changes: 53 additions & 0 deletions src/components/modals/NotFindUserModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import Icon from '@/assets/empty-search.png';
import CloseIcon from '@/assets/icons/close.svg?react';
import React from 'react';
import Container from '@/styles/modals/NotFindUserModal';
import { useNavigate } from 'react-router-dom';

interface NotFindUserModalProp {
setIsShow: (value: boolean) => void;
type : boolean;
}
const NotFindUserModal : React.FC<NotFindUserModalProp> = ({setIsShow, type}) => {
const navigate = useNavigate();
// type (true => 이메일 찾기 결과 / false => 비밀번호 찾기 결과)

const handleCloseBtn = () => {
setIsShow(false);
}
const handleJoinBtn = () => {
navigate('/sign-up')
}
const handleReload = () => {
window.location.reload();
}

return (
<Container>
<div className="contentWrap">
<div className="textContent">
<div className='closeWrap'>
<CloseIcon width={28} height={28} onClick={handleCloseBtn}/>
</div>
<img src={Icon}/>
<span className='title'>존재하지 않는 회원 정보</span>
<div className='subtitleWrap'>
<span className='subtitle'>{type ?
"이름 및 전화 번호를 다시 확인해주세요!" :
"이메일/이름/전화번호를 다시 확인해주세요!"}
</span>
<span className='subtitle'>
아직 회원이 아니시라면, 회원가입으로 우리와 함께해요!
</span>
</div>
</div>
<div className="btnContent">
<button className='b_btn' onClick={handleJoinBtn}>회원가입 하기</button>
<button className='w_btn' onClick={handleReload}>다시 입력하기</button>
</div>
</div>
</Container>
);
}

export default NotFindUserModal;
16 changes: 16 additions & 0 deletions src/models/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,19 @@ export interface UpdatePasswordRequest {
new_password: string;
confirm_password: string;
}

export interface NickNameRequest {
nick_name: string;
}
export interface NickNameResponse {}

export interface FindEmailResponse {
success : boolean;
message : string;
email : string;
}

export interface FindEmailRequest {
name : string;
phone_number : string;
}
Loading
Loading