Skip to content

Commit 759146d

Browse files
authored
feat: server stats and activity (#1201)
1 parent e5f6369 commit 759146d

34 files changed

Lines changed: 2404 additions & 171 deletions

components/AdminLayout.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,9 @@ const AdminLayout = ({ children, title }) => {
103103
</div>
104104
</div>
105105
<div className='flex flex-col w-full md:space-y-4'>
106-
<header className='w-full h-16 z-40 hidden md:flex items-center justify-between'>
107-
<div className='relative z-20 flex flex-col justify-end h-full px-3 md:w-full'>
108-
<div className='relative p-1 flex items-center w-full space-x-4 justify-end top-4'>
106+
<header className='w-full h-24 z-40 hidden md:flex items-center justify-between bg-primary-900 border-b border-gray-800'>
107+
<div className='z-20 flex flex-col justify-end h-full p-3 md:w-full'>
108+
<div className='p-1 flex items-center w-full space-x-4 justify-end top-4'>
109109
<SessionNavProfile key='session-nav-profile' user={user} />
110110
</div>
111111
</div>

components/Checkbox.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ import clsx from 'clsx'
55
const Checkbox = forwardRef((props, ref) => {
66
const {
77
id,
8+
inputClassName = '',
89
className = '',
910
placeholder = '',
1011
label = '',
1112
onChange = () => {},
1213
...rest
1314
} = props
14-
const inputClass = clsx(`
15+
const checkboxClass = clsx(`
1516
form-tick
1617
appearance-none
1718
bg-black
@@ -23,7 +24,9 @@ const Checkbox = forwardRef((props, ref) => {
2324
rounded-md
2425
checked:bg-accent-500
2526
checked:border-transparent
26-
focus:outline-none`
27+
focus:outline-none
28+
${inputClassName}
29+
`
2730
)
2831

2932
const handleChange = (e) => {
@@ -36,7 +39,7 @@ const Checkbox = forwardRef((props, ref) => {
3639
<input
3740
ref={ref}
3841
type='checkbox'
39-
className={inputClass}
42+
className={checkboxClass}
4043
id={id}
4144
placeholder={placeholder}
4245
onChange={handleChange}

components/DateTimePicker.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import Datetime from '@nateradebaugh/react-datetime'
33
import clsx from 'clsx'
44

55
// eslint-disable-next-line react/display-name
6-
const DateTimePicker = forwardRef(({ className, ...rest }, ref) => {
6+
const DateTimePicker = forwardRef(({ className = '', ...rest }, ref) => {
77
const inputClass = clsx(`
88
flex-1
99
appearance-none

components/Dropdown.js

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,19 @@
1-
import { cloneElement, forwardRef, useRef } from 'react'
1+
import { cloneElement, createContext, forwardRef, useRef } from 'react'
22
import clsx from 'clsx'
33
import Link from 'next/link'
44
import { useDetectOutsideClick } from '../utils'
5-
import Button from './Button'
65

7-
const Dropdown = ({ trigger = '', children }) => {
6+
const DropdownContext = createContext({ isActive: false, setIsActive: () => {} })
7+
8+
const Dropdown = ({ trigger = () => {}, children }) => {
89
const dropdownRef = useRef(null)
910
const [isActive, setIsActive] = useDetectOutsideClick(dropdownRef, false)
10-
const onClick = () => setIsActive(!isActive)
11+
const onClickToggle = () => setIsActive(!isActive)
1112

1213
return (
1314
<div className='relative inline-block text-left'>
1415
<div>
15-
<Button
16-
type='button'
17-
onClick={onClick}
18-
>
19-
{trigger}
20-
</Button>
16+
{trigger({ onClickToggle })}
2117
</div>
2218
<div
2319
ref={dropdownRef}
@@ -32,33 +28,53 @@ const Dropdown = ({ trigger = '', children }) => {
3228
aria-orientation='vertical'
3329
aria-labelledby='options-menu'
3430
>
35-
{children}
31+
<DropdownContext.Provider value={{ isActive, setIsActive }}>
32+
{children}
33+
</DropdownContext.Provider>
3634
</div>
3735
</div>
3836
</div>
3937
)
4038
}
4139

4240
const Item = ({ href = '', children, name, onClick, icon, className = '' }) => {
43-
return (
44-
<Link href={href} passHref>
45-
<ItemLink name={name} href={href} onClick={onClick} className={className} icon={icon}>{children}</ItemLink>
46-
</Link>
47-
)
41+
if (href) {
42+
return (
43+
<Link href={href} passHref>
44+
<ItemLink name={name} href={href} onClick={onClick} className={className} icon={icon}>{children}</ItemLink>
45+
</Link>
46+
)
47+
} else {
48+
return <ItemLink name={name} onClick={onClick} className={className} icon={icon}>{children}</ItemLink>
49+
}
4850
}
4951

5052
// eslint-disable-next-line react/display-name
5153
const ItemLink = forwardRef(({ name, onClick, href, className, icon, children }, ref) => {
5254
return (
53-
<a href={href} onClick={onClick} ref={ref} className={`flex items-center z-10 px-4 bg-gray-800 py-2 text-md text-gray-100 hover:text-accent-200 hover:bg-gray-600 ${className}`} role='menuitem'>
54-
{icon && cloneElement(icon, {
55-
className: 'flex-shrink-0 h-6 w-6 mr-4'
56-
})}
57-
<span className='flex flex-col'>
58-
{name}
59-
</span>
60-
{children}
61-
</a>
55+
<DropdownContext.Consumer>
56+
{({ setIsActive }) => (
57+
<a
58+
href={href}
59+
onClick={(...args) => {
60+
setIsActive(false)
61+
62+
onClick(...args)
63+
}}
64+
ref={ref}
65+
className={`flex cursor-pointer items-center z-10 px-4 bg-gray-800 py-2 text-md text-gray-100 hover:text-accent-200 hover:bg-gray-600 ${className}`}
66+
role='menuitem'
67+
>
68+
{icon && cloneElement(icon, {
69+
className: 'flex-shrink-0 h-6 w-6 mr-4'
70+
})}
71+
<span className='flex flex-col'>
72+
{name}
73+
</span>
74+
{children}
75+
</a>
76+
)}
77+
</DropdownContext.Consumer>
6278
)
6379
})
6480

components/Nav.js

Lines changed: 35 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@ import Image from 'next/image'
22
import { useRouter } from 'next/router'
33
import Link from 'next/link'
44
import { Fragment, useEffect, useState, isValidElement } from 'react'
5-
import clsx from 'clsx'
6-
import { Transition } from '@headlessui/react'
7-
import { RemoveScroll } from 'react-remove-scroll'
85
import { FaBars } from 'react-icons/fa'
96
import PageContainer from './PageContainer'
107
import PlayerSelector from './admin/PlayerSelector'
8+
import NavigationOverlay from './NavigationOverlay'
119

1210
export default function Nav ({ leftItems, mobileItems, rightItems }) {
1311
const router = useRouter()
@@ -74,77 +72,42 @@ export default function Nav ({ leftItems, mobileItems, rightItems }) {
7472
</div>
7573
</div>
7674
</PageContainer>
77-
<Transition
78-
show={drawerOpen}
79-
enter='duration-200 ease-out'
80-
enterFrom='opacity-0 scale-95'
81-
enterTo='opacity-100 scale-100'
82-
leave='duration-100 ease-in'
83-
leaveFrom='opacity-100 scale-100'
84-
leaveTo='opacity-0 scale-95'
85-
>
86-
{(ref) => (
87-
<div ref={ref} className='z-10 fixed inset-0 transition-opacity'>
88-
<div className='absolute inset-0 bg-black opacity-50' tabIndex='0' onClick={() => setDrawerOpen(false)} />
89-
</div>
90-
)}
91-
</Transition>
92-
<RemoveScroll forwardProps enabled={drawerOpen}>
93-
<aside
94-
className={clsx('top-0 right-0 w-72 bg-gray-800 fixed h-full overflow-auto ease-in-out transition-all duration-300 z-30', RemoveScroll.classNames.zeroRight,
95-
{
96-
'translate-x-0': drawerOpen,
97-
'translate-x-full': !drawerOpen
98-
})}
99-
>
100-
<div className='pt-5 pb-6 px-5'>
101-
<div className='flex items-center justify-between'>
102-
<div>
103-
<Link href='/' passHref key='logo-icon'>
104-
<a>
105-
<span className='sr-only'>Home</span>
106-
<Image width='40' height='40' src='/images/banmanager-icon.png' alt='Logo' />
75+
<NavigationOverlay drawerOpen={drawerOpen} setDrawerOpen={setDrawerOpen}>
76+
<NavigationOverlay.Header>
77+
<Link href='/' passHref key='logo-icon'>
78+
<a>
79+
<span className='sr-only'>Home</span>
80+
<Image width='40' height='40' src='/images/banmanager-icon.png' alt='Logo' />
81+
</a>
82+
</Link>
83+
</NavigationOverlay.Header>
84+
<NavigationOverlay.Body className='!px-2 flex flex-col sm:flex-row sm:justify-around'>
85+
<nav>
86+
{renderMenu(rightItems)}
87+
{mobileItems.map(({ href, name, icon, label, splitBorder }) => (
88+
<Fragment key={`${href}${name}`}>
89+
<Link href={href} passHref>
90+
<a className='hover:text-accent-200 hover:bg-gray-600 flex transition-colors text-gray-100 text-xl p-2 my-4 rounded-lg'>
91+
{icon}
92+
<span className='mx-4 text-lg font-normal'>
93+
{name}
94+
</span>
95+
{label &&
96+
<span className='flex-grow text-right'>
97+
<button type='button' className='w-6 h-6 text-xs rounded-full text-white bg-accent-500'>
98+
<span className='p-1'>
99+
{label}
100+
</span>
101+
</button>
102+
</span>}
107103
</a>
108104
</Link>
109-
</div>
110-
<div className='-mr-2'>
111-
<button type='button' className='rounded-md p-2 inline-flex items-center justify-center text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-grey-500' onClick={() => setDrawerOpen(false)}>
112-
<span className='sr-only'>Close menu</span>
113-
<svg className='h-6 w-6' xmlns='http:www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='currentColor' aria-hidden='true'>
114-
<path strokeLinecap='round' strokeLinejoin='round' strokeWidth='2' d='M6 18L18 6M6 6l12 12' />
115-
</svg>
116-
</button>
117-
</div>
118-
</div>
119-
</div>
120-
<div className='px-2 flex flex-col sm:flex-row sm:justify-around'>
121-
<nav>
122-
{renderMenu(rightItems)}
123-
{mobileItems.map(({ href, name, icon, label, splitBorder }) => (
124-
<Fragment key={`${href}${name}`}>
125-
<Link href={href} passHref>
126-
<a className='hover:text-accent-200 hover:bg-gray-600 flex transition-colors text-gray-100 text-xl p-2 my-4 rounded-lg'>
127-
{icon}
128-
<span className='mx-4 text-lg font-normal'>
129-
{name}
130-
</span>
131-
{label &&
132-
<span className='flex-grow text-right'>
133-
<button type='button' className='w-6 h-6 text-xs rounded-full text-white bg-accent-500'>
134-
<span className='p-1'>
135-
{label}
136-
</span>
137-
</button>
138-
</span>}
139-
</a>
140-
</Link>
141-
{splitBorder && <span className='text-5xl pb-4 mb-4 border-b border-accent-200 leading-none' />}
142-
</Fragment>
143-
))}
144-
</nav>
145-
</div>
146-
</aside>
147-
</RemoveScroll>
105+
{splitBorder && <span className='text-5xl pb-4 mb-4 border-b border-accent-200 leading-none' />}
106+
</Fragment>
107+
))}
108+
</nav>
109+
</NavigationOverlay.Body>
110+
</NavigationOverlay>
148111
</div>
149112
)
150113
}

components/NavigationOverlay.js

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { createContext } from 'react'
2+
import { Transition } from '@headlessui/react'
3+
import { RemoveScroll } from 'react-remove-scroll'
4+
import clsx from 'clsx'
5+
6+
const NavigationOverlayContext = createContext()
7+
8+
const NavigationOverlay = ({ children, drawerOpen, setDrawerOpen }) => {
9+
return (
10+
<NavigationOverlayContext.Provider value={{ drawerOpen, setDrawerOpen }}>
11+
<Transition
12+
show={drawerOpen}
13+
enter='transition-opacity ease-linear duration-300'
14+
enterFrom='opacity-0'
15+
enterTo='opacity-100'
16+
leave='transition-opacity ease-linear duration-300'
17+
leaveFrom='opacity-100'
18+
leaveTo='opacity-0'
19+
>
20+
<div className='z-10 fixed inset-0 transition-opacity'>
21+
<div className='absolute inset-0 bg-black opacity-50' tabIndex='0' onClick={() => setDrawerOpen(false)} />
22+
</div>
23+
</Transition>
24+
<RemoveScroll forwardProps enabled={drawerOpen}>
25+
<aside
26+
className={clsx('top-0 right-0 w-72 bg-gray-800 fixed h-full overflow-auto ease-in-out transition-all duration-300 z-30', RemoveScroll.classNames.zeroRight,
27+
{
28+
'translate-x-0': drawerOpen,
29+
'translate-x-full': !drawerOpen
30+
})}
31+
>
32+
{children}
33+
</aside>
34+
</RemoveScroll>
35+
</NavigationOverlayContext.Provider>
36+
)
37+
}
38+
39+
const Header = ({ children }) => {
40+
return (
41+
<NavigationOverlayContext.Consumer>
42+
{({ setDrawerOpen }) => (
43+
<div className='pt-5 pb-6 px-5'>
44+
<div className='flex items-center justify-between'>
45+
<div>
46+
{children}
47+
</div>
48+
<div className='-mr-2'>
49+
<button type='button' className='rounded-md p-2 inline-flex items-center justify-center text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none' onClick={() => setDrawerOpen(false)}>
50+
<span className='sr-only'>Close menu</span>
51+
<svg className='h-6 w-6' xmlns='http:www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='currentColor' aria-hidden='true'>
52+
<path strokeLinecap='round' strokeLinejoin='round' strokeWidth='2' d='M6 18L18 6M6 6l12 12' />
53+
</svg>
54+
</button>
55+
</div>
56+
</div>
57+
</div>
58+
)}
59+
</NavigationOverlayContext.Consumer>
60+
)
61+
}
62+
63+
const Body = ({ children, className = '' }) => {
64+
return (
65+
<div className={`px-5 ${className}`}>
66+
{children}
67+
</div>
68+
)
69+
}
70+
71+
NavigationOverlay.Header = Header
72+
NavigationOverlay.Body = Body
73+
74+
export default NavigationOverlay

components/Select.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const Select = forwardRef(({ options, isLoading, onInputChange, onChange, value,
2020
onInputChange={onInputChange}
2121
onChange={onChange}
2222
defaultValue={defaultValue || setDefaultValue}
23-
// value={options.find((option) => (getOptionValue ? getOptionValue(option) : option.value) === value)}
23+
value={options.find((option) => (getOptionValue ? getOptionValue(option) : option.value) === value)}
2424
filterOption={filterOption}
2525
noOptionsMessage={noOptionsMessage}
2626
isClearable={isClearable}

components/SessionNavProfile.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { mutate } from 'swr'
44
import Favicon from 'react-favicon'
55
import Dropdown from './Dropdown'
66
import Avatar from './Avatar'
7+
import Button from './Button'
78
import NotificationBadge from './NotificationBadge'
89
import { CgProfile } from 'react-icons/cg'
910
import { FaPencilAlt } from 'react-icons/fa'
@@ -75,14 +76,16 @@ export default function SessionNavProfile ({ user }) {
7576
/>
7677
<div className='hidden md:block'>
7778
<Dropdown
78-
trigger={(
79-
<>
79+
trigger={({ onClickToggle }) => (
80+
<Button
81+
onClick={onClickToggle}
82+
>
8083
<Avatar width='36' height='36' uuid={user.id} />
8184
<span className='hidden md:inline-block ml-4'>
8285
{user.name}
8386
</span>
8487
{data?.unreadNotificationCount > 0 && <NotificationBadge>{data.unreadNotificationCount}</NotificationBadge>}
85-
</>
88+
</Button>
8689
)}
8790
>
8891
<Dropdown.Item name='Notifications' href='/notifications' icon={<MdOutlineNotifications />}>

0 commit comments

Comments
 (0)