Proyectos de Subversion LeadersLinked - SPA

Rev

Rev 3409 | Rev 3416 | Ir a la última revisión | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
2630 stevensc 1
import React, { useRef, useState, useEffect } from 'react'
2
import { Link } from 'react-router-dom'
3
import { useForm } from 'react-hook-form'
4
import { useDispatch, useSelector } from 'react-redux'
2865 stevensc 5
import { styled, Typography } from '@mui/material'
2630 stevensc 6
import { Mail, Lock, Person, CheckCircleOutline } from '@mui/icons-material'
7
import Recaptcha from 'react-recaptcha'
8
 
2865 stevensc 9
import { axios } from '@utils'
3409 stevensc 10
import { useFetchHelper } from '@hooks'
2865 stevensc 11
import { addNotification } from '@store/notification/notification.actions'
12
import CryptoJSAesJson from '@utils/crypto-js/cryptojs-aes-format'
2630 stevensc 13
 
2865 stevensc 14
import Input from '@components/UI/inputs/Input'
15
import Button from '@components/UI/buttons/Buttons'
3410 stevensc 16
import Select from '@components/UI/inputs/Select'
2865 stevensc 17
import Spinner from '@components/UI/Spinner'
3199 stevensc 18
import Form from '@components/common/form'
2865 stevensc 19
import SwitchInput from '@components/UI/SwitchInput'
20
import CheckboxInput from '@components/UI/inputs/Checkbox'
2630 stevensc 21
 
2865 stevensc 22
const StyledCheck = styled('div')`
2630 stevensc 23
  display: flex;
24
  flex-direction: column;
25
  justify-content: center;
26
  align-items: center;
27
  gap: 0.5rem;
28
  p {
29
    text-align: center;
30
  }
31
`
2865 stevensc 32
const StyledSpinnerContainer = styled('div')`
2630 stevensc 33
  position: absolute;
34
  left: 0;
35
  top: 0;
36
  width: 100%;
37
  height: 100%;
38
  background: rgba(255, 255, 255, 0.4);
39
  display: flex;
40
  justify-content: center;
41
  align-items: center;
42
  z-index: 300;
43
`
44
 
45
const Signup = () => {
46
  const [registered, setRegistered] = useState(false)
47
  const [isLoading, setIsLoading] = useState(false)
48
  const [isAdult, setIsAdult] = useState(false)
49
  const [isVerified, setIsVerified] = useState(false)
50
  const reCaptchaInstance = useRef(null)
51
  const reCaptchaToken = useRef('')
52
  const dispatch = useDispatch()
53
  const { site_key, aes } = useSelector(({ auth }) => auth)
54
 
3409 stevensc 55
  const { data: timezones } = useFetchHelper('timezones')
56
 
2802 stevensc 57
  const {
58
    control,
59
    handleSubmit,
60
    setError,
61
    watch,
62
    formState: { errors }
63
  } = useForm({
2630 stevensc 64
    mode: 'all'
65
  })
66
 
67
  const signupVerifyCallbackHandler = (response) => {
68
    if (!response) return
69
    reCaptchaToken.current = response
70
    setIsVerified(true)
71
  }
72
 
73
  const signupExpiredCallbackHandler = () => {
74
    reCaptchaToken.current = ''
75
    setIsVerified(false)
76
  }
77
 
78
  const handleOnRecaptchaLoad = () => {
79
    reCaptchaToken.current = ''
80
  }
81
 
82
  const onSubmitHandler = handleSubmit(
83
    async ({
84
      email,
85
      first_name,
86
      last_name,
87
      password,
88
      confirmation,
89
      terms_and_conditions
90
    }) => {
91
      setIsLoading(true)
92
      const formData = new FormData()
93
      formData.append('first_name', first_name)
94
      formData.append('last_name', last_name)
95
      formData.append('email', CryptoJSAesJson.encrypt(email, aes))
96
      formData.append('password', CryptoJSAesJson.encrypt(password, aes))
97
      formData.append(
98
        'confirmation',
99
        CryptoJSAesJson.encrypt(confirmation, aes)
100
      )
101
      formData.append('terms_and_conditions', terms_and_conditions ? 1 : 0)
102
 
103
      formData.append('captcha', reCaptchaToken.current)
104
      formData.append('is_adult', isAdult ? 'y' : 'n')
105
 
106
      await axios
107
        .post('/signup', formData)
108
        .then(({ data }) => {
109
          if (!data.success) {
110
            if (typeof data.data !== 'string') {
111
              Object.entries(data.data).forEach(([key, value]) => {
112
                setError(key, {
113
                  type: 'manual',
114
                  message: Array.isArray(value) ? value[0] : value
115
                })
116
              })
117
              return
118
            }
119
 
120
            dispatch(addNotification({ style: 'danger', msg: data.data }))
121
            reCaptchaInstance.current.reset()
122
            signupVerifyCallbackHandler()
123
            return
124
          }
125
 
126
          reCaptchaInstance.current.reset()
127
          signupExpiredCallbackHandler()
128
          setRegistered(true)
129
        })
130
        .catch((err) => {
131
          console.log(`Error: ${err}`)
132
          dispatch(
133
            addNotification({
134
              style: 'danger',
135
              msg: 'Disculpe, ha ocurrido un error'
136
            })
137
          )
138
        })
139
        .finally(() => setIsLoading(false))
140
    }
141
  )
142
 
143
  useEffect(() => {
144
    reCaptchaInstance.current?.reset()
145
  }, [])
146
 
147
  if (registered) {
148
    return (
149
      <StyledCheck>
150
        <CheckCircleOutline sx={{ color: '#7FFF00', fontSize: '3rem' }} />
151
 
2864 stevensc 152
        <Typography>
2630 stevensc 153
          Se ha registrado correctamente. Por favor, active la cuenta desde su
154
          correo
2864 stevensc 155
        </Typography>
2630 stevensc 156
 
157
        <Link to='/signin'>
158
          <button className='btn btn-primary'>Entrar</button>
159
        </Link>
160
      </StyledCheck>
161
    )
162
  }
163
 
164
  return (
3199 stevensc 165
    <Form onSubmit={onSubmitHandler}>
166
      <Typography variant='h3'>Registrarse</Typography>
2630 stevensc 167
 
168
      <Input
169
        type='email'
170
        name='email'
171
        placeholder='Correo electrónico'
2865 stevensc 172
        icon={<Mail />}
2630 stevensc 173
        control={control}
174
        rules={{
175
          required: 'Este campo es requerido',
176
          pattern: {
3230 stevensc 177
            value: /^[\w-.]+@([\w-]+\.)+[\w-]{2,}$/i,
2630 stevensc 178
            message: 'Debe ser una dirección de correo electrónico valida'
179
          }
180
        }}
181
        error={errors.email?.message}
182
      />
183
 
184
      <Input
185
        type='text'
186
        name='first_name'
2865 stevensc 187
        icon={<Person />}
2630 stevensc 188
        placeholder='Nombre'
189
        control={control}
190
        rules={{
191
          required: 'Este campo es requerido',
192
          maxLength: {
193
            value: 64,
194
            message: 'Limite de carateres superior al permitido'
195
          }
196
        }}
197
        error={errors.first_name?.message}
198
      />
199
 
200
      <Input
201
        type='text'
202
        name='last_name'
2865 stevensc 203
        icon={<Person />}
2630 stevensc 204
        placeholder='Apellido'
205
        control={control}
206
        rules={{
207
          required: 'Este campo es requerido',
208
          maxLength: {
209
            value: 64,
210
            message: 'Limite de carateres superior al permitido'
211
          }
212
        }}
213
        error={errors.last_name?.message}
214
      />
215
 
216
      <Input
217
        type='password'
218
        name='password'
2865 stevensc 219
        icon={<Lock />}
2630 stevensc 220
        placeholder='Clave'
221
        control={control}
222
        rules={{
223
          required: 'Este campo es requerido',
224
          pattern: {
225
            value:
226
              /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$^x%x*-]).{6,16}$/i,
227
            message:
228
              'Debe contener entre 6 y 16 caracteres, incluida una letra mayúscula, un número y un carácter especial #?!@$^%*-'
229
          }
230
        }}
231
        error={errors.password?.message}
232
      />
233
 
234
      <Input
235
        type='password'
236
        name='confirmation'
2865 stevensc 237
        icon={<Lock />}
2630 stevensc 238
        placeholder='Confirme su clave'
239
        control={control}
240
        rules={{
241
          required: 'Este campo es requerido',
242
          validate: (v) =>
243
            v === watch('password') ||
244
            'Disculpe, las claves tienen que coincidir'
245
        }}
246
        error={errors.confirmation?.message}
247
      />
248
 
3409 stevensc 249
      <Select
250
        label='Zona horaria'
251
        name='timezone'
252
        control={control}
253
        rules={{ required: 'Este campo es requerido' }}
254
        error={errors.timezone?.message}
255
        options={Object.entries(timezones).map(([key, value]) => ({
256
          name: key,
257
          value
258
        }))}
259
      />
260
 
2630 stevensc 261
      <SwitchInput
262
        label='Eres mayor de 18'
263
        setValue={(value) => setIsAdult(value)}
264
      />
265
 
2865 stevensc 266
      <CheckboxInput
2630 stevensc 267
        name='terms_and_conditions'
268
        control={control}
269
        label='Si, acepto los Términos y Condiciones.'
2865 stevensc 270
        rules={{ required: 'Este campo es requerido' }}
2630 stevensc 271
        error={errors.terms_and_conditions?.message}
272
      />
273
 
274
      <Recaptcha
275
        sitekey={site_key}
276
        verifyCallback={signupVerifyCallbackHandler}
277
        verifyCallbackName='signupVerifyCallbackHandler'
278
        expiredCallback={signupExpiredCallbackHandler}
279
        expiredCallbackName='signupExpiredCallbackHandler'
280
        ref={reCaptchaInstance}
281
        render='explicit'
282
        onloadCallback={handleOnRecaptchaLoad}
283
        hl='es'
284
      />
285
 
286
      <div className='links'>
287
        <Link to='/signin'>¿Ya tienes cuenta?</Link>
288
      </div>
289
 
3156 stevensc 290
      <Button color='secondary' type='submit' disabled={!isVerified}>
2630 stevensc 291
        Registrarse
292
      </Button>
293
 
294
      {isLoading && (
295
        <StyledSpinnerContainer>
296
          <Spinner />
297
        </StyledSpinnerContainer>
298
      )}
3199 stevensc 299
    </Form>
2630 stevensc 300
  )
301
}
302
 
303
export default Signup