이번 프로젝트에선 공유하기 모달창이 있다!
사실 별 복잡하지 않은 구조의 모달이었고, 사용자 입장에서도 그닥 중요하지 않은 모달창인데...
왜인지 모르게 은근히 시간이 오래 걸려 기록한다.

공유하기 모달 컴포넌트 전체 코드

import React, { useRef, useState } from 'react';
import styled from 'styled-components';

const JobDetailShareModal = ({ isShareOpen, handleShareModal }) => {
  const link = useRef();
  const modal = useRef();
  const closeBtn = useRef();

  const [isCopied, setIsCopied] = useState(false);

  const toClipboard = () => {
    if (!isCopied) {
      navigator.clipboard.writeText(link.current.innerHTML);
      setIsCopied(true);
    }
  };

  const closeModal = e => {
    if (!modal.current.contains(e.target) || e.target === closeBtn.current) {
      handleShareModal();
      setIsCopied(false);
    }
  };

  return (
    <ModalWrap isShareOpen={isShareOpen} onClick={closeModal}>
      <ShareModal ref={modal}>
        <ModalDesc>
          <h1>공유하기</h1>
          <i
            className="fa-solid fa-xmark"
            ref={closeBtn}
            onClick={closeModal}
          />
          <p>
            이 포지션과 어울리는 사람을 알고 있다면, 공유해주세요!
            <br />
            공유 후 추천까지 완료하면,
            <strong> 지원자 최종합격시 보상금을 지급해드립니다.</strong>
          </p>
        </ModalDesc>
        <LinkShare>
          <h1>링크 공유</h1>
          <LinkButton>
            <span className="url" ref={link}>
              {window.location.href}
            </span>
            <span className="copy" onClick={toClipboard}>
              {isCopied ? <i className="fa-solid fa-check" /> : '복사'}
            </span>
          </LinkButton>
          {isCopied && <h2>복사되었습니다!</h2>}
        </LinkShare>
      </ShareModal>
    </ModalWrap>
  );
};

const ModalWrap = styled.div`
  display: ${({ isShareOpen }) => (isShareOpen ? 'block' : 'none')};
  position: fixed;
  left: 0;
  top: 0;
  width: 100vw;
  height: 100vh;
  background-color: rgba(0, 0, 0, 0.5);
  overflow: hidden;
  z-index: 1100;
`;

const ShareModal = styled.div`
  position: absolute;
  border-radius: 5px;
  background-color: #fff;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 100%;
  max-width: 500px;
`;

const ModalDesc = styled.div`
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 20px 20px;
  border-bottom: 1px solid ${({ theme }) => theme.borderGray};
  .fa-xmark {
    position: absolute;
    top: 20px;
    right: 20px;
    font-size: 16px;
    cursor: pointer;
  }
  h1 {
    font-size: 16px;
    line-height: 19px;
    margin-bottom: 40px;
  }
  p {
    text-align: center;
    font-size: 14px;
    line-height: 23px;
    color: ${({ theme }) => theme.fontGray};
    strong {
      font-weight: 600;
    }
  }
`;

const LinkShare = styled.div`
  padding: 20px;
  font-size: 14px;
  h1 {
    font-weight: 400;
    margin-bottom: 12px;
  }
  h2 {
    margin-top: 12px;
    margin-right: 2px;
    font-size: 12px;
    color: ${({ theme }) => theme.themePurple};
    font-weight: 500;
    text-align: right;
  }
`;

const LinkButton = styled.div`
  width: 100%;
  text-align: left;
  font-size: 14px;
  .url {
    display: inline-block;
    width: 80%;
    padding: 16px 0 16px 16px;
    border: 1px solid ${({ theme }) => theme.borderGray};
    border-radius: 5px 0 0 5px;
  }
  .copy {
    display: inline-block;
    border: 1px solid ${({ theme }) => theme.borderGray};
    border-left: none;
    border-radius: 0 5px 5px 0;
    text-align: center;
    width: 20%;
    padding: 16px 0;
    color: ${({ theme }) => theme.themePurple};
    font-weight: 500;
  }
`;

export default JobDetailShareModal;

1. 현재 링크를 넣자

<span className="url" ref={link}>
  {window.location.href}
</span>

사실 원티드에서는 현재 링크와 달리 축소된 다른 링크를 주었다. 하지만 이건 다음 추가 구현으로 넘기자...
window.location.href를 통하여 간편하게 링크를 가져올 수 있었다 (useLocation 사용 없이)


2. 복사 전, 복사 후를 다르게 렌더링 할 state 선언

const [isCopied, setIsCopied] = useState(false);

<LinkShare>
  <h1>링크 공유</h1>
  <LinkButton>
    <span className="url" ref={link}>
      {window.location.href}
    </span>
    <span className="copy" onClick={toClipboard}>
      {isCopied ? <i className="fa-solid fa-check" /> : '복사'}
    </span>
  </LinkButton>
  {isCopied && <h2>복사되었습니다!</h2>}
</LinkShare>

isCopied 값에 따라 렌더링을 달리 하기!


3. 복사 버튼 클릭 시 클립보드에 링크 넣기

const toClipboard = () => {
  if (!isCopied) {
    navigator.clipboard.writeText(link.current.innerHTML);
    setIsCopied(true);
  }
};

<LinkButton>
  <span className="url" ref={link}>
    {window.location.href}
  </span>
  <span className="copy" onClick={toClipboard}>
    {isCopied ? <i className="fa-solid fa-check" /> : '복사'}
  </span>
</LinkButton>
  1. 복사 버튼 클릭 시 toClipboard 함수 실행
  2. isCopied가 false일 시 navigator.clipboard.writeText(link.current.innerHTML) 클립보드에 link 요소의 innerHTML에 있는 텍스트를 복사한다.
  3. isCopied는 true로 만들어서 또다시 복사하지 못하게 한다.

4. 모달창을 닫으면 초기화 시켜주기

그냥 이렇게 끝내려고 했다, 하지만 테스트 해보니 이 상태로는 복사를 마치고 모달창을 닫고, 다시 열면 isCopied가 계속 true 상태여서 또 복사를 하지 못한다. 이건 UX를 해친다고 판단하여 모달창을 닫으면 초기화 시켜주는 부분까지 넣기!

const closeModal = e => {
  if (!modal.current.contains(e.target) || e.target === closeBtn.current) {
    handleShareModal(); // 모달 닫기
    setIsCopied(false); // isCopied를 다시 false로 만들어 다시 들어오면 또 복사할 수 있도록 하기
  }
};
profile
Dig a little deeper

0개의 댓글

Powered by GraphCDN, the GraphQL CDN