CoastalCommitsPastes/client/components/header/index.tsx

207 lines
6.6 KiB
TypeScript

import { ButtonGroup, Button, Page, Spacer, useBodyScroll, useMediaQuery, } from "@geist-ui/core";
import { useCallback, useEffect, useMemo, useState } from "react";
import styles from './header.module.css';
import useSignedIn from "../../lib/hooks/use-signed-in";
import HomeIcon from '@geist-ui/icons/home';
import MenuIcon from '@geist-ui/icons/menu';
import GitHubIcon from '@geist-ui/icons/github';
import SignOutIcon from '@geist-ui/icons/userX';
import SignInIcon from '@geist-ui/icons/user';
import SignUpIcon from '@geist-ui/icons/userPlus';
import NewIcon from '@geist-ui/icons/plusCircle';
import YourIcon from '@geist-ui/icons/list'
import MoonIcon from '@geist-ui/icons/moon';
import SettingsIcon from '@geist-ui/icons/settings';
import SunIcon from '@geist-ui/icons/sun';
import { useTheme } from "next-themes"
import useUserData from "@lib/hooks/use-user-data";
import Link from "next/link";
import { useRouter } from "next/router";
type Tab = {
name: string
icon: JSX.Element
value: string
onClick?: () => void
href?: string
}
const Header = () => {
const router = useRouter()
const [expanded, setExpanded] = useState<boolean>(false)
const [, setBodyHidden] = useBodyScroll(null, { scrollLayer: true })
const isMobile = useMediaQuery('xs', { match: 'down' })
const { signedIn: isSignedIn, signout } = useSignedIn()
const userData = useUserData();
const [pages, setPages] = useState<Tab[]>([])
const { setTheme, resolvedTheme } = useTheme()
useEffect(() => {
setBodyHidden(expanded)
}, [expanded, setBodyHidden])
useEffect(() => {
if (!isMobile) {
setExpanded(false)
}
}, [isMobile])
useEffect(() => {
const defaultPages: Tab[] = [
{
name: isMobile ? "GitHub" : "",
href: "https://github.com/maxleiter/drift",
icon: <GitHubIcon />,
value: "github"
},
{
name: isMobile ? "Change theme" : "",
onClick: function () {
if (typeof window !== 'undefined')
setTheme(resolvedTheme === 'light' ? 'dark' : 'light');
},
icon: resolvedTheme === 'light' ? <MoonIcon /> : <SunIcon />,
value: "theme",
}
]
if (isSignedIn)
setPages([
{
name: 'new',
icon: <NewIcon />,
value: 'new',
href: '/new'
},
{
name: 'yours',
icon: <YourIcon />,
value: 'yours',
href: '/mine'
},
// {
// name: 'settings',
// icon: <SettingsIcon />,
// value: 'settings',
// href: '/settings'
// },
{
name: 'sign out',
icon: <SignOutIcon />,
value: 'signout',
// onClick: signout,
href: '/signout'
},
...defaultPages
])
else
setPages([
{
name: 'home',
icon: <HomeIcon />,
value: 'home',
href: '/'
},
{
name: 'Sign in',
icon: <SignInIcon />,
value: 'signin',
href: '/signin'
},
{
name: 'Sign up',
icon: <SignUpIcon />,
value: 'signup',
href: '/signup'
},
...defaultPages
])
if (userData?.role === "admin") {
setPages((pages) => [
...pages,
{
name: 'admin',
icon: <SettingsIcon />,
value: 'admin',
href: '/admin'
}
])
}
// TODO: investigate deps causing infinite loop
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isMobile, isSignedIn, resolvedTheme, userData])
const onTabChange = useCallback((tab: string) => {
if (typeof window === 'undefined') return
const match = pages.find(page => page.value === tab)
if (match?.onClick) {
match.onClick()
}
}, [pages])
const getButton = useCallback((tab: Tab) => {
const activeStyle = router.pathname === tab.href ? styles.active : ""
if (tab.onClick) {
return <Button
auto={isMobile ? false : true}
key={tab.value}
icon={tab.icon}
onClick={() => onTabChange(tab.value)}
className={`${styles.tab} ${activeStyle}`}
shadow={false}
>
{tab.name ? tab.name : undefined}
</Button>
} else if (tab.href) {
return <Link key={tab.value} href={tab.href}>
<a className={styles.tab}>
<Button
className={activeStyle}
auto={isMobile ? false : true}
icon={tab.icon}
shadow={false}
>
{tab.name ? tab.name : undefined}
</Button>
</a>
</Link>
}
}, [isMobile, onTabChange, router.pathname])
const buttons = useMemo(() => pages.map(getButton), [pages, getButton])
return (
<Page.Header height={'var(--page-nav-height)'} marginBottom={2}>
<div className={styles.tabs}>
<div className={styles.buttons}>
{buttons}
</div>
</div>
<div className={styles.controls}>
<Button
effect={false}
auto
type="abort"
onClick={() => setExpanded(!expanded)}
aria-label="Menu"
>
<Spacer height={5 / 6} width={0} />
<MenuIcon />
</Button>
</div>
{isMobile && expanded && (<div className={styles.mobile}>
<ButtonGroup vertical style={{
background: "var(--bg)",
}}>
{buttons}
</ButtonGroup>
</div>)}
</Page.Header >
)
}
export default Header