storage.tsx
const storage = {
getItem: <T,>(key: string, initialValue: T) => {
const value = localStorage.getItem(key);
return value === null ? initialValue : JSON.parse(value);
},
setItem: <T,>(key: string, value: T) => {
try {
localStorage.setItem(key, JSON.stringify(value));
} catch (error) {
console.error(error);
}
},
removeItem: (key: string) => {
localStorage.removeItem(key);
},
};
export default storage;
Modal.tsx
import styled from "@emotion/styled";
import storage from "./storage";
import { useEffect, useState } from "react";
const Modal = () => {
const [isOpen, setIsOpen] = useState<boolean>(true);
useEffect(() => {
const today = new Date().getTime();
const popUp = storage.getItem("popup", true);
if (today > popUp) {
storage.removeItem("popup");
setIsOpen(true);
} else {
setIsOpen(false);
}
}, []);
const hideModal = () => {
const today = new Date();
storage.setItem(
"popup",
new Date(today.setDate(today.getDate() + 1)).getTime()
);
setIsOpen(false);
};
const closeModal = () => {
setIsOpen(false);
};
return (
<>
{isOpen ? (
<Contain>
<Card>
<img src="" />
<BtnWrap>
<span onClick={hideModal}>하루동안 보지 않기</span>
<span onClick={closeModal}>창 닫기</span>
</BtnWrap>
</Card>
</Contain>
) : null}
</>
);
};
export default Modal;
const Contain = styled.div`
position: fixed;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.3);
top: 0;
left: 0;
`;
const Card = styled.div`
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 280px;
height: 350px;
background: #fff;
border-radius: 20px;
overflow: hidden;
position: relative;
img {
width: 100%;
height: 295px;
object-fit: cover;
vertical-align: bottom;
}
`;
const BtnWrap = styled.div`
display: grid;
grid-template-columns: 1fr 1fr;
height: 55px;
span {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
font-size: 14px;
}
span:last-child {
border-left: 1px solid #eee;
}
span:hover {
background: #eee;
cursor: pointer;
}
`;