Proyectos de Subversion LeadersLinked - SPA

Rev

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

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