미새문지

24.08.22 day51 작업 일지 본문

개발 TIL

24.08.22 day51 작업 일지

문미새 2024. 8. 22. 21:20
728x90

회원가입 페이지가 총 3페이지로 나누어져 있어서 카운트 변수를 만들어 해당 변수값에 따라 컴포넌트를 보여주기로 했다.

import styled from "styled-components";
import Signup1 from "../components/signup/signup1";
import Signup2 from "../components/signup/signup2";
import Signup3 from "../components/signup/signup3";
import BackHeader from "../components/common/backHeader";
import { useState } from "react";

const Signup: React.FC = () => {
  const [step, setStep] = useState(1);

  const handleNext = () => {
    if (step < 3) {
      setStep(step + 1);
    }
  };

  const handleBack = () => {
    if (step > 1) {
      setStep(step - 1);
    }
  };

  return (
    <>
      <SignupWrapper>
        <BackHeader onBack={handleBack} />
        {step === 1 && <Signup1 onNext={handleNext} />}
        {step === 2 && <Signup2 onNext={handleNext} />}
        {step === 3 && <Signup3 />}
      </SignupWrapper>
    </>
  );
};
export default Signup;

const SignupWrapper = styled.div`
  width: 55%;
  margin: 0 auto;
`;

해당 BackHeader 컴포넌트로 카운트를 낮춰서 회원가입의 뒤로가기 구현을 했다. 이제 걸리는 점은 저 뒤로가기 컴포넌트를 다른 곳에서도 사용해야 하는데 지금 사용하는 변수 낮추기와는 다르게 그 때는 navigate를 사용해 페이지를 이동시켜야 한다. onClick시의 함수 변화를 상황에 따라 다르게 주거나 아니면 컴포넌트를 나눠서 현재 뒤로가기는 회원가입에서만 사용하던지 결정해야 한다. 이 부분은 나중에 기능 작업 들어갈 때 수정할 예정

 

뒤로가기는 해당 컴포넌트로 사용되고 넘어가는 건 각 회원가입마다 다음 버튼이 있는데 해당 버튼을 상호작용해서 넘어가는 방식이다.

import styled from "styled-components";
import BackHeader from "../common/backHeader";
import CommonInput from "../common/commonInput";
import NextBtn from "./nextBtn";
import SignupCount from "./signupCount";
import SignupGuide from "./signupGuide";
import PwVisible from "../common/pwVisible";
import React, { useState } from "react";

interface NextProps {
  onNext: () => void;
}

const Signup1: React.FC<NextProps> = ({ onNext }) => {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [passwordConfirm, setPasswordConfirm] = useState("");

  return (
    <>
      <Signup1Wrapper>
        <SignupBox>
          <SignupCount count="1" />
          <SignupGuide text="이메일과 비밀번호를 입력해주세요." />
          <EmailBox>
            <CommonInput
              typeValue="email"
              placeholderValue="이메일"
              value={email}
              onChange={(e) => setEmail(e.target.value)}
            />
            <EmailCheck>√ 8자리 이상</EmailCheck>
            <EmailCheck>
              √ 대문자, 소문자, 숫자, 특수문자 중 2개 이상
            </EmailCheck>
          </EmailBox>
          <CommonInput
            typeValue="password"
            placeholderValue="비밀번호"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
          />
          <PwVisible />
          <CommonInput
            typeValue="password"
            placeholderValue="비밀번호 확인"
            value={passwordConfirm}
            onChange={(e) => setPasswordConfirm(e.target.value)}
          />
          <NextBtn onClick={onNext} />
        </SignupBox>
      </Signup1Wrapper>
    </>
  );
};
export default Signup1;

const Signup1Wrapper = styled.div`
  width: 100%;
  display: flex;
  flex-direction: column;
`;

const SignupBox = styled.div`
  width: 100%;
  margin: 50px auto;
`;

const EmailBox = styled.div`
  display: flex;
  flex-direction: column;
  margin: 10px 0;
`;

const EmailCheck = styled.div`
  font-size: 11px;
  margin-left: 10px;
  color: #c9c9c9;
`;

회원가입 1번을 보면 이메일과 비밀번호를 입력하는 input칸이 있고 맨 밑에 NextBtn 컴포넌트가 있다.

import styled from "styled-components";

const NextBtn = ({ onClick }) => {
  return (
    <>
      <NextBtnCss onClick={onClick}>다음</NextBtnCss>
    </>
  );
};
export default NextBtn;

const NextBtnCss = styled.button`
  width: 100%;
  background-color: rgba(255, 164, 228, 0.7);
  border: none;
  border-radius: 10px;
  padding: 10px 0;
  margin-top: 20px;
  outline: none;
  font-size: 14px;
  font-weight: bold;
  color: white;
  cursor: pointer;
`;

해당 컴포넌트는 버튼만 작성되어있는 컴포넌트이고 해당 버튼에 onClick을 지정하되 그걸 상위 컴포넌트까지 가지고 와서 입력해주는 방식이다.

그래서 회원가입 페이지에서 입력한 값을 클릭이벤트에 담아 하위로 보내 작동시킨다.

import styled from "styled-components";
import BackHeader from "../common/backHeader";
import SignupCount from "./signupCount";
import SignupGuide from "./signupGuide";
import CommonInput from "../common/commonInput";
import NextBtn from "./nextBtn";
import { useState } from "react";

interface NextProps {
  onNext: () => void;
}

const Signup2: React.FC<NextProps> = ({ onNext }) => {
  const [nickname, setNickname] = useState("");

  return (
    <>
      <Signup2Wrapper>
        <SignupBox>
          <SignupCount count="2" />
          <SignupGuide text="닉네임을 설정해주세요" />
          <NicknameBox>
            <CommonInput
              typeValue="text"
              placeholderValue="닉네임"
              value={nickname}
              onChange={(e) => setNickname(e.target.value)}
            />
            <NickCheckWrapper>
              <NicknameCheck>사용할 수 있는 닉네임이에요</NicknameCheck>
              <span>0/10</span>
            </NickCheckWrapper>
            <NickCheckWrapper>
              <NicknameCheck>사용할 수 없는 닉네임이에요</NicknameCheck>
              <span>10/10</span>
            </NickCheckWrapper>
            <RandomCreate>랜덤 생성</RandomCreate>
          </NicknameBox>
          <NextBtn onClick={onNext} />
        </SignupBox>
      </Signup2Wrapper>
    </>
  );
};
export default Signup2;

const Signup2Wrapper = styled.div`
  width: 100%;
  display: flex;
  flex-direction: column;
`;

const SignupBox = styled.div`
  width: 100%;
  margin: 50px auto;
`;

const NicknameBox = styled.div`
  display: flex;
  flex-direction: column;
  margin: 10px 0;
`;

const NicknameCheck = styled.div`
  font-size: 11px;
  margin-left: 10px;
  color: #585858;
`;

const NickCheckWrapper = styled.div`
  display: flex;
  justify-content: space-between;

  span {
    font-size: 10px;
  }
`;

const RandomCreate = styled.button`
  width: 30%;
  border: 1px solid #b0b0b0;
  border-radius: 5px;
  background-color: white;
  color: #848484;
  font-size: 10px;
  font-weight: bold;
  margin: 10px 0;
  padding: 3px 0;
`;

회원가입 2번에도 동일하게 닉네임을 담는 input칸과 다음으로 넘어가는 버튼이 있고

import styled from "styled-components";
import BackHeader from "../common/backHeader";
import SignupCount from "./signupCount";
import SignupGuide from "./signupGuide";
import CommonInput from "../common/commonInput";
import { useState } from "react";
import CommonCheckBox from "./commonCheckbox";
import CommonRadioBox from "./commonRadiobox";
import CompleteBtn from "./completeBtn";

const Signup3: React.FC = () => {
  const [nickname, setNickname] = useState("");

  return (
    <>
      <Signup3Wrapper>
        <SignupBox>
          <SignupCount count="3" />
          <SignupGuide text="태어난 연도를 알려주세요" />
          <CommonInput
            typeValue="text"
            placeholderValue="예) 1995"
            value={nickname}
            onChange={(e) => setNickname(e.target.value)}
          />
          <SignupGuide text="성별을 선택해주세요" />
          <GenderBox>
            <CommonRadioBox label="남자" name="gender" />
            <CommonRadioBox label="여자" name="gender" />
          </GenderBox>
          <SignupGuide text="어떤 피부 타입인가요?" />
          <SkinBox1>
            <CommonRadioBox label="건성" name="skin" />
            <CommonRadioBox label="중성" name="skin" />
            <CommonRadioBox label="지성" name="skin" />
          </SkinBox1>
          <SkinBox2>
            <CommonRadioBox label="복합성" name="skin" />
            <CommonRadioBox label="수부지" name="skin" />
          </SkinBox2>
          <SignupGuide text="퍼스널컬러를 골라주세요" />
          <ColorBox1>
            <CommonRadioBox label="봄웜톤" name="color" />
            <CommonRadioBox label="여름쿨톤" name="color" />
            <CommonRadioBox label="가을웜톤" name="color" />
            <CommonRadioBox label="겨울쿨톤" name="color" />
          </ColorBox1>
          <ColorBox2>
            <CommonRadioBox label="잘 모르겠어요.." name="color" />
          </ColorBox2>
          <SignupGuide text="피부 고민이 있나요?" />
          <TroubleBox>
            <CommonCheckBox label="아토피" />
            <CommonCheckBox label="여드름" />
            <CommonCheckBox label="민감성" />
            <CommonCheckBox label="홍조" />
            <CommonCheckBox label="각질" />
            <CommonCheckBox label="속건조" />
            <CommonCheckBox label="등" />
            <CommonCheckBox label="등등" />
            <CommonCheckBox label="등등등" />
          </TroubleBox>
          <CompleteBtn />
        </SignupBox>
      </Signup3Wrapper>
    </>
  );
};
export default Signup3;

const Signup3Wrapper = styled.div`
  width: 100%;
  display: flex;
  flex-direction: column;
`;

const SignupBox = styled.div`
  width: 100%;
  margin: 50px auto;
`;

const GenderBox = styled.div`
  width: 100%;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
`;

const SkinBox1 = styled.div`
  width: 100%;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 5px;
`;

const SkinBox2 = styled.div`
  width: 72%;
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 5px;
`;

const ColorBox1 = styled.div`
  width: 100%;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 5px;
`;

const ColorBox2 = styled.div`
  width: 100%;
`;

const TroubleBox = styled.div`
  width: 100%;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 5px;
`;

회원가입 3번은 마지막 컴포넌트라 다음 버튼 대신 회원가입을 완료하는 버튼이 있다.

아직 데이터를 저장하는 리액트 훅을 작성하진 않았는데 이 후에 기능 작업에 들어가면서 백엔드와 연동할 때 리덕스를 사용해 회원가입 데이터를 담아줄 생각이다.

예전에 다른 프로젝트를 진행했을 때도 회원가입이 페이지가 5페이지가 있었는데 원래는 navigate의 localtion 기능에 컨텍스트 api처럼 데이터를 담아 보낼 수 있는 기능이 있다고 했으나 매번 데이터를 누적시켜서 마지막 페이지까지 보내는게 너무 까다롭고 불필요해 보여서 리덕스 툴킷을 사용해서 해볼 예정이다.

 3번의 버튼들은 필수가 아닌 선택형이며 제일 하단의 컨텐츠만 체크박스로 중복선택이 가능하고 나머지는 라디오 버튼으로 하나만 선택 가능하게 해놨다.

import styled from "styled-components";

const CommonRadioBox = ({ label, name }: { label: string; name: string }) => {
  return (
    <>
      <Label>
        <HiddenRadioButton type="radio" name={name} />
        <RadioButtonText>{label}</RadioButtonText>
      </Label>
    </>
  );
};
export default CommonRadioBox;

const Label = styled.label`
  display: flex;
  align-items: center;
  cursor: pointer;
`;

const HiddenRadioButton = styled.input`
  position: absolute;
  opacity: 0;
  cursor: pointer;
`;

const RadioButtonText = styled.div`
  width: 100%;
  border: 3px solid rgba(255, 164, 228, 0.5);
  border-radius: 13px;
  padding: 10px 10px;
  margin-bottom: 5px;
  font-size: 16px;
  text-align: center;
  outline: none;
  color: #848484;

  ${HiddenRadioButton}:checked + & {
    background-color: #ffa4e4;
    color: white;
    font-weight: bold;
  }
`;

체크박스와 라디오박스는 css는 비슷하게 해놨으나 기능이 다르기에 컴포넌트를 나누어놨고 해당 체크박스 선택 부분에는 grid를 사용해 같은 비율로 지정을 해놓았다. flex도 좋지만 grid도 사용할 줄 알면 되게 편리해서 익숙해져야 할 것 같다. 

728x90

'개발 TIL' 카테고리의 다른 글

24.08.26 day53 작업 일지  (2) 2024.08.26
24.08.23 day52 캡슐화, 미들웨어  (0) 2024.08.23
24.08.21 day50 공용 컴포넌트 작성 방식  (0) 2024.08.21
24.08.20 day49 로그인 UI  (0) 2024.08.20
24.08.19 day48 HTML 작성 규칙  (0) 2024.08.19