Proyectos de Subversion LeadersLinked - SPA

Rev

Rev 3190 | Rev 3262 | Ir a la última revisión | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |

import React, { useRef, useState, useEffect } from 'react'
import { Link, useNavigate } from 'react-router-dom'
import { useForm } from 'react-hook-form'
import { useDispatch, useSelector } from 'react-redux'
import { Button, styled, Typography } from '@mui/material'
import { Mail, Lock } from '@mui/icons-material'
import Recaptcha from 'react-recaptcha'

import { useMobile } from '@hooks'
import CryptoJSAesJson from '@utils/crypto-js/cryptojs-aes-format'

import FacebookIcon from '@components/UI/icons/FacebookIcon'
import XIcon from '@components/UI/icons/XIcon'
import GoogleIcon from '@components/UI/icons/GoogleIcon'
import { axios } from '@utils'
import { addNotification } from '@store/notification/notification.actions'
import { login } from '@store/auth/auth.actions'
import Form from '@components/common/form'
import Input from '@components/UI/inputs/Input'
import CheckboxInput from '@components/UI/inputs/Checkbox'
import Spinner from '@components/UI/Spinner'

const SocialButton = styled(Button)`
  background-color: white;
  border: 1px solid black;
  padding: 0.5rem 1rem;
  font-size: 1rem;
  color: #383838;
  width: 100%;
  box-sizing: border-box;
  margin-bottom: 10px;
  svg {
    width: 16px;
    height: 16px;
  }
`

const Login = ({
  facebookOauth = '/signin/facebook',
  twitterOauth = '/signin/twitter',
  googleOauth = '/signin/google'
}) => {
  const [isLoading, setIsLoading] = useState(false)
  const [isVerified, setIsVerified] = useState(false)
  const isMobile = useMobile()

  const reCaptchaToken = useRef('')
  const reCaptchaInstance = useRef(null)

  const navigate = useNavigate()

  const dispatch = useDispatch()
  const { site_key, aes, access_usign_social_networks } = useSelector(
    ({ auth }) => auth
  )
  const rrssOptions = [
    { label: 'Facebook', icon: FacebookIcon, href: facebookOauth },
    { label: 'Twitter', icon: XIcon, href: twitterOauth },
    { label: 'Google', icon: GoogleIcon, href: googleOauth }
  ]

  const {
    handleSubmit,
    control,
    setError,
    getValues,
    setValue,
    reset,
    formState: { errors }
  } = useForm({ mode: 'all' })

  const onSubmitHandler = handleSubmit(
    async ({ email, password, remember }) => {
      const formData = new FormData()
      formData.append('email', CryptoJSAesJson.encrypt(email, aes))
      formData.append('password', CryptoJSAesJson.encrypt(password, aes))
      formData.append('remember', remember ? 1 : 0)
      formData.append('captcha', reCaptchaToken.current)

      await axios
        .post('/signin', formData)
        .then(({ data: response }) => {
          const { success, data } = response

          if (!success) {
            loginExpiredCallbackHandler()
            reCaptchaInstance.current.reset()

            if (data.constructor.name === 'Object') {
              Object.entries(data).forEach(([key, value]) => {
                if (key in getValues()) {
                  setError(key, {
                    type: 'manual',
                    message: Array.isArray(value) ? value[0] : value
                  })
                }
              })
              return
            }

            dispatch(addNotification({ style: 'danger', msg: data }))
            return
          }

          const url = data.redirect.split('.com')[1]
          reCaptchaInstance.current.reset()
          loginExpiredCallbackHandler()
          reset()
          dispatch(login())

          isMobile ? navigate('/apps-navigation') : navigate(url)
        })
        .catch((err) => {
          console.log(err)
          reCaptchaInstance.current.reset()

          loginExpiredCallbackHandler()
          setValue('password', '')

          dispatch(
            addNotification({
              style: 'danger',
              msg: 'Disculpe, ha ocurrido un error'
            })
          )
        })
        .finally(() => setIsLoading(false))
    }
  )

  const loginVerifyCallbackHandler = (response) => {
    reCaptchaToken.current = response
    setIsVerified(true)
  }

  const loginExpiredCallbackHandler = () => {
    reCaptchaToken.current = ''
    setIsVerified(false)
  }

  const handleOnRecaptchaLoad = () => {
    reCaptchaToken.current = ''
  }

  const getRedirectUrl = async (endpoint) => {
    try {
      const res = await axios.get(endpoint)
      if (res.data && res.data.data) {
        window.location.href = res.data.data
      }
    } catch (error) {
      console.log('>>: error > ', error)
    }
  }

  useEffect(() => {
    reCaptchaInstance.current?.reset()
  }, [])

  return (
    <Form onSubmit={onSubmitHandler}>
      {isLoading && <Spinner absolute />}

      <Typography variant='h3'>Entrar</Typography>

      <Input
        type='email'
        name='email'
        icon={<Mail />}
        placeholder='Correo electrónico'
        rules={{
          required: 'Este campo es requerido',
          pattern: {
            value: /^[\w-.]+@([\w-]+\.)+[\w-]{2,}$/i,
            message: 'Debe ser una dirección de correo electrónico valida'
          },
          maxLength: {
            value: 64,
            message: 'Debe ser menor a 64 caracteres'
          }
        }}
        control={control}
        error={errors.email?.message}
      />

      <Input
        type='password'
        name='password'
        icon={<Lock />}
        placeholder='Clave'
        control={control}
        rules={{
          required: 'Este campo es requerido',
          pattern: {
            value:
              /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$^x%x*-]).{6,16}$/i,
            message:
              'Debe contener entre 6 y 16 caracteres, incluida una letra mayúscula, un número y un carácter especial #?!@$^%*-'
          }
        }}
        error={errors.password?.message}
      />

      <CheckboxInput control={control} name='remember' label='Recuerdame' />

      {site_key && (
        <Recaptcha
          sitekey={site_key}
          verifyCallback={loginVerifyCallbackHandler}
          verifyCallbackName='loginVerifyCallbackHandler'
          expiredCallback={loginExpiredCallbackHandler}
          expiredCallbackName='loginExpiredCallbackHandler'
          ref={reCaptchaInstance}
          render='explicit'
          onloadCallback={handleOnRecaptchaLoad}
          hl='es'
        />
      )}

      <div className='links'>
        <Link to='/forgot-password'>¿Has olvidado tu contraseña?</Link>
        <Link to='/signup'>¿No tienes cuenta?</Link>
      </div>

      <Button color='secondary' type='submit' disabled={!isVerified}>
        Entrar
      </Button>

      {access_usign_social_networks === 'y' && (
        <>
          <h4>Entrar usando su red social</h4>
          <ul>
            {rrssOptions.map(({ label, icon: Icon, href }) => (
              <li key={label}>
                <SocialButton onClick={() => getRedirectUrl(href)}>
                  <Icon />
                  {`Iniciar sesión con ${label}`}
                </SocialButton>
              </li>
            ))}
          </ul>
        </>
      )}
    </Form>
  )
}

export default Login