feature/share-libs
tsx 149 lines 4.3 KB
Raw
1 'use client';
2
3 import Link from 'next/link';
4 import { menus, type Item } from './menus';
5 import { useSelectedLayoutSegment } from 'next/navigation';
6 import { MenuAlt2Icon, XIcon } from '@heroicons/react/solid';
7 import clsx from 'clsx';
8 import { useContext, useState } from 'react';
9 import Image from 'next/image';
10 import { UserContext } from '../../lib/current-user-context';
11 import { useLogger } from '@/lib/logger';
12 import { PARAMS_USER_ID } from '@/lib/params';
13
14 export function GlobalNav() {
15
16 const [isOpen, setIsOpen] = useState(false);
17 const close = () => setIsOpen(false);
18 const user = useContext(UserContext);
19
20 return (
21 <div className="fixed top-0 z-10 flex w-full flex-col border-b border-gray-800 bg-black lg:bottom-0 lg:z-auto lg:w-72 lg:border-b-0 lg:border-r lg:border-gray-800">
22 <div className="flex h-14 items-center px-4 py-4 lg:h-auto">
23 <Link
24 href="/"
25 className="group flex w-full items-center gap-x-2.5"
26 onClick={close}
27 >
28 <div className="h-7 w-7 rounded-sm border border-white/30 group-hover:border-white/50">
29 <Image src="/logo192.png" alt="SplitFire" width={40} height={40} />
30 </div>
31
32 <h3 className="font-semibold tracking-wide text-gray-400 group-hover:text-gray-50">
33 SplitFire
34 </h3>
35 </Link>
36 </div>
37 <button
38 type="button"
39 className="group absolute right-0 top-0 flex h-14 items-center gap-x-2 px-4 lg:hidden"
40 onClick={() => setIsOpen(!isOpen)}
41 >
42 <div className="font-medium text-gray-100 group-hover:text-gray-400">
43 Menu
44 </div>
45 {isOpen ? (
46 <XIcon className="block w-6 text-gray-400" />
47 ) : (
48 <MenuAlt2Icon className="block w-6 text-gray-400" />
49 )}
50 </button>
51
52 <div
53 className={clsx('overflow-y-auto lg:static lg:block', {
54 'fixed inset-x-0 bottom-0 top-14 mt-px bg-black': isOpen,
55 hidden: !isOpen,
56 })}
57 >
58 <nav className="space-y-6 px-2 pb-24 pt-5">
59 {menus.map((section, index) => {
60 return (
61 <div key={index}>
62
63 <div className="space-y-1">
64 {section.items.map((item) => (
65 <GlobalNavItem key={item.slug} item={item} close={close} />
66 ))}
67 </div>
68
69 </div>
70 );
71 })}
72 <div className="mb-2 px-3 text-xs font-semibold uppercase tracking-wider text-gray-400/80">
73 <div>{"Account"}</div>
74 </div>
75
76 {user.user ? <LoggedInNav /> : <LoggedOutNav />}
77
78 <div className="mb-2 px-3 text-xs font-semibold uppercase tracking-wider text-gray-400/80">
79 <div>{"Settings"}</div>
80 </div>
81
82 <SettingsNav />
83 </nav>
84 </div>
85 </div>
86 );
87 }
88
89 function LoggedOutNav() {
90 return (
91 <div className="space-y-1">
92 <GlobalNavItem item={{ name: 'Login', slug: 'login' }} close={() => {}} />
93 <GlobalNavItem item={{ name: 'Register', slug: 'register' }} close={() => {}} />
94 </div>
95 );
96 }
97
98 function LoggedInNav() {
99 const log = useLogger('LoggedInNav');
100 const currentUser = useContext(UserContext);
101 const user = currentUser?.user?.user;
102 // Sanity check
103 if (!user) {
104 log.error('No user context');
105 return null;
106 }
107
108 return (
109 <div className="space-y-1">
110 <GlobalNavItem item={{ name: 'Profile', slug: `profile?${PARAMS_USER_ID}=${user.id}` }} close={() => {}} />
111 <GlobalNavItem item={{ name: 'Logout', slug: 'logout' }} close={() => {}} />
112 </div>
113 );
114 }
115
116 function SettingsNav() {
117 return (
118 <div className="space-y-1">
119 <GlobalNavItem item={{ name: 'Debug', slug: 'debug' }} close={() => {}} />
120 </div>
121 );
122 }
123
124 function GlobalNavItem({
125 item,
126 close,
127 }: {
128 item: Item;
129 close: () => false | void;
130 }) {
131 const segment = useSelectedLayoutSegment();
132 const isActive = item.slug === segment;
133
134 return (
135 <Link
136 onClick={close}
137 href={`/${item.slug}`}
138 className={clsx(
139 'block rounded-md px-3 py-2 text-sm font-medium hover:text-gray-300',
140 {
141 'text-gray-400 hover:bg-gray-800': !isActive,
142 'text-white': isActive,
143 },
144 )}
145 >
146 {item.name}
147 </Link>
148 );
149 }