split appbar code

This commit is contained in:
João Geonizeli
2022-08-10 20:31:42 +00:00
parent 20555f642b
commit 838075c3d9
7 changed files with 286 additions and 236 deletions

View File

@@ -1,239 +1,17 @@
import React, { FC, Fragment, useState } from 'react'
import { useHistory, useLocation } from 'react-router';
import { Menu, Transition } from '@headlessui/react'
import { ChartBarIcon, ClipboardListIcon } from '@heroicons/react/outline'
import React from 'react';
import { Dialog } from '../Dialog'
import { useDispatch, useSelector } from 'react-redux';
import { useCurrentUser } from '../../contexts';
import { RootState } from '../../services/store';
import { classNames } from '../../utils';
import { DashboardRoutePaths, QuestionRoutePaths, SessionRoutePaths } from '../../routes'
import { turnOff } from '../../services/store/unsavedChanges';
import { CurrentUserAvatar } from "../CurrentUserAvatar";
import { localFetch } from '../../utils/localFetch';
import { notEmpty } from '../../utils/notEmpty';
import { UserRole } from '../../__generated__/graphql-schema';
const UserMenu: FC = () => {
const { user } = useCurrentUser();
const history = useHistory();
const [confirmLogout, setConfirmLogout] = useState(false)
const unsavedChanges = useSelector((state: RootState) => state.unsavedChanges)
const dispatch = useDispatch()
const doLogout = () => {
setConfirmLogout(false)
dispatch(turnOff())
localFetch('/users/sign_out', {
method: 'DELETE'
}).then(() => {
window.location.href = '/'
})
}
const handleLogout = () => {
if (unsavedChanges && !confirmLogout) {
setConfirmLogout(true)
} else {
doLogout()
}
}
const [newPath, setNewPath] = useState<string>()
const handleForcedRedirect = () => {
if (!newPath) return
dispatch(turnOff())
setNewPath(undefined)
history.push(newPath)
}
const handleLinkClick = (pathname: string) => {
if (unsavedChanges) {
setNewPath(pathname)
} else {
history.push(pathname)
}
}
type MenuItem = {
onClick: Function
label: string
}
const menuItems: MenuItem[] = [
(user?.roles.includes(UserRole.Admin) && {
onClick: () => { window.location.href = '/admin'},
label: 'Painel de Administração'
}),
{
onClick: () => { handleLinkClick(SessionRoutePaths.show) },
label: 'Perfil'
},
{
onClick: handleLogout,
label: 'Sair'
}
].filter(notEmpty)
return (
<>
<Dialog
isOpen={!!newPath}
setIsOpen={(value) => setNewPath(value ? newPath : undefined)}
onConfirmation={handleForcedRedirect}
title="Modificações não Salvas"
text="Todas as alterações serão descartadas. Deseja continuar?"
/>
<Dialog
isOpen={confirmLogout}
setIsOpen={setConfirmLogout}
onConfirmation={handleLogout}
title="Modificações não Salvas"
text="Todas as alterações serão descartadas. Deseja continuar?"
/>
<Menu as="div" className="relative h-full">
{({ open }) => (
<>
<Menu.Button
className="h-full flex flex-row px-2 items-center hover:bg-primary-dark text-gray-100 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-800 focus:ring-white"
>
<span className="hidden md:block pr-2">
{user?.name}
</span>
<div className="w-12">
<CurrentUserAvatar />
</div>
</Menu.Button>
<Transition
show={open}
as={Fragment}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<Menu.Items
static
className="z-50 origin-top-right absolute right-0 mt-2 w-48 rounded-md shadow-lg py-1 bg-white ring-1 ring-black ring-opacity-5 focus:outline-none cursor-pointer"
>
{menuItems.map((item) => (
<Menu.Item key={`menu-item-${item.label}`} onClick={item.onClick}>
{({ active }) => (
<span
className={classNames(
active ? 'bg-gray-100' : '',
'block px-4 py-2 text-sm text-gray-900'
)}
>
{item.label}
</span>
)}
</Menu.Item>
))}
</Menu.Items>
</Transition>
</>
)}
</Menu>
</>
)
}
const Links: FC = () => {
const unsavedChanges = useSelector((state: RootState) => state.unsavedChanges)
const dispatch = useDispatch()
const location = useLocation()
const history = useHistory()
const [newPath, setNewPath] = useState<string>()
const handleForcedRedirect = () => {
if (!newPath) return
dispatch(turnOff())
setNewPath(undefined)
history.push(newPath)
}
const handleLinkClick = (pathname: string) => {
if (unsavedChanges) {
setNewPath(pathname)
} else {
history.push(pathname)
}
}
const links = [{
icon: <ChartBarIcon className="w-6" />,
tabel: 'Painel',
pathname: DashboardRoutePaths.index,
isCurrent: location.pathname.includes('dashboard'),
},
{
icon: <ClipboardListIcon className="w-6" />,
tabel: 'Edição',
pathname: QuestionRoutePaths.index,
isCurrent: location.pathname.includes('question'),
}]
return (
<>
<Dialog
isOpen={!!newPath}
setIsOpen={(value) => setNewPath(value ? newPath : undefined)}
onConfirmation={handleForcedRedirect}
title="Modificações não Salvas"
text="Todas as alterações serão descartadas. Deseja continuar?"
/>
<div className="h-full flex items-center pl-4">
{links.map((link) => (
<button
className={`h-full flex items-center px-2 mx-2 text-gray-300 hover:bg-primary-dark ${link.isCurrent ? 'underline bg-primary-dark' : ''}`}
key={`navbar-link-${link.pathname}`}
onClick={() => handleLinkClick(link.pathname)}
>
<span className="pr-2 ">
{link.icon}
</span>
{link.tabel}
</button>
))}
</div>
</>
)
}
const Logo: FC = () => (
<div className="h-full grid place-items-center">
<img
alt="Símbolo do Unifeso"
className="hidden md:block h-12 w-auto"
src={'https://www.unifeso.edu.br/images/logo/UNIFESO-BRANCO.png'}
/>
<img
alt="Logotipo do Unifeso"
className="md:hidden h-12 w-12 object-cover object-left"
src={'https://www.unifeso.edu.br/images/logo/UNIFESO-BRANCO.png'}
/>
</div>
)
import { AppbarLogo } from './AppbarLogo';
import { AppbarTabs } from './AppbarTabs';
import { AppbarUserMenu } from './AppbarUserMenu';
export const Appbar = () => {
return (
<div className="px-4 bg-primary-normal flex items-center justify-between h-16 shadow-md">
<div className="flex h-full">
<Logo />
<Links />
<AppbarLogo />
<AppbarTabs />
</div>
<UserMenu />
<AppbarUserMenu />
</div>
)
}

View File

@@ -0,0 +1,16 @@
import React from 'react'
export const AppbarLogo = () => (
<div className="h-full grid place-items-center">
<img
alt="Símbolo do Unifeso"
className="hidden md:block h-12 w-auto"
src={'https://www.unifeso.edu.br/images/logo/UNIFESO-BRANCO.png'}
/>
<img
alt="Logotipo do Unifeso"
className="md:hidden h-12 w-12 object-cover object-left"
src={'https://www.unifeso.edu.br/images/logo/UNIFESO-BRANCO.png'}
/>
</div>
)

View File

@@ -0,0 +1,75 @@
import { ChartBarIcon, ClipboardListIcon } from "@heroicons/react/outline";
import React, { useState } from 'react';
import { useDispatch, useSelector } from "react-redux";
import { useHistory, useLocation } from 'react-router';
import { DashboardRoutePaths, QuestionRoutePaths } from "../../routes";
import { RootState } from "../../services/store";
import { turnOff } from "../../services/store/unsavedChanges";
import { Dialog } from '../Dialog';
export const AppbarTabs = () => {
const unsavedChanges = useSelector((state: RootState) => state.unsavedChanges)
const dispatch = useDispatch()
const location = useLocation()
const history = useHistory()
const [newPath, setNewPath] = useState<string>()
const handleForcedRedirect = () => {
if (!newPath) return
dispatch(turnOff())
setNewPath(undefined)
history.push(newPath)
}
const handleLinkClick = (pathname: string) => {
if (unsavedChanges) {
setNewPath(pathname)
} else {
history.push(pathname)
}
}
const links = [{
icon: <ChartBarIcon className="w-6" />,
tabel: 'Painel',
pathname: DashboardRoutePaths.index,
isCurrent: location.pathname.includes('dashboard'),
},
{
icon: <ClipboardListIcon className="w-6" />,
tabel: 'Edição',
pathname: QuestionRoutePaths.index,
isCurrent: location.pathname.includes('question'),
}]
return (
<>
<Dialog
isOpen={!!newPath}
setIsOpen={(value) => setNewPath(value ? newPath : undefined)}
onConfirmation={handleForcedRedirect}
title="Modificações não Salvas"
text="Todas as alterações serão descartadas. Deseja continuar?"
/>
<div className="h-full flex items-center pl-4">
{links.map((link) => (
<button
className={`h-full flex items-center px-2 mx-2 text-gray-300 hover:bg-primary-dark ${link.isCurrent ? 'underline bg-primary-dark' : ''}`}
key={`navbar-link-${link.pathname}`}
onClick={() => handleLinkClick(link.pathname)}
>
<span className="pr-2 ">
{link.icon}
</span>
{link.tabel}
</button>
))}
</div>
</>
)
}

View File

@@ -0,0 +1,156 @@
import { Menu, Transition } from '@headlessui/react';
import React, { Fragment, useState } from 'react';
import { useHistory } from 'react-router';
import { useDispatch, useSelector } from 'react-redux';
import { useCurrentUser } from '../../contexts';
import { SessionRoutePaths } from '../../routes';
import { RootState } from '../../services/store';
import { turnOff } from '../../services/store/unsavedChanges';
import { classNames } from '../../utils';
import { localFetch } from '../../utils/localFetch';
import { notEmpty } from '../../utils/notEmpty';
import { UserRole } from '../../__generated__/graphql-schema';
import { CurrentUserAvatar } from "../CurrentUserAvatar";
import { Dialog } from '../Dialog';
export const AppbarUserMenu = () => {
const { user } = useCurrentUser();
const history = useHistory();
const [confirmLogout, setConfirmLogout] = useState(false)
const [newPath, setNewPath] = useState<string>()
const unsavedChanges = useSelector((state: RootState) => state.unsavedChanges)
const dispatch = useDispatch()
const doLogout = () => {
setConfirmLogout(false)
dispatch(turnOff())
localFetch('/users/sign_out', {
method: 'DELETE'
}).then(() => {
window.location.href = '/'
})
}
const handleLogout = () => {
if (unsavedChanges && !confirmLogout) {
setConfirmLogout(true)
} else {
doLogout()
}
}
const handleForcedRedirect = () => {
if (!newPath) return
dispatch(turnOff())
setNewPath(undefined)
history.push(newPath)
}
const handleLinkClick = (pathname: string) => {
if (unsavedChanges) {
setNewPath(pathname)
} else {
history.push(pathname)
}
}
type MenuItem = {
onClick: Function
label: string
}
const menuItems: MenuItem[] = [
{
onClick: () => { handleLinkClick(SessionRoutePaths.show) },
label: 'Perfil'
},
{
onClick: handleLogout,
label: 'Sair'
}
]
if (user?.roles.includes(UserRole.Admin)) {
menuItems.push({
onClick: () => { window.location.href = '/admin'},
label: 'Painel de Administração'
})
}
return (
<>
<Dialog
isOpen={!!newPath}
setIsOpen={(value) => setNewPath(value ? newPath : undefined)}
onConfirmation={handleForcedRedirect}
title="Modificações não Salvas"
text="Todas as alterações serão descartadas. Deseja continuar?"
/>
<Dialog
isOpen={confirmLogout}
setIsOpen={setConfirmLogout}
onConfirmation={handleLogout}
title="Modificações não Salvas"
text="Todas as alterações serão descartadas. Deseja continuar?"
/>
<Menu as="div" className="relative h-full">
{({ open }) => (
<>
<Menu.Button
className="h-full flex flex-row px-2 items-center hover:bg-primary-dark text-gray-100 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-800 focus:ring-white"
>
<span className="hidden md:block pr-2">
{user?.name}
</span>
<div className="w-12">
<CurrentUserAvatar />
</div>
</Menu.Button>
<Transition
show={open}
as={Fragment}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<Menu.Items
static
className="z-50 origin-top-right absolute right-0 mt-2 w-48 rounded-md shadow-lg py-1 bg-white ring-1 ring-black ring-opacity-5 focus:outline-none cursor-pointer"
>
{menuItems.map((item) => (
<div
key={`menu-item-${item.label}`}
onClick={() => {
item.onClick()
}}
>
<Menu.Item>
{({ active }) => (
<span
className={classNames(
active ? 'bg-gray-100' : '',
'block px-4 py-2 text-sm text-gray-900'
)}
>
{item.label}
</span>
)}
</Menu.Item>
</div>
))}
</Menu.Items>
</Transition>
</>
)}
</Menu>
</>
)
}