Hook up the select-all checkboxes
This commit is contained in:
parent
1096e70052
commit
034b4ad3b0
4 changed files with 89 additions and 18 deletions
|
@ -8,9 +8,11 @@ import { Button } from '@/components/elements/button/index';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
user: User;
|
user: User;
|
||||||
|
selected?: boolean;
|
||||||
|
onRowChange: (user: User, selected: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const UserTableRow = ({ user }: Props) => {
|
const UserTableRow = ({ user, selected, onRowChange }: Props) => {
|
||||||
const [ visible, setVisible ] = useState(false);
|
const [ visible, setVisible ] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -30,7 +32,7 @@ const UserTableRow = ({ user }: Props) => {
|
||||||
<tr>
|
<tr>
|
||||||
<td className={'whitespace-nowrap'}>
|
<td className={'whitespace-nowrap'}>
|
||||||
<div className={'flex justify-end items-center w-8'}>
|
<div className={'flex justify-end items-center w-8'}>
|
||||||
<Checkbox/>
|
<Checkbox checked={selected} onChange={e => onRowChange(user, e.currentTarget.checked)}/>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td className={'pl-6 py-4 whitespace-nowrap'}>
|
<td className={'pl-6 py-4 whitespace-nowrap'}>
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { Fragment, useEffect, useState } from 'react';
|
||||||
import http from '@/api/http';
|
import http from '@/api/http';
|
||||||
|
import { UUID } from '@/api/definitions';
|
||||||
import { Transformers, User } from '@definitions/admin';
|
import { Transformers, User } from '@definitions/admin';
|
||||||
|
import { Transition } from '@/components/elements/transitions';
|
||||||
import { LockOpenIcon, PlusIcon, SupportIcon, TrashIcon } from '@heroicons/react/solid';
|
import { LockOpenIcon, PlusIcon, SupportIcon, TrashIcon } from '@heroicons/react/solid';
|
||||||
import { Button } from '@/components/elements/button/index';
|
import { Button } from '@/components/elements/button/index';
|
||||||
import { Checkbox, InputField } from '@/components/elements/inputs';
|
import { Checkbox, InputField } from '@/components/elements/inputs';
|
||||||
|
@ -8,6 +10,8 @@ import UserTableRow from '@/components/admin/users/UserTableRow';
|
||||||
|
|
||||||
const UsersContainerV2 = () => {
|
const UsersContainerV2 = () => {
|
||||||
const [ users, setUsers ] = useState<User[]>([]);
|
const [ users, setUsers ] = useState<User[]>([]);
|
||||||
|
const [ selected, setSelected ] = useState<UUID[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.title = 'Admin | Users';
|
document.title = 'Admin | Users';
|
||||||
}, []);
|
}, []);
|
||||||
|
@ -20,6 +24,15 @@ const UsersContainerV2 = () => {
|
||||||
.catch(console.error);
|
.catch(console.error);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const onRowChange = (user: User, checked: boolean) => {
|
||||||
|
setSelected((state) => {
|
||||||
|
return checked ? [ ...state, user.uuid ] : selected.filter((uuid) => uuid !== user.uuid);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const selectAllChecked = users.length > 0 && selected.length > 0;
|
||||||
|
const onSelectAll = () => setSelected((state) => state.length > 0 ? [] : users.map(({ uuid }) => uuid));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className={'flex justify-end mb-4'}>
|
<div className={'flex justify-end mb-4'}>
|
||||||
|
@ -29,7 +42,11 @@ const UsersContainerV2 = () => {
|
||||||
</div>
|
</div>
|
||||||
<div className={'relative flex items-center rounded-t bg-neutral-700 px-4 py-2'}>
|
<div className={'relative flex items-center rounded-t bg-neutral-700 px-4 py-2'}>
|
||||||
<div className={'mr-6'}>
|
<div className={'mr-6'}>
|
||||||
<Checkbox/>
|
<Checkbox
|
||||||
|
checked={selectAllChecked}
|
||||||
|
indeterminate={selected.length !== users.length}
|
||||||
|
onChange={onSelectAll}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={'flex-1'}>
|
<div className={'flex-1'}>
|
||||||
<InputField
|
<InputField
|
||||||
|
@ -39,20 +56,26 @@ const UsersContainerV2 = () => {
|
||||||
className={'w-56 focus:w-96'}
|
className={'w-56 focus:w-96'}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={'absolute rounded-t bg-neutral-700 w-full h-full top-0 left-0 flex items-center justify-end space-x-4 px-4'}>
|
<Transition.Fade as={Fragment} show={selected.length > 0} duration={'duration-75'}>
|
||||||
<div className={'flex-1'}>
|
<div className={'absolute rounded-t bg-neutral-700 w-full h-full top-0 left-0 flex items-center justify-end space-x-4 px-4'}>
|
||||||
<Checkbox indeterminate/>
|
<div className={'flex-1'}>
|
||||||
|
<Checkbox
|
||||||
|
checked={selectAllChecked}
|
||||||
|
indeterminate={selected.length !== users.length}
|
||||||
|
onChange={onSelectAll}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Button.Text square>
|
||||||
|
<SupportIcon className={'w-4 h-4'}/>
|
||||||
|
</Button.Text>
|
||||||
|
<Button.Text square>
|
||||||
|
<LockOpenIcon className={'w-4 h-4'}/>
|
||||||
|
</Button.Text>
|
||||||
|
<Button.Text square>
|
||||||
|
<TrashIcon className={'w-4 h-4'}/>
|
||||||
|
</Button.Text>
|
||||||
</div>
|
</div>
|
||||||
<Button.Text square>
|
</Transition.Fade>
|
||||||
<SupportIcon className={'w-4 h-4'}/>
|
|
||||||
</Button.Text>
|
|
||||||
<Button.Text square>
|
|
||||||
<LockOpenIcon className={'w-4 h-4'}/>
|
|
||||||
</Button.Text>
|
|
||||||
<Button.Text square>
|
|
||||||
<TrashIcon className={'w-4 h-4'}/>
|
|
||||||
</Button.Text>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<table className={'min-w-full rounded bg-neutral-700'}>
|
<table className={'min-w-full rounded bg-neutral-700'}>
|
||||||
<thead className={'bg-neutral-900'}>
|
<thead className={'bg-neutral-900'}>
|
||||||
|
@ -64,7 +87,14 @@ const UsersContainerV2 = () => {
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{users.map(user => <UserTableRow user={user} key={user.uuid}/>)}
|
{users.map(user => (
|
||||||
|
<UserTableRow
|
||||||
|
key={user.uuid}
|
||||||
|
user={user}
|
||||||
|
selected={selected.includes(user.uuid)}
|
||||||
|
onRowChange={onRowChange}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { Transition } from '@headlessui/react';
|
||||||
|
|
||||||
|
type Duration = `duration-${number}`;
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
as?: React.ElementType;
|
||||||
|
duration?: Duration | [ Duration, Duration ];
|
||||||
|
show: boolean;
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ({ children, duration, ...props }: Props) => {
|
||||||
|
const [ enterDuration, exitDuration ] = Array.isArray(duration)
|
||||||
|
? duration
|
||||||
|
: (!duration ? [ 'duration-200', 'duration-100' ] : [ duration, duration ]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Transition
|
||||||
|
{...props}
|
||||||
|
enter={`ease-out ${enterDuration}`}
|
||||||
|
enterFrom={'opacity-0'}
|
||||||
|
enterTo={'opacity-100'}
|
||||||
|
leave={`ease-in ${exitDuration}`}
|
||||||
|
leaveFrom={'opacity-100'}
|
||||||
|
leaveTo={'opacity-0'}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Transition>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { Transition as TransitionComponent } from '@headlessui/react';
|
||||||
|
import FadeTransition from '@/components/elements/transitions/FadeTransition';
|
||||||
|
|
||||||
|
const Transition = Object.assign(TransitionComponent, {
|
||||||
|
Fade: FadeTransition,
|
||||||
|
});
|
||||||
|
|
||||||
|
export { Transition };
|
Loading…
Reference in a new issue