Case completion and tasks completion gadgets added.
This commit is contained in:
@@ -4,6 +4,8 @@ import { useMemo } from 'react';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useAuth } from '@/lib/hooks/useAuth';
|
||||
import {
|
||||
canEditCases,
|
||||
canEditTreatment,
|
||||
canViewAppointmentsTab,
|
||||
canViewCases,
|
||||
canViewLabCasesOrTasks,
|
||||
@@ -22,7 +24,9 @@ import {
|
||||
import { TodayDashboardGrid } from '@/components/today/TodayDashboardGrid';
|
||||
import { TodayDonutChart, TodayDonutChartLegend } from '@/components/today/TodayDonutChart';
|
||||
import { TodayHorizontalBarChart } from '@/components/today/TodayHorizontalBarChart';
|
||||
import { TodayCaseCompletionKpiCard } from '@/components/today/TodayCaseCompletionKpiCard';
|
||||
import { TodayPartnerCasesStackedBarChart } from '@/components/today/TodayPartnerCasesStackedBarChart';
|
||||
import { Package, Stethoscope, type LucideIcon } from 'lucide-react';
|
||||
import { TodayCompletionGaugeKpiCard } from '@/components/today/TodayCompletionGaugeKpiCard';
|
||||
import {
|
||||
mapLabTaskActivityChartData,
|
||||
TodayLabTaskActivityChart,
|
||||
@@ -42,6 +46,7 @@ import { getEligibleTodayKpis, getVisibleTodayKpis } from '@/components/today/wi
|
||||
import { prosthesisTypeColor } from '@/components/ui/treatment/prosthesisTypeDisplay';
|
||||
import { treatmentTypeColor } from '@/components/ui/treatment/treatmentTypeDisplay';
|
||||
import type {
|
||||
TodayCompletionGauge,
|
||||
TodaySubscriptionSnapshot,
|
||||
TodaySummaryActions,
|
||||
TodaySummaryCharts,
|
||||
@@ -78,6 +83,12 @@ export function TodayDashboard({
|
||||
currentOrganization &&
|
||||
canViewMyAppointmentsWeekChart(currentOrganization);
|
||||
|
||||
const showCasePartnersChart = Boolean(
|
||||
currentOrganization &&
|
||||
((orgType === 'CLINIC' && canEditTreatment(currentOrganization)) ||
|
||||
(orgType === 'LAB' && canEditCases(currentOrganization))),
|
||||
);
|
||||
|
||||
const showCharts = useMemo(() => {
|
||||
if (!orgType || !currentOrganization) return false;
|
||||
if (orgType === 'CLINIC') {
|
||||
@@ -104,12 +115,18 @@ export function TodayDashboard({
|
||||
Boolean(currentOrganization && canViewCases(currentOrganization)) &&
|
||||
(isInitialLoad || charts.caseCompletion !== undefined);
|
||||
|
||||
const showTreatmentPlanCompletionCard =
|
||||
orgType === 'CLINIC' &&
|
||||
Boolean(currentOrganization && canEditTreatment(currentOrganization)) &&
|
||||
(isInitialLoad || charts.treatmentPlanCompletion !== undefined);
|
||||
|
||||
const cells = useMemo(() => {
|
||||
if (isInitialLoad) {
|
||||
return buildSkeletonCells({
|
||||
kpiDefinitions,
|
||||
showSubscriptionCard,
|
||||
showCaseCompletionCard,
|
||||
showTreatmentPlanCompletionCard,
|
||||
showUpcoming: Boolean(showUpcoming),
|
||||
showCharts,
|
||||
orgType,
|
||||
@@ -118,6 +135,7 @@ export function TodayDashboard({
|
||||
currentOrganization &&
|
||||
canViewMyAppointmentsWeekChart(currentOrganization),
|
||||
),
|
||||
showCasePartnersChart,
|
||||
charts,
|
||||
});
|
||||
}
|
||||
@@ -133,6 +151,9 @@ export function TodayDashboard({
|
||||
showSubscriptionCard: showSubscriptionCard && Boolean(subscription),
|
||||
showCaseCompletionCard:
|
||||
showCaseCompletionCard && charts.caseCompletion !== undefined,
|
||||
showTreatmentPlanCompletionCard:
|
||||
showTreatmentPlanCompletionCard &&
|
||||
charts.treatmentPlanCompletion !== undefined,
|
||||
showUpcoming: Boolean(showUpcoming),
|
||||
showCharts,
|
||||
orgType,
|
||||
@@ -144,6 +165,7 @@ export function TodayDashboard({
|
||||
kpiDefinitions,
|
||||
showSubscriptionCard,
|
||||
showCaseCompletionCard,
|
||||
showTreatmentPlanCompletionCard,
|
||||
showUpcoming,
|
||||
showCharts,
|
||||
orgType,
|
||||
@@ -176,11 +198,13 @@ function buildSkeletonCells(options: {
|
||||
kpiDefinitions: ReturnType<typeof getEligibleTodayKpis>;
|
||||
showSubscriptionCard: boolean;
|
||||
showCaseCompletionCard: boolean;
|
||||
showTreatmentPlanCompletionCard: boolean;
|
||||
showUpcoming: boolean;
|
||||
showCharts: boolean;
|
||||
orgType?: 'CLINIC' | 'LAB';
|
||||
isOwner: boolean;
|
||||
showMyAppointmentsWeekChart: boolean;
|
||||
showCasePartnersChart: boolean;
|
||||
charts: TodaySummaryCharts;
|
||||
}): TodayDashboardCell[] {
|
||||
const cells: TodayDashboardCell[] = [];
|
||||
@@ -191,6 +215,7 @@ function buildSkeletonCells(options: {
|
||||
options.orgType,
|
||||
options.isOwner,
|
||||
options.showMyAppointmentsWeekChart,
|
||||
options.showCasePartnersChart,
|
||||
);
|
||||
for (let index = 0; index < Math.min(chartCount, 4); index += 1) {
|
||||
cells.push({
|
||||
@@ -237,6 +262,14 @@ function buildSkeletonCells(options: {
|
||||
});
|
||||
}
|
||||
|
||||
if (options.showTreatmentPlanCompletionCard) {
|
||||
cells.push({
|
||||
id: 'treatment-plan-completion-skeleton',
|
||||
layout: TODAY_DASHBOARD_LAYOUT.subscription,
|
||||
content: <KpiCardSkeleton tall />,
|
||||
});
|
||||
}
|
||||
|
||||
for (const definition of options.kpiDefinitions) {
|
||||
cells.push({
|
||||
id: `kpi-skeleton-${definition.key}`,
|
||||
@@ -258,6 +291,7 @@ function buildDashboardCells(options: {
|
||||
kpiDefinitions: ReturnType<typeof getVisibleTodayKpis>;
|
||||
showSubscriptionCard: boolean;
|
||||
showCaseCompletionCard: boolean;
|
||||
showTreatmentPlanCompletionCard: boolean;
|
||||
showUpcoming: boolean;
|
||||
showCharts: boolean;
|
||||
orgType?: 'CLINIC' | 'LAB';
|
||||
@@ -277,6 +311,12 @@ function buildDashboardCells(options: {
|
||||
options.currentOrganization &&
|
||||
canViewMyAppointmentsWeekChart(options.currentOrganization),
|
||||
),
|
||||
showCasePartnersChart:
|
||||
Boolean(options.currentOrganization) &&
|
||||
((options.orgType === 'CLINIC' &&
|
||||
canEditTreatment(options.currentOrganization)) ||
|
||||
(options.orgType === 'LAB' &&
|
||||
canEditCases(options.currentOrganization))),
|
||||
dayLabelFormatter: options.dayLabelFormatter,
|
||||
}),
|
||||
);
|
||||
@@ -301,17 +341,35 @@ function buildDashboardCells(options: {
|
||||
}
|
||||
|
||||
if (options.showCaseCompletionCard && options.charts.caseCompletion !== undefined) {
|
||||
const caseCompletion = options.charts.caseCompletion;
|
||||
cells.push({
|
||||
pushCompletionGaugeCell(cells, {
|
||||
id: 'case-completion',
|
||||
layout: TODAY_DASHBOARD_LAYOUT.subscription,
|
||||
content: (
|
||||
<TodayCaseCompletionKpiCard
|
||||
completed={caseCompletion.completed}
|
||||
total={caseCompletion.total}
|
||||
percent={caseCompletion.percent}
|
||||
/>
|
||||
),
|
||||
gauge: options.charts.caseCompletion,
|
||||
title: options.t('chartCaseCompletionTitle'),
|
||||
subtitle: options.t('chartCaseCompletionSubtitle'),
|
||||
percentLabel: options.t('chartCaseCompletionPercent', {
|
||||
percent: options.charts.caseCompletion.percent,
|
||||
}),
|
||||
ratioLabel: options.t('chartCaseCompletionTasks'),
|
||||
href: '/cases',
|
||||
icon: Package,
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
options.showTreatmentPlanCompletionCard &&
|
||||
options.charts.treatmentPlanCompletion !== undefined
|
||||
) {
|
||||
pushCompletionGaugeCell(cells, {
|
||||
id: 'treatment-plan-completion',
|
||||
gauge: options.charts.treatmentPlanCompletion,
|
||||
title: options.t('chartTreatmentPlanCompletionTitle'),
|
||||
subtitle: options.t('chartTreatmentPlanCompletionSubtitle'),
|
||||
percentLabel: options.t('chartCaseCompletionPercent', {
|
||||
percent: options.charts.treatmentPlanCompletion.percent,
|
||||
}),
|
||||
ratioLabel: options.t('chartTreatmentPlanCompletionRatio'),
|
||||
href: '/appointments',
|
||||
icon: Stethoscope,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -345,6 +403,7 @@ function buildChartCells(options: {
|
||||
orgType?: 'CLINIC' | 'LAB';
|
||||
isOwner: boolean;
|
||||
showMyAppointmentsWeekChart: boolean;
|
||||
showCasePartnersChart: boolean;
|
||||
dayLabelFormatter: ReturnType<typeof useTodayDayLabelFormatter>;
|
||||
}): TodayDashboardCell[] {
|
||||
const { t, charts, orgType, isOwner, showMyAppointmentsWeekChart } = options;
|
||||
@@ -528,6 +587,38 @@ function buildChartCells(options: {
|
||||
});
|
||||
}
|
||||
|
||||
const casePartnersData = charts.casePartnersMonth ?? [];
|
||||
if (options.showCasePartnersChart && charts.casePartnersMonth !== undefined) {
|
||||
cells.push({
|
||||
id: 'chart-case-partners-month',
|
||||
layout: barChart,
|
||||
content: (
|
||||
<ChartCard
|
||||
title={
|
||||
orgType === 'CLINIC'
|
||||
? t('chartCasePartnersClinicTitle')
|
||||
: t('chartCasePartnersLabTitle')
|
||||
}
|
||||
subtitle={t('chartCasePartnersSubtitle')}
|
||||
isEmpty={casePartnersData.every(
|
||||
(row) => row.completed === 0 && row.pending === 0,
|
||||
)}
|
||||
emptyMessage={t('chartEmpty')}
|
||||
>
|
||||
<TodayPartnerCasesStackedBarChart
|
||||
data={casePartnersData}
|
||||
completedLabel={t('chartLabTaskCompletedLegend')}
|
||||
pendingLabel={
|
||||
orgType === 'CLINIC'
|
||||
? t('chartCasePartnersSentLegend')
|
||||
: t('chartCasePartnersOpenLegend')
|
||||
}
|
||||
/>
|
||||
</ChartCard>
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
return cells;
|
||||
}
|
||||
|
||||
@@ -536,6 +627,7 @@ function countVisibleCharts(
|
||||
orgType?: 'CLINIC' | 'LAB',
|
||||
isOwner = false,
|
||||
showMyAppointmentsWeekChart = false,
|
||||
showCasePartnersChart = false,
|
||||
): number {
|
||||
let count = 0;
|
||||
if (orgType === 'CLINIC') {
|
||||
@@ -544,10 +636,12 @@ function countVisibleCharts(
|
||||
showMyAppointmentsWeekChart && charts.appointmentsWeekMine !== undefined ? 1 : 0;
|
||||
count += charts.appointmentsByProvider !== undefined ? 1 : 0;
|
||||
count += charts.treatmentMixWeek !== undefined ? 1 : 0;
|
||||
count += showCasePartnersChart && charts.casePartnersMonth !== undefined ? 1 : 0;
|
||||
}
|
||||
if (orgType === 'LAB') {
|
||||
count += charts.labTaskActivityWeek !== undefined ? 1 : 0;
|
||||
count += charts.tasksByProsthesis !== undefined ? 1 : 0;
|
||||
count += showCasePartnersChart && charts.casePartnersMonth !== undefined ? 1 : 0;
|
||||
}
|
||||
if (
|
||||
isOwner &&
|
||||
@@ -558,3 +652,35 @@ function countVisibleCharts(
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
function pushCompletionGaugeCell(
|
||||
cells: TodayDashboardCell[],
|
||||
options: {
|
||||
id: string;
|
||||
gauge: TodayCompletionGauge;
|
||||
title: string;
|
||||
subtitle: string;
|
||||
percentLabel: string;
|
||||
ratioLabel: string;
|
||||
href: string;
|
||||
icon: LucideIcon;
|
||||
},
|
||||
) {
|
||||
cells.push({
|
||||
id: options.id,
|
||||
layout: TODAY_DASHBOARD_LAYOUT.subscription,
|
||||
content: (
|
||||
<TodayCompletionGaugeKpiCard
|
||||
completed={options.gauge.completed}
|
||||
total={options.gauge.total}
|
||||
percent={options.gauge.percent}
|
||||
title={options.title}
|
||||
subtitle={options.subtitle}
|
||||
percentLabel={options.percentLabel}
|
||||
ratioLabel={options.ratioLabel}
|
||||
href={options.href}
|
||||
icon={options.icon}
|
||||
/>
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user