[PROJECT 1] 햄릿증후군을 위한 술자리 결정 웹 서비스 #5 안주선택

세나정·2023년 1월 23일
1
post-thumbnail

안주선택 (detail.js) UI

우선 Main에서 명언문을 클릭하여 이러한 Detail 페이지로 이동할 수 있습니다. 파라미터 문법을 활용하여 데이터베이스에 미리 저장돼있는 술, 안주 데이터를 갖고 옵니다.
예시) 소주 0번 파라미터 - 데이터베이스의 적재된 배열의 0번 인덱스

  // ID에 유저 ID를 대입하여 mypage의 데이터베이스에서 찜목록 갖고 오기
  const ID = sessionStorage.getItem("ID");
  
  // useParams를 활용하여 해당하는 파라미터의 값 갖고오기
  // *메인에서 Link를 활용하여 미리 각 술에 대해 해당 페이지를 줬음
  // detail/0 : 소주 | detail/1 : 양주 | detail/2 : 와인 | detail/3 : 맥주 detail/4 : 막걸리
  const { id } = useParams();
  
  
  useEffect(() => {
    axios.get("detail").then((주류응답) => {
      setCategory(주류응답.data[id]);
    });

    axios.get("/food").then((음식응답) => {
      setfoodCago(음식응답.data[id]);
    });

    axios.post("/mypage", { data: ID }).then((응답) => {
      내거변경([...응답.data]);
    });
  }, []);

useEffect를 활용하여 페이지가 랜더링 될 시에 해당하는 주류, 음식 정보를 가지고 오고 mypage에 post요청을 하는 이유는 mypage에 저장돼 있는 찜목록을 반영하기 위해서 입니다.

즉, 위 주석에 나와 있듯이 미리 main에서 페이지를 지정하여 이동을 시킨 뒤, 해당하는 페이지를 useParams를 활용하여 갖고 온 후에, 해당하는 페이지 넘버와 데이터베이스의 배열의 인덱스에 접근하여 가지고 오는 것입니다.


- 상단 (선택 주류 정보 및 대표 안주)

이렇게 해당하는 주류 페이지에 들어갔다면 자신이 선택했던 술의 정보와 간단한 대표 안주 사진들이 slide에 나옵니다 (Auto 슬라이드로서 3.5초마다 순환하며 다른 이미지를 띄움)

const images = [
{ url: `/assets/snacks/${id}/0.jpg` }, 
{ url: `/assets/snacks/${id}/1.jpg` },
{ url: `/assets/snacks/${id}/2.jpg` }];
<div className="col-lg-3 mx-auto test2">
   <div class="mt-2 p-1 ">
      <h2 class="m-3 text-center text-light">음료 Pick✔</h2>
   </div>
   <img class="border border-secondary rounded img-fluid shadow-lg" src={`/assets/${id}/${id}.jpg`} id="liveToastBtn" width="250" height="250"></img>
   <div class="mt-2 p-1 ">
      <h2 class="m-3 text-center text-light">{category.drink}</h2>
   </div>
</div>

... 중간 생략

<div className="test p-3">
   <SimpleImageSlider width={600} height={400} images={images} showBullets={true} showNavs={true} autoPlay={true} autoPlayDelay={3.5} />
</div>

이곳에서도 이전에 받아온 Params를 통해 assets에 미리 저장해놓은 해당 주류에 관한 사진을 보여줍니다.

객체 category의 category.drink의 값은 아래 데이터베이스 저장 형태처럼 미리 넣어놓은 주류와 안주 개수에서 주류를 가지고 옵니다.


- 중단 (해당 주류 안주 카테고리)

이렇게 상단에 정보들을 간단히 띄운 뒤 해당 주류에 관련한 안주의 카테고리들을 데이터베이스로부터 받아올 겁니다.

데이터베이스에 저장된 형태

소주
양주

<div className="test2">
  <div className="container bg-light rounded shadow-lg storeOpacity">
    {category.안주개수 &&
       category.안주개수.map((v, i) => {
         return (
          <button type="button" class="btn btn-lg press_btn g-2 m-3 rounded-pill shadow-sm" key={i} name={v} onClick={handleClickButton}>
                 {v}
          </button>
             );
           })}
   </div>
</div>

위에 useEffect를 활용하여 페이지가 랜더링 될 때에 데이터베이스에서 가져온 데이터를 state를 활용하여 setCategory에 저장 해놓았으므로 category변수(객체) 접근하여 해당 주류에 관한 안주들의 카테고리를 나열합니다.

-- handleClickButton

  const handleClickButton = (e) => {
    const { name } = e.target;
    setContent(name);
  };

나열된 카테고리에 handleClickButton 함수를 만들어 해당하는 name (q배열의 해당 value값)을 클릭시 클릭한 name이 state로 이루어진 content 변수에 저장이 됩니다.


- 하단 (식당 정보와 찜하기, 찜목록)

이제 나열된 안주의 카테고리를 클릭시 해당 안주에 대한 여러 식당들의 정보가 나오고, 찜을 하여 마이페이지에 보내는 가장 중요한 하단 부분입니다.

위에 onClick을 활용하여 content의 값을 내가 선택한 안주 카테고리에 값이 들어갔을 때

<div className="container bg-light rounded shadow-lg storeOpacity2">{content && selectComponent[content]}</div>

<div className="text-center">
	<button class="col-xl-2 btn btn-lg press_btn g-2 m-3">
         <Link to="/Main" style={{ textDecoration: "none", color: "white" }}>
           다른 술 고를래요
         </Link>
	</button>
</div>

다른 술 고를래요라는 버튼은 Link를 통해 다시 Main로 이동하여 다른 술을 선택할 수 있는 페이지로 이동을하게 됩니다.

또한, 우리가 선택한 content의 값과 selectComponent라는 객체의 key값을 비교하여 일치했을 때 해당하는 안주들을 보여줍니다.

회를 클릭하였으면 회에 대한 식당명, 식당 위치, 특징, 평균가격 (3-4곳)의 정보들이 나열 되고 동시에 해당 안주에 대한 식당 상세 페이지로 이동 (랜더링)을 합니다.

이때 페이지에 foodcago, 내거, Mine 3가지를 전달 해줍니다.

- foodcago (데이터베이스에 저장되어 있는 식당, 가격, 특징, 위치 정보)

[서버] - 데이터베이스의 food에 있는 정보를 가지고 옴
app.get("/food", function (요청, 응답) {
  db.collection("food")
    .find()
    .toArray(function (에러, 결과) {
      응답.json(결과);
    });
});

- 내거

[서버] - 데이터베이스의 selection에서 find를 통해
        나의 ID에 해당하는 일치값을 가져옴 
app.post("/mypage", function (요청, 응답) {
  db.collection("selection")
    .find({ id: 요청.body.data })
    .toArray(function (에러, 결과) {
      응답.json(결과);
    });
});

- Mine

const Mine = () => {
  return (
    <>
      <div className="test2">
        <div class=" col-6 bg-light rounded p-1 mx-auto shadow-lg">
          <div className="pt-2">
            <Link to="/Mypage">
              <div class="btn col-lg-4 btn-lg  press_btn rounded mx-auto ">
                <h4 className="text-center text-light ">찜 목록</h4>
              </div>
            </Link>
          </div>
        <div className="p-2">
          {내거.length != 0 ? (
            내거.map((v, i) => {
              return (
            <p class="bg-dark mx-3 p-2 text-light rounded storeOpacity">
                {내거[i].식당}-{내거[i].평균가격}
            </p>
            );})) 
            : (
             <div className="p-1">
               <h4 className="text-secondary">가게를 찜해보세요😋</h4>
             </div>
              )}
            </div>
          </div>
        </div>
      </>
    );
  };

Mine은 내가 찜했던 목록을 보여주는 것이며 "내거" (내가 이전에 찜한 목록)을 보여주며 삼항연산자를 활용하여 비어있을 땐 가게를 찜해보길 권유합니다.
*여기서 Mine을 안주의 상세페이지 (Fish.js)에 넣지 않고 Detail.js에 넣은 이유는 기존 찜목록과 더불어 안주를 추가할시에 바로바로 랜더링을 하기 위해 부모 컴포넌트에 넣었습니다.


- 최하단 (예시 Fish.js)

상세 페이지로 이동(랜더링) 됐을 때 각 술집에 대한 정보 + 찜목록에 대한 정보들이 존재하고 각 술집에 대한 정보와 더불어 하트 이미지를 통해 찜목록에 추가할 수 있으며 하트의 채워짐으로 시각적인 피드백을 얻을 수 있습니다.

<div className="text-center p-3">
  <img
    src={like[i] ? process.env.PUBLIC_URL + "/assets/heart.png" : process.env.PUBLIC_URL + "/assets/em_heart.png"}
    
    onClick={() => {
      let copy = [...like];
      copy[i] = !copy[i];
      setLike([...copy]);

      let body = {
        id: sessionStorage.getItem("ID"),
        식당: foodCago.회[i].식당,
        위치: foodCago.회[i].위치,
        특징: foodCago.회[i].특징,
        평균가격: foodCago.회[i].가격,
        삭제용: sessionStorage.getItem("ID") + foodCago.회[i].식당,
        drink: "소주",
        종류: "회",
      };

      {
        !내거.find((e) => e.식당 === foodCago.회[i].식당) 
        ? (alert("해당 상품이 마이페이지 찜목록에 추가 되었습니다."), axios.post("/selection", body).then(내거.push(body)))
        : alert("이미 찜목록에 존재하므로 찜목록 담기가 불가합니다.");
      }
    }}
    style={{ width: 50, height: 50 }}
  />
</div>

하트 이미지를 미리 선언 돼있던 like state를 활용하여 넣어준 후에 하트를 클릭시 setLike를 통해 하트의 상태를 바꿔주며 상태를 저장합니다. 동시에 body에 데이터베이스에 저장할 여러 정보들을 넣어주며 post요청을 합니다.

이 때, 내가 이전에 찜한 식당일 경우네느 찜목록 담기가 불가하다는 경고창을 띄우고 그렇지 않을 때에만 정상적으로 찜목록에 추가가 되며 그 후 "내 거"라는 찜목록에도 바로 추가를 하여 찜목록에 상태를 반영합니다.

[서버]
app.post("/selection", function (요청, 응답) {
  db.collection("selection").insertOne(
    {
      drink: 요청.body.drink, // 해당 주류 정보
      식당: 요청.body.식당, // 해당 식당 이름
      위치: 요청.body.위치, // 해당 식당 위치
      특징: 요청.body.특징, // 해당 식당 특징 
      평균가격: 요청.body.평균가격, // 평균가격
      id: 요청.body.id, // 사용자 id
      종류: 요청.body.종류, // 음식 종류 
      삭제용: 요청.body.삭제용,
    }
  );
});

여기서 삭제용은 추후 mypage에서 찜목록에 있는 것을 삭제할 때 구별하기 위한 자신의 ID + 식당정보로서 데이터베이스에 해당 삭제용을 찾아 삭제합니다.

profile
기록, 꺼내 쓸 수 있는 즐거움

0개의 댓글

관련 채용 정보