diff --git a/app/home/[account]/_components/team-account-benefit-statistics.tsx b/app/home/[account]/_components/team-account-benefit-statistics.tsx
index 95f35a6..36a2426 100644
--- a/app/home/[account]/_components/team-account-benefit-statistics.tsx
+++ b/app/home/[account]/_components/team-account-benefit-statistics.tsx
@@ -3,10 +3,12 @@ import React, { use } from 'react';
import { redirect } from 'next/navigation';
import { formatCurrency } from '@/packages/shared/src/utils';
+import { Database } from '@/packages/supabase/src/database.types';
import { PiggyBankIcon, Settings } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { Card, CardTitle } from '@kit/ui/card';
+import { cn } from '@kit/ui/lib/utils';
import { Button } from '@kit/ui/shadcn/button';
import { Trans } from '@kit/ui/trans';
@@ -14,15 +16,27 @@ import pathsConfig from '~/config/paths.config';
import { createPath } from '~/config/team-account-navigation.config';
interface TeamAccountBenefitStatisticsProps {
+ employeeCount: number;
accountSlug: string;
+ companyParams: Database['medreport']['Tables']['company_params']['Row'];
}
const StatisticsCard = ({ children }: { children: React.ReactNode }) => {
return {children};
};
-const StatisticsCardTitle = ({ children }: { children: React.ReactNode }) => {
- return {children};
+const StatisticsCardTitle = ({
+ children,
+ className,
+}: {
+ children: React.ReactNode;
+ className?: string;
+}) => {
+ return (
+
+ {children}
+
+ );
};
const StatisticsDescription = ({ children }: { children: React.ReactNode }) => {
@@ -34,7 +48,9 @@ const StatisticsValue = ({ children }: { children: React.ReactNode }) => {
};
const TeamAccountBenefitStatistics = ({
+ employeeCount,
accountSlug,
+ companyParams,
}: TeamAccountBenefitStatisticsProps) => {
const {
i18n: { language },
@@ -76,7 +92,8 @@ const TeamAccountBenefitStatistics = ({
i18nKey="teams:benefitStatistics.budget.volume"
values={{
volume: formatCurrency({
- value: 15000,
+ value:
+ (Number(companyParams.benefit_amount) || 0) * employeeCount,
locale: language,
currencyCode: 'EUR',
}),
@@ -87,11 +104,17 @@ const TeamAccountBenefitStatistics = ({
+
+
+
+
+ 1800 €
+
- 18 %
+ 200 €
- 22 %
+ 200 €
- 20 %
+ 200 €
- E-konsultatsioon
- 17 %
+
+
+
+ 200 €
-
+
+
-
-
- 23 %
-
-
-
-
-
- 1800 €
-
-
-
-
-
-
+
200 €
+
+
+
+
);
diff --git a/app/home/[account]/_components/team-account-health-details.tsx b/app/home/[account]/_components/team-account-health-details.tsx
index 904a2bc..666a029 100644
--- a/app/home/[account]/_components/team-account-health-details.tsx
+++ b/app/home/[account]/_components/team-account-health-details.tsx
@@ -1,33 +1,36 @@
import React from 'react';
+import { Database } from '@/packages/supabase/src/database.types';
+
import { Card } from '@kit/ui/card';
import { Trans } from '@kit/ui/trans';
import { cn } from '@kit/ui/utils';
-import {
- NormStatus,
- getAccountHealthDetailsFields,
-} from '../_lib/server/load-team-account-health-details';
+import { getAccountHealthDetailsFields } from '../_lib/server/load-team-account-health-details';
import { TeamAccountStatisticsProps } from './team-account-statistics';
const TeamAccountHealthDetails = ({
memberParams,
+ bmiThresholds,
+ members,
}: {
memberParams: TeamAccountStatisticsProps['memberParams'];
+ bmiThresholds: Omit<
+ Database['medreport']['Tables']['bmi_thresholds']['Row'],
+ 'id'
+ >[];
+ members: Database['medreport']['Functions']['get_account_members']['Returns'];
}) => {
- const accountHealthDetailsFields =
- getAccountHealthDetailsFields(memberParams);
+ const accountHealthDetailsFields = getAccountHealthDetailsFields(
+ memberParams,
+ bmiThresholds,
+ members,
+ );
return (
- {accountHealthDetailsFields.map(({ title, Icon, value, normStatus }) => (
+ {accountHealthDetailsFields.map(({ title, Icon, value, iconBg }) => (
-
+
diff --git a/app/home/[account]/_components/team-account-statistics.tsx b/app/home/[account]/_components/team-account-statistics.tsx
index 98b0b83..d4cf88c 100644
--- a/app/home/[account]/_components/team-account-statistics.tsx
+++ b/app/home/[account]/_components/team-account-statistics.tsx
@@ -1,12 +1,24 @@
'use client';
+import { useState } from 'react';
+
import { redirect } from 'next/navigation';
import { Database } from '@/packages/supabase/src/database.types';
-import { ChevronRight, Euro, User } from 'lucide-react';
+import { format } from 'date-fns';
+import { enGB, et } from 'date-fns/locale';
+import { CalendarIcon, ChevronRight, Euro, User } from 'lucide-react';
+import { useTranslation } from 'react-i18next';
import { Card } from '@kit/ui/card';
import { Trans } from '@kit/ui/makerkit/trans';
+import { Button } from '@kit/ui/shadcn/button';
+import { Calendar, DateRange } from '@kit/ui/shadcn/calendar';
+import {
+ Popover,
+ PopoverContent,
+ PopoverTrigger,
+} from '@kit/ui/shadcn/popover';
import pathsConfig from '~/config/paths.config';
import { createPath } from '~/config/team-account-navigation.config';
@@ -20,82 +32,145 @@ export interface TeamAccountStatisticsProps {
Database['medreport']['Tables']['account_params']['Row'],
'weight' | 'height'
>[];
+ bmiThresholds: Omit<
+ Database['medreport']['Tables']['bmi_thresholds']['Row'],
+ 'id'
+ >[];
+ members: Database['medreport']['Functions']['get_account_members']['Returns'];
+ companyParams: Database['medreport']['Tables']['company_params']['Row'];
}
export default function TeamAccountStatistics({
teamAccount,
memberParams,
+ bmiThresholds,
+ members,
+ companyParams,
}: TeamAccountStatisticsProps) {
+ const [date, setDate] = useState({
+ from: new Date(),
+ to: new Date(),
+ });
+ const {
+ i18n: { language },
+ } = useTranslation();
+ const dateFormatOptions = {
+ locale: language === 'et' ? et : enGB,
+ };
+
return (
-
-
+ <>
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
- redirect(
- createPath(
- pathsConfig.app.accountMembers,
- teamAccount.slug || '',
- ),
- )
- }
- >
-
+
+
+
+
+
+
+
+
+
+
+
+
+ redirect(
+ createPath(
+ pathsConfig.app.accountMembers,
+ teamAccount.slug || '',
+ ),
+ )
+ }
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ redirect(
+ createPath(
+ pathsConfig.app.accountBilling,
+ teamAccount.slug || '',
+ ),
+ )
+ }
+ >
-
-
-
-
- redirect(
- createPath(
- pathsConfig.app.accountBilling,
- teamAccount.slug || '',
- ),
- )
- }
- >
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
+ >
);
}
diff --git a/app/home/[account]/_lib/server/load-team-account-health-details.ts b/app/home/[account]/_lib/server/load-team-account-health-details.ts
index e723846..0c4ff72 100644
--- a/app/home/[account]/_lib/server/load-team-account-health-details.ts
+++ b/app/home/[account]/_lib/server/load-team-account-health-details.ts
@@ -1,8 +1,14 @@
import React from 'react';
+import { Database } from '@/packages/supabase/src/database.types';
+import Isikukood from 'isikukood';
import { Clock, TrendingUp, User } from 'lucide-react';
-import { bmiFromMetric } from '~/lib/utils';
+import {
+ bmiFromMetric,
+ getBmiBackgroundColor,
+ getBmiStatus,
+} from '~/lib/utils';
import { TeamAccountStatisticsProps } from '../../_components/team-account-statistics';
@@ -14,66 +20,89 @@ interface AccountHealthDetailsField {
color?: string;
className?: string;
}>;
- normStatus: NormStatus;
-}
-
-export enum NormStatus {
- CRITICAL = 'CRITICAL',
- WARNING = 'WARNING',
- NORMAL = 'NORMAL',
+ iconBg: string;
}
export const getAccountHealthDetailsFields = (
memberParams: TeamAccountStatisticsProps['memberParams'],
+ bmiThresholds: Omit<
+ Database['medreport']['Tables']['bmi_thresholds']['Row'],
+ 'id'
+ >[],
+ members: Database['medreport']['Functions']['get_account_members']['Returns'],
): AccountHealthDetailsField[] => {
- const averageBMI = (
- memberParams.reduce((sum, { height, weight }) => {
- return bmiFromMetric(weight ?? 0, height ?? 0) + sum;
- }, 0) / memberParams.length
- ).toFixed(0);
+ const avarageWeight =
+ memberParams.reduce((sum, r) => sum + r.weight!, 0) / memberParams.length;
+ const avarageHeight =
+ memberParams.reduce((sum, r) => sum + r.height!, 0) / memberParams.length;
+ const avarageAge =
+ members.reduce((sum, r) => {
+ const person = new Isikukood(r.personal_code);
+ return sum + person.getAge();
+ }, 0) / members.length;
+ const numberOfMaleMembers = members.filter((r) => {
+ const person = new Isikukood(r.personal_code);
+ return person.getGender() === 'male';
+ }).length;
+ const numberOfFemaleMembers = members.filter((r) => {
+ const person = new Isikukood(r.personal_code);
+ return person.getGender() === 'female';
+ }).length;
+ const averageBMI = bmiFromMetric(avarageWeight, avarageHeight);
+ const bmiStatus = getBmiStatus(bmiThresholds, {
+ age: avarageAge,
+ height: avarageHeight,
+ weight: avarageWeight,
+ });
+ const malePercentage = members.length
+ ? (numberOfMaleMembers / members.length) * 100
+ : 0;
+ const femalePercentage = members.length
+ ? (numberOfFemaleMembers / members.length) * 100
+ : 0;
return [
{
title: 'teams:healthDetails.women',
- value: `50% (${memberParams.length})`,
+ value: `${femalePercentage}% (${numberOfFemaleMembers})`,
Icon: User,
- normStatus: NormStatus.NORMAL,
+ iconBg: 'bg-success',
},
{
title: 'teams:healthDetails.men',
- value: `50% (${memberParams.length})`,
+ value: `${malePercentage}% (${numberOfMaleMembers})`,
Icon: User,
- normStatus: NormStatus.NORMAL,
+ iconBg: 'bg-success',
},
{
title: 'teams:healthDetails.avgAge',
- value: '56',
+ value: avarageAge.toFixed(0),
Icon: Clock,
- normStatus: NormStatus.NORMAL,
+ iconBg: 'bg-success',
},
{
title: 'teams:healthDetails.bmi',
value: averageBMI,
Icon: TrendingUp,
- normStatus: NormStatus.WARNING,
+ iconBg: getBmiBackgroundColor(bmiStatus),
},
{
title: 'teams:healthDetails.cholesterol',
- value: '6.1',
+ value: '-',
Icon: TrendingUp,
- normStatus: NormStatus.WARNING,
+ iconBg: 'bg-warning',
},
{
title: 'teams:healthDetails.vitaminD',
- value: '76',
+ value: '-',
Icon: TrendingUp,
- normStatus: NormStatus.NORMAL,
+ iconBg: 'bg-warning',
},
{
title: 'teams:healthDetails.smokers',
- value: '22%',
+ value: '-',
Icon: TrendingUp,
- normStatus: NormStatus.CRITICAL,
+ iconBg: 'bg-warning',
},
];
};
diff --git a/app/home/[account]/page.tsx b/app/home/[account]/page.tsx
index 46a0c2b..262a35c 100644
--- a/app/home/[account]/page.tsx
+++ b/app/home/[account]/page.tsx
@@ -2,6 +2,7 @@
import { use } from 'react';
+import { createAccountsApi } from '@/packages/features/accounts/src/server/api';
import { CompanyGuard } from '@/packages/features/team-accounts/src/components';
import { createTeamAccountsApi } from '@/packages/features/team-accounts/src/server/api';
import { getSupabaseServerClient } from '@/packages/supabase/src/clients/server-client';
@@ -11,6 +12,10 @@ import { Trans } from '@kit/ui/trans';
import { createI18nServerInstance } from '~/lib/i18n/i18n.server';
import { withI18n } from '~/lib/i18n/with-i18n';
+import {
+ PAGE_VIEW_ACTION,
+ createPageViewLog,
+} from '~/lib/services/audit/pageView.service';
import { Dashboard } from './_components/dashboard';
import { TeamAccountLayoutPageHeader } from './_components/team-account-layout-page-header';
@@ -31,25 +36,32 @@ export const generateMetadata = async () => {
function TeamAccountHomePage({ params }: TeamAccountHomePageProps) {
const account = use(params).account;
const client = getSupabaseServerClient();
- const api = createTeamAccountsApi(client);
- const teamAccount = use(api.getTeamAccount(account));
- const { memberParams } = use(api.getMembers(account));
+ const teamAccountsApi = createTeamAccountsApi(client);
+ const accountsApi = createAccountsApi(client);
+ const teamAccount = use(teamAccountsApi.getTeamAccount(account));
+ const { memberParams, members } = use(teamAccountsApi.getMembers(account));
+ const bmiThresholds = use(accountsApi.fetchBmiThresholds());
+ const companyParams = use(
+ teamAccountsApi.getTeamAccountParams(teamAccount.id),
+ );
+
+ use(
+ createPageViewLog({
+ accountId: teamAccount.id,
+ action: PAGE_VIEW_ACTION.VIEW_TEAM_ACCOUNT_DASHBOARD,
+ }),
+ );
return (
- <>
-
- }
+
+
-
-
-
-
- >
+
);
}
diff --git a/lib/services/audit/pageView.service.ts b/lib/services/audit/pageView.service.ts
index 28fc458..92ce10e 100644
--- a/lib/services/audit/pageView.service.ts
+++ b/lib/services/audit/pageView.service.ts
@@ -4,6 +4,7 @@ export enum PAGE_VIEW_ACTION {
VIEW_ANALYSIS_RESULTS = 'VIEW_ANALYSIS_RESULTS',
REGISTRATION_SUCCESS = 'REGISTRATION_SUCCESS',
VIEW_ORDER_ANALYSIS = 'VIEW_ORDER_ANALYSIS',
+ VIEW_TEAM_ACCOUNT_DASHBOARD = 'VIEW_TEAM_ACCOUNT_DASHBOARD',
}
export const createPageViewLog = async ({
diff --git a/lib/utils.ts b/lib/utils.ts
index 592732f..e056699 100644
--- a/lib/utils.ts
+++ b/lib/utils.ts
@@ -70,15 +70,13 @@ export function getBmiStatus(
export function getBmiBackgroundColor(bmiStatus: BmiCategory | null): string {
switch (bmiStatus) {
case BmiCategory.UNDER_WEIGHT:
+ case BmiCategory.OVER_WEIGHT:
return 'bg-warning';
case BmiCategory.NORMAL:
return 'bg-success';
- case BmiCategory.OVER_WEIGHT:
- return 'bg-warning';
case BmiCategory.VERY_OVERWEIGHT:
- return 'bg-destructive';
case BmiCategory.OBESE:
- return 'bg-error';
+ return 'bg-destructive';
default:
return 'bg-success';
}
diff --git a/packages/features/team-accounts/src/server/api.ts b/packages/features/team-accounts/src/server/api.ts
index 44b0379..de706f1 100644
--- a/packages/features/team-accounts/src/server/api.ts
+++ b/packages/features/team-accounts/src/server/api.ts
@@ -291,6 +291,7 @@ export class TeamAccountsApi {
.single();
if (error) {
+ console.warn('Error fetching company params', error);
throw error;
}
diff --git a/packages/supabase/src/database.types.ts b/packages/supabase/src/database.types.ts
index 9093fe4..14db6a3 100644
--- a/packages/supabase/src/database.types.ts
+++ b/packages/supabase/src/database.types.ts
@@ -1726,6 +1726,7 @@ export type Database = {
primary_owner_user_id: string
name: string
email: string
+ personal_code: string
picture_url: string
created_at: string
updated_at: string
diff --git a/public/locales/et/common.json b/public/locales/et/common.json
index fd3a5e9..2faf3e8 100644
--- a/public/locales/et/common.json
+++ b/public/locales/et/common.json
@@ -122,7 +122,8 @@
"weight": "Kaal",
"height": "Pikkus",
"occurance": "Toetuse sagedus",
- "amount": "Summa"
+ "amount": "Summa",
+ "date": "Vali kuupäev"
},
"wallet": {
"balance": "Sinu MedReporti konto seis",
diff --git a/public/locales/et/teams.json b/public/locales/et/teams.json
index 515d538..f262a7a 100644
--- a/public/locales/et/teams.json
+++ b/public/locales/et/teams.json
@@ -1,7 +1,7 @@
{
"home": {
"pageTitle": "Ülevaade",
- "headerTitle": "{{companyName}} tervise ülevaade",
+ "headerTitle": "{{companyName}} Tervisekassa kokkuvõte",
"healthDetails": "Ettevõtte terviseandmed",
"membersSettingsButtonTitle": "Halda töötajaid",
"membersSettingsButtonDescription": "Lisa, muuda või eemalda töötajaid.",
@@ -31,13 +31,14 @@
"volume": "Eelarve maht {{volume}}"
},
"data": {
- "reservations": "{{value}} broneeringut",
+ "reservations": "{{value}} teenust",
"analysis": "Analüüsid",
"doctorsAndSpecialists": "Eriarstid ja spetsialistid",
"researches": "Uuringud",
"healthResearchPlans": "Terviseuuringute paketid",
"serviceUsage": "{{value}} teenuse kasutust",
- "serviceSum": "Teenuste summa"
+ "serviceSum": "Teenuste summa",
+ "eclinic": "Digikliinik"
}
},
"healthDetails": {
diff --git a/supabase/migrations/20250825110100_improve_members_queries.sql b/supabase/migrations/20250825110100_improve_members_queries.sql
new file mode 100644
index 0000000..2674dd5
--- /dev/null
+++ b/supabase/migrations/20250825110100_improve_members_queries.sql
@@ -0,0 +1,48 @@
+DROP FUNCTION IF EXISTS medreport.get_account_members(text);
+
+CREATE OR REPLACE FUNCTION medreport.get_account_members(account_slug text)
+ RETURNS TABLE(
+ id uuid,
+ user_id uuid,
+ account_id uuid,
+ role character varying,
+ role_hierarchy_level integer,
+ primary_owner_user_id uuid,
+ name character varying,
+ email character varying,
+ personal_code text,
+ picture_url character varying,
+ created_at timestamp with time zone,
+ updated_at timestamp with time zone
+)
+ LANGUAGE plpgsql
+ SET search_path TO ''
+AS $function$begin
+ return QUERY
+ select
+ acc.id,
+ am.user_id,
+ am.account_id,
+ am.account_role,
+ r.hierarchy_level,
+ a.primary_owner_user_id,
+ acc.name,
+ acc.email,
+ acc.personal_code,
+ acc.picture_url,
+ am.created_at,
+ am.updated_at
+ from
+ medreport.accounts_memberships am
+ join medreport.accounts a on a.id = am.account_id
+ join medreport.accounts acc on acc.id = am.user_id
+ join medreport.roles r on r.name = am.account_role
+ where
+ a.slug = account_slug;
+
+end;$function$
+;
+
+grant
+ execute on function medreport.get_account_members (text) to authenticated,
+ service_role;
\ No newline at end of file