SEB_FE_44/과제

[coz-shopping] Modal

언젠간코딩잘함 2023. 5. 15. 22:51

Modal.js 컴포넌트 생성

더보기
import React from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faStar } from "@fortawesome/free-solid-svg-icons";
import { faX } from "@fortawesome/free-solid-svg-icons";

import classes from "./Modal.module.css";

const Modal = ({
  imageUrl,
  handleModalClose,
  isBookmarked,
  handleBookmark,
  title,
}) => {
  const handleOverlayClick = event => {
    if (event.target === event.currentTarget) {
      handleModalClose();
    }
  };

  return (
    <div className={classes.modalOverlay} onClick={handleOverlayClick}>
      <div className={classes.modal}>
        <FontAwesomeIcon
          className={classes.close}
          icon={faX}
          size="lg"
          color="white"
          onClick={handleModalClose}
        />
        <img className={classes.img} src={imageUrl} alt="modalImg" />
        <span className={classes.title}>{title}</span>
        <FontAwesomeIcon
          className={isBookmarked ? classes.bookcolor : classes.bookmark}
          size="lg"
          icon={faStar}
          onClick={handleBookmark}
        />
      </div>
    </div>
  );
};

export default Modal;

 

Modal.module.css 스타일 생성

더보기
.modalOverlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  z-index: 9998;
  display: flex;
  justify-content: center;
  align-items: center;
}

.modal {
  display: flex;
  justify-content: flex-end;
  position: fixed;
  top: 50%;
  left: 50%;
  width: 750px;
  height: 480px;
  border-radius: 8px;
  z-index: 9999;
  transform: translate(-50%, -50%);
  box-shadow: 0 4px 20px;
}

.img {
  width: 100%;
  height: 100%;
  border-radius: 8px;
  object-fit: cover;
}

.close {
  margin: 20px;
  position: absolute;
  z-index: 1;
  cursor: pointer;
}

.bookmark {
  position: absolute;
  bottom: 20px;
  left: 20px;
  color: #ffffff;
  cursor: pointer;
}

.bookcolor {
  position: absolute;
  bottom: 20px;
  left: 20px;
  color: yellow;
  cursor: pointer;
}

.title {
  bottom: 20px;
  left: 50px;
  position: absolute;
  font-weight: 800;
  color: white;
}

 

Item.js 컴포넌트 변경

더보기
import React from "react";
import React, { useState } from "react";
import Modal from "../UI/Modal";

import classes from "./Item.module.css";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faStar } from "@fortawesome/free-solid-svg-icons";

const Item = ({ item, setBookmarkState, isBookmarked }) => {
  const [modalState, setModalState] = useState(false);

  const handleModalOpen = () => {
    setModalState(true);
  };

  const handleModalClose = () => {
    setModalState(false);
  };

  const handleBookmark = item => {
    const bookmark = JSON.parse(localStorage.getItem("bookmark")) || [];

    const existingItemIndex = bookmark.findIndex(x => x.id === item.id);
    const isExistingItem = existingItemIndex !== -1;
    if (isExistingItem) {
      bookmark.splice(existingItemIndex, 1);
    } else {
      bookmark.unshift(item);
    }
    localStorage.setItem("bookmark", JSON.stringify(bookmark));
    setBookmarkState(JSON.parse(localStorage.getItem("bookmark")));
  };

  return (
    <div className={classes.item}>
      <div className={classes.imgBox}>
        <img
          className={classes.img}
          src={item.image_url ? item.image_url : item.brand_image_url}
          alt="img"
        />
        <FontAwesomeIcon
          className={isBookmarked ? classes.bookcolor : classes.bookmark}
          size="lg"
          icon={faStar}
          onClick={() => {
            handleBookmark(item);
          }}
    <>
      {modalState && (
        <Modal
          imageUrl={item.image_url || item.brand_image_url}
          handleModalClose={handleModalClose}
          isBookmarked={isBookmarked}
          handleBookmark={() => handleBookmark(item)}
          title={item.title || item.brand_name}
        />
      </div>
      <div className={classes.firstLine}>
        {
          <span className={classes.title}>
            {item.title ? item.title : item.brand_name}
          </span>
        }
        {(() => {
          switch (item.type) {
            case "Brand":
              return <span className={classes.customer}>관심고객수</span>;
            case "Product":
              return (
                <span className={classes.percent}>
                  {item.discountPercentage}%
                </span>
              );
            default:
              return "";
      )}
      <div className={classes.item}>
        <div className={classes.imgBox}>
          <img
            className={classes.img}
            src={item.image_url ? item.image_url : item.brand_image_url}
            alt="img"
            onClick={handleModalOpen}
          />
          <FontAwesomeIcon
            className={isBookmarked ? classes.bookcolor : classes.bookmark}
            size="lg"
            icon={faStar}
            onClick={() => {
              handleBookmark(item);
            }}
          />
        </div>
        <div className={classes.firstLine}>
          {
            <span className={classes.title}>
              {item.title ? item.title : item.brand_name}
            </span>
          }
        })()}
      </div>
      <div className={classes.firstLine}>
        <span>{item.sub_title ? item.sub_title : ""}</span>
        <span className={classes.follower}>
          {(() => {
            switch (item.type) {
              case "Product":
                return `${item.price
                  .toString()
                  .replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",")}원`;
              case "Brand":
                return item.follower
                  .toString()
                  .replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",");
                return <span className={classes.customer}>관심고객수</span>;
              case "Product":
                return (
                  <span className={classes.percent}>
                    {item.discountPercentage}%
                  </span>
                );
              default:
                return "";
            }
          })()}
        </span>
        </div>
        <div className={classes.firstLine}>
          <span>{item.sub_title ? item.sub_title : ""}</span>
          <span className={classes.follower}>
            {(() => {
              switch (item.type) {
                case "Product":
                  return `${item.price
                    .toString()
                    .replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",")}원`;
                case "Brand":
                  return item.follower
                    .toString()
                    .replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",");
                default:
                  return "";
              }
            })()}
          </span>
        </div>
      </div>
    </div>
    </>
  );
};

export default Item;

Modal.js 컴포넌트 변경

더보기
import React from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faStar } from "@fortawesome/free-solid-svg-icons";
import { faX } from "@fortawesome/free-solid-svg-icons";

import classes from "./Modal.module.css";

const Modal = ({
  imageUrl,
  handleModalClose,
  title,
  setWillBookmarked,
  willBookmarked,
}) => {
  const handleOverlayClick = event => {
    if (event.target === event.currentTarget) {
      handleModalClose();
    }
  };

  const handleModalBookmark = () => {
    setWillBookmarked(prev => !prev);
  };

  return (
    <div className={classes.modalOverlay} onClick={handleOverlayClick}>
      <div className={classes.modal}>
        <FontAwesomeIcon
          className={classes.close}
          icon={faX}
          size="lg"
          color="white"
          onClick={handleModalClose}
        />
        <img className={classes.img} src={imageUrl} alt="modalImg" />
        <span className={classes.title}>{title}</span>
        <FontAwesomeIcon
          className={willBookmarked ? classes.bookcolor : classes.bookmark}
          size="lg"
          icon={faStar}
          onClick={handleModalBookmark}
        />
      </div>
    </div>
  );
};

export default Modal;

 

Item.js 컴포넌트 변경

더보기
const Item = ({ item, setBookmarkState, isBookmarked }) => {
  const [modalState, setModalState] = useState(false);
  const [willBookmarked, setWillBookmarked] = useState(false);

  const handleModalOpen = () => {
    setModalState(true);
    setWillBookmarked(isBookmarked);
  };

  const handleModalClose = () => {
    if (isBookmarked && !willBookmarked) {
      const bookmark = JSON.parse(localStorage.getItem("bookmark"));
      const existingItemIndex = bookmark.findIndex(x => x.id === item.id);
      bookmark.splice(existingItemIndex, 1);
      localStorage.setItem("bookmark", JSON.stringify(bookmark));
      setBookmarkState(JSON.parse(localStorage.getItem("bookmark")));
    }
    if (!isBookmarked && willBookmarked) {
      const bookmark = JSON.parse(localStorage.getItem("bookmark")) || [];
      bookmark.unshift(item);
      localStorage.setItem("bookmark", JSON.stringify(bookmark));
      setBookmarkState(JSON.parse(localStorage.getItem("bookmark")));
    }
    setModalState(false);
  };

  const handleBookmark = item => {
    const bookmark = JSON.parse(localStorage.getItem("bookmark")) || [];
    const existingItemIndex = bookmark.findIndex(x => x.id === item.id);
    const isExistingItem = existingItemIndex !== -1;
    if (isExistingItem) {
      bookmark.splice(existingItemIndex, 1);
    } else {
      bookmark.unshift(item);
    }
    localStorage.setItem("bookmark", JSON.stringify(bookmark));
    setBookmarkState(JSON.parse(localStorage.getItem("bookmark")));
  };
  return (
    <>
      {modalState && (
        <Modal
          imageUrl={item.image_url || item.brand_image_url}
          handleModalClose={handleModalClose}
          isBookmarked={isBookmarked}
          handleBookmark={() => handleBookmark(item)}
          title={item.title || item.brand_name}
          setWillBookmarked={setWillBookmarked}
          willBookmarked={willBookmarked}
        />
      )}
      <div className={classes.item}>
        <div className={classes.imgBox}>
          <img
            className={classes.img}
            src={item.image_url ? item.image_url : item.brand_image_url}
            alt="img"
            onClick={handleModalOpen}
          />
          <FontAwesomeIcon
            className={isBookmarked ? classes.bookcolor : classes.bookmark}
            size="lg"
            icon={faStar}
            onClick={() => {
              handleBookmark(item);
            }}
          />
        </div>
        <div className={classes.firstLine}>
          {
            <span className={classes.title}>
              {item.title ? item.title : item.brand_name}
            </span>
          }
          {(() => {
            switch (item.type) {
              case "Brand":
                return <span className={classes.customer}>관심고객수</span>;
              case "Product":
                return (
                  <span className={classes.percent}>
                    {item.discountPercentage}%
                  </span>
                );
              default:
                return "";
            }
          })()}
        </div>
        <div className={classes.firstLine}>
          <span>{item.sub_title ? item.sub_title : ""}</span>
          <span className={classes.follower}>
            {(() => {
              switch (item.type) {
                case "Product":
                  return `${item.price
                    .toString()
                    .replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",")}원`;
                case "Brand":
                  return item.follower
                    .toString()
                    .replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",");
                default:
                  return "";
              }
            })()}
          </span>
        </div>
      </div>
    </>
  );
};
export default Item;