Commit b763bf99 authored by Omar Luna Hernández's avatar Omar Luna Hernández
Browse files

Se agrega la ventana para cambiar la contraseña

parent 59dd0547
Loading
Loading
Loading
Loading
+114 −7
Original line number Diff line number Diff line
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faSignOut, faUser } from "@fortawesome/free-solid-svg-icons";
import { faEye, faEyeSlash, faSignOut, faUser, faWindowClose } from "@fortawesome/free-solid-svg-icons";
import { Link } from "react-router-dom";
import './assets/styles/style.css';
import { UserRole } from "../../constants/roles";
import { useUserData } from "../../hooks/useUserData";
import { Dispatch, SetStateAction, useState } from "react";
import { useAdminChangePassword } from "../../hooks/useAdminChangePassword";
import { usePasswoordVisibility } from "../../hooks/usePasswordVisibility";

interface props{
  windowActive: boolean;
  isWindowActive: boolean;
  setIsWindowActive: Dispatch<SetStateAction<boolean>>;
}

export const AdminPanelNavBar = ({windowActive}:props) => {
export const AdminPanelNavBar = ({isWindowActive, setIsWindowActive}:props) => {
  const {user, handleLogout, setToggle, toggle, userData} = useUserData();
  const [changePasswordWindowActive, setChangePasswordWindowActive] = useState(false);
  const setChangePasswordWindowVisibility = (visibility: boolean) => {
    setIsWindowActive(visibility);
    setChangePasswordWindowActive(visibility);
  }
  const {register, handleSubmit, errors, onSubmit} = useAdminChangePassword(setChangePasswordWindowVisibility);
  const {
    values: valuesPrevPassword, 
    handleClickShowPassword: handleClickShowPrevPassword,
    handleMouseDownPassword: handleMouseDownPrevPassword
  } = usePasswoordVisibility();
  const {
    values: valuesNewPassword, 
    handleClickShowPassword: handleClickShowNewPassword,
    handleMouseDownPassword: handleMouseDownNewPassword
  } = usePasswoordVisibility();
  const {
    values: valuesNewPasswordConfirm, 
    handleClickShowPassword: handleClickShowNewPasswordConfirm,
    handleMouseDownPassword: handleMouseDownNewPasswordConfirm
  } = usePasswoordVisibility();
  

  if(!user ){
    return null;
@@ -25,14 +51,14 @@ export const AdminPanelNavBar = ({windowActive}:props) => {
      <div className="profile">
        <img src={require("./assets/images/Admin-595b40b65ba036ed117d36fe.png")} className="user-pic" 
          onClick={() => {
            windowActive
            isWindowActive
            ?
              setToggle(false)
            :
              setToggle(!toggle)
          }}
          style={
            windowActive
            isWindowActive
            ?
            {cursor: "auto"}
            :
@@ -48,9 +74,9 @@ export const AdminPanelNavBar = ({windowActive}:props) => {
            </div>
            <hr/>

            <Link to="/" className="sub-menu-link">
            <Link to="/" onClick={() => {setChangePasswordWindowVisibility(true); setToggle(false);}} className="sub-menu-link">
              <FontAwesomeIcon icon={faUser} className="sub-menu-link-icon"/>
              <p>Editar cuenta</p>
              <p>Cambiar contraseña</p>
            </Link>

            <Link onClick={handleLogout} to="/" className="sub-menu-link">
@@ -61,6 +87,87 @@ export const AdminPanelNavBar = ({windowActive}:props) => {
        </div>
        }
      </div>
      {
        changePasswordWindowActive && 
        <div className="change-password-window">
          <div className="header">
            Cambio de contraseña
            <FontAwesomeIcon icon={faWindowClose} className="close_btn"
              onClick={() => setChangePasswordWindowVisibility(false)}/>
          </div>

          <div className="content">
            <form onSubmit={handleSubmit(onSubmit)}>
              <div className="input_cnt">
                <label>Contraseña actual</label>
                <div className="password_cnt">
                  <input
                    type={
                      valuesPrevPassword.showPassword
                      ? "text"
                      : "password"
                    }
                    {...register('prevPassword')}
                    autoComplete="off"
                  />
                  <FontAwesomeIcon className="visibility-button"
                    onClick={handleClickShowPrevPassword}
                    onMouseDown={handleMouseDownPrevPassword}
                    icon={valuesPrevPassword.showPassword ? faEye : faEyeSlash}
                  />
                </div>
                <p className="error">{errors.prevPassword?.message}</p>
              </div>

              <div className="input_cnt">
                <label>Nueva contraseña</label>
                <div className="password_cnt">
                  <input
                    type={
                      valuesNewPassword.showPassword
                      ? "text"
                      : "password"
                    }
                    {...register('newPassword')}
                    autoComplete="off"
                  />
                  <FontAwesomeIcon className="visibility-button"
                    onClick={handleClickShowNewPassword}
                    onMouseDown={handleMouseDownNewPassword}
                    icon={valuesNewPassword.showPassword ? faEye : faEyeSlash}
                  />
                </div>
                <p className="error">{errors.newPassword?.message}</p>
              </div>

              <div className="input_cnt">
                <label>Confirmar nueva contraseña</label>
                <div className="password_cnt">
                  <input
                    type={
                      valuesNewPasswordConfirm.showPassword
                      ? "text"
                      : "password"
                    }
                    {...register('newPasswordConfirm')}
                    autoComplete="off"
                  />
                  <FontAwesomeIcon className="visibility-button"
                    onClick={handleClickShowNewPasswordConfirm}
                    onMouseDown={handleMouseDownNewPasswordConfirm}
                    icon={valuesNewPasswordConfirm.showPassword ? faEye : faEyeSlash}
                  />
                </div>
                <p className="error">{errors.newPasswordConfirm?.message}</p>
              </div>

              <div className="input_cnt">
                <input className="submit_btn" type="submit" content="Registrar"/>
              </div> 
            </form> 
          </div>
        </div>
      }
    </div>
  );
}
 No newline at end of file
+137 −47
Original line number Diff line number Diff line
@@ -89,3 +89,93 @@
  padding: 8px;
  margin-right: 15px;
}

.change-password-window {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  margin: auto;
  width: 30vw;
  height: 40vh;
  background: green;
  display: flex;
  flex-direction: column;
  z-index: 5;
}

.change-password-window .header  {
  display: flex;
  width: 100%;
  align-items: center;
  justify-content: center;
  padding: 5px;
}

.change-password-window .header .close_btn{
  display: inline-block;
  cursor: pointer;
  height: 5%;
  position: absolute;
  right: 5px;
}

.change-password-window .content {
  background: white;
  width: 100%;
  flex-grow: 1;
  display: flex;
  flex-direction: column;
}

.change-password-window .content form{
  display: flex;
  flex-direction: column;
  flex-grow: 1;
}

.change-password-window .content form .input_cnt{
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  padding: 5px 0;
}

.change-password-window .content form .input_cnt input{
  width: 80%;
  padding: 5px 20px;
  border: 1px solid  lightgray;
  border-radius: 5px;
}

.error{
  color: red;
  font-size: 12px;
  padding: 0;
  margin: 0;
}

.change-password-window .content form .input_cnt .submit_btn{
  width: 30%;
}

.change-password-window .content form .input_cnt .password_cnt{
  position: relative;
  width: 80%;
}

.change-password-window .content form .input_cnt .password_cnt input{
  width: 100%;
  padding-left: 20px;
  padding-right: 30px;
}

.change-password-window .content form .input_cnt .password_cnt .visibility-button{
  position: absolute;
  top: 50%;
  right: 5px;
  transform: translateY(-50%);
  cursor: pointer;
}
 No newline at end of file
+88 −0
Original line number Diff line number Diff line
import { FieldErrors, Resolver, SubmitHandler, useForm } from "react-hook-form";
import { AdminDatasourceProd } from "../data/datasources/prod/admin_datasource";
import { AdminRepositoryProd } from "../data/repositories/prod/admin_repository";
import { AdminPasswordValues } from "../infraestructure/entities/admin_form_values";
import { useState } from "react";
import axios, { AxiosError } from "axios";
import { toast } from "react-toastify";

const adminDatasource = new AdminDatasourceProd();
const adminRepository = new AdminRepositoryProd(adminDatasource);

const resolver: Resolver<AdminPasswordValues> = async (data) => {
  const errors: FieldErrors<AdminPasswordValues> = {};

  if (!data.prevPassword) {
    errors.prevPassword = {
      type: "required",
      message: "Se requiere la contraseña actual"
    };
  }

  if (!data.newPassword) {
    errors.newPassword = {
      type: "required",
      message: "Se requiere una nueva contraseña"
    };
  }else if(data.newPasswordConfirm!==data.newPassword){
    errors.newPasswordConfirm = {
      type: "validate",
      message: "Las contraseñas deben coincidir"
    }; 
  }

  if (!data.newPasswordConfirm) {
    errors.newPasswordConfirm = {
      type: "required",
      message: "Se requiere confirmar la nueva contraseña"
    };
  }

  return {
    values: Object.keys(errors).length > 0 ? {} : data,
    errors: errors,
  };
};

export const useAdminChangePassword = (setChangePasswordWindowVisibility: (visibility: boolean) => void) => {
  const {
    register,
    handleSubmit,
    formState: {errors},
    setError
  } = useForm<AdminPasswordValues>({resolver});
  const [errorMessage, setErrorMessage] = useState('');

  const onSubmit: SubmitHandler<AdminPasswordValues> = (data: AdminPasswordValues) => {
    const fetch = async () => {
      try{
        const token = localStorage.getItem('token') || '';
        await adminRepository.changePassword(token, data.prevPassword, data.newPassword);
        setChangePasswordWindowVisibility(false);
      }catch(error: any){
        if(axios.isAxiosError(error)){
          error as AxiosError;
          switch(error.code){
            case(axios.AxiosError.ERR_BAD_REQUEST):
              setErrorMessage("Acceso no autorizado");
              setError('prevPassword', {type: 'validate', message: 'Contraseña incorrecta'})
              break;
            case(axios.AxiosError.ERR_NETWORK):
              setErrorMessage("Conexión con el servidor fallida");
              break;
          }
        }
        throw new Error();
      }
    }
    toast.promise(
      fetch(),{
        pending: "Actualizando contraseña...",
        success: "La contraseña se ha actualizado",
        error: errorMessage
      }
    )
  }

  return {register, handleSubmit, errors, onSubmit};
}
 No newline at end of file