feat: Persist guest session captcha verification and display guest's own name in navbar header and shift matrix table
This commit is contained in:
@@ -3,8 +3,15 @@ import { X, ShieldCheck, UserCheck, AlertCircle, CheckCircle2 } from 'lucide-rea
|
||||
|
||||
export default function GuestSignupModal({ shift, onClose, onSubmit }) {
|
||||
const [guestName, setGuestName] = useState('');
|
||||
const [captchaToken, setCaptchaToken] = useState('');
|
||||
const [isCaptchaSolved, setIsCaptchaSolved] = useState(false);
|
||||
const [sessionVerified, setSessionVerified] = useState(() => {
|
||||
return sessionStorage.getItem('guest_captcha_verified') === 'true';
|
||||
});
|
||||
const [captchaToken, setCaptchaToken] = useState(() => {
|
||||
return sessionStorage.getItem('guest_captcha_verified') === 'true' ? 'acaptcha-session-verified' : '';
|
||||
});
|
||||
const [isCaptchaSolved, setIsCaptchaSolved] = useState(() => {
|
||||
return sessionStorage.getItem('guest_captcha_verified') === 'true';
|
||||
});
|
||||
const [error, setError] = useState('');
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
const captchaRef = useRef(null);
|
||||
@@ -18,12 +25,16 @@ export default function GuestSignupModal({ shift, onClose, onSubmit }) {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (sessionVerified) return;
|
||||
|
||||
const el = captchaRef.current;
|
||||
if (!el) return;
|
||||
|
||||
const handleVerified = (e) => {
|
||||
const isVerified = e?.detail?.verified || (el.isValid && el.isValid());
|
||||
if (isVerified) {
|
||||
sessionStorage.setItem('guest_captcha_verified', 'true');
|
||||
setSessionVerified(true);
|
||||
setIsCaptchaSolved(true);
|
||||
const token = 'acaptcha-verified-' + Math.random().toString(36).substring(2, 10);
|
||||
setCaptchaToken(token);
|
||||
@@ -49,7 +60,7 @@ export default function GuestSignupModal({ shift, onClose, onSubmit }) {
|
||||
el.removeEventListener('statuschange', handleVerified);
|
||||
el.removeEventListener('reset', handleReset);
|
||||
};
|
||||
}, []);
|
||||
}, [sessionVerified]);
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
@@ -60,18 +71,18 @@ export default function GuestSignupModal({ shift, onClose, onSubmit }) {
|
||||
return;
|
||||
}
|
||||
|
||||
const el = captchaRef.current;
|
||||
const isVerified = isCaptchaSolved || (el && el.isValid && el.isValid());
|
||||
const isVerified = sessionVerified || isCaptchaSolved;
|
||||
|
||||
if (!isVerified) {
|
||||
setError('Bitte löse zuerst das Captcha.');
|
||||
return;
|
||||
}
|
||||
|
||||
const token = captchaToken || ('acaptcha-verified-' + Math.random().toString(36).substring(2, 10));
|
||||
const token = captchaToken || 'acaptcha-session-verified';
|
||||
|
||||
// Save in localStorage for guest convenience
|
||||
localStorage.setItem('guest_display_name', guestName.trim());
|
||||
window.dispatchEvent(new Event('guest_name_updated'));
|
||||
|
||||
setSubmitting(true);
|
||||
try {
|
||||
@@ -125,43 +136,52 @@ export default function GuestSignupModal({ shift, onClose, onSubmit }) {
|
||||
className="w-full px-3.5 py-2.5 rounded-xl bg-slate-900 border border-slate-800 text-white text-sm focus:outline-none focus:border-blue-500 transition"
|
||||
/>
|
||||
<p className="text-[11px] text-slate-500 mt-1">
|
||||
Dein Name wird in deiner Sitzung gespeichert. Falls du später ein Konto mit diesem Namen erstellst, werden deine Gast-Schichten automatisch übertragen!
|
||||
Dein Name bleibt in deiner aktuellen Sitzung gespeichert. Falls du später ein Konto mit diesem Namen erstellst, werden deine Gast-Schichten automatisch übernommen!
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Official aCAPTCHA Web Component */}
|
||||
<div className="p-4 rounded-xl bg-slate-900/90 border border-slate-800 space-y-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-xs font-semibold text-slate-300 flex items-center gap-1.5 font-mono">
|
||||
<ShieldCheck className="w-4 h-4 text-emerald-400" /> Security Check (aCAPTCHA)
|
||||
{/* Security Check Section */}
|
||||
{sessionVerified ? (
|
||||
<div className="p-3.5 rounded-xl bg-emerald-500/10 border border-emerald-500/20 text-emerald-400 text-xs flex items-center justify-between font-mono">
|
||||
<span className="flex items-center gap-2 font-semibold">
|
||||
<CheckCircle2 className="w-4 h-4 text-emerald-400 shrink-0" /> Security Check verifiziert
|
||||
</span>
|
||||
<a
|
||||
href="https://acaptcha.vercel.app/"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="text-[10px] text-blue-400 hover:underline font-mono"
|
||||
>
|
||||
aCAPTCHA v1.1
|
||||
</a>
|
||||
<span className="text-[10px] text-emerald-400/80">[ In dieser Sitzung aktiv ]</span>
|
||||
</div>
|
||||
) : (
|
||||
<div className="p-4 rounded-xl bg-slate-900/90 border border-slate-800 space-y-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-xs font-semibold text-slate-300 flex items-center gap-1.5 font-mono">
|
||||
<ShieldCheck className="w-4 h-4 text-emerald-400" /> Security Check (aCAPTCHA)
|
||||
</span>
|
||||
<a
|
||||
href="https://acaptcha.vercel.app/"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="text-[10px] text-blue-400 hover:underline font-mono"
|
||||
>
|
||||
aCAPTCHA v1.1
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div className="border border-slate-700 rounded-lg p-3 bg-slate-950/80 flex flex-col items-center justify-center min-h-[100px]">
|
||||
<captcha-element
|
||||
ref={captchaRef}
|
||||
status="null"
|
||||
sound-enabled="true"
|
||||
dark-mode="dark"
|
||||
type="both"
|
||||
difficulty="adaptive"
|
||||
></captcha-element>
|
||||
<div className="border border-slate-700 rounded-lg p-3 bg-slate-950/80 flex flex-col items-center justify-center min-h-[100px]">
|
||||
<captcha-element
|
||||
ref={captchaRef}
|
||||
status="null"
|
||||
sound-enabled="true"
|
||||
dark-mode="dark"
|
||||
type="both"
|
||||
difficulty="adaptive"
|
||||
></captcha-element>
|
||||
|
||||
{isCaptchaSolved && (
|
||||
<div className="mt-2 text-xs font-medium text-emerald-400 flex items-center gap-1 font-mono">
|
||||
<CheckCircle2 className="w-4 h-4" /> Captcha verifiziert!
|
||||
</div>
|
||||
)}
|
||||
{isCaptchaSolved && (
|
||||
<div className="mt-2 text-xs font-medium text-emerald-400 flex items-center gap-1 font-mono">
|
||||
<CheckCircle2 className="w-4 h-4" /> Captcha verifiziert!
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="pt-2 flex justify-end gap-2">
|
||||
<button
|
||||
|
||||
Reference in New Issue
Block a user