| 'use client' | |
| import { useState } from 'react' | |
| import { useForm } from 'react-hook-form' | |
| import { zodResolver } from '@hookform/resolvers/zod' | |
| import { useRouter, useSearchParams } from 'next/navigation' | |
| import { Button } from 'components/ui/button' | |
| import { pinEntrySchema, type PinEntryForm as PinEntryFormType } from 'lib/validations/code' | |
| export function PinEntryForm() { | |
| const [loading, setLoading] = useState(false) | |
| const [error, setError] = useState<string | null>(null) | |
| const router = useRouter() | |
| const searchParams = useSearchParams() | |
| const code = searchParams.get('code') | |
| const { | |
| register, | |
| handleSubmit, | |
| formState: { errors } | |
| } = useForm<PinEntryFormType>({ | |
| resolver: zodResolver(pinEntrySchema) | |
| }) | |
| const onSubmit = async (data: PinEntryFormType) => { | |
| if (!code) { | |
| setError('Chybí kód místnosti') | |
| return | |
| } | |
| try { | |
| setLoading(true) | |
| setError(null) | |
| const response = await fetch('/api/codes/verify-pin', { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ | |
| code: code.toUpperCase(), | |
| pin: data.pin | |
| }) | |
| }) | |
| const result = await response.json() | |
| if (!response.ok) { | |
| if (response.status === 401) { | |
| setError('Neplatný PIN') | |
| } else if (response.status === 429) { | |
| setError('Příliš mnoho pokusů. Zkuste to později.') | |
| } else { | |
| setError(result.error || 'Nastala chyba při ověřování PIN') | |
| } | |
| return | |
| } | |
| if (result.roomId) { | |
| router.push(`/room/${result.roomId}?code=${code}`) | |
| } | |
| } catch { | |
| setError('Došlo k neočekávané chybě') | |
| } finally { | |
| setLoading(false) | |
| } | |
| } | |
| return ( | |
| <form onSubmit={handleSubmit(onSubmit)} className="space-y-4"> | |
| <div> | |
| <label htmlFor="pin" className="block text-sm font-medium text-gray-700 mb-2"> | |
| Zadejte PIN pro kód {code} | |
| </label> | |
| <input | |
| {...register('pin')} | |
| type="password" | |
| id="pin" | |
| maxLength={5} | |
| placeholder="12345" | |
| autoComplete="new-password" | |
| inputMode="numeric" | |
| pattern="[0-9]*" | |
| aria-label={`PIN pro kód ${code}`} | |
| className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-500 focus:border-brand-500 text-center text-2xl font-mono tracking-widest" | |
| /> | |
| {errors.pin && ( | |
| <p className="mt-1 text-sm text-red-600">{errors.pin.message}</p> | |
| )} | |
| </div> | |
| {error && ( | |
| <div className="p-3 text-sm text-red-600 bg-red-50 rounded-md"> | |
| {error} | |
| </div> | |
| )} | |
| <Button type="submit" className="w-full" disabled={loading}> | |
| {loading ? 'Ověřuji PIN...' : 'Vstoupit do místnosti'} | |
| </Button> | |
| <div className="text-center"> | |
| <button | |
| type="button" | |
| onClick={() => router.push('/')} | |
| className="text-sm text-gray-600 hover:text-gray-800" | |
| > | |
| ← Zpět na zadání kódu | |
| </button> | |
| </div> | |
| </form> | |
| ) | |
| } |