File size: 7,265 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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
'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 { z } from 'zod'
import { pinEntrySchema, type PinEntryForm as PinEntryFormType } from 'lib/validations/code'

export function PinSetupForm() {
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState<string | null>(null)
  const [skipPin, setSkipPin] = useState(false)
  const [manualCode, setManualCode] = useState('')
  const router = useRouter()
  const searchParams = useSearchParams()
  const codeFromParams = searchParams.get('code')

  // Define schema typed for the form to ensure TypeScript knows pin + confirmPin exist
  const setupSchema = pinEntrySchema.extend({
    confirmPin: pinEntrySchema.shape.pin
  }).refine((data) => data.pin === data.confirmPin, {
    message: "PIN se neshoduje",
    path: ["confirmPin"],
  })

  const {
    register,
    handleSubmit,
    formState: { errors }
  } = useForm<z.infer<typeof setupSchema>>({
    resolver: zodResolver(setupSchema)
  })

  // Use effectiveCode: prefer query param, otherwise manual input
  const effectiveCode = (codeFromParams || manualCode || '').toUpperCase()

  const onSubmit = async (data: PinEntryFormType | { pin?: string }) => {
    const code = effectiveCode
    if (!code) {
      setError('Chybí kód místnosti')
      return
    }

    try {
      setLoading(true)
      setError(null)

      const response = await fetch('/api/codes/setup', {
        method: 'POST',
        credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          code: code.toUpperCase(),
          pin: (data as any).pin ? (data as any).pin : undefined,
          userAgent: navigator.userAgent
        })
      })

      const result = await response.json()

      if (!response.ok) {
        setError(result.error || 'Nastala chyba při nastavování')
        return
      }

      if (result.roomId) {
        router.push(`/room/${result.roomId}?code=${code}`)
      }
    } catch (e) {
      console.error('PinSetup submit error:', e)
      setError('Došlo k neočekávané chybě')
    } finally {
      setLoading(false)
    }
  }

  const handleSkipPin = async () => {
    // Ensure we have a code
    if (!effectiveCode) {
      setError('Zadejte prosím kód místnosti před pokračováním bez PIN.')
      return
    }
    setSkipPin(true)
    await onSubmit({ pin: '' })
  }

  if (skipPin) {
    return (
      <div className="space-y-4">

        <div className="p-4 bg-yellow-50 rounded-lg">

          <p className="text-yellow-800 text-sm">

            <strong>Upozornění:</strong> Bez PIN ochrany se o místnost přijdete při smazání cookies prohlížeče.

          </p>

        </div>

        <Button onClick={handleSkipPin} className="w-full" disabled={loading} variant="secondary" >

          {loading ? 'Vytvářím místnost...' : 'Pokračovat bez PIN'}

        </Button>

      </div>
    )
  }

  return (
    <div className="space-y-6">

      <div className="p-4 bg-blue-50 rounded-lg">

        <h3 className="font-medium text-blue-900 mb-2">Ochrana místnosti</h3>

        <p className="text-blue-800 text-sm">

          Nastavte si 5-číselný PIN pro ochranu přístupu do této místnosti.

          Bez PIN se o přístup přijdete při smazání cookies.

        </p>

      </div>



      {/* If no code in query, allow user to type it */}

      {!codeFromParams && (

        <div>

          <label htmlFor="manualCode" className="block text-sm font-medium text-gray-700 mb-1">

            Kód místnosti (5 znaků)

          </label>

          <input

            value={manualCode}

            onChange={(e) => setManualCode(e.target.value.toUpperCase())}

            type="text"

            id="manualCode"

            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 focus:border-brand-500 uppercase text-center font-mono"

            style={{ textTransform: 'uppercase' }}

          />

          <p className="mt-1 text-xs text-gray-500">Zadejte kód místnosti, který chcete vytvořit nebo použít.</p>

        </div>

      )}



      <form onSubmit={handleSubmit(onSubmit)} className="space-y-4">

        <div>

          <label htmlFor="pin" className="block text-sm font-medium text-gray-700 mb-2">

            Nový PIN (5 číslic)

          </label>

          <input

            {...register('pin')}

            type="password"

            id="pin"

            maxLength={5}

            placeholder="12345"

            autoComplete="new-password"

            inputMode="numeric"

            pattern="[0-9]*"

            aria-label="Nový PIN (5 číslic)"

            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-xl font-mono tracking-widest"

          />

          {errors?.pin && (

            <p className="mt-1 text-sm text-red-600">{errors.pin.message}</p>

          )}

        </div>



        <div>

          <label htmlFor="confirmPin" className="block text-sm font-medium text-gray-700 mb-2">

            Potvrdit PIN

          </label>

          <input

            {...register('confirmPin')}

            type="password"

            id="confirmPin"

            maxLength={5}

            placeholder="12345"

            autoComplete="new-password"

            inputMode="numeric"

            pattern="[0-9]*"

            aria-label="Potvrzení PIN"

            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-xl font-mono tracking-widest"

          />

          {errors?.confirmPin && (

            <p className="mt-1 text-sm text-red-600">{errors.confirmPin.message}</p>

          )}

        </div>



        {error && (

          <div className="p-3 text-sm text-red-600 bg-red-50 rounded-md">

            {error}

          </div>

        )}



        <div className="space-y-2">

          <Button type="submit" className="w-full" disabled={loading}>

            {loading ? 'Nastavuji PIN...' : 'Vytvořit místnost s PIN'}

          </Button>

          

          <button

            type="button"

            onClick={handleSkipPin}

            className="w-full px-4 py-2 text-sm text-gray-600 hover:text-gray-800 border border-gray-300 rounded-md hover:bg-gray-50"

          >

            Pokračovat bez PIN ochrany

          </button>

        </div>

      </form>



      <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>

    </div>
  )
}