Restyle users and profile workspace pages
This commit is contained in:
parent
82d5f49261
commit
5cc34803fe
@ -1,180 +1,265 @@
|
|||||||
import {
|
import { mdiUpload } from '@mdi/js';
|
||||||
mdiChartTimelineVariant,
|
|
||||||
mdiUpload,
|
|
||||||
} from '@mdi/js';
|
|
||||||
import Head from 'next/head';
|
|
||||||
import React, { ReactElement, useEffect, useState } from 'react';
|
|
||||||
import { ToastContainer, toast } from 'react-toastify';
|
|
||||||
import DatePicker from 'react-datepicker';
|
|
||||||
import 'react-datepicker/dist/react-datepicker.css';
|
|
||||||
|
|
||||||
import CardBox from '../components/CardBox';
|
|
||||||
import LayoutAuthenticated from '../layouts/Authenticated';
|
|
||||||
import SectionMain from '../components/SectionMain';
|
|
||||||
import SectionTitleLineWithButton from '../components/SectionTitleLineWithButton';
|
|
||||||
import { getPageTitle } from '../config';
|
|
||||||
|
|
||||||
import { Field, Form, Formik } from 'formik';
|
import { Field, Form, Formik } from 'formik';
|
||||||
import FormField from '../components/FormField';
|
import Head from 'next/head';
|
||||||
import BaseDivider from '../components/BaseDivider';
|
import Image from 'next/image';
|
||||||
import BaseButtons from '../components/BaseButtons';
|
|
||||||
import BaseButton from '../components/BaseButton';
|
|
||||||
import FormCheckRadio from '../components/FormCheckRadio';
|
|
||||||
import FormCheckRadioGroup from '../components/FormCheckRadioGroup';
|
|
||||||
import FormImagePicker from '../components/FormImagePicker';
|
|
||||||
import { SwitchField } from '../components/SwitchField';
|
|
||||||
import { SelectField } from '../components/SelectField';
|
|
||||||
|
|
||||||
import { update, fetch } from '../stores/users/usersSlice';
|
|
||||||
import { useAppDispatch, useAppSelector } from '../stores/hooks';
|
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import {findMe} from "../stores/authSlice";
|
import React, { ReactElement, useEffect, useState } from 'react';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
import FormImagePicker from '../components/FormImagePicker';
|
||||||
|
import { SelectField } from '../components/SelectField';
|
||||||
|
import { SwitchField } from '../components/SwitchField';
|
||||||
|
import { getPageTitle } from '../config';
|
||||||
|
import LayoutAuthenticated from '../layouts/Authenticated';
|
||||||
|
import { findMe } from '../stores/authSlice';
|
||||||
|
import { useAppDispatch, useAppSelector } from '../stores/hooks';
|
||||||
|
import { update } from '../stores/users/usersSlice';
|
||||||
|
|
||||||
|
type ProfileValues = {
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
|
phoneNumber: string;
|
||||||
|
email: string;
|
||||||
|
app_role: any;
|
||||||
|
disabled: boolean;
|
||||||
|
avatar: any[];
|
||||||
|
password: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const initVals: ProfileValues = {
|
||||||
|
firstName: '',
|
||||||
|
lastName: '',
|
||||||
|
phoneNumber: '',
|
||||||
|
email: '',
|
||||||
|
app_role: '',
|
||||||
|
disabled: false,
|
||||||
|
avatar: [],
|
||||||
|
password: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
function Panel({
|
||||||
|
children,
|
||||||
|
className = '',
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
className?: string;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<section
|
||||||
|
className={`rounded-lg border border-[#19192d]/10 bg-white ${className}`}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function FieldWrap({
|
||||||
|
label,
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
label: string;
|
||||||
|
children: React.ReactNode;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<label className='block'>
|
||||||
|
<span className='mb-2 block text-sm font-semibold text-[#19192d]'>
|
||||||
|
{label}
|
||||||
|
</span>
|
||||||
|
{children}
|
||||||
|
</label>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const inputClassName =
|
||||||
|
'w-full rounded-lg border border-[#19192d]/10 bg-[#fffdf9] px-3 py-2 text-sm text-[#19192d] outline-none focus:border-[#35b7a5] focus:ring-2 focus:ring-[#35b7a5]/15 disabled:bg-[#fbf8f1] disabled:text-[#72798a]';
|
||||||
|
|
||||||
const EditUsers = () => {
|
const EditUsers = () => {
|
||||||
const { currentUser, isFetching, token } = useAppSelector(
|
const { currentUser } = useAppSelector((state) => state.auth);
|
||||||
(state) => state.auth,
|
const router = useRouter();
|
||||||
);
|
const dispatch = useAppDispatch();
|
||||||
const router = useRouter();
|
const [initialValues, setInitialValues] = useState(initVals);
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const notify = (type, msg) => toast(msg, { type });
|
|
||||||
const initVals = {
|
|
||||||
firstName: '',
|
|
||||||
lastName: '',
|
|
||||||
phoneNumber: '',
|
|
||||||
email: '',
|
|
||||||
app_role: '',
|
|
||||||
disabled: false,
|
|
||||||
avatar: [],
|
|
||||||
password: ''
|
|
||||||
};
|
|
||||||
const [initialValues, setInitialValues] = useState(initVals);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (currentUser?.id && typeof currentUser === 'object') {
|
if (currentUser?.id && typeof currentUser === 'object') {
|
||||||
const newInitialVal = { ...initVals };
|
const newInitialVal = { ...initVals } as Record<string, any>;
|
||||||
|
|
||||||
Object.keys(initVals).forEach(
|
Object.keys(initVals).forEach((key) => {
|
||||||
(el) => (newInitialVal[el] = currentUser[el]),
|
newInitialVal[key] = currentUser[key];
|
||||||
);
|
});
|
||||||
|
|
||||||
setInitialValues(newInitialVal);
|
setInitialValues(newInitialVal);
|
||||||
}
|
}
|
||||||
}, [currentUser]);
|
}, [currentUser]);
|
||||||
|
|
||||||
const handleSubmit = async (data) => {
|
const handleSubmit = async (data: ProfileValues) => {
|
||||||
await dispatch(update({ id: currentUser.id, data }));
|
await dispatch(update({ id: currentUser.id, data }));
|
||||||
await dispatch(findMe());
|
await dispatch(findMe());
|
||||||
await router.push('/users/users-list');
|
await router.push('/users/users-list');
|
||||||
notify('success', 'Profile was updated!');
|
toast('Profile was updated!', { type: 'success' });
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
const avatarUrl = currentUser?.avatar?.[0]?.publicUrl;
|
||||||
<>
|
|
||||||
<Head>
|
return (
|
||||||
<title>{getPageTitle('Edit profile')}</title>
|
<>
|
||||||
</Head>
|
<Head>
|
||||||
<SectionMain>
|
<title>{getPageTitle('Edit profile')}</title>
|
||||||
<SectionTitleLineWithButton
|
</Head>
|
||||||
icon={mdiChartTimelineVariant}
|
|
||||||
title='Edit profile'
|
<main className='mx-auto max-w-5xl px-6 py-6'>
|
||||||
main
|
<div className='mb-4 rounded-lg bg-[#19192d] p-5 text-white'>
|
||||||
|
<div className='flex items-center gap-3 text-[#b17a1e]'>
|
||||||
|
<span className='text-lg'>●</span>
|
||||||
|
<span className='text-xs font-semibold uppercase tracking-[0.22em]'>
|
||||||
|
Account
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<h1 className='mt-3 text-xl font-semibold'>Profile</h1>
|
||||||
|
<p className='mt-2 max-w-2xl text-sm leading-6 text-[#fffdf9]'>
|
||||||
|
Update your workspace profile, avatar, role, and password.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Panel className='p-5'>
|
||||||
|
<Formik
|
||||||
|
enableReinitialize
|
||||||
|
initialValues={initialValues}
|
||||||
|
onSubmit={(values) => handleSubmit(values)}
|
||||||
|
>
|
||||||
|
<Form className='grid gap-5'>
|
||||||
|
<div className='grid gap-5 md:grid-cols-[220px_1fr]'>
|
||||||
|
<div>
|
||||||
|
<p className='text-sm font-semibold text-[#19192d]'>Avatar</p>
|
||||||
|
<div className='mt-3 flex h-32 w-32 items-center justify-center overflow-hidden rounded-full border border-[#19192d]/10 bg-[#f3fbf8]'>
|
||||||
|
{avatarUrl ? (
|
||||||
|
<Image
|
||||||
|
className='h-full w-full object-cover object-center'
|
||||||
|
src={avatarUrl}
|
||||||
|
alt='Avatar'
|
||||||
|
width={128}
|
||||||
|
height={128}
|
||||||
|
unoptimized
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<span className='text-3xl font-semibold text-[#35b7a5]'>
|
||||||
|
{currentUser?.firstName?.[0] ||
|
||||||
|
currentUser?.email?.[0] ||
|
||||||
|
'U'}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className='mt-4'>
|
||||||
|
<Field
|
||||||
|
label='Avatar'
|
||||||
|
color='info'
|
||||||
|
icon={mdiUpload}
|
||||||
|
path='users/avatar'
|
||||||
|
name='avatar'
|
||||||
|
id='avatar'
|
||||||
|
schema={{
|
||||||
|
size: undefined,
|
||||||
|
formats: undefined,
|
||||||
|
}}
|
||||||
|
component={FormImagePicker}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='grid gap-4 md:grid-cols-2'>
|
||||||
|
<FieldWrap label='First name'>
|
||||||
|
<Field
|
||||||
|
className={inputClassName}
|
||||||
|
name='firstName'
|
||||||
|
placeholder='First name'
|
||||||
|
/>
|
||||||
|
</FieldWrap>
|
||||||
|
|
||||||
|
<FieldWrap label='Last name'>
|
||||||
|
<Field
|
||||||
|
className={inputClassName}
|
||||||
|
name='lastName'
|
||||||
|
placeholder='Last name'
|
||||||
|
/>
|
||||||
|
</FieldWrap>
|
||||||
|
|
||||||
|
<FieldWrap label='Phone number'>
|
||||||
|
<Field
|
||||||
|
className={inputClassName}
|
||||||
|
name='phoneNumber'
|
||||||
|
placeholder='Phone number'
|
||||||
|
/>
|
||||||
|
</FieldWrap>
|
||||||
|
|
||||||
|
<FieldWrap label='Email'>
|
||||||
|
<Field
|
||||||
|
className={inputClassName}
|
||||||
|
name='email'
|
||||||
|
placeholder='Email'
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
</FieldWrap>
|
||||||
|
|
||||||
|
<FieldWrap label='App role'>
|
||||||
|
<Field
|
||||||
|
name='app_role'
|
||||||
|
id='app_role'
|
||||||
|
component={SelectField}
|
||||||
|
options={initialValues.app_role}
|
||||||
|
itemRef='roles'
|
||||||
|
showField='name'
|
||||||
|
/>
|
||||||
|
</FieldWrap>
|
||||||
|
|
||||||
|
<FieldWrap label='Password'>
|
||||||
|
<Field
|
||||||
|
className={inputClassName}
|
||||||
|
name='password'
|
||||||
|
placeholder='New password'
|
||||||
|
/>
|
||||||
|
</FieldWrap>
|
||||||
|
|
||||||
|
<div className='md:col-span-2'>
|
||||||
|
<FieldWrap label='Disabled'>
|
||||||
|
<Field
|
||||||
|
name='disabled'
|
||||||
|
id='disabled'
|
||||||
|
component={SwitchField}
|
||||||
|
/>
|
||||||
|
</FieldWrap>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='flex flex-wrap justify-end gap-3 border-t border-[#19192d]/10 pt-5'>
|
||||||
|
<button
|
||||||
|
type='button'
|
||||||
|
className='rounded-full border border-[#19192d]/10 bg-white px-4 py-2 text-sm font-semibold text-[#19192d]'
|
||||||
|
onClick={() => router.push('/users/users-list')}
|
||||||
>
|
>
|
||||||
{''}
|
Cancel
|
||||||
</SectionTitleLineWithButton>
|
</button>
|
||||||
<CardBox>
|
<button
|
||||||
{currentUser?.avatar[0]?.publicUrl && <div className={'grid grid-cols-6 gap-4 mb-4'}>
|
type='reset'
|
||||||
<div className="col-span-1 w-80 h-80 overflow-hidden border-2 rounded-full inline-flex items-center justify-center mb-8">
|
className='rounded-full border border-[#19192d]/10 bg-white px-4 py-2 text-sm font-semibold text-[#19192d]'
|
||||||
<img className="w-80 h-80 max-w-full max-h-full object-cover object-center" src={`${currentUser?.avatar[0]?.publicUrl}`} alt="Avatar" />
|
>
|
||||||
</div>
|
Reset
|
||||||
</div>}
|
</button>
|
||||||
<Formik
|
<button
|
||||||
enableReinitialize
|
type='submit'
|
||||||
initialValues={initialValues}
|
className='rounded-full bg-[#35b7a5] px-4 py-2 text-sm font-semibold text-white'
|
||||||
onSubmit={(values) => handleSubmit(values)}
|
>
|
||||||
>
|
Save profile
|
||||||
<Form>
|
</button>
|
||||||
<FormField>
|
</div>
|
||||||
<Field
|
</Form>
|
||||||
label='Avatar'
|
</Formik>
|
||||||
color='info'
|
</Panel>
|
||||||
icon={mdiUpload}
|
</main>
|
||||||
path={'users/avatar'}
|
</>
|
||||||
name='avatar'
|
);
|
||||||
id='avatar'
|
|
||||||
schema={{
|
|
||||||
size: undefined,
|
|
||||||
formats: undefined,
|
|
||||||
}}
|
|
||||||
component={FormImagePicker}
|
|
||||||
></Field>
|
|
||||||
</FormField>
|
|
||||||
<FormField label='First Name'>
|
|
||||||
<Field name='firstName' placeholder='First Name' />
|
|
||||||
</FormField>
|
|
||||||
|
|
||||||
<FormField label='Last Name'>
|
|
||||||
<Field name='lastName' placeholder='Last Name' />
|
|
||||||
</FormField>
|
|
||||||
|
|
||||||
<FormField label='Phone Number'>
|
|
||||||
<Field name='phoneNumber' placeholder='Phone Number' />
|
|
||||||
</FormField>
|
|
||||||
|
|
||||||
<FormField label='E-Mail'>
|
|
||||||
<Field name='email' placeholder='E-Mail' disabled />
|
|
||||||
</FormField>
|
|
||||||
|
|
||||||
<FormField label='App Role' labelFor='app_role'>
|
|
||||||
<Field
|
|
||||||
name='app_role'
|
|
||||||
id='app_role'
|
|
||||||
component={SelectField}
|
|
||||||
options={initialValues.app_role}
|
|
||||||
itemRef={'roles'}
|
|
||||||
showField={'name'}
|
|
||||||
></Field>
|
|
||||||
</FormField>
|
|
||||||
|
|
||||||
<FormField label='Disabled' labelFor='disabled'>
|
|
||||||
<Field
|
|
||||||
name='disabled'
|
|
||||||
id='disabled'
|
|
||||||
component={SwitchField}
|
|
||||||
></Field>
|
|
||||||
</FormField>
|
|
||||||
|
|
||||||
<FormField
|
|
||||||
label="Password"
|
|
||||||
>
|
|
||||||
<Field
|
|
||||||
name="password"
|
|
||||||
placeholder="password"
|
|
||||||
/>
|
|
||||||
</FormField>
|
|
||||||
|
|
||||||
<BaseDivider />
|
|
||||||
|
|
||||||
<BaseButtons>
|
|
||||||
<BaseButton type='submit' color='info' label='Submit' />
|
|
||||||
<BaseButton type='reset' color='info' outline label='Reset' />
|
|
||||||
<BaseButton
|
|
||||||
type='reset'
|
|
||||||
color='danger'
|
|
||||||
outline
|
|
||||||
label='Cancel'
|
|
||||||
onClick={() => router.push('/users/users-list')}
|
|
||||||
/>
|
|
||||||
</BaseButtons>
|
|
||||||
</Form>
|
|
||||||
</Formik>
|
|
||||||
</CardBox>
|
|
||||||
</SectionMain>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
EditUsers.getLayout = function getLayout(page: ReactElement) {
|
EditUsers.getLayout = function getLayout(page: ReactElement) {
|
||||||
return <LayoutAuthenticated>{page}</LayoutAuthenticated>;
|
return <LayoutAuthenticated>{page}</LayoutAuthenticated>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default EditUsers;
|
export default EditUsers;
|
||||||
|
|||||||
@ -1,166 +1,201 @@
|
|||||||
import { mdiChartTimelineVariant } from '@mdi/js'
|
import axios from 'axios';
|
||||||
import Head from 'next/head'
|
import Head from 'next/head';
|
||||||
|
import React, { ReactElement, useState } from 'react';
|
||||||
import { uniqueId } from 'lodash';
|
import { uniqueId } from 'lodash';
|
||||||
import React, { ReactElement, useState } from 'react'
|
import CardBoxModal from '../../components/CardBoxModal';
|
||||||
import CardBox from '../../components/CardBox'
|
import DragDropFilePicker from '../../components/DragDropFilePicker';
|
||||||
import LayoutAuthenticated from '../../layouts/Authenticated'
|
import TableUsers from '../../components/Users/TableUsers';
|
||||||
import SectionMain from '../../components/SectionMain'
|
import { getPageTitle } from '../../config';
|
||||||
import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
|
import { hasPermission } from '../../helpers/userPermissions';
|
||||||
import { getPageTitle } from '../../config'
|
import LayoutAuthenticated from '../../layouts/Authenticated';
|
||||||
import TableUsers from '../../components/Users/TableUsers'
|
import { useAppDispatch, useAppSelector } from '../../stores/hooks';
|
||||||
import BaseButton from '../../components/BaseButton'
|
import { setRefetch, uploadCsv } from '../../stores/users/usersSlice';
|
||||||
import axios from "axios";
|
|
||||||
import Link from "next/link";
|
|
||||||
import {useAppDispatch, useAppSelector} from "../../stores/hooks";
|
|
||||||
import CardBoxModal from "../../components/CardBoxModal";
|
|
||||||
import DragDropFilePicker from "../../components/DragDropFilePicker";
|
|
||||||
import {setRefetch, uploadCsv} from '../../stores/users/usersSlice';
|
|
||||||
|
|
||||||
|
function Panel({
|
||||||
|
children,
|
||||||
|
className = '',
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
className?: string;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<section
|
||||||
|
className={`rounded-lg border border-[#19192d]/10 bg-white ${className}`}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
import {hasPermission} from "../../helpers/userPermissions";
|
function ActionButton({
|
||||||
|
children,
|
||||||
|
href,
|
||||||
|
onClick,
|
||||||
|
variant = 'primary',
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
href?: string;
|
||||||
|
onClick?: () => void;
|
||||||
|
variant?: 'primary' | 'secondary';
|
||||||
|
}) {
|
||||||
|
const className =
|
||||||
|
variant === 'primary'
|
||||||
|
? 'rounded-full bg-[#35b7a5] px-4 py-2 text-sm font-semibold text-white'
|
||||||
|
: 'rounded-full border border-[#19192d]/10 bg-white px-4 py-2 text-sm font-semibold text-[#19192d]';
|
||||||
|
|
||||||
|
if (href) {
|
||||||
|
return (
|
||||||
|
<a href={href} className={className}>
|
||||||
|
{children}
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button type='button' className={className} onClick={onClick}>
|
||||||
|
{children}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const UsersTablesPage = () => {
|
const UsersTablesPage = () => {
|
||||||
const [filterItems, setFilterItems] = useState([]);
|
const [filterItems, setFilterItems] = useState([]);
|
||||||
const [csvFile, setCsvFile] = useState<File | null>(null);
|
const [csvFile, setCsvFile] = useState<File | null>(null);
|
||||||
const [isModalActive, setIsModalActive] = useState(false);
|
const [isModalActive, setIsModalActive] = useState(false);
|
||||||
const [showTableView, setShowTableView] = useState(false);
|
|
||||||
|
|
||||||
|
|
||||||
const { currentUser } = useAppSelector((state) => state.auth);
|
const { currentUser } = useAppSelector((state) => state.auth);
|
||||||
|
|
||||||
|
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
|
const [filters] = useState([
|
||||||
const [filters] = useState([{label: 'First Name', title: 'firstName'},{label: 'Last Name', title: 'lastName'},{label: 'Phone Number', title: 'phoneNumber'},{label: 'E-Mail', title: 'email'},
|
{ label: 'First Name', title: 'firstName' },
|
||||||
|
{ label: 'Last Name', title: 'lastName' },
|
||||||
|
{ label: 'Phone Number', title: 'phoneNumber' },
|
||||||
|
{ label: 'E-Mail', title: 'email' },
|
||||||
|
{ label: 'App Role', title: 'app_role' },
|
||||||
|
{ label: 'Custom Permissions', title: 'custom_permissions' },
|
||||||
{label: 'App Role', title: 'app_role'},
|
|
||||||
|
|
||||||
|
|
||||||
{label: 'Custom Permissions', title: 'custom_permissions'},
|
|
||||||
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const hasCreatePermission = currentUser && hasPermission(currentUser, 'CREATE_USERS');
|
const hasCreatePermission =
|
||||||
|
currentUser && hasPermission(currentUser, 'CREATE_USERS');
|
||||||
|
|
||||||
|
const addFilter = () => {
|
||||||
const addFilter = () => {
|
const newItem = {
|
||||||
const newItem = {
|
id: uniqueId(),
|
||||||
id: uniqueId(),
|
fields: {
|
||||||
fields: {
|
filterValue: '',
|
||||||
filterValue: '',
|
filterValueFrom: '',
|
||||||
filterValueFrom: '',
|
filterValueTo: '',
|
||||||
filterValueTo: '',
|
selectedField: filters[0].title,
|
||||||
selectedField: '',
|
},
|
||||||
},
|
|
||||||
};
|
|
||||||
newItem.fields.selectedField = filters[0].title;
|
|
||||||
setFilterItems([...filterItems, newItem]);
|
|
||||||
};
|
};
|
||||||
|
setFilterItems([...filterItems, newItem]);
|
||||||
|
};
|
||||||
|
|
||||||
const getUsersCSV = async () => {
|
const getUsersCSV = async () => {
|
||||||
const response = await axios({url: '/users?filetype=csv', method: 'GET',responseType: 'blob'});
|
const response = await axios({
|
||||||
const type = response.headers['content-type']
|
url: '/users?filetype=csv',
|
||||||
const blob = new Blob([response.data], { type: type })
|
method: 'GET',
|
||||||
const link = document.createElement('a')
|
responseType: 'blob',
|
||||||
link.href = window.URL.createObjectURL(blob)
|
});
|
||||||
link.download = 'usersCSV.csv'
|
const type = response.headers['content-type'];
|
||||||
link.click()
|
const blob = new Blob([response.data], { type });
|
||||||
};
|
const link = document.createElement('a');
|
||||||
|
link.href = window.URL.createObjectURL(blob);
|
||||||
|
link.download = 'usersCSV.csv';
|
||||||
|
link.click();
|
||||||
|
};
|
||||||
|
|
||||||
const onModalConfirm = async () => {
|
const onModalConfirm = async () => {
|
||||||
if (!csvFile) return;
|
if (!csvFile) {
|
||||||
await dispatch(uploadCsv(csvFile));
|
return;
|
||||||
dispatch(setRefetch(true));
|
}
|
||||||
setCsvFile(null);
|
|
||||||
setIsModalActive(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onModalCancel = () => {
|
await dispatch(uploadCsv(csvFile));
|
||||||
setCsvFile(null);
|
dispatch(setRefetch(true));
|
||||||
setIsModalActive(false);
|
setCsvFile(null);
|
||||||
};
|
setIsModalActive(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onModalCancel = () => {
|
||||||
|
setCsvFile(null);
|
||||||
|
setIsModalActive(false);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head>
|
<Head>
|
||||||
<title>{getPageTitle('Users')}</title>
|
<title>{getPageTitle('Users')}</title>
|
||||||
</Head>
|
</Head>
|
||||||
<SectionMain>
|
|
||||||
<SectionTitleLineWithButton icon={mdiChartTimelineVariant} title="Users" main>
|
|
||||||
{''}
|
|
||||||
</SectionTitleLineWithButton>
|
|
||||||
<CardBox id="usersList" className='mb-6' cardBoxClassName='flex flex-wrap'>
|
|
||||||
|
|
||||||
{hasCreatePermission && <BaseButton className={'mr-3'} href={'/users/users-new'} color='info' label='Add/Invite User'/>}
|
<main className='mx-auto max-w-7xl px-6 py-6'>
|
||||||
|
<div className='mb-4 rounded-lg bg-[#19192d] p-5 text-white'>
|
||||||
<BaseButton
|
<div className='flex items-center gap-3 text-[#b17a1e]'>
|
||||||
className={'mr-3'}
|
<span className='text-lg'>●</span>
|
||||||
color='info'
|
<span className='text-xs font-semibold uppercase tracking-[0.22em]'>
|
||||||
label='Filter'
|
Team access
|
||||||
onClick={addFilter}
|
</span>
|
||||||
/>
|
|
||||||
<BaseButton className={'mr-3'} color='info' label='Download CSV' onClick={getUsersCSV} />
|
|
||||||
|
|
||||||
{hasCreatePermission && (
|
|
||||||
<BaseButton
|
|
||||||
color='info'
|
|
||||||
label='Upload CSV'
|
|
||||||
onClick={() => setIsModalActive(true)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className='md:inline-flex items-center ms-auto'>
|
|
||||||
<div id='delete-rows-button'></div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<h1 className='mt-3 text-xl font-semibold'>Users</h1>
|
||||||
|
<p className='mt-2 max-w-2xl text-sm leading-6 text-[#fffdf9]'>
|
||||||
|
Manage workspace members, roles, and export or import user records.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
</CardBox>
|
<Panel className='mb-4 p-4'>
|
||||||
|
<div className='flex flex-wrap items-center gap-3'>
|
||||||
|
{hasCreatePermission && (
|
||||||
|
<ActionButton href='/users/users-new'>Add user</ActionButton>
|
||||||
|
)}
|
||||||
|
<ActionButton variant='secondary' onClick={addFilter}>
|
||||||
|
Filter
|
||||||
|
</ActionButton>
|
||||||
|
<ActionButton variant='secondary' onClick={getUsersCSV}>
|
||||||
|
Download CSV
|
||||||
|
</ActionButton>
|
||||||
|
{hasCreatePermission && (
|
||||||
|
<ActionButton
|
||||||
|
variant='secondary'
|
||||||
|
onClick={() => setIsModalActive(true)}
|
||||||
|
>
|
||||||
|
Upload CSV
|
||||||
|
</ActionButton>
|
||||||
|
)}
|
||||||
|
<div className='ms-auto' id='delete-rows-button'></div>
|
||||||
|
</div>
|
||||||
|
</Panel>
|
||||||
|
|
||||||
<CardBox className="mb-6" hasTable>
|
<Panel className='overflow-hidden'>
|
||||||
<TableUsers
|
<TableUsers
|
||||||
filterItems={filterItems}
|
filterItems={filterItems}
|
||||||
setFilterItems={setFilterItems}
|
setFilterItems={setFilterItems}
|
||||||
filters={filters}
|
filters={filters}
|
||||||
showGrid={false}
|
showGrid={false}
|
||||||
/>
|
|
||||||
</CardBox>
|
|
||||||
|
|
||||||
</SectionMain>
|
|
||||||
<CardBoxModal
|
|
||||||
title='Upload CSV'
|
|
||||||
buttonColor='info'
|
|
||||||
buttonLabel={'Confirm'}
|
|
||||||
// buttonLabel={false ? 'Deleting...' : 'Confirm'}
|
|
||||||
isActive={isModalActive}
|
|
||||||
onConfirm={onModalConfirm}
|
|
||||||
onCancel={onModalCancel}
|
|
||||||
>
|
|
||||||
<DragDropFilePicker
|
|
||||||
file={csvFile}
|
|
||||||
setFile={setCsvFile}
|
|
||||||
formats={'.csv'}
|
|
||||||
/>
|
/>
|
||||||
|
</Panel>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<CardBoxModal
|
||||||
|
title='Upload CSV'
|
||||||
|
buttonColor='info'
|
||||||
|
buttonLabel='Confirm'
|
||||||
|
isActive={isModalActive}
|
||||||
|
onConfirm={onModalConfirm}
|
||||||
|
onCancel={onModalCancel}
|
||||||
|
>
|
||||||
|
<DragDropFilePicker
|
||||||
|
file={csvFile}
|
||||||
|
setFile={setCsvFile}
|
||||||
|
formats='.csv'
|
||||||
|
/>
|
||||||
</CardBoxModal>
|
</CardBoxModal>
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
UsersTablesPage.getLayout = function getLayout(page: ReactElement) {
|
UsersTablesPage.getLayout = function getLayout(page: ReactElement) {
|
||||||
return (
|
return (
|
||||||
<LayoutAuthenticated
|
<LayoutAuthenticated permission='READ_USERS'>{page}</LayoutAuthenticated>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
permission={'READ_USERS'}
|
export default UsersTablesPage;
|
||||||
|
|
||||||
>
|
|
||||||
{page}
|
|
||||||
</LayoutAuthenticated>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default UsersTablesPage
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user