<div id="app"></div>
body {
margin: 0;
}
#modal {
margin: 0;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 50%;
height: 50%;
background-color: white;
border: 2px solid black;
padding: 7px;
minheight: 100px;
}
@media only screen and (max-width: 768px) {
#modal {
width: 100%;
height: 100%;
}
}
.centered {
margin: 0;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
display: flex;
flex-direction: column;
}
.gray {
background-color: gray;
}
/*
* https://frontendeval.com/questions/modal-overlay
*
* Build a modal control and overlay
*/
const { useState, useRef, useEffect } = React;
const App = () => {
const offerNumberStrings = ["one", "two"];
const defaultAcceptedOffers = { one: false, two: false };
const [modalVisible, setModalVisible] = useState(false);
const [modalOfferNumber, setModalOfferNumber] = useState("one");
const [acceptedOffers, setAcceptedOffers] = useState(defaultAcceptedOffers);
const modalRef = useRef();
useEffect(() => {
const outsideModalClickHandler = (event) => {
console.log("triggered click handler");
if (!modalRef.current?.contains(event.target)) {
setModalVisible(false);
}
};
const escapeModalKeypressHandler = (event) => {
console.log("triggered escape handler");
if (event.keyCode === 27) {
setModalVisible(false);
}
};
document
.getElementById("container")
.addEventListener("click", outsideModalClickHandler);
document.addEventListener("keydown", escapeModalKeypressHandler);
return () => {
document
.getElementById("container")
.removeEventListener("click", outsideModalClickHandler);
document.removeEventListener("keydown", escapeModalKeypressHandler);
};
}, [modalRef]);
const handleClickShow = (e) => {
const offerNumber = e.target.innerHTML.split(" ")[2];
setModalOfferNumber(offerNumber);
setModalVisible(true);
event.stopPropagation();
};
const handleClickX = () => {
setModalVisible(false);
};
const handleClickAccept = (e) => {
const offerNumber = e.target.innerHTML.slice(-3);
const updatedAcceptedOffers = {
...acceptedOffers,
[modalOfferNumber]: true
};
console.log(updatedAcceptedOffers);
setAcceptedOffers(updatedAcceptedOffers);
setModalVisible(false);
};
const ShowOfferButton = ({ offerNumberString, offerAccepted }) => {
return offerAccepted ? (
<p style={{ marginBlock: "0px", marginBottom: "18px" }}>
Offer {offerNumberString} accepted
</p>
) : (
<button onClick={handleClickShow}>Show offer {offerNumberString}</button>
);
};
const Modal = ({ modalOfferNumber }) => {
return (
<div id="modal" ref={modalRef}>
<div
style={{
height: "100%",
display: "flex",
flexDirection: "column",
justifyContent: "space-between"
}}
>
<button style={{ width: "fit-content" }} onClick={handleClickX}>
x
</button>
<p
style={{
textAlign: "center"
}}
>
Click the button below to accept our amazing offer!
</p>
<button
style={{
width: "fit-content",
margin: "10px",
alignSelf: "center"
}}
onClick={handleClickAccept}
>
Accept offer {modalOfferNumber}
</button>
</div>
</div>
);
};
return (
<div
id="container"
class={modalVisible && "gray"}
style={{ height: "100vh", width: "100%" }}
>
{modalVisible ? (
<Modal modalOfferNumber={modalOfferNumber} />
) : (
<div class="centered">
{offerNumberStrings.map((offerNumberString) => {
return (
<ShowOfferButton
offerNumberString={offerNumberString}
offerAccepted={acceptedOffers[offerNumberString]}
/>
);
})}
</div>
)}
</div>
);
};
ReactDOM.render(<App />, document.getElementById("app"));
View Compiled
This Pen doesn't use any external CSS resources.