165 lines
5.5 KiB
TypeScript
165 lines
5.5 KiB
TypeScript
import * as icon from '@mdi/js'
|
|
import Head from 'next/head'
|
|
import React, { ReactElement } from 'react'
|
|
import axios from 'axios'
|
|
import LayoutAuthenticated from '../layouts/Authenticated'
|
|
import SectionMain from '../components/SectionMain'
|
|
import SectionTitleLineWithButton from '../components/SectionTitleLineWithButton'
|
|
import BaseIcon from '../components/BaseIcon'
|
|
import { getPageTitle } from '../config'
|
|
import Link from 'next/link'
|
|
import { useAppSelector } from '../stores/hooks'
|
|
import { hasPermission } from '../helpers/userPermissions'
|
|
|
|
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 loadingMessage = 'Loading...'
|
|
|
|
const [leads, setLeads] = React.useState(loadingMessage)
|
|
const [projects, setProjects] = React.useState(loadingMessage)
|
|
const [tasks, setTasks] = React.useState(loadingMessage)
|
|
|
|
async function loadData() {
|
|
const entities = ['leads', 'projects', 'tasks']
|
|
const fns = [setLeads, setProjects, setTasks]
|
|
|
|
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])
|
|
|
|
return (
|
|
<>
|
|
<Head>
|
|
<title>{getPageTitle('Dashboard')}</title>
|
|
</Head>
|
|
<SectionMain>
|
|
<SectionTitleLineWithButton
|
|
icon={icon.mdiChartTimelineVariant}
|
|
title="TeamFlow PM Dashboard"
|
|
main
|
|
>
|
|
{''}
|
|
</SectionTitleLineWithButton>
|
|
|
|
<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>
|
|
<BaseIcon
|
|
className={`${iconsColor}`}
|
|
w="w-16"
|
|
h="h-16"
|
|
size={48}
|
|
path={icon.mdiAccountMultiple}
|
|
/>
|
|
</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">
|
|
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}
|
|
/>
|
|
</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">
|
|
Open 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}
|
|
path={icon.mdiFormatListBulleted}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Link>
|
|
)}
|
|
</div>
|
|
</SectionMain>
|
|
</>
|
|
)
|
|
}
|
|
|
|
Dashboard.getLayout = function getLayout(page: ReactElement) {
|
|
return <LayoutAuthenticated>{page}</LayoutAuthenticated>
|
|
}
|
|
|
|
export default Dashboard
|
|
|