170 lines
4.4 KiB
JavaScript
170 lines
4.4 KiB
JavaScript
/**
|
|
* This file is part of the SplendidBear Websites' projects.
|
|
*
|
|
* Copyright (c) 2026 @ www.splendidbear.org
|
|
*
|
|
* For the full copyright and license information, please view the LICENSE
|
|
* file that was distributed with this source code.
|
|
*/
|
|
import React, { useEffect, useState } from 'react';
|
|
|
|
const CAPTCHA_STORAGE_KEY = 'mineseeker_captcha_verified';
|
|
const CAPTCHA_TOKEN_KEY = 'mineseeker_captcha_token';
|
|
const RECAPTCHA_ACTION = 'mineseeker_play';
|
|
|
|
const CaptchaOverlay = ({ siteKey, onVerified, children }) => {
|
|
const [verified, setVerified] = useState(false);
|
|
const [loading, setLoading] = useState(false);
|
|
const [error, setError] = useState(false);
|
|
|
|
useEffect(() => {
|
|
const storedToken = sessionStorage.getItem(CAPTCHA_TOKEN_KEY);
|
|
const storedTime = sessionStorage.getItem(CAPTCHA_STORAGE_KEY);
|
|
|
|
if (storedToken && storedTime) {
|
|
const elapsed = (Date.now() - parseInt(storedTime)) / 1000;
|
|
if (110 > elapsed) {
|
|
const wrapper = document.getElementById('mine-wrapper');
|
|
if (wrapper) {
|
|
wrapper.dataset.captchaToken = storedToken;
|
|
}
|
|
setVerified(true);
|
|
onVerified?.();
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (window.grecaptcha) {
|
|
window.grecaptcha.ready(() => {
|
|
window.grecaptcha
|
|
.execute(siteKey, { action: RECAPTCHA_ACTION })
|
|
.then(token => {
|
|
handleToken(token);
|
|
})
|
|
.catch(() => {
|
|
setError(true);
|
|
});
|
|
});
|
|
}
|
|
}, [siteKey, onVerified]);
|
|
|
|
const handleToken = token => {
|
|
const wrapper = document.getElementById('mine-wrapper');
|
|
if (wrapper) {
|
|
wrapper.dataset.captchaToken = token;
|
|
}
|
|
sessionStorage.setItem(CAPTCHA_TOKEN_KEY, token);
|
|
sessionStorage.setItem(CAPTCHA_STORAGE_KEY, Date.now().toString());
|
|
setVerified(true);
|
|
onVerified?.();
|
|
};
|
|
|
|
const handleClick = () => {
|
|
setLoading(true);
|
|
setError(false);
|
|
|
|
window.grecaptcha.ready(() => {
|
|
window.grecaptcha
|
|
.execute(siteKey, { action: RECAPTCHA_ACTION })
|
|
.then(token => {
|
|
handleToken(token);
|
|
setLoading(false);
|
|
})
|
|
.catch(() => {
|
|
setLoading(false);
|
|
setError(true);
|
|
setTimeout(() => setError(false), 2000);
|
|
});
|
|
});
|
|
};
|
|
|
|
if (verified) {
|
|
return <>{children}</>;
|
|
}
|
|
|
|
const overlayStyles = {
|
|
position: 'fixed',
|
|
top: 0,
|
|
left: 0,
|
|
width: '100%',
|
|
height: '100%',
|
|
background: 'rgba(7, 9, 13, 0.95)',
|
|
backdropFilter: 'blur(8px)',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
zIndex: 1000,
|
|
};
|
|
|
|
const contentStyles = {
|
|
textAlign: 'center',
|
|
color: '#fff',
|
|
maxWidth: '400px',
|
|
padding: '40px',
|
|
};
|
|
|
|
const iconStyles = {
|
|
fontSize: '64px',
|
|
color: '#236f87',
|
|
marginBottom: '24px',
|
|
};
|
|
|
|
const h1Styles = {
|
|
font: '800 32px Rajdhani, sans-serif',
|
|
margin: '0 0 16px',
|
|
letterSpacing: '1px',
|
|
};
|
|
|
|
const pStyles = {
|
|
color: 'rgba(149, 207, 245, 0.7)',
|
|
font: '400 16px Rajdhani, sans-serif',
|
|
margin: '0 0 32px',
|
|
letterSpacing: '0.5px',
|
|
};
|
|
|
|
const buttonStyles = {
|
|
background: error
|
|
? 'linear-gradient(#8a2323 0%, #681a1a 100%)'
|
|
: loading
|
|
? 'linear-gradient(#236f87 0%, #1a5068 100%)'
|
|
: 'linear-gradient(#236f87 0%, #1a5068 100%)',
|
|
border: `2px solid ${error ? '#9a2e2e' : loading ? '#2e7a9a' : '#2e7a9a'}`,
|
|
borderRadius: '8px',
|
|
color: '#e0f4ff',
|
|
cursor: loading ? 'wait' : 'pointer',
|
|
font: '800 18px Rajdhani, sans-serif',
|
|
letterSpacing: '2px',
|
|
padding: '16px 40px',
|
|
textTransform: 'uppercase',
|
|
transition: 'all 0.3s ease',
|
|
display: 'inline-flex',
|
|
alignItems: 'center',
|
|
gap: '12px',
|
|
opacity: loading ? 0.7 : 1,
|
|
};
|
|
|
|
return (
|
|
<div style={overlayStyles}>
|
|
<div style={contentStyles}>
|
|
<div style={iconStyles}>
|
|
<i className="fa fa-shield-halved" />
|
|
</div>
|
|
<h1 style={h1Styles}>Ready to Play?</h1>
|
|
<p style={pStyles}>
|
|
Click below to verify you're human and start playing.
|
|
</p>
|
|
<button
|
|
style={buttonStyles}
|
|
onClick={handleClick}
|
|
disabled={loading}
|
|
>
|
|
<i className={`fa ${loading ? 'fa-spinner fa-spin' : error ? 'fa-exclamation-circle' : 'fa-play'}`} />
|
|
{loading ? 'Verifying...' : error ? 'Try Again' : 'Start Playing'}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default CaptchaOverlay;
|