Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
Tags
- 엘리스 AI 트랙 5기
- 날씨 웹 만들기
- 자바스크립트 sort()
- [파이썬 실습] 기초 문제
- 자바스크립트 reduce()
- 프론트개발공부
- [AI 5기] 연습 문제집
- 프론트개발
- 자바스크립트
- [파이썬 실습] 중급 문제
- 삼항연산자
- reactnativecli
- 간단한 날씨 웹 만들기
- leetcode
- 코딩부트캠프
- HTML
- 엘리스 ai 트랙
- 부트캠프
- 자바스크립트 split()
- 리트코드
- 프로그래머스
- 개발공부
- 자바스크립트 날씨
- 개발일기
- 코드스테이츠
- 자바스크립트 날씨 웹 만들기
- JavaScript
- [파이썬 실습] 심화 문제
- RN 프로젝트
- 엘리스
Archives
- Today
- Total
개발조각
[모두의 이력서_15일차] 회원가입기능 구현 본문
728x90
반응형
로그인 기능 구현할 때 cors, react-query, axios, recoil을 세팅했으므로 로그인 기능과 똑같이 구현해 주시면 됩니다.
회원가입 기능 구성
이메일, 닉네임, 비밀번호, 비밀번호 확인 → 회원가입 버튼
- 알맞은 일메일을 작성할 경우 : 알맞은 이메일 형식입니다.
- 알맞은 닉네임을 작성할 경우 : 알맞은 닉네임 형식입니다.
- 알맞은 비밀번호를 작성할 경우 : 알맞은 비밀번호 형식입니다.
- 비밀번호, 비밀번호 확인이 일치할 경우: 비밀번호가 일치합니다.
라는 문구를 띄우게 했습니다.
api > user.ts
import instance from ".";
interface User {
email: string;
nickName: string;
password: string;
}
// 회원가입
export const register = async ({ email, nickName, password }: User) => {
const result = await instance.post("/users/register", {
email,
nickName,
password,
});
return result;
};
axios로 회원가입 api 정의해 주었습니다.
utils > regExp.ts
입력한 값(이메일, 닉네임, 비밀번호)이 알맞은 값인지 확인하기 위해 정규식을 사용했습니다.
이메일, 닉네임, 비밀번호는 회원 관련 기능을 구현할 때 자주 사용되므로 utils폴더 안에 넣어주었습니다.
로그인 기능 구현할 때도 사용했습니다.
// 이메일: (영어대소문자+숫자) + @ + (영어소문자) + (.com)
export const validateEmail = (email: string) => {
return /([\d\w])+@{1}([a-z])+(.com$)/.test(email);
};
// 닉네임: 특수문자제외, 공백제외, 2~8글자
export const validateNickname = (nickname: string) => {
return /^[가-힣\d\w]{2,8}$/.test(nickname);
};
// 비밀번호: 4~10글자
export const validatePassword = (value: string) => {
return value.length >= 4 && value.length <= 10;
};
vaidateEmail(입력한 이메일 값)을 넣어주면 true, false 값이 나옵니다.
Register.tsx
import { ChangeEvent, FormEvent, useContext, useState } from "react";
import { useRouter } from "next/router";
import { useMutation } from "@tanstack/react-query";
import Logo from "../components/common/Logo";
import { ThemeContext } from "../context/themeContext";
import { IsDark } from "../context/type";
import {
validateEmail,
validateNickname,
validatePassword,
} from "../utils/regExp";
import { register } from "../api/user";
import * as authStyled from "../styles/components/Auth";
import * as styled from "../styles/pages/Register";
// 이메일, 닉네임, 비밀번호, 비밀번호 확인 -> 회원가입
const Register = () => {
const router = useRouter();
const { isDark } = useContext(ThemeContext) as IsDark;
const mode = isDark ? "darkTheme" : "lightTheme";
const [email, setEmail] = useState("");
const [nickName, setNickName] = useState("");
const [password, setPassword] = useState("");
const [checkPassword, setCechkPassword] = useState("");
const onEmailHandler = (e: ChangeEvent<HTMLInputElement>) => {
const { value } = e.target as any;
setEmail(value);
};
const onNickNameHandler = (e: ChangeEvent<HTMLInputElement>) => {
const { value } = e.target as any;
setNickName(value);
};
const onPasswordHandler = (e: ChangeEvent<HTMLInputElement>) => {
const { value } = e.target as any;
setPassword(value);
};
const onCheckPasswordHandler = (e: ChangeEvent<HTMLInputElement>) => {
const { value } = e.target as any;
setCechkPassword(value);
};
const mutation = useMutation({
mutationFn: register,
onSuccess: (data) => {
router.replace("/Login", "/auth/register");
},
});
const onSubmitHandler = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault(); // 리프레시 막기
if (
validateEmail(email) &&
validateNickname(nickName) &&
validatePassword(password) &&
password === checkPassword
) {
mutation.mutate({ email: email, nickName: nickName, password: password });
} else {
alert("회원가입 실패했습니다. 다시 수정해주세요.");
}
};
return (
<authStyled.AuthWrap mode={mode}>
<authStyled.AuthCon mode={mode}>
<styled.TitleWrap>
<Logo />
<h2>이메일로 가입하기</h2>
</styled.TitleWrap>
<authStyled.LoginformWrap>
<form onSubmit={onSubmitHandler}>
<authStyled.InputBox mode={mode}>
<p>이메일</p>
<input
autoFocus
type="text"
value={email}
onChange={onEmailHandler}
/>
</authStyled.InputBox>
{validateEmail(email) && (
<authStyled.Msg state={"success"}>
알맞은 이메일 형식입니다.
</authStyled.Msg>
)}
<authStyled.InputBox mode={mode}>
<p>닉네임</p>
<input type="text" onChange={onNickNameHandler} />
</authStyled.InputBox>
{validateNickname(nickName) && (
<authStyled.Msg state={"success"}>
알맞은 닉네임 형식입니다.
</authStyled.Msg>
)}
<authStyled.InputBox mode={mode}>
<p>비밀번호</p>
<input type="password" onChange={onPasswordHandler} />
</authStyled.InputBox>
{validatePassword(password) && (
<authStyled.Msg state={"success"}>
알맞은 비밀번호 형식입니다.
</authStyled.Msg>
)}
<authStyled.InputBox mode={mode}>
<p>비밀번호 확인</p>
<input type="password" onChange={onCheckPasswordHandler} />
</authStyled.InputBox>
{validatePassword(password) && password === checkPassword && (
<authStyled.Msg state={"success"}>
비밀번호가 일치합니다.
</authStyled.Msg>
)}
<authStyled.btn type="submit">회원가입</authStyled.btn>
</form>
</authStyled.LoginformWrap>
</authStyled.AuthCon>
</authStyled.AuthWrap>
);
};
export default Register;
Auth.ts
Login.ts css와 유사해서 공통으로 사용되는 부분은 Auth에 넣어주었고
Register에서만 사용되는 css는 Register.ts에 넣어주었습니다.
import styled from "styled-components";
export const AuthWrap = styled.div<{ mode: "darkTheme" | "lightTheme" }>`
${({ theme }) => theme.common.flexCenter}
height: 100vh;
background: ${({ theme, mode }) => theme.colors[mode].lightBg};
`;
export const AuthCon = styled.div<{ mode: "darkTheme" | "lightTheme" }>`
${({ theme }) => theme.common.flexCenter}
flex-direction: column;
padding: 88px 0;
width: 640px;
border-radius: 10px;
background: ${({ theme, mode }) => theme.colors[mode].bg};
${({ theme }) => theme.device.mobile} {
width: 100%;
height: 100vh;
padding: 28px 24px;
}
`;
export const LoginformWrap = styled.div`
margin-top: 48px;
width: 320px;
form {
width: 100%;
}
`;
export const InputBox = styled.div<{ mode: "darkTheme" | "lightTheme" }>`
margin-top: 16px;
p {
font-weight: 700;
font-size: ${({ theme }) => theme.fonts.size.small};
}
input {
margin-top: 8px;
padding: 10px 12px;
width: 100%;
border: 1px solid ${({ theme, mode }) => theme.colors[mode].border};
border-radius: 4px;
background: ${({ theme, mode }) => theme.colors[mode].lightBg};
&:focus {
border: 1px solid ${({ theme }) => theme.colors.lightMain};
}
}
`;
export const btn = styled.button`
display: block;
margin-top: 36px;
width: 100%;
height: 48px;
border-radius: 4px;
background: ${({ theme }) => theme.colors.main};
color: ${({ theme }) => theme.colors.lightTheme.bg};
transition: all 0.1s;
&:hover {
background: ${({ theme }) => theme.colors.lightMain};
}
`;
export const Msg = styled.span<{ state: "warning" | "success" }>`
display: block;
margin-top: 12px;
font-weight: 300;
font-size: ${({ theme }) => theme.fonts.size.small};
line-height: ${({ theme }) => theme.fonts.lineHeight.base};
color: ${({ theme, state }) => theme.colors[state]};
`;
Register.ts
import styled from "styled-components";
export const TitleWrap = styled.div`
text-align: center;
h1 a img {
width: auto;
height: 16px;
}
h2 {
margin-top: 16px;
font-weight: 700;
font-size: ${({ theme }) => theme.fonts.size.title};
}
`;
728x90
반응형
'모두의 이력서' 카테고리의 다른 글
[모두의 이력서_14일차] Next.js TS에서 로그인 구현 (cors + react-query + axios + recoil) (0) | 2023.04.10 |
---|---|
[모두의 이력서_13일차] Next.js TS에서 Styled-components 적용 안되는 에러 (0) | 2023.04.07 |
[모두의 이력서_12일차] Next url표시 방법, Next 특정 페이지에서 header안보이게 하기 (0) | 2023.04.06 |
[모두의 이력서_10-11일차] 다크모드(React Context API + Next.js + TS + styled-component) (0) | 2023.04.05 |
[모두의 이력서_9일차] 헤더, 푸터 ui 구현(+ 반응형) (0) | 2023.04.03 |
Comments