108 lines
3.3 KiB
JavaScript
108 lines
3.3 KiB
JavaScript
import { useState, useEffect, useRef } from 'react'
|
|
import { GROOMSMEN, validateGroomsman } from '../groommen'
|
|
import './NameModal.css'
|
|
|
|
const STORAGE_KEY_PIN = 'cabo_voter_pin'
|
|
|
|
export default function NameModal({ onSubmit }) {
|
|
const [name, setName] = useState('')
|
|
const [pin, setPin] = useState('')
|
|
const [error, setError] = useState('')
|
|
const [step, setStep] = useState(1) // 1 = name, 2 = pin
|
|
const inputRef = useRef(null)
|
|
|
|
useEffect(() => {
|
|
if (step === 1) inputRef.current?.focus()
|
|
}, [step])
|
|
|
|
const handleNameNext = (e) => {
|
|
e.preventDefault()
|
|
if (!name.trim()) return
|
|
|
|
const key = name.trim().toLowerCase().replace(/\s+/g, '')
|
|
if (!GROOMSMEN[key]) {
|
|
setError(`"${name}" is not on the guest list. Check with the groom.`)
|
|
return
|
|
}
|
|
setError('')
|
|
setStep(2)
|
|
// Pre-fill pin from localStorage if saved
|
|
const saved = localStorage.getItem(STORAGE_KEY_PIN)
|
|
if (saved) setPin(saved)
|
|
}
|
|
|
|
const handlePinSubmit = (e) => {
|
|
e.preventDefault()
|
|
if (pin.length !== 4) {
|
|
setError('Enter the last 4 digits of your phone number.')
|
|
return
|
|
}
|
|
|
|
const key = name.trim().toLowerCase().replace(/\s+/g, '')
|
|
if (!validateGroomsman(name, pin)) {
|
|
setError('Wrong PIN. Make sure you\'re using the correct name + last 4 digits.')
|
|
return
|
|
}
|
|
|
|
localStorage.setItem(STORAGE_KEY_PIN, pin)
|
|
onSubmit(name.trim())
|
|
}
|
|
|
|
const handleBack = () => {
|
|
setStep(1)
|
|
setPin('')
|
|
setError('')
|
|
}
|
|
|
|
return (
|
|
<div className="modal-overlay">
|
|
<div className="modal">
|
|
<div className="drag-handle"></div>
|
|
|
|
{step === 1 ? (
|
|
<>
|
|
<h2>🏄 Who's Voting?</h2>
|
|
<p>Enter your <strong>full name</strong> as it appears on the guest list.</p>
|
|
<form onSubmit={handleNameNext}>
|
|
<input
|
|
ref={inputRef}
|
|
type="text"
|
|
value={name}
|
|
onChange={e => { setName(e.target.value); setError('') }}
|
|
placeholder="e.g. Jon, Toph, Hans…"
|
|
maxLength={30}
|
|
autoComplete="off"
|
|
autoCapitalize="words"
|
|
/>
|
|
{error && <div className="name-error">{error}</div>}
|
|
<button type="submit" disabled={!name.trim()}>Next →</button>
|
|
</form>
|
|
</>
|
|
) : (
|
|
<>
|
|
<h2>🔐 Verify with PIN</h2>
|
|
<p>Enter the <strong>last 4 digits</strong> of your phone number, {name.split(' ')[0]}.</p>
|
|
<form onSubmit={handlePinSubmit}>
|
|
<input
|
|
ref={inputRef}
|
|
type="password"
|
|
inputMode="numeric"
|
|
pattern="[0-9]*"
|
|
maxLength={4}
|
|
value={pin}
|
|
onChange={e => { setPin(e.target.value.replace(/\D/g, '')); setError('') }}
|
|
placeholder="••••"
|
|
autoComplete="off"
|
|
className="pin-input"
|
|
/>
|
|
{error && <div className="name-error">{error}</div>}
|
|
<button type="submit" disabled={pin.length !== 4}>Join the Vote →</button>
|
|
<button type="button" className="back-btn" onClick={handleBack}>← Back</button>
|
|
</form>
|
|
</>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|