Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
protected.layout.tsx 3.87 KiB
import { fetchUser } from '@api/user.fetch';
import logo from '@assets/logo.svg';
import { fetchPnds } from '@component/devices/api/pnd.fetch';
import { faCircleUser, faRightFromBracket } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { useAppDispatch, useAppSelector } from '@hooks';
import { useAuth } from "@provider/auth.provider";
import { MenuProvider } from '@provider/menu/menu.provider';
import { DEVICE_URL, LOGIN_URL } from '@routes';
import React, { useEffect } from "react";
import { Dropdown } from "react-bootstrap";
import { useTranslation } from "react-i18next";
import { Link, Outlet, useNavigate } from "react-router-dom";
import "./protected.layout.scss";


export const ProtectedLayout = () => {
  const { isAuthenticated, logout } = useAuth();
  const { user } = useAppSelector(state => state.user);
  const navigate = useNavigate();
  const { t } = useTranslation('common')
  const dispatch = useAppDispatch();

  useEffect(() => {
    if (!isAuthenticated()) {
      navigate(LOGIN_URL)
      return;
    }

    dispatch(fetchUser());
    dispatch(fetchPnds());
  }, [dispatch]);

  /**
   * Applies active css class to link if the link is active
   */
  const handleActiveLink = (targetPath: string): string => {
    const href = window.location.href;
    return href.includes(targetPath) ? ' active' : '';
  }

  /** renders the corpus for the user icon dropdown  */
  const UserIconToggle = React.forwardRef(({ children, onClick }: React.LinkHTMLAttributes<any>, ref: any) => (
    <div
      ref={ref}
      onClick={(e) => {
        e.preventDefault();
        onClick!(e);
      }}
    >
      {children}
    </div>
  ));

  /** renders the single items inside the user dropdown corpus */
  const UserIconMenu = React.forwardRef(
    ({ children, style, className, 'aria-labelledby': labeledBy }: React.LinkHTMLAttributes<any>, ref: any) => {
      return (
        <div
          ref={ref}
          style={style}
          className={className}
          aria-labelledby={labeledBy}
        >
          <ul className="list-unstyled">
            {React.Children.toArray(children)}
          </ul>
        </div>
      );
    }
  );

  const VerticalSidebar = () => {
    return (
      <div className="d-flex fixed-top flex-column flex-shrink-0 bg-white sidebar justify-content-end border-end border-dark py-3 z-2">
        <FontAwesomeIcon className="clickable icon" icon={faRightFromBracket} onClick={logout} size="2x" />
      </div>
    )
  }

  const HorizontalNavbar = () => {
    return (
      <nav className="bg-white border-bottom border-dark py-2 d-flex align-items-center z-3 position-relative">
        <Link to="/"><img src={logo} className="mx-4 me-5" width={25} alt="logo" /></Link>
        <Link className={"head-links" + handleActiveLink(DEVICE_URL)} to="/">{t('protected.link.device_list')}</Link>
        <Link className={"head-links" + handleActiveLink('/map')} to="/">{t('protected.link.map')}</Link>
        <Link className={"head-links" + handleActiveLink('/configuration_management')} to="/">{t('protected.link.configuration_mgmt')}</Link>

        <Dropdown className="ms-auto px-3">
          <Dropdown.Toggle as={UserIconToggle}>
            <FontAwesomeIcon icon={faCircleUser} className="icon clickable" />
          </Dropdown.Toggle>

          <Dropdown.Menu as={UserIconMenu}>
            <Dropdown.Item eventKey="1">{user?.name}</Dropdown.Item>
            <hr />
            <Dropdown.Item eventKey="1">
              <Link className="text-decoration-none text-reset" to="/">{t('protected.link.settings')}</Link>
            </Dropdown.Item>
          </Dropdown.Menu>
        </Dropdown>
      </nav>
    )
  }

  return (
    <div>
      <MenuProvider>
        {HorizontalNavbar()}
        {VerticalSidebar()}
        <div className='main-content'>
          <Outlet />
        </div>
      </MenuProvider>
    </div>
  )
};