Proyectos de Subversion LeadersLinked - SPA

Rev

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

Rev Autor Línea Nro. Línea
3416 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
 
3416 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
 
3416 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
 
3416 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
  }
3416 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;
3416 stevensc 43
`;
2630 stevensc 44
 
45
const Signup = () => {
3416 stevensc 46
  const [registered, setRegistered] = useState(false);
47
  const [loading, setloading] = 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
 
3416 stevensc 55
  const { data: timezones } = useFetchHelper("timezones");
3409 stevensc 56
 
2802 stevensc 57
  const {
58
    control,
59
    handleSubmit,
60
    setError,
61
    watch,
3416 stevensc 62
    formState: { errors },
2802 stevensc 63
  } = useForm({
3416 stevensc 64
    mode: "all",
65
  });
2630 stevensc 66
 
67
  const signupVerifyCallbackHandler = (response) => {
3416 stevensc 68
    if (!response) return;
69
    reCaptchaToken.current = response;
70
    setIsVerified(true);
71
  };
2630 stevensc 72
 
73
  const signupExpiredCallbackHandler = () => {
3416 stevensc 74
    reCaptchaToken.current = "";
75
    setIsVerified(false);
76
  };
2630 stevensc 77
 
78
  const handleOnRecaptchaLoad = () => {
3416 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,
3416 stevensc 89
      terms_and_conditions,
2630 stevensc 90
    }) => {
3416 stevensc 91
      setloading(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(
3416 stevensc 98
        "confirmation",
2630 stevensc 99
        CryptoJSAesJson.encrypt(confirmation, aes)
3416 stevensc 100
      );
101
      formData.append("terms_and_conditions", terms_and_conditions ? 1 : 0);
2630 stevensc 102
 
3416 stevensc 103
      formData.append("captcha", reCaptchaToken.current);
104
      formData.append("is_adult", isAdult ? "y" : "n");
2630 stevensc 105
 
106
      await axios
3416 stevensc 107
        .post("/signup", formData)
2630 stevensc 108
        .then(({ data }) => {
109
          if (!data.success) {
3416 stevensc 110
            if (typeof data.data !== "string") {
2630 stevensc 111
              Object.entries(data.data).forEach(([key, value]) => {
112
                setError(key, {
3416 stevensc 113
                  type: "manual",
114
                  message: Array.isArray(value) ? value[0] : value,
115
                });
116
              });
117
              return;
2630 stevensc 118
            }
119
 
3416 stevensc 120
            dispatch(addNotification({ style: "danger", msg: data.data }));
121
            reCaptchaInstance.current.reset();
122
            signupVerifyCallbackHandler();
123
            return;
2630 stevensc 124
          }
125
 
3416 stevensc 126
          reCaptchaInstance.current.reset();
127
          signupExpiredCallbackHandler();
128
          setRegistered(true);
2630 stevensc 129
        })
130
        .catch((err) => {
3416 stevensc 131
          console.log(`Error: ${err}`);
2630 stevensc 132
          dispatch(
133
            addNotification({
3416 stevensc 134
              style: "danger",
135
              msg: "Disculpe, ha ocurrido un error",
2630 stevensc 136
            })
3416 stevensc 137
          );
2630 stevensc 138
        })
3416 stevensc 139
        .finally(() => setloading(false));
2630 stevensc 140
    }
3416 stevensc 141
  );
2630 stevensc 142
 
143
  useEffect(() => {
3416 stevensc 144
    reCaptchaInstance.current?.reset();
145
  }, []);
2630 stevensc 146
 
147
  if (registered) {
148
    return (
149
      <StyledCheck>
3416 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
 
3416 stevensc 157
        <Link to="/signin">
158
          <button className="btn btn-primary">Entrar</button>
2630 stevensc 159
        </Link>
160
      </StyledCheck>
3416 stevensc 161
    );
2630 stevensc 162
  }
163
 
164
  return (
3199 stevensc 165
    <Form onSubmit={onSubmitHandler}>
3416 stevensc 166
      <Typography variant="h3">Registrarse</Typography>
2630 stevensc 167
 
168
      <Input
3416 stevensc 169
        type="email"
170
        name="email"
171
        placeholder="Correo electrónico"
2865 stevensc 172
        icon={<Mail />}
2630 stevensc 173
        control={control}
174
        rules={{
3416 stevensc 175
          required: "Este campo es requerido",
2630 stevensc 176
          pattern: {
3230 stevensc 177
            value: /^[\w-.]+@([\w-]+\.)+[\w-]{2,}$/i,
3416 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
3416 stevensc 185
        type="text"
186
        name="first_name"
2865 stevensc 187
        icon={<Person />}
3416 stevensc 188
        placeholder="Nombre"
2630 stevensc 189
        control={control}
190
        rules={{
3416 stevensc 191
          required: "Este campo es requerido",
2630 stevensc 192
          maxLength: {
193
            value: 64,
3416 stevensc 194
            message: "Limite de carateres superior al permitido",
195
          },
2630 stevensc 196
        }}
197
        error={errors.first_name?.message}
198
      />
199
 
200
      <Input
3416 stevensc 201
        type="text"
202
        name="last_name"
2865 stevensc 203
        icon={<Person />}
3416 stevensc 204
        placeholder="Apellido"
2630 stevensc 205
        control={control}
206
        rules={{
3416 stevensc 207
          required: "Este campo es requerido",
2630 stevensc 208
          maxLength: {
209
            value: 64,
3416 stevensc 210
            message: "Limite de carateres superior al permitido",
211
          },
2630 stevensc 212
        }}
213
        error={errors.last_name?.message}
214
      />
215
 
216
      <Input
3416 stevensc 217
        type="password"
218
        name="password"
2865 stevensc 219
        icon={<Lock />}
3416 stevensc 220
        placeholder="Clave"
2630 stevensc 221
        control={control}
222
        rules={{
3416 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:
3416 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
3416 stevensc 235
        type="password"
236
        name="confirmation"
2865 stevensc 237
        icon={<Lock />}
3416 stevensc 238
        placeholder="Confirme su clave"
2630 stevensc 239
        control={control}
240
        rules={{
3416 stevensc 241
          required: "Este campo es requerido",
2630 stevensc 242
          validate: (v) =>
3416 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
3416 stevensc 250
        label="Zona horaria"
251
        name="timezone"
3409 stevensc 252
        control={control}
3416 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,
3416 stevensc 257
          value,
3409 stevensc 258
        }))}
259
      />
260
 
2630 stevensc 261
      <SwitchInput
3416 stevensc 262
        label="Eres mayor de 18"
2630 stevensc 263
        setValue={(value) => setIsAdult(value)}
264
      />
265
 
2865 stevensc 266
      <CheckboxInput
3416 stevensc 267
        name="terms_and_conditions"
2630 stevensc 268
        control={control}
3416 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}
3416 stevensc 277
        verifyCallbackName="signupVerifyCallbackHandler"
2630 stevensc 278
        expiredCallback={signupExpiredCallbackHandler}
3416 stevensc 279
        expiredCallbackName="signupExpiredCallbackHandler"
2630 stevensc 280
        ref={reCaptchaInstance}
3416 stevensc 281
        render="explicit"
2630 stevensc 282
        onloadCallback={handleOnRecaptchaLoad}
3416 stevensc 283
        hl="es"
2630 stevensc 284
      />
285
 
3416 stevensc 286
      <div className="links">
287
        <Link to="/signin">¿Ya tienes cuenta?</Link>
2630 stevensc 288
      </div>
289
 
3416 stevensc 290
      <Button color="secondary" type="submit" disabled={!isVerified}>
2630 stevensc 291
        Registrarse
292
      </Button>
293
 
3416 stevensc 294
      {loading && (
2630 stevensc 295
        <StyledSpinnerContainer>
296
          <Spinner />
297
        </StyledSpinnerContainer>
298
      )}
3199 stevensc 299
    </Form>
3416 stevensc 300
  );
301
};
2630 stevensc 302
 
3416 stevensc 303
export default Signup;