[실전 프로젝트] 로그인 전 다이어리 페이지 접근 시 팝업창 띄우기 / 음원 활성화/비활성화 구현
본문 바로가기
항해 중/8-13주차 실전 프로젝트

[실전 프로젝트] 로그인 전 다이어리 페이지 접근 시 팝업창 띄우기 / 음원 활성화/비활성화 구현

by 은돌1113 2021. 12. 31.

오늘 한 일

1. 로그인 유도 팝업창 어떤 상황에서 띄울 지 아침 회의에서 정함

2. 로그인 전에 다이어리 페이지 접근 하려고 하면 로그인 유도 팝업창 띄우기

3. 음원 활성화 시 play, 비활성화 시 pause 되도록 구현

 

코드 구현

1) 로그인 전에 다이어리 페이지 접근 하려고 하면 로그인 유도 팝업창 띄우기 → 첫 시도에는 모달창이 켜지는 데 그 뒤에는 켜지지 않음 (Modal이 false가 되어서 안켜지는 것 같음) → RequireLogin.js와 Navigation.js 코드 수정

(미니 프로젝트 할 때 메인 → 로그인 팝업 띄울 때 상황이랑 똑같아서 미니 프로젝트 코드를 참고했다.)

더보기
더보기
// src/components/Navigation.js

import React from "react";
import styled from "styled-components";
import { useHistory } from "react-router-dom";
import RequireLogin from "../components/RequireLogin";

const Navigation = (props) => {
  const history = useHistory();
  const token = localStorage.getItem("token");
  const [diaryModal, setDiaryModal] = React.useState(false);

  const diary = () => {
    if (!token) {
      setDiaryModal(true);
    } else {
      history.push("/diary");
    }
  };

  return (
    <>
      <div
        style={{
          display: "flex",
          justifyContent: "space-between",
          width: "300px",
          backgroundColor: "#dddddd",
          margin: "auto",
          marginTop: `${props.marginTop ? props.marginTop : ""}`,
          padding: "10px",
        }}
      >
        <div
          onClick={() => {
            history.push("/");
          }}
        >
          <Icon></Icon>홈
        </div>
        <div
          onClick={() => {
            history.push("/asmr");
          }}
        >
          <Icon></Icon>ASMR
        </div>
        <div onClick={diary}>
          <Icon></Icon>다이어리
        </div>
        {diaryModal && (
          <RequireLogin
            modal={diaryModal}
            setDiaryModal={setDiaryModal}
          ></RequireLogin>
        )}
        <div
          onClick={() => {
            history.push("/mypage");
          }}
        >
          <Icon></Icon>마이
        </div>
      </div>
    </>
  );
};

const Icon = styled.div`
  width: 30px;
  height: 30px;
  border: 1px dotted black;
  margin: auto;
`;

export default Navigation;
// src/components/RequireLogin.js

import { fontWeight, margin, textAlign } from "@mui/system";
import React from "react";
import Modal from "react-modal";
import { history } from "../redux/configureStore";
const RequireLogin = (props) => {
  const [modal, setModal] = React.useState(props.modal ? true : false); // 모달창

  const modalOff = () => {    
    setModal(false);
    props.setDiaryModal(false);
  };

  return (
    <>
      <Modal
        isOpen={modal}
        ariaHideApp={false}
        onRequestClose={modalOff}
        style={{
          overlay: {
            position: "fixed",
            top: 0,
            left: 0,
            right: 0,
            bottom: 0,
            backgroundColor: "rgba(255, 255, 255, 0)",
          },
          content: {
            position: "absolute",
            top: "200px",
            left: "40%",
            width: "20%",
            height: "40%",
            border: "1px solid #ccc",
            background: "#C4C4C4ff",
            overflow: "auto",
            WebkitOverflowScrolling: "touch",
            borderRadius: "30px",
            outline: "none",
            padding: "0px",
          },
        }}
      >
        <div>
          <p
            style={{
              fontSize: "13px",
              fontWeight: "700",
              textAlign: "center",
              margin: "40px 0px 0px 0px",
            }}
          >
            해당 서비스는 로그인 후 이용 가능합니다
          </p>
          <p
            style={{
              fontSize: "13px",
              fontWeight: "500",
              textAlign: "center",
              margin: "10px 0px 0px 0px",
            }}
          >
            로그인하러 가시겠습니까?
          </p>
        </div>
        <div
          style={{
            display: "flex",
            alignContent: "flex-end",
            position: "absolute",
            bottom: "0px",
            width: "100%",
          }}
        >
          <button
            style={{
              width: "100%",
              height: "50px",
              border: "none",
              margin: "0px 1px 0px 0px",
            }}
            onClick={() => history.push("/login")}
          >
            예
          </button>
          <button
            style={{ width: "100%", height: "50px", border: "none" }}
            onClick={modalOff}
          >
            아니오
          </button>
        </div>
      </Modal>
    </>
  );
};

export default RequireLogin;

 

2) 음원 활성화 시 play, 비활성화 시 pause 되도록 구현

: 음원 활성화 시 재생 / 비활성화 시 정지 기능 구현 할 때 pause가 안되서 질문을 올렸었는데! 아래처럼 답변이 왔다.

- 접점을 만들어 주기 위해서 컴포넌트에 audio 객체를 담을 state를 3개 만들어 줬다.

  const [song1, setSong1] = React.useState(new Audio());
  const [song2, setSong2] = React.useState(new Audio());
  const [song3, setSong3] = React.useState(new Audio());

- 음원 선택 시 활성화 되면 음원 재생

        // 음원 선택 시 활성화 되면서 음원 재생
        if (!song1.src) {
          song1.src = asmrUrl;
          song1.loop = true;
          song1.play();
        } else if (!song2.src) {
          song2.src = asmrUrl;
          song2.loop = true;
          song2.play();
        } else if (!song3.src) {
          song3.src = asmrUrl;
          song3.loop = true;
          song3.play();
        }

- 음원 다시 한번 더 선택 시 비활성화 되면 음원 정지

      // 비활성화 시 음원도 해당 음원 재생 정지
      if (song1.src.indexOf(asmrUrl) !== -1) {
        song1.pause();
        setSong1(new Audio());
      } else if (song2.src.indexOf(asmrUrl) !== -1) {
        song2.pause();
        setSong2(new Audio());
      } else if (song3.src.indexOf(asmrUrl) !== -1) {
        song3.pause();
        setSong3(new Audio());
      }

되도록 코드를 변경했다!

 

전체 코드

더보기
더보기
import React from "react";
import styled from "styled-components";
import { useDispatch, useSelector } from "react-redux";
import { useHistory } from "react-router-dom";
import { actionCreators as asmrActions } from "../redux/modules/asmr";
import AsmrPopUp from "../components/AsmrPopUp";

const Asmr = ({ location }) => {
  const [getCategory, setCategory] = React.useState(
    location.category ? location.category : "전체"
  );
  const [sound, setSound] = React.useState([]);
  const asmrInfo = useSelector((state) => state.asmr.asmrList);
  const [play, setPlay] = React.useState([]);

  const [song1, setSong1] = React.useState(new Audio());
  const [song2, setSong2] = React.useState(new Audio());
  const [song3, setSong3] = React.useState(new Audio());

  const history = useHistory();
  const dispatch = useDispatch();
  const [openModal, setOpenmodal] = React.useState(false);

  React.useEffect(() => {
    // 1) 카테고리별 활성화 유무
    const arr = ["전체", "자연", "공간", "물체"];

    arr.forEach((arrItem) => {
      if (arrItem !== getCategory) {
        // 비활성화
        document.getElementById(arrItem).style.color = "black";
      }
      document.getElementById(getCategory).style.color = "white"; // 활성화
    });

    // 2) 음원 데이터 유무
    if (!asmrInfo) {
      dispatch(asmrActions.getAsmrDB());
    }

    // 3) 음원을 출력하기 전에 카테고리에 맞게 필터링
    if (getCategory === "전체") {
      const all = asmrInfo.filter((item) => {
        if (item.categoryName === "전체") {
          return item;
        }
      });
      setSound(all);
    } else if (getCategory === "자연") {
      const nature = asmrInfo.filter((item) => {
        if (item.categoryName === "자연") {
          return item;
        }
      });
      setSound(nature);
    } else if (getCategory === "공간") {
      const place = asmrInfo.filter((item) => {
        if (item.categoryName === "공간") {
          return item;
        }
      });
      setSound(place);
    } else if (getCategory === "물체") {
      const object = asmrInfo.filter((item) => {
        if (item.categoryName === "물체") {
          return item;
        }
      });
      setSound(object);
    }

    // 4) 카테고리가 바뀌면 활성화된 음원 초기화
    setPlay([]);
  }, [getCategory]);

  const select = (asmrUrl) => {
    if (play.includes(asmrUrl)) {
      // 비활성화
      let arr = [...play];
      arr = arr.filter((item) => {
        if (asmrUrl !== item) {
          return item;
        }
      });
      setPlay(arr);

      // 비활성화 시 음원도 해당 음원 재생 정지
      if (song1.src.indexOf(asmrUrl) !== -1) {
        song1.pause();
        setSong1(new Audio());
      } else if (song2.src.indexOf(asmrUrl) !== -1) {
        song2.pause();
        setSong2(new Audio());
      } else if (song3.src.indexOf(asmrUrl) !== -1) {
        song3.pause();
        setSong3(new Audio());
      }

      // 선택한 음원 비활성화 style
      const deleteItem = document.getElementById(asmrUrl);
      deleteItem.style.backgroundColor = "gray";
    } else {
      // 활성화
      if (play.length > 2) {
        window.alert("음원은 3개까지만 담으실 수 있습니다.");
      } else {
        const arr = [...play, asmrUrl];
        setPlay(arr);

        // 음원 선택 시 활성화 되면서 음원 재생
        if (!song1.src) {
          song1.src = asmrUrl;
          song1.loop = true;
          song1.play();
        } else if (!song2.src) {
          song2.src = asmrUrl;
          song2.loop = true;
          song2.play();
        } else if (!song3.src) {
          song3.src = asmrUrl;
          song3.loop = true;
          song3.play();
        }

        // 선택한 음원 활성화 style
        const selectItem = document.getElementById(asmrUrl);
        selectItem.style.backgroundColor = "#dddddd";
      }
    }
  };

  return (
    <>
      <div>
        {" "}
        {/* 나중에 여기로 전체 크기 핸드폰 사이즈로 바꿔야함 */}
        <div
          onClick={() => {
            history.push("/");
          }}
        >
          ASMR 페이지
        </div>
        <div style={{ display: "flex", margin: "0px 40%" }}>
          <Category
            id="전체"
            onClick={() => {
              setCategory("전체");
            }}
          >
            전체
          </Category>
          <Category
            id="자연"
            onClick={() => {
              setCategory("자연");
            }}
          >
            자연
          </Category>
          <Category
            id="공간"
            onClick={() => {
              setCategory("공간");
            }}
          >
            공간
          </Category>
          <Category
            id="물체"
            onClick={() => {
              setCategory("물체");
            }}
          >
            물체
          </Category>
        </div>
        <div style={{ margin: "0px 40%", display: "flex", flexWrap: "wrap" }}>
          {sound.map((item) => {
            return (
              <Sound
                id={item.asmrUrl}
                key={item.categoryIdx}
                onClick={() => {
                  select(item.asmrUrl);
                }}
              >
                <p>{item.asmrUrl}</p>
                <p>{item.title}</p>
              </Sound>
            );
          })}
        </div>
        {play.length > 0 ? (
          <button
            onClick={() => {
              setOpenmodal(true);
              console.log("음원 url 가지고 이동!!!", play);
            }}
          >
            음량 조절 하러 가기
          </button>
        ) : null}
        {openModal && <AsmrPopUp play={play} closeModal={setOpenmodal} />}
      </div>
    </>
  );
};

const Category = styled.div`
  width: 100px;
  height: 50px;
  line-height: 50px;
  background-color: gray;
`;

const Sound = styled.div`
  width: 100px;
  height: 100px;
  background-color: gray;
  margin: 10px;
`;

export default Asmr;

 

댓글