File size: 4,615 Bytes
9853b20 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | '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>
)
} |