기업과제 7번

H Kim·2022년 3월 4일
0

기업과제

목록 보기
4/8
post-thumbnail

원티드 X 코드스테이츠 프리온보딩 프론트엔드 과정 기업과제 7번

담당했던 부분 : 생성한 폼 목록 페이지 / 입력된 데이터 목록 페이지 작성


✨ 주요 기능

  • 구글 설문지와 같은 자체 폼 서비스입니다.
  • 사용자가 원하는 형식으로 폼 생성이 가능하며 사용자에게 폼을 전달하여 데이터를 입력받을 수 있습니다.
  • 생성한 폼 목록을 볼 수 있으며 폼 생성하기를 누르면 폼 생성 화면으로 넘어갑니다.
  • 폼 생성 페이지에서는 필드를 자유롭게 추가할 수 있습니다.
  • 드래그 앤 드랍 기능이 구현됩니다.
  • 파일 첨부 시, 프로그레스 바를 출력합니다.
  • 배송지는 카카오 우편번호 서비스를 이용해 검색할 수 있습니다.
  • 폼에서 생성된 필드를 기준으로 사용자가 입력한 데이터를 일괄 확인할 수 있습니다.

  1. 생성한 폼 목록 페이지


별 거 아닌 부분이기는 하지만 이번 프로젝트에서는 버튼을 만들 때 가장 신경을 쓴 것 같다.
pure css이지만... 어쨌든 이번 기회에 이것저것 만져보면서 transform에 대해 조금 이해도를 높인 것 같다.
또 다른 부분은, 타입스크립트를 사용했던 부분이었는데 솔직히 이해는 잘 못 했고 팀원들의 도움을 많이 받아서 코스가 끝나면 혼자서 좀 공부를 해봐야 할 것 같다.
셋팅부터 좀 어려웠던 지점이 있어서 시간이 많이 걸렸다.



import React from "react";
import styled from "styled-components";
import { useRouter } from "next/router";

const Header = () => {
  const router = useRouter();

  return (
    <>
      <HeaderWrapper>
        <LogoName
          onClick={() => {
            router.push("/");
          }}
        >
          datable
        </LogoName>
        <CreateFormBtn
          onClick={() => {
            router.push("/forms");
          }}
        />
      </HeaderWrapper>
    </>
  );
};

const HeaderWrapper = styled.div`
  display: flex;
  flex-direction: row;
  justify-content: space-around;
`;

const LogoName = styled.div`
  font-size: 7rem;
  font-weight: 700;
  padding: 3rem;
  width: 50rem;
  height: 10rem;
  text-align: center;
  font-family: "Ubuntu", sans-serif;
  cursor: pointer;
`;

const CreateFormBtn = styled.button`
  position: relative;
  display: inline-flex;
  width: 150px;
  height: 55px;
  margin: 45px 115px 35px 35px;
  perspective: none;
  font-size: 19px;
  letter-spacing: 1px;
  transform-style: preserve-3d;
  transform: translateZ(-25px);
  transition: transform 0.25s;
  font-family: "Montserrat", sans-serif;
  :before,
  :after {
    position: absolute;
    content: "CREATE FORM";
    height: 55px;
    width: 180px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 5px solid rgba(46, 124, 240);
    box-sizing: border-box;
  }
  :before {
    color: #fff;
    background: rgba(46, 124, 240);
    transform: rotateY(0deg) translateZ(25px);
  }
  :after {
    color: rgba(46, 124, 240);
    transform: rotateX(90deg) translateZ(25px);
  }
  :hover {
    transform: translateZ(-25px) rotateX(-90deg);
  }
`;

export default Header;

  1. 입력된 데이터 목록 페이지


여기서 가장 고민했던 부분은 Data 스타일드 컴포넌트가 안에 들어간 정보의 양에 따라서 박스가 늘어났다가 줄어들었다 해야 하는 거였다.
분명 DataListWrapper가 display:flex로 설정이 되어 있고 그 위의 컴포넌트들 역시 모두 그렇게 설정되어 있었는데도 Data에 flex-grow:1을 주어도 아무 변화가 나타나지 않아서 인터넷을 뒤지고 자료를 찾아보고 그랬다.
그런데 어이없게도... min-height와 height가 설정되어 있어서 이 값을 먼저 받으니까 크기가 변하지 않았던 거여서 DataListWrapper에 있는 height 설정을 모두 지워주었더니 원하는대로 작동하게 되었다.
정말... 다 내가 잘못하는 거지 코드는 정직하구나...^^


import type { NextPage } from "next";
import { useRouter } from "next/router";
import styled from "styled-components";
import { FcTodoList } from "react-icons/fc";
import { useAppSelector, selectForm } from "redux/slice";
import Header from "components/Header";
import { Fragment, ReactElement } from "react";

const DataList: NextPage = () => {
  const router = useRouter();
  const { id } = router.query;
  const i = Number(router.query["i"]);
  const selectedForm = useAppSelector(selectForm).data.find((v) => v.id === id);

  const showForms = () => {
    const result = selectedForm!.dataList[i];
    return Object.keys(result).map((v) => {
      let value: ReactElement;
      if (result[v].type === "agreement") {
        value = (
          <InputValue>{result[v].value ? "동의함" : "동의안함"}</InputValue>
        );
      } else if (result[v].type === "file") {
        value = <Image src={result[v].value as string} alt="image" />;
      } else {
        value = <InputValue>{result[v].value}</InputValue>;
      }

      return (
        <Fragment key={result[v].type}>
          <TitleValue>
            <FcTodoList size="2.5rem" style={{ marginRight: "15px" }} />
            {v}
          </TitleValue>
          {value}
        </Fragment>
      );
    });
  };

  const goPrev = () => {
    if (i === 0) {
      alert("첫 페이지입니다.");
      return;
    }
    router.push(`/dataList/${id}/${i - 1}`);
  };
  const goNext = () => {
    if (i === selectedForm!.dataList.length - 1) {
      alert("마지막 페이지입니다.");
      return;
    }
    router.push(`/dataList/${id}/${i + 1}`);
  };

  return (
    <>
      <DataListWrapper>
        <Header />
        <Data>
          {showForms()}
          <PrevBtn onClick={goPrev} />
          <NextBtn onClick={goNext} />
        </Data>
      </DataListWrapper>
    </>
  );
};

const DataListWrapper = styled.main`
  min-width: 50rem;
  max-width: 80rem;
  border: solid 1px rgba(0, 0, 0, 0.2);
  margin: 0 auto;
  box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;
  display: flex;
  flex-direction: column;
`;

const Data = styled.div`
  box-shadow: rgba(67, 71, 85, 0.27) 0px 0px 0.25em,
    rgba(90, 125, 188, 0.05) 0px 0.25em 1em;
  border-radius: 10px;
  width: 80%;
  margin: 4rem 0rem 2rem 0rem;
  background-color: #f5f5f5;
  position: relative;
  left: 50%;
  transform: translateX(-50%);
  padding: 5% 10% 0% 10%;
  flex-grow: 1;
  overflow: scroll;
`;
const TitleValue = styled.div`
  font-size: 2.5rem;
  font-weight: 700;
  margin: 0 0 2rem 3rem;
`;

const InputValue = styled.div`
  background-color: white;
  font-size: 2rem;
  margin: 1rem 0 2rem 0;
  min-height: 5rem;
  border-radius: 0.5rem;
  border: 1px solid gray;
  padding: 0.2rem 0.2rem 0.2rem 3rem;
  line-height: 5rem;
  overflow: auto;
`;

const Image = styled.img`
  width: 100%;
  height: 100%;
  object-fit: cover;
`;

const PrevBtn = styled.button`
  position: relative;
  display: inline-flex;
  width: 150px;
  height: 55px;
  margin: 45px 35px 35px 35px;
  perspective: none;
  font-size: 19px;
  letter-spacing: 1px;
  transform-style: preserve-3d;
  transform: translateZ(-25px);
  transition: transform 0.25s;
  font-family: "Montserrat", sans-serif;
  :before,
  :after {
    position: absolute;
    content: "PREV";
    height: 55px;
    width: 180px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 5px solid rgba(46, 124, 240);
    box-sizing: border-box;
  }
  :before {
    color: #fff;
    background: rgba(46, 124, 240);
    transform: rotateY(0deg) translateZ(25px);
  }
  :after {
    color: rgba(46, 124, 240);
    transform: rotateX(90deg) translateZ(25px);
  }
  :hover {
    transform: translateZ(-25px) rotateX(-90deg);
  }
`;

const NextBtn = styled(PrevBtn)`
  :before,
  :after {
    content: "NEXT";
  }
`;

export default DataList;

0개의 댓글