817 lines
40 KiB
TypeScript
817 lines
40 KiB
TypeScript
import * as icon from '@mdi/js';
|
|
import Head from 'next/head'
|
|
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 { getPageTitle } from '../config'
|
|
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 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 [users, setUsers] = React.useState(loadingMessage);
|
|
const [roles, setRoles] = React.useState(loadingMessage);
|
|
const [permissions, setPermissions] = React.useState(loadingMessage);
|
|
const [refresh_tokens, setRefresh_tokens] = React.useState(loadingMessage);
|
|
const [categories, setCategories] = React.useState(loadingMessage);
|
|
const [locations, setLocations] = React.useState(loadingMessage);
|
|
const [businesses, setBusinesses] = React.useState(loadingMessage);
|
|
const [business_photos, setBusiness_photos] = React.useState(loadingMessage);
|
|
const [business_categories, setBusiness_categories] = React.useState(loadingMessage);
|
|
const [service_prices, setService_prices] = React.useState(loadingMessage);
|
|
const [business_badges, setBusiness_badges] = React.useState(loadingMessage);
|
|
const [verification_submissions, setVerification_submissions] = React.useState(loadingMessage);
|
|
const [verification_evidences, setVerification_evidences] = React.useState(loadingMessage);
|
|
const [leads, setLeads] = React.useState(loadingMessage);
|
|
const [lead_photos, setLead_photos] = React.useState(loadingMessage);
|
|
const [lead_matches, setLead_matches] = React.useState(loadingMessage);
|
|
const [messages, setMessages] = React.useState(loadingMessage);
|
|
const [lead_events, setLead_events] = React.useState(loadingMessage);
|
|
const [reviews, setReviews] = React.useState(loadingMessage);
|
|
const [disputes, setDisputes] = React.useState(loadingMessage);
|
|
const [audit_logs, setAudit_logs] = React.useState(loadingMessage);
|
|
const [badge_rules, setBadge_rules] = React.useState(loadingMessage);
|
|
const [trust_adjustments, setTrust_adjustments] = React.useState(loadingMessage);
|
|
|
|
|
|
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','refresh_tokens','categories','locations','businesses','business_photos','business_categories','service_prices','business_badges','verification_submissions','verification_evidences','leads','lead_photos','lead_matches','messages','lead_events','reviews','disputes','audit_logs','badge_rules','trust_adjustments',];
|
|
const fns = [setUsers,setRoles,setPermissions,setRefresh_tokens,setCategories,setLocations,setBusinesses,setBusiness_photos,setBusiness_categories,setService_prices,setBusiness_badges,setVerification_submissions,setVerification_evidences,setLeads,setLead_photos,setLead_matches,setMessages,setLead_events,setReviews,setDisputes,setAudit_logs,setBadge_rules,setTrust_adjustments,];
|
|
|
|
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);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
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('Overview')}
|
|
</title>
|
|
</Head>
|
|
<SectionMain>
|
|
<SectionTitleLineWithButton
|
|
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 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} animate-spin mr-5`}
|
|
w='w-16'
|
|
h='h-16'
|
|
size={48}
|
|
path={icon.mdiLoading}
|
|
/>{' '}
|
|
Loading widgets...
|
|
</div>
|
|
)}
|
|
|
|
{ rolesWidgets &&
|
|
rolesWidgets.map((widget) => (
|
|
<SmartWidget
|
|
key={widget.id}
|
|
userId={currentUser?.id}
|
|
widget={widget}
|
|
roleId={widgetsRole?.role?.value || ''}
|
|
admin={hasPermission(currentUser, 'CREATE_ROLES')}
|
|
/>
|
|
))}
|
|
</div>
|
|
|
|
{!!rolesWidgets.length && <hr className='my-6 ' />}
|
|
|
|
<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>
|
|
</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_REFRESH_TOKENS') && <Link href={'/refresh_tokens/refresh_tokens-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">
|
|
Refresh tokens
|
|
</div>
|
|
<div className="text-3xl leading-tight font-semibold">
|
|
{refresh_tokens}
|
|
</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={'mdiLock' in icon ? icon['mdiLock' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Link>}
|
|
|
|
{hasPermission(currentUser, 'READ_CATEGORIES') && <Link href={'/categories/categories-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">
|
|
Categories
|
|
</div>
|
|
<div className="text-3xl leading-tight font-semibold">
|
|
{categories}
|
|
</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={'mdiShape' in icon ? icon['mdiShape' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Link>}
|
|
|
|
{hasPermission(currentUser, 'READ_LOCATIONS') && <Link href={'/locations/locations-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">
|
|
Locations
|
|
</div>
|
|
<div className="text-3xl leading-tight font-semibold">
|
|
{locations}
|
|
</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={'mdiMapMarker' in icon ? icon['mdiMapMarker' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Link>}
|
|
|
|
{hasPermission(currentUser, 'READ_BUSINESSES') && <Link href={'/businesses/businesses-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">
|
|
Businesses
|
|
</div>
|
|
<div className="text-3xl leading-tight font-semibold">
|
|
{businesses}
|
|
</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={'mdiStore' in icon ? icon['mdiStore' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Link>}
|
|
|
|
{hasPermission(currentUser, 'READ_BUSINESS_PHOTOS') && <Link href={'/business_photos/business_photos-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">
|
|
Business photos
|
|
</div>
|
|
<div className="text-3xl leading-tight font-semibold">
|
|
{business_photos}
|
|
</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={'mdiImageMultiple' in icon ? icon['mdiImageMultiple' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Link>}
|
|
|
|
{hasPermission(currentUser, 'READ_BUSINESS_CATEGORIES') && <Link href={'/business_categories/business_categories-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">
|
|
Business categories
|
|
</div>
|
|
<div className="text-3xl leading-tight font-semibold">
|
|
{business_categories}
|
|
</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={'mdiTagMultiple' in icon ? icon['mdiTagMultiple' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Link>}
|
|
|
|
{hasPermission(currentUser, 'READ_SERVICE_PRICES') && <Link href={'/service_prices/service_prices-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">
|
|
Service prices
|
|
</div>
|
|
<div className="text-3xl leading-tight font-semibold">
|
|
{service_prices}
|
|
</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={'mdiCurrencyUsd' in icon ? icon['mdiCurrencyUsd' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Link>}
|
|
|
|
{hasPermission(currentUser, 'READ_BUSINESS_BADGES') && <Link href={'/business_badges/business_badges-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">
|
|
Business badges
|
|
</div>
|
|
<div className="text-3xl leading-tight font-semibold">
|
|
{business_badges}
|
|
</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={'mdiShieldCheck' in icon ? icon['mdiShieldCheck' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Link>}
|
|
|
|
{hasPermission(currentUser, 'READ_VERIFICATION_SUBMISSIONS') && <Link href={'/verification_submissions/verification_submissions-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">
|
|
Verification submissions
|
|
</div>
|
|
<div className="text-3xl leading-tight font-semibold">
|
|
{verification_submissions}
|
|
</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={'mdiFileCheck' in icon ? icon['mdiFileCheck' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Link>}
|
|
|
|
{hasPermission(currentUser, 'READ_VERIFICATION_EVIDENCES') && <Link href={'/verification_evidences/verification_evidences-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">
|
|
Verification evidences
|
|
</div>
|
|
<div className="text-3xl leading-tight font-semibold">
|
|
{verification_evidences}
|
|
</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={'mdiFileUpload' in icon ? icon['mdiFileUpload' as keyof typeof icon] : icon.mdiTable || 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={'mdiClipboardText' in icon ? icon['mdiClipboardText' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Link>}
|
|
|
|
{hasPermission(currentUser, 'READ_LEAD_PHOTOS') && <Link href={'/lead_photos/lead_photos-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">
|
|
Lead photos
|
|
</div>
|
|
<div className="text-3xl leading-tight font-semibold">
|
|
{lead_photos}
|
|
</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={'mdiCamera' in icon ? icon['mdiCamera' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Link>}
|
|
|
|
{hasPermission(currentUser, 'READ_LEAD_MATCHES') && <Link href={'/lead_matches/lead_matches-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">
|
|
Lead matches
|
|
</div>
|
|
<div className="text-3xl leading-tight font-semibold">
|
|
{lead_matches}
|
|
</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={'mdiLinkVariant' in icon ? icon['mdiLinkVariant' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Link>}
|
|
|
|
{hasPermission(currentUser, 'READ_MESSAGES') && <Link href={'/messages/messages-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">
|
|
Messages
|
|
</div>
|
|
<div className="text-3xl leading-tight font-semibold">
|
|
{messages}
|
|
</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={'mdiMessageText' in icon ? icon['mdiMessageText' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Link>}
|
|
|
|
{hasPermission(currentUser, 'READ_LEAD_EVENTS') && <Link href={'/lead_events/lead_events-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">
|
|
Lead events
|
|
</div>
|
|
<div className="text-3xl leading-tight font-semibold">
|
|
{lead_events}
|
|
</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={'mdiTimelineText' in icon ? icon['mdiTimelineText' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Link>}
|
|
|
|
{hasPermission(currentUser, 'READ_REVIEWS') && <Link href={'/reviews/reviews-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">
|
|
Reviews
|
|
</div>
|
|
<div className="text-3xl leading-tight font-semibold">
|
|
{reviews}
|
|
</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={'mdiStar' in icon ? icon['mdiStar' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Link>}
|
|
|
|
{hasPermission(currentUser, 'READ_DISPUTES') && <Link href={'/disputes/disputes-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">
|
|
Disputes
|
|
</div>
|
|
<div className="text-3xl leading-tight font-semibold">
|
|
{disputes}
|
|
</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={'mdiAlertOctagon' in icon ? icon['mdiAlertOctagon' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Link>}
|
|
|
|
{hasPermission(currentUser, 'READ_AUDIT_LOGS') && <Link href={'/audit_logs/audit_logs-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">
|
|
Audit logs
|
|
</div>
|
|
<div className="text-3xl leading-tight font-semibold">
|
|
{audit_logs}
|
|
</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={'mdiClipboardList' in icon ? icon['mdiClipboardList' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Link>}
|
|
|
|
{hasPermission(currentUser, 'READ_BADGE_RULES') && <Link href={'/badge_rules/badge_rules-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">
|
|
Badge rules
|
|
</div>
|
|
<div className="text-3xl leading-tight font-semibold">
|
|
{badge_rules}
|
|
</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={'mdiShieldCrown' in icon ? icon['mdiShieldCrown' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Link>}
|
|
|
|
{hasPermission(currentUser, 'READ_TRUST_ADJUSTMENTS') && <Link href={'/trust_adjustments/trust_adjustments-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">
|
|
Trust adjustments
|
|
</div>
|
|
<div className="text-3xl leading-tight font-semibold">
|
|
{trust_adjustments}
|
|
</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={'mdiTuneVariant' in icon ? icon['mdiTuneVariant' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Link>}
|
|
|
|
|
|
</div>
|
|
</SectionMain>
|
|
</>
|
|
)
|
|
}
|
|
|
|
Dashboard.getLayout = function getLayout(page: ReactElement) {
|
|
return <LayoutAuthenticated>{page}</LayoutAuthenticated>
|
|
}
|
|
|
|
export default Dashboard
|