Sessions 5-7a: 955 tests, deployment ready
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
const PREF_KEY = 'vyndr.sportsbook_modal.suppress';
|
||||
|
||||
type Props = {
|
||||
book: string;
|
||||
url: string;
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
};
|
||||
|
||||
export default function SportsbookModal({ book, url, open, onClose }: Props) {
|
||||
const [dontShowAgain, setDontShowAgain] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
const onKey = (e: KeyboardEvent) => {
|
||||
if (e.key === 'Escape') onClose();
|
||||
};
|
||||
document.addEventListener('keydown', onKey);
|
||||
return () => document.removeEventListener('keydown', onKey);
|
||||
}, [open, onClose]);
|
||||
|
||||
if (!open) return null;
|
||||
|
||||
const continueOut = () => {
|
||||
if (dontShowAgain) {
|
||||
try { localStorage.setItem(PREF_KEY, '1'); } catch { /* private mode */ }
|
||||
}
|
||||
window.open(url, '_blank', 'noopener,noreferrer');
|
||||
onClose();
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="sportsbook-modal-title"
|
||||
onClick={onClose}
|
||||
style={{
|
||||
position: 'fixed',
|
||||
inset: 0,
|
||||
zIndex: 100,
|
||||
background: 'rgba(6, 6, 11, 0.72)',
|
||||
backdropFilter: 'blur(8px)',
|
||||
WebkitBackdropFilter: 'blur(8px)',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
padding: 16,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
className="surface diagonal-cut"
|
||||
style={{ maxWidth: 400, width: '100%', padding: 24 }}
|
||||
>
|
||||
<p className="lbl" style={{ color: 'var(--grade-c)' }}>LEAVING VYNDR</p>
|
||||
<p id="sportsbook-modal-title" style={{ fontSize: 16, fontWeight: 600, marginTop: 8 }}>
|
||||
You're being redirected to {book}.
|
||||
</p>
|
||||
<p style={{ color: 'var(--text-1)', fontSize: 14, marginTop: 8 }}>
|
||||
VYNDR doesn't place bets, handle money, or guarantee outcomes.
|
||||
</p>
|
||||
<div style={{ display: 'flex', gap: 12, marginTop: 20 }}>
|
||||
<button type="button" className="btn-primary" style={{ flex: 1 }} onClick={continueOut}>
|
||||
Continue to {book} →
|
||||
</button>
|
||||
<button type="button" className="btn-ghost" style={{ flex: 1 }} onClick={onClose}>
|
||||
Stay on VYNDR
|
||||
</button>
|
||||
</div>
|
||||
<label
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 8,
|
||||
marginTop: 16,
|
||||
cursor: 'pointer',
|
||||
userSelect: 'none',
|
||||
}}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={dontShowAgain}
|
||||
onChange={(e) => setDontShowAgain(e.target.checked)}
|
||||
/>
|
||||
<span style={{ color: 'var(--text-2)', fontSize: 12 }}>Don't show this again</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function shouldSkipSportsbookModal(): boolean {
|
||||
try {
|
||||
return localStorage.getItem(PREF_KEY) === '1';
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function openSportsbookSafely(url: string) {
|
||||
window.open(url, '_blank', 'noopener,noreferrer');
|
||||
}
|
||||
Reference in New Issue
Block a user