Proyectos de Subversion LeadersLinked - SPA

Rev

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

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