Revert to version 9bb4dbe
This commit is contained in:
parent
251c57f6f7
commit
b9c795278d
@ -45,17 +45,7 @@ const ListComments = ({ comments, loading, onDelete, currentPage, numPages, onPa
|
||||
'flex-1 px-4 py-6 h-24 flex divide-x-2 divide-stone-300 items-center overflow-hidden`}> dark:divide-dark-700 overflow-x-auto'
|
||||
}
|
||||
>
|
||||
<div className="flex flex-col ml-4">
|
||||
<div className="text-lg font-semibold text-gray-800 dark:text-white">
|
||||
{item.author?.fullName || 'Anonymous'}
|
||||
</div>
|
||||
<div className="text-sm text-gray-500 dark:text-gray-400">
|
||||
{dataFormatter.dateFormatter(item.created)}
|
||||
</div>
|
||||
<div className="mt-2 text-gray-600 dark:text-gray-300">
|
||||
{item.content}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</Link>
|
||||
<ListActionsPopover
|
||||
onDelete={onDelete}
|
||||
|
||||
@ -33,23 +33,12 @@ const menuAside: MenuAsideItem[] = [
|
||||
permissions: 'READ_PERMISSIONS'
|
||||
},
|
||||
{
|
||||
href: '/leads/leads-list',
|
||||
label: 'Leads',
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
icon: 'mdiAccountMultiple' in icon ? icon['mdiAccountMultiple' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable,
|
||||
permissions: 'READ_LEADS',
|
||||
menu: [
|
||||
{
|
||||
href: '/leads/list',
|
||||
label: 'Leads List',
|
||||
permissions: 'READ_LEADS',
|
||||
},
|
||||
{
|
||||
href: '/leads/kanban',
|
||||
label: 'Kanban',
|
||||
permissions: 'READ_LEADS',
|
||||
},
|
||||
],
|
||||
permissions: 'READ_LEADS'
|
||||
},
|
||||
{
|
||||
href: '/projects/projects-list',
|
||||
|
||||
@ -1,155 +1,373 @@
|
||||
import * as icon from '@mdi/js'
|
||||
import * as icon from '@mdi/js';
|
||||
import Head from 'next/head'
|
||||
import React, { ReactElement } from 'react'
|
||||
import axios from 'axios'
|
||||
import React from 'react'
|
||||
import axios from 'axios';
|
||||
import type { ReactElement } from 'react'
|
||||
import LayoutAuthenticated from '../layouts/Authenticated'
|
||||
import SectionMain from '../components/SectionMain'
|
||||
import SectionTitleLineWithButton from '../components/SectionTitleLineWithButton'
|
||||
import BaseIcon from '../components/BaseIcon'
|
||||
import BaseIcon from "../components/BaseIcon";
|
||||
import { getPageTitle } from '../config'
|
||||
import Link from 'next/link'
|
||||
import { useAppSelector } from '../stores/hooks'
|
||||
import { hasPermission } from '../helpers/userPermissions'
|
||||
import Link from "next/link";
|
||||
|
||||
import { hasPermission } from "../helpers/userPermissions";
|
||||
import { fetchWidgets } from '../stores/roles/rolesSlice';
|
||||
import { WidgetCreator } from '../components/WidgetCreator/WidgetCreator';
|
||||
import { SmartWidget } from '../components/SmartWidget/SmartWidget';
|
||||
|
||||
import { useAppDispatch, useAppSelector } from '../stores/hooks';
|
||||
const Dashboard = () => {
|
||||
const iconsColor = useAppSelector((state) => state.style.iconsColor)
|
||||
const corners = useAppSelector((state) => state.style.corners)
|
||||
const cardsStyle = useAppSelector((state) => state.style.cardsStyle)
|
||||
const { currentUser } = useAppSelector((state) => state.auth)
|
||||
const dispatch = useAppDispatch();
|
||||
const iconsColor = useAppSelector((state) => state.style.iconsColor);
|
||||
const corners = useAppSelector((state) => state.style.corners);
|
||||
const cardsStyle = useAppSelector((state) => state.style.cardsStyle);
|
||||
|
||||
const loadingMessage = 'Loading...'
|
||||
const loadingMessage = 'Loading...';
|
||||
|
||||
const [leads, setLeads] = React.useState(loadingMessage)
|
||||
const [projects, setProjects] = React.useState(loadingMessage)
|
||||
const [tasks, setTasks] = React.useState(loadingMessage)
|
||||
|
||||
const [users, setUsers] = React.useState(loadingMessage);
|
||||
const [roles, setRoles] = React.useState(loadingMessage);
|
||||
const [permissions, setPermissions] = React.useState(loadingMessage);
|
||||
const [leads, setLeads] = React.useState(loadingMessage);
|
||||
const [projects, setProjects] = React.useState(loadingMessage);
|
||||
const [tasks, setTasks] = React.useState(loadingMessage);
|
||||
const [comments, setComments] = React.useState(loadingMessage);
|
||||
const [attachments, setAttachments] = React.useState(loadingMessage);
|
||||
|
||||
async function loadData() {
|
||||
const entities = ['leads', 'projects', 'tasks']
|
||||
const fns = [setLeads, setProjects, setTasks]
|
||||
|
||||
const [widgetsRole, setWidgetsRole] = React.useState({
|
||||
role: { value: '', label: '' },
|
||||
});
|
||||
const { currentUser } = useAppSelector((state) => state.auth);
|
||||
const { isFetchingQuery } = useAppSelector((state) => state.openAi);
|
||||
|
||||
const { rolesWidgets, loading } = useAppSelector((state) => state.roles);
|
||||
|
||||
|
||||
async function loadData() {
|
||||
const entities = ['users','roles','permissions','leads','projects','tasks','comments','attachments',];
|
||||
const fns = [setUsers,setRoles,setPermissions,setLeads,setProjects,setTasks,setComments,setAttachments,];
|
||||
|
||||
const requests = entities.map((entity, index) => {
|
||||
if (hasPermission(currentUser, `READ_${entity.toUpperCase()}`)) {
|
||||
return axios.get(`/${entity.toLowerCase()}/count`)
|
||||
} else {
|
||||
fns[index](null)
|
||||
return Promise.resolve({ data: { count: null } })
|
||||
}
|
||||
})
|
||||
const requests = entities.map((entity, index) => {
|
||||
|
||||
if(hasPermission(currentUser, `READ_${entity.toUpperCase()}`)) {
|
||||
return axios.get(`/${entity.toLowerCase()}/count`);
|
||||
} else {
|
||||
fns[index](null);
|
||||
return Promise.resolve({data: {count: null}});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Promise.allSettled(requests).then((results) => {
|
||||
results.forEach((result, i) => {
|
||||
if (result.status === 'fulfilled') {
|
||||
fns[i](result.value.data.count)
|
||||
} else {
|
||||
fns[i](result.reason.message)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!currentUser) return
|
||||
loadData().then()
|
||||
}, [currentUser])
|
||||
Promise.allSettled(requests).then((results) => {
|
||||
results.forEach((result, i) => {
|
||||
if (result.status === 'fulfilled') {
|
||||
fns[i](result.value.data.count);
|
||||
} else {
|
||||
fns[i](result.reason.message);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function getWidgets(roleId) {
|
||||
await dispatch(fetchWidgets(roleId));
|
||||
}
|
||||
React.useEffect(() => {
|
||||
if (!currentUser) return;
|
||||
loadData().then();
|
||||
setWidgetsRole({ role: { value: currentUser?.app_role?.id, label: currentUser?.app_role?.name } });
|
||||
}, [currentUser]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!currentUser || !widgetsRole?.role?.value) return;
|
||||
getWidgets(widgetsRole?.role?.value || '').then();
|
||||
}, [widgetsRole?.role?.value]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>{getPageTitle('Dashboard')}</title>
|
||||
<title>
|
||||
{getPageTitle('Overview')}
|
||||
</title>
|
||||
</Head>
|
||||
<SectionMain>
|
||||
<SectionTitleLineWithButton
|
||||
icon={icon.mdiChartTimelineVariant}
|
||||
title="TeamFlow PM Dashboard"
|
||||
main
|
||||
>
|
||||
icon={icon.mdiChartTimelineVariant}
|
||||
title='Overview'
|
||||
main>
|
||||
{''}
|
||||
</SectionTitleLineWithButton>
|
||||
|
||||
{hasPermission(currentUser, 'CREATE_ROLES') && <WidgetCreator
|
||||
currentUser={currentUser}
|
||||
isFetchingQuery={isFetchingQuery}
|
||||
setWidgetsRole={setWidgetsRole}
|
||||
widgetsRole={widgetsRole}
|
||||
/>}
|
||||
{!!rolesWidgets.length &&
|
||||
hasPermission(currentUser, 'CREATE_ROLES') && (
|
||||
<p className=' text-gray-500 dark:text-gray-400 mb-4'>
|
||||
{`${widgetsRole?.role?.label || 'Users'}'s widgets`}
|
||||
</p>
|
||||
)}
|
||||
|
||||
<div id="dashboard" className="grid grid-cols-1 gap-6 lg:grid-cols-3 mb-6">
|
||||
{hasPermission(currentUser, 'READ_LEADS') && (
|
||||
<Link href={'/leads/leads-list'}>
|
||||
<div
|
||||
className={`${
|
||||
corners !== 'rounded-full' ? corners : 'rounded-3xl'
|
||||
} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}
|
||||
>
|
||||
<div className="flex justify-between align-center">
|
||||
<div>
|
||||
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400">
|
||||
Potential Leads
|
||||
</div>
|
||||
<div className="text-3xl leading-tight font-semibold">{leads}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className='grid grid-cols-1 gap-6 lg:grid-cols-4 mb-6 grid-flow-dense'>
|
||||
{(isFetchingQuery || loading) && (
|
||||
<div className={` ${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 text-lg leading-tight text-gray-500 flex items-center ${cardsStyle} dark:border-dark-700 p-6`}>
|
||||
<BaseIcon
|
||||
className={`${iconsColor}`}
|
||||
w="w-16"
|
||||
h="h-16"
|
||||
size={48}
|
||||
path={icon.mdiAccountMultiple}
|
||||
/>
|
||||
</div>
|
||||
className={`${iconsColor} animate-spin mr-5`}
|
||||
w='w-16'
|
||||
h='h-16'
|
||||
size={48}
|
||||
path={icon.mdiLoading}
|
||||
/>{' '}
|
||||
Loading widgets...
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
)}
|
||||
)}
|
||||
|
||||
{hasPermission(currentUser, 'READ_PROJECTS') && (
|
||||
<Link href={'/projects/projects-list'}>
|
||||
<div
|
||||
className={`${
|
||||
corners !== 'rounded-full' ? corners : 'rounded-3xl'
|
||||
} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}
|
||||
>
|
||||
<div className="flex justify-between align-center">
|
||||
<div>
|
||||
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400">
|
||||
Active Projects
|
||||
</div>
|
||||
<div className="text-3xl leading-tight font-semibold">{projects}</div>
|
||||
</div>
|
||||
<div>
|
||||
<BaseIcon
|
||||
className={`${iconsColor}`}
|
||||
w="w-16"
|
||||
h="h-16"
|
||||
size={48}
|
||||
path={icon.mdiFolder}
|
||||
{ rolesWidgets &&
|
||||
rolesWidgets.map((widget) => (
|
||||
<SmartWidget
|
||||
key={widget.id}
|
||||
userId={currentUser?.id}
|
||||
widget={widget}
|
||||
roleId={widgetsRole?.role?.value || ''}
|
||||
admin={hasPermission(currentUser, 'CREATE_ROLES')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
)}
|
||||
))}
|
||||
</div>
|
||||
|
||||
{hasPermission(currentUser, 'READ_TASKS') && (
|
||||
<Link href={'/tasks/tasks-list'}>
|
||||
<div
|
||||
className={`${
|
||||
corners !== 'rounded-full' ? corners : 'rounded-3xl'
|
||||
} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}
|
||||
>
|
||||
<div className="flex justify-between align-center">
|
||||
<div>
|
||||
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400">
|
||||
Open Tasks
|
||||
{!!rolesWidgets.length && <hr className='my-6 text-pastelEmeraldTheme-mainBG ' />}
|
||||
|
||||
<div id="dashboard" className='grid grid-cols-1 gap-6 lg:grid-cols-3 mb-6'>
|
||||
|
||||
|
||||
{hasPermission(currentUser, 'READ_USERS') && <Link href={'/users/users-list'}>
|
||||
<div
|
||||
className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}
|
||||
>
|
||||
<div className="flex justify-between align-center">
|
||||
<div>
|
||||
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400">
|
||||
Users
|
||||
</div>
|
||||
<div className="text-3xl leading-tight font-semibold">
|
||||
{users}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<BaseIcon
|
||||
className={`${iconsColor}`}
|
||||
w="w-16"
|
||||
h="h-16"
|
||||
size={48}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
path={icon.mdiAccountGroup || icon.mdiTable}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-3xl leading-tight font-semibold">{tasks}</div>
|
||||
</div>
|
||||
<div>
|
||||
<BaseIcon
|
||||
className={`${iconsColor}`}
|
||||
w="w-16"
|
||||
h="h-16"
|
||||
size={48}
|
||||
path={icon.mdiFormatListBulleted}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
)}
|
||||
</Link>}
|
||||
|
||||
{hasPermission(currentUser, 'READ_ROLES') && <Link href={'/roles/roles-list'}>
|
||||
<div
|
||||
className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}
|
||||
>
|
||||
<div className="flex justify-between align-center">
|
||||
<div>
|
||||
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400">
|
||||
Roles
|
||||
</div>
|
||||
<div className="text-3xl leading-tight font-semibold">
|
||||
{roles}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<BaseIcon
|
||||
className={`${iconsColor}`}
|
||||
w="w-16"
|
||||
h="h-16"
|
||||
size={48}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
path={icon.mdiShieldAccountVariantOutline || icon.mdiTable}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>}
|
||||
|
||||
{hasPermission(currentUser, 'READ_PERMISSIONS') && <Link href={'/permissions/permissions-list'}>
|
||||
<div
|
||||
className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}
|
||||
>
|
||||
<div className="flex justify-between align-center">
|
||||
<div>
|
||||
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400">
|
||||
Permissions
|
||||
</div>
|
||||
<div className="text-3xl leading-tight font-semibold">
|
||||
{permissions}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<BaseIcon
|
||||
className={`${iconsColor}`}
|
||||
w="w-16"
|
||||
h="h-16"
|
||||
size={48}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
path={icon.mdiShieldAccountOutline || icon.mdiTable}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>}
|
||||
|
||||
{hasPermission(currentUser, 'READ_LEADS') && <Link href={'/leads/leads-list'}>
|
||||
<div
|
||||
className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}
|
||||
>
|
||||
<div className="flex justify-between align-center">
|
||||
<div>
|
||||
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400">
|
||||
Leads
|
||||
</div>
|
||||
<div className="text-3xl leading-tight font-semibold">
|
||||
{leads}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<BaseIcon
|
||||
className={`${iconsColor}`}
|
||||
w="w-16"
|
||||
h="h-16"
|
||||
size={48}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
path={'mdiAccountMultiple' in icon ? icon['mdiAccountMultiple' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>}
|
||||
|
||||
{hasPermission(currentUser, 'READ_PROJECTS') && <Link href={'/projects/projects-list'}>
|
||||
<div
|
||||
className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}
|
||||
>
|
||||
<div className="flex justify-between align-center">
|
||||
<div>
|
||||
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400">
|
||||
Projects
|
||||
</div>
|
||||
<div className="text-3xl leading-tight font-semibold">
|
||||
{projects}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<BaseIcon
|
||||
className={`${iconsColor}`}
|
||||
w="w-16"
|
||||
h="h-16"
|
||||
size={48}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
path={'mdiFolder' in icon ? icon['mdiFolder' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>}
|
||||
|
||||
{hasPermission(currentUser, 'READ_TASKS') && <Link href={'/tasks/tasks-list'}>
|
||||
<div
|
||||
className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}
|
||||
>
|
||||
<div className="flex justify-between align-center">
|
||||
<div>
|
||||
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400">
|
||||
Tasks
|
||||
</div>
|
||||
<div className="text-3xl leading-tight font-semibold">
|
||||
{tasks}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<BaseIcon
|
||||
className={`${iconsColor}`}
|
||||
w="w-16"
|
||||
h="h-16"
|
||||
size={48}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
path={'mdiFormatListBulleted' in icon ? icon['mdiFormatListBulleted' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>}
|
||||
|
||||
{hasPermission(currentUser, 'READ_COMMENTS') && <Link href={'/comments/comments-list'}>
|
||||
<div
|
||||
className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}
|
||||
>
|
||||
<div className="flex justify-between align-center">
|
||||
<div>
|
||||
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400">
|
||||
Comments
|
||||
</div>
|
||||
<div className="text-3xl leading-tight font-semibold">
|
||||
{comments}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<BaseIcon
|
||||
className={`${iconsColor}`}
|
||||
w="w-16"
|
||||
h="h-16"
|
||||
size={48}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
path={'mdiCommentText' in icon ? icon['mdiCommentText' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>}
|
||||
|
||||
{hasPermission(currentUser, 'READ_ATTACHMENTS') && <Link href={'/attachments/attachments-list'}>
|
||||
<div
|
||||
className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}
|
||||
>
|
||||
<div className="flex justify-between align-center">
|
||||
<div>
|
||||
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400">
|
||||
Attachments
|
||||
</div>
|
||||
<div className="text-3xl leading-tight font-semibold">
|
||||
{attachments}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<BaseIcon
|
||||
className={`${iconsColor}`}
|
||||
w="w-16"
|
||||
h="h-16"
|
||||
size={48}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
path={'mdiPaperclip' in icon ? icon['mdiPaperclip' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>}
|
||||
|
||||
|
||||
</div>
|
||||
</SectionMain>
|
||||
</>
|
||||
@ -161,4 +379,3 @@ Dashboard.getLayout = function getLayout(page: ReactElement) {
|
||||
}
|
||||
|
||||
export default Dashboard
|
||||
|
||||
|
||||
@ -1,64 +0,0 @@
|
||||
import { mdiChartTimelineVariant } from '@mdi/js'
|
||||
import Head from 'next/head'
|
||||
import React, { ReactElement } from 'react'
|
||||
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 BaseButton from '../../components/BaseButton'
|
||||
import { useAppSelector } from '../../stores/hooks'
|
||||
import { hasPermission } from '../../helpers/userPermissions'
|
||||
import KanbanBoard from '../../components/KanbanBoard/KanbanBoard'
|
||||
import Link from 'next/link'
|
||||
import { deleteItem, update } from '../../stores/leads/leadsSlice'
|
||||
|
||||
const LeadsKanbanPage = () => {
|
||||
const { currentUser } = useAppSelector((state) => state.auth)
|
||||
const hasCreatePermission = currentUser && hasPermission(currentUser, 'CREATE_LEADS')
|
||||
|
||||
const columns = [
|
||||
{ id: 'New', label: 'New' },
|
||||
{ id: 'Contacted', label: 'Contacted' },
|
||||
{ id: 'Qualified', label: 'Qualified' },
|
||||
{ id: 'Proposal', label: 'Proposal' },
|
||||
{ id: 'Converted', label: 'Converted' },
|
||||
{ id: 'Lost', label: 'Lost' },
|
||||
]
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>{getPageTitle('Leads Kanban')}</title>
|
||||
</Head>
|
||||
<SectionMain>
|
||||
<SectionTitleLineWithButton icon={mdiChartTimelineVariant} title="Leads Kanban" main>
|
||||
{''}
|
||||
</SectionTitleLineWithButton>
|
||||
|
||||
<CardBox className="mb-6" cardBoxClassName="flex flex-wrap">
|
||||
{hasCreatePermission && <BaseButton className={'mr-3'} href={'/leads/leads-new'} color="info" label="New Item" />}
|
||||
<div className="md:inline-flex items-center ms-auto">
|
||||
<Link href={'/leads/list'}>Switch to List</Link>
|
||||
</div>
|
||||
</CardBox>
|
||||
|
||||
<KanbanBoard
|
||||
columns={columns}
|
||||
entityName="leads"
|
||||
columnFieldName="stage"
|
||||
showFieldName="name"
|
||||
deleteThunk={deleteItem}
|
||||
updateThunk={update}
|
||||
filtersQuery={'&orderBy=createdAt&orderDirection=asc'}
|
||||
/>
|
||||
</SectionMain>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
LeadsKanbanPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return <LayoutAuthenticated permission={'READ_LEADS'}>{page}</LayoutAuthenticated>
|
||||
}
|
||||
|
||||
export default LeadsKanbanPage
|
||||
@ -117,7 +117,7 @@ const LeadsTablesPage = () => {
|
||||
</div>
|
||||
|
||||
<div className='md:inline-flex items-center ms-auto'>
|
||||
<Link href={'/leads/kanban'}>Switch to Kanban</Link>
|
||||
<Link href={'/leads/leads-table'}>Switch to Table</Link>
|
||||
</div>
|
||||
|
||||
</CardBox>
|
||||
@ -68,7 +68,7 @@ module.exports = {
|
||||
|
||||
|
||||
pastelEmeraldTheme: {
|
||||
text: '#030A0D',
|
||||
text: '#515564',
|
||||
iconsColor: '#030A0D',
|
||||
mainBG: '#DFECF2',
|
||||
buttonColor: '#030A0D',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user