Files
5chan/src/components/CaptchaModal.jsx
T

361 lines
8.3 KiB
React
Raw Normal View History

2023-04-07 17:47:51 +02:00
import React, { useEffect, useState, useRef } from 'react';
2023-04-08 13:27:17 +02:00
import useGeneralStore from '../hooks/stores/useGeneralStore';
2023-03-09 17:51:56 +01:00
import Modal from 'react-modal';
import styled from 'styled-components';
2023-03-16 21:16:59 +01:00
import Draggable from 'react-draggable';
2023-03-09 17:51:56 +01:00
const StyledModal = styled(Modal)`
2023-03-16 21:16:59 +01:00
.hide-modal-overlay {
display: none;
}
2023-03-09 17:51:56 +01:00
.modal-content {
2023-03-16 21:16:59 +01:00
position: fixed;
2023-03-17 14:35:03 +01:00
top: calc(50% - 150px);
left: calc(50% - 150px);
2023-03-16 21:16:59 +01:00
display: block;
padding: 2px;
font-size: 10pt;
border-left: none;
border-top: none;
2023-03-09 17:51:56 +01:00
}
2023-03-16 21:16:59 +01:00
.modal-header {
font-size: 10pt;
text-align: center;
margin-bottom: 1px;
padding: 0;
height: 18px;
line-height: 18px;
cursor: move;
font-weight: 700;
}
.icon {
all: unset;
float: right;
cursor: pointer;
margin-bottom: -4px;
width: 18px;
height: 18px;
border: none;
}
2023-04-07 17:47:51 +02:00
#field {
2023-03-16 21:16:59 +01:00
border: 1px solid #aaa;
font-family: Arial, Helvetica, sans-serif;
font-size: 10pt;
outline: medium none;
width: 298px;
padding: 2px;
}
textarea {
min-width: 296px;
float: left;
font-size: 10pt;
font-family: Arial, Helvetica, sans-serif;
}
#captcha-container {
position: relative;
clear: both;
width: 302px;
overflow: hidden;
margin-bottom: 3px;
}
#response {
width: 100%;
box-sizing: border-box;
font-size: 11px;
height: 18px;
margin: 0px;
padding: 0px 2px;
font-family: monospace;
vertical-align: middle;
2023-03-09 17:51:56 +01:00
}
img {
2023-03-16 21:16:59 +01:00
height: 100%;
width: 100%;
margin-top: 2px;
position: relative;
display: block;
2023-03-09 17:51:56 +01:00
}
2023-04-07 17:47:51 +02:00
#nav {
2023-03-16 21:16:59 +01:00
float: right;
margin: 0;
2023-04-07 17:47:51 +02:00
width: 40px;
2023-03-09 17:51:56 +01:00
}
2023-03-15 15:25:09 +01:00
${({ selectedStyle }) => {
switch (selectedStyle) {
case 'Yotsuba':
2023-03-16 21:16:59 +01:00
return `
.modal-content {
background-color: #f0e0d6;
border: 1px solid #d9bfb7;
}
2023-03-15 15:25:09 +01:00
2023-03-16 21:16:59 +01:00
.modal-header {
background-color: #ea8;
color: #800;
border: 1px solid #800;
}
.icon {
background-image: url(/assets/buttons/cross_red.png);
}
span {
color: maroon;
}`;
case 'Yotsuba-B':
return `
.modal-content {
background-color: #d6daf0;
border: 1px solid #b7c5d9;
}
.modal-header {
background-color: #98e;
color: #000;
border: 1px solid #000;
}
.icon {
background-image: url(/assets/buttons/cross_blue.png);
}
span {
color: #000;
}`;
2023-03-15 15:25:09 +01:00
case 'Futaba':
2023-03-16 21:16:59 +01:00
return `
.modal-content {
background-color: #f0e0d6;
border: 1px solid #d9bfb7;
}
.modal-header {
background-color: #ea8;
color: #800;
border: 1px solid #800;
}
.icon {
background-image: url(/assets/buttons/cross_red.png);
}
span {
color: maroon;
}`;
2023-03-15 15:25:09 +01:00
case 'Burichan':
2023-03-16 21:16:59 +01:00
return `
.modal-content {
background-color: #d6daf0;
border: 1px solid #b7c5d9;
}
.modal-header {
background-color: #98e;
color: #000;
border: 1px solid #000;
}
.icon {
background-image: url(/assets/buttons/cross_blue.png);
}
span {
color: #000;
}`;
2023-03-15 15:25:09 +01:00
case 'Tomorrow':
2023-03-16 21:16:59 +01:00
return `
.modal-content {
background-color: #282a2e;
border: 1px solid #111;
}
.modal-header {
background-color: #282a2e;
color: #c5c8c6;
}
.icon {
background-image: url(/assets/buttons/cross_dark.png);
}
2023-04-07 17:47:51 +02:00
#field {
2023-03-16 21:16:59 +01:00
background-color: #282a2e;
color: #c5c8c6;
border: 1px solid #515151;
width: 296px;
}
textarea {
background-color: #282a2e;
color: #c5c8c6;
border: 1px solid #515151;
}
#response {
background-color: #282a2e;
color: #c5c8c6;
outline: none;
border: 1px solid #515151;
}
span {
color: #c5c8c6;
}
#next {
filter: brightness(80%);
}`;
2023-03-15 15:25:09 +01:00
case 'Photon':
2023-03-16 21:16:59 +01:00
return `
.modal-content {
background-color: #ddd;
border: 1px solid #ccc;
}
.modal-header {
background-color: #ddd;
color: #333;
}
.icon {
background-image: url(/assets/buttons/cross_photon.png);
}
span {
color: #333;
}`;
2023-03-15 15:25:09 +01:00
}
}}
2023-03-09 17:51:56 +01:00
`;
2023-04-07 17:47:51 +02:00
const CaptchaModal = ({ isOpen, closeModal }) => {
const {
challengesArray,
pendingComment,
selectedStyle,
setCaptchaResponse,
2023-04-08 13:27:17 +02:00
} = useGeneralStore(state => state);
2023-03-12 22:07:15 +01:00
2023-04-07 17:47:51 +02:00
const [imageSources, setImageSources] = useState([]);
const [currentChallengeIndex, setCurrentChallengeIndex] = useState(0);
const [totalChallenges, setTotalChallenges] = useState(0);
2023-04-03 15:08:45 +02:00
const responseRef = useRef();
const nodeRef = useRef(null);
2023-04-07 17:47:51 +02:00
useEffect(() => {
if (challengesArray) {
const challenges = challengesArray.challenges;
const decryptedChallenges = [];
2023-04-08 09:54:35 +02:00
for (let i = 0; i < challenges?.length; i++) {
2023-04-07 17:47:51 +02:00
const imageString = challenges[i].challenge;
const imageSource = `data:image/png;base64,${imageString}`;
decryptedChallenges.push(imageSource);
}
setImageSources(decryptedChallenges);
setTotalChallenges(decryptedChallenges.length);
}
}, [challengesArray]);
2023-04-03 15:08:45 +02:00
const handleKeyDown = (event) => {
if (event.key === "Enter") {
event.preventDefault();
setCaptchaResponse(responseRef.current.value);
closeModal();
}
2023-03-09 17:51:56 +01:00
};
return (
<StyledModal
2023-03-16 21:16:59 +01:00
isOpen={isOpen}
onRequestClose={closeModal}
contentLabel="Captcha Modal"
shouldCloseOnEsc={false}
shouldCloseOnOverlayClick={false}
selectedStyle={selectedStyle}
overlayClassName="hide-modal-overlay">
2023-03-22 20:55:36 +01:00
<Draggable handle=".modal-header" nodeRef={nodeRef}>
<div className="modal-content" ref={nodeRef}>
2023-03-16 21:16:59 +01:00
<div className="modal-header">
2023-04-07 17:47:51 +02:00
{pendingComment.parentCid ?
("Challenges for Reply c/" + pendingComment.cid) :
"Challenges for New Thread"}
2023-04-03 15:08:45 +02:00
<button className="icon" onClick={() => closeModal()} title="close" />
2023-03-16 21:16:59 +01:00
</div>
<div id="form">
2023-04-07 17:47:51 +02:00
{pendingComment.displayName ? (
<div>
<input id="field" type="text" placeholder={pendingComment.displayName} disabled />
</div>
) : null}
{pendingComment.title ? (
<div>
<input id="field" type="text" placeholder={pendingComment.title} disabled />
</div>
) : null}
{pendingComment.content ? (
<div>
<textarea
rows="4"
placeholder={pendingComment.content || "Comment"}
wrap="soft"
disabled
/>
</div>
) : null}
{pendingComment.link ? (
<div>
<input id="field" type="text" placeholder={pendingComment.link} disabled />
</div>
) : null}
2023-03-16 21:16:59 +01:00
<div id="captcha-container">
<input
id="response"
type="text"
autoComplete='off'
placeholder="TYPE THE CAPTCHA HERE AND PRESS ENTER"
2023-04-03 15:08:45 +02:00
ref={responseRef}
onKeyDown={handleKeyDown}
2023-03-16 21:16:59 +01:00
autoFocus />
2023-04-07 17:47:51 +02:00
<img src={imageSources[currentChallengeIndex]} alt="captcha" />
2023-03-16 21:16:59 +01:00
</div>
<div>
2023-04-07 17:47:51 +02:00
<span style={{lineHeight: '1.7'}}>
Challenge {currentChallengeIndex + 1} of {totalChallenges}
</span>
<button id="nav" onClick={() => {
setCurrentChallengeIndex((currentChallengeIndex + 1) % totalChallenges)
}
}>&gt;</button>
<button id="nav" onClick={()=> {
setCurrentChallengeIndex((currentChallengeIndex - 1 + totalChallenges) % totalChallenges)
}}>&lt;</button>
2023-03-16 21:16:59 +01:00
</div>
</div>
</div>
</Draggable>
2023-03-09 17:51:56 +01:00
</StyledModal>
);
};
Modal.setAppElement('#root');
2023-03-21 11:17:54 +01:00
export default CaptchaModal;