| 'use client' | |
| import { useState } from 'react' | |
| import { useForm } from 'react-hook-form' | |
| import { zodResolver } from '@hookform/resolvers/zod' | |
| import { Button } from 'components/ui/button' | |
| import { codeWithPinSchema, type CodeWithPinForm } from 'lib/validations/code' | |
| interface TransferCodeFormProps { | |
| onSuccess: () => void | |
| onCancel: () => void | |
| } | |
| export function TransferCodeForm({ onSuccess, onCancel }: TransferCodeFormProps) { | |
| const [loading, setLoading] = useState(false) | |
| const [error, setError] = useState<string | null>(null) | |
| const [needsPin, setNeedsPin] = useState(false) | |
| const { | |
| register, | |
| handleSubmit, | |
| formState: { errors }, | |
| watch | |
| } = useForm<CodeWithPinForm>({ | |
| resolver: zodResolver(codeWithPinSchema) | |
| }) | |
| const codeValue = watch('code') | |
| const onSubmit = async (data: CodeWithPinForm) => { | |
| try { | |
| setLoading(true) | |
| setError(null) | |
| const response = await fetch('/api/users/transfer-code', { | |
| method: 'POST', | |
| credentials: 'include', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ | |
| code: data.code.toUpperCase(), | |
| pin: data.pin || undefined | |
| }) | |
| }) | |
| const result = await response.json() | |
| if (!response.ok) { | |
| if (response.status === 400 && result.needsPin) { | |
| setNeedsPin(true) | |
| return | |
| } else if (response.status === 401) { | |
| setError('Neplatný kód nebo PIN') | |
| } else if (response.status === 409) { | |
| setError('Kód již máte ve svém profilu') | |
| } else { | |
| setError(result.error || 'Nastala chyba při převodu kódu') | |
| } | |
| return | |
| } | |
| onSuccess() | |
| } catch { | |
| setError('Došlo k neočekávané chybě') | |
| } finally { | |
| setLoading(false) | |
| } | |
| } | |
| return ( | |
| <div className="bg-white p-6 rounded-lg shadow-md"> | |
| <h3 className="text-lg font-semibold text-gray-900 mb-4"> | |
| Převést anonymní kód | |
| </h3> | |
| <p className="text-sm text-gray-600 mb-6"> | |
| Zadejte kód a PIN (pokud je nastaven) pro převedení anonymní místnosti pod váš profil. | |
| </p> | |
| <form onSubmit={handleSubmit(onSubmit)} className="space-y-4"> | |
| <div> | |
| <label htmlFor="code" className="block text-sm font-medium text-gray-700 mb-1"> | |
| Kód místnosti | |
| </label> | |
| <input | |
| {...register('code')} | |
| type="text" | |
| id="code" | |
| maxLength={5} | |
| placeholder="A1B2C" | |
| className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-500 uppercase text-center font-mono" | |
| style={{ textTransform: 'uppercase' }} | |
| /> | |
| {errors.code && ( | |
| <p className="mt-1 text-sm text-red-600">{errors.code.message}</p> | |
| )} | |
| </div> | |
| {(needsPin || codeValue?.length === 5) && ( | |
| <div> | |
| <label htmlFor="pin" className="block text-sm font-medium text-gray-700 mb-1"> | |
| PIN (pokud je nastaven) | |
| </label> | |
| <input | |
| {...register('pin')} | |
| type="password" | |
| id="pin" | |
| maxLength={5} | |
| placeholder="12345" | |
| className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-500 text-center font-mono" | |
| /> | |
| {errors.pin && ( | |
| <p className="mt-1 text-sm text-red-600">{errors.pin.message}</p> | |
| )} | |
| <p className="mt-1 text-xs text-gray-500"> | |
| Nechte prázdné, pokud místnost není chráněna PIN | |
| </p> | |
| </div> | |
| )} | |
| {error && ( | |
| <div className="p-3 text-sm text-red-600 bg-red-50 rounded-md"> | |
| {error} | |
| </div> | |
| )} | |
| <div className="flex gap-3"> | |
| <button | |
| type="submit" | |
| className="flex-1 bg-gray-800 text-white hover:bg-gray-900 px-4 py-2 rounded-md" | |
| disabled={loading} | |
| > | |
| {loading ? 'Převádím...' : 'Převést kód'} | |
| </button> | |
| <button | |
| type="button" | |
| className="flex-none px-4 py-2 text-sm text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-md" | |
| onClick={onCancel} | |
| > | |
| Zrušit | |
| </button> | |
| </div> | |
| </form> | |
| </div> | |
| ) | |
| } |