Break table rows into own component
This commit is contained in:
parent
8e731e838f
commit
9f934b5ab8
2 changed files with 94 additions and 83 deletions
80
resources/scripts/components/admin/users/UserTableRow.tsx
Normal file
80
resources/scripts/components/admin/users/UserTableRow.tsx
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
import { Checkbox } from '@/components/elements/inputs';
|
||||||
|
import { Dropdown } from '@/components/elements/dropdown';
|
||||||
|
import { BanIcon, DotsVerticalIcon, LockOpenIcon, PencilIcon, SupportIcon, TrashIcon } from '@heroicons/react/solid';
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import { User } from '@/api/admin/user';
|
||||||
|
import { Dialog } from '@/components/elements/dialog';
|
||||||
|
import { Button } from '@/components/elements/button/index';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
user: User;
|
||||||
|
}
|
||||||
|
|
||||||
|
const UserTableRow = ({ user }: Props) => {
|
||||||
|
const [ visible, setVisible ] = useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Dialog title={'Delete account'} visible={visible} onDismissed={() => setVisible(false)}>
|
||||||
|
<Dialog.Icon type={'danger'}/>
|
||||||
|
This account will be permanently deleted.
|
||||||
|
<Dialog.Buttons>
|
||||||
|
<Button.Text
|
||||||
|
onClick={() => setVisible(false)}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button.Text>
|
||||||
|
<Button.Danger>Delete</Button.Danger>
|
||||||
|
</Dialog.Buttons>
|
||||||
|
</Dialog>
|
||||||
|
<tr>
|
||||||
|
<td className={'whitespace-nowrap'}>
|
||||||
|
<div className={'flex justify-end items-center w-8'}>
|
||||||
|
<Checkbox/>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td className={'pl-6 py-4 whitespace-nowrap'}>
|
||||||
|
<div className={'flex items-center'}>
|
||||||
|
<div className={'w-10 h-10'}>
|
||||||
|
<img src={user.avatarUrl} className={'w-10 h-10 rounded-full'} alt={'User avatar'}/>
|
||||||
|
</div>
|
||||||
|
<div className={'ml-4'}>
|
||||||
|
<p className={'font-medium'}>
|
||||||
|
{user.email}
|
||||||
|
</p>
|
||||||
|
<p className={'text-sm text-neutral-400'}>
|
||||||
|
{user.uuid}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td className={'pl-2 py-4 whitespace-nowrap'}>
|
||||||
|
{user.isUsingTwoFactor &&
|
||||||
|
<span className={'bg-green-100 uppercase text-green-700 font-semibold text-xs px-2 py-0.5 rounded'}>
|
||||||
|
2-FA Enabled
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
<td className={'px-6 py-4 whitespace-nowrap'}>
|
||||||
|
<Dropdown>
|
||||||
|
<Dropdown.Button className={'px-2'}>
|
||||||
|
<DotsVerticalIcon/>
|
||||||
|
</Dropdown.Button>
|
||||||
|
<Dropdown.Item icon={<PencilIcon/>}>Edit</Dropdown.Item>
|
||||||
|
<Dropdown.Item icon={<SupportIcon/>}>Reset Password</Dropdown.Item>
|
||||||
|
<Dropdown.Item icon={<LockOpenIcon/>} disabled={!user.isUsingTwoFactor}>
|
||||||
|
Disable 2-FA
|
||||||
|
</Dropdown.Item>
|
||||||
|
<Dropdown.Item icon={<BanIcon/>}>Suspend</Dropdown.Item>
|
||||||
|
<Dropdown.Gap/>
|
||||||
|
<Dropdown.Item icon={<TrashIcon/>} onClick={() => setVisible(true)} danger>Delete
|
||||||
|
Account
|
||||||
|
</Dropdown.Item>
|
||||||
|
</Dropdown>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default UserTableRow;
|
|
@ -2,19 +2,10 @@ import React, { useEffect, useState } from 'react';
|
||||||
import http from '@/api/http';
|
import http from '@/api/http';
|
||||||
import { User } from '@/api/admin/user';
|
import { User } from '@/api/admin/user';
|
||||||
import { AdminTransformers } from '@/api/admin/transformers';
|
import { AdminTransformers } from '@/api/admin/transformers';
|
||||||
import { Dropdown } from '@/components/elements/dropdown';
|
import { LockOpenIcon, PlusIcon, SupportIcon, TrashIcon } from '@heroicons/react/solid';
|
||||||
import {
|
|
||||||
BanIcon,
|
|
||||||
DotsVerticalIcon,
|
|
||||||
LockOpenIcon,
|
|
||||||
PencilIcon,
|
|
||||||
PlusIcon,
|
|
||||||
SupportIcon,
|
|
||||||
TrashIcon,
|
|
||||||
} from '@heroicons/react/solid';
|
|
||||||
import { Button } from '@/components/elements/button/index';
|
import { Button } from '@/components/elements/button/index';
|
||||||
import { Dialog } from '@/components/elements/dialog';
|
|
||||||
import { Checkbox, InputField } from '@/components/elements/inputs';
|
import { Checkbox, InputField } from '@/components/elements/inputs';
|
||||||
|
import UserTableRow from '@/components/admin/users/UserTableRow';
|
||||||
|
|
||||||
const UsersContainerV2 = () => {
|
const UsersContainerV2 = () => {
|
||||||
const [ users, setUsers ] = useState<User[]>([]);
|
const [ users, setUsers ] = useState<User[]>([]);
|
||||||
|
@ -22,8 +13,6 @@ const UsersContainerV2 = () => {
|
||||||
document.title = 'Admin | Users';
|
document.title = 'Admin | Users';
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const [ visible, setVisible ] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
http.get('/api/application/users')
|
http.get('/api/application/users')
|
||||||
.then(({ data }) => {
|
.then(({ data }) => {
|
||||||
|
@ -39,37 +28,30 @@ const UsersContainerV2 = () => {
|
||||||
Add User <PlusIcon className={'ml-2 w-5 h-5'}/>
|
Add User <PlusIcon className={'ml-2 w-5 h-5'}/>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<Dialog title={'Delete account'} visible={visible} onDismissed={() => setVisible(false)}>
|
|
||||||
<Dialog.Icon type={'danger'}/>
|
|
||||||
This account will be permanently deleted.
|
|
||||||
<Dialog.Buttons>
|
|
||||||
<Button.Text
|
|
||||||
onClick={() => setVisible(false)}
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</Button.Text>
|
|
||||||
<Button.Danger>Delete</Button.Danger>
|
|
||||||
</Dialog.Buttons>
|
|
||||||
</Dialog>
|
|
||||||
<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/>
|
||||||
</div>
|
</div>
|
||||||
<div className={'flex-1'}>
|
<div className={'flex-1'}>
|
||||||
<InputField type={'text'} name={'filter'} placeholder={'Begin typing to filter...'} className={'w-56 focus:w-96'} />
|
<InputField
|
||||||
|
type={'text'}
|
||||||
|
name={'filter'}
|
||||||
|
placeholder={'Begin typing to filter...'}
|
||||||
|
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'}>
|
<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'}>
|
||||||
<div className={'flex-1'}>
|
<div className={'flex-1'}>
|
||||||
<Checkbox indeterminate />
|
<Checkbox indeterminate/>
|
||||||
</div>
|
</div>
|
||||||
<Button.Text square>
|
<Button.Text square>
|
||||||
<SupportIcon className={'w-4 h-4'} />
|
<SupportIcon className={'w-4 h-4'}/>
|
||||||
</Button.Text>
|
</Button.Text>
|
||||||
<Button.Text square>
|
<Button.Text square>
|
||||||
<LockOpenIcon className={'w-4 h-4'} />
|
<LockOpenIcon className={'w-4 h-4'}/>
|
||||||
</Button.Text>
|
</Button.Text>
|
||||||
<Button.Text square>
|
<Button.Text square>
|
||||||
<TrashIcon className={'w-4 h-4'} />
|
<TrashIcon className={'w-4 h-4'}/>
|
||||||
</Button.Text>
|
</Button.Text>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -83,58 +65,7 @@ const UsersContainerV2 = () => {
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{users.map(user => (
|
{users.map(user => <UserTableRow user={user} key={user.uuid}/>)}
|
||||||
<tr key={user.uuid}>
|
|
||||||
<td className={'whitespace-nowrap'}>
|
|
||||||
<div className={'flex justify-end items-center w-8'}>
|
|
||||||
<Checkbox/>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td className={'pl-6 py-4 whitespace-nowrap'}>
|
|
||||||
<div className={'flex items-center'}>
|
|
||||||
<div className={'w-10 h-10'}>
|
|
||||||
<img
|
|
||||||
src={user.avatarUrl}
|
|
||||||
className={'w-10 h-10 rounded-full'}
|
|
||||||
alt={'User avatar'}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className={'ml-4'}>
|
|
||||||
<p className={'font-medium'}>
|
|
||||||
{user.email}
|
|
||||||
</p>
|
|
||||||
<p className={'text-sm text-neutral-400'}>
|
|
||||||
{user.uuid}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td className={'pl-2 py-4 whitespace-nowrap'}>
|
|
||||||
{user.isUsingTwoFactor &&
|
|
||||||
<span className={'bg-green-100 uppercase text-green-600 font-semibold text-xs px-2 py-0.5 rounded'}>
|
|
||||||
2-FA Enabled
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
</td>
|
|
||||||
<td className={'px-6 py-4 whitespace-nowrap'}>
|
|
||||||
<Dropdown>
|
|
||||||
<Dropdown.Button className={'px-2'}>
|
|
||||||
<DotsVerticalIcon/>
|
|
||||||
</Dropdown.Button>
|
|
||||||
<Dropdown.Item icon={<PencilIcon/>}>Edit</Dropdown.Item>
|
|
||||||
<Dropdown.Item icon={<SupportIcon/>}>Reset Password</Dropdown.Item>
|
|
||||||
<Dropdown.Item icon={<LockOpenIcon/>} disabled={!user.isUsingTwoFactor}>
|
|
||||||
Disable 2-FA
|
|
||||||
</Dropdown.Item>
|
|
||||||
<Dropdown.Item icon={<BanIcon/>}>Suspend</Dropdown.Item>
|
|
||||||
<Dropdown.Gap/>
|
|
||||||
<Dropdown.Item icon={<TrashIcon/>} onClick={() => setVisible(true)} danger>Delete
|
|
||||||
Account
|
|
||||||
</Dropdown.Item>
|
|
||||||
</Dropdown>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue