37317-vm/frontend/src/pages/dashboard.tsx
2026-01-08 12:06:16 +00:00

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