Proyectos de Subversion LeadersLinked - SPA

Rev

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