From aec736af3d8c6549839d10fd7d712d73a3a58747 Mon Sep 17 00:00:00 2001 From: Karli Date: Wed, 1 Oct 2025 01:47:36 +0300 Subject: [PATCH 1/3] feat(MED-171): update benefits info in company members table --- .../_lib/server/members-page.loader.ts | 7 ++++- .../members/account-members-table.tsx | 23 ++++++++++++-- packages/supabase/src/database.types.ts | 1 + public/locales/en/teams.json | 3 +- public/locales/et/teams.json | 3 +- public/locales/ru/teams.json | 3 +- ...1316_update_benefits_usage_calculation.sql | 30 +++++++++++++++++++ 7 files changed, 64 insertions(+), 6 deletions(-) create mode 100644 supabase/migrations/20251001011316_update_benefits_usage_calculation.sql diff --git a/app/home/[account]/members/_lib/server/members-page.loader.ts b/app/home/[account]/members/_lib/server/members-page.loader.ts index 8df60c8..b767dcc 100644 --- a/app/home/[account]/members/_lib/server/members-page.loader.ts +++ b/app/home/[account]/members/_lib/server/members-page.loader.ts @@ -73,6 +73,7 @@ export async function loadAccountMembersBenefitsUsage( { personal_account_id: string; benefit_amount: number; + benefit_unused_amount: number; }[] > { const { data, error } = await client @@ -86,7 +87,11 @@ export async function loadAccountMembersBenefitsUsage( return []; } - return data ?? []; + return (data ?? []) as unknown as { + personal_account_id: string; + benefit_amount: number; + benefit_unused_amount: number; + }[]; } /** diff --git a/packages/features/team-accounts/src/components/members/account-members-table.tsx b/packages/features/team-accounts/src/components/members/account-members-table.tsx index d1fbcac..d4a68a0 100644 --- a/packages/features/team-accounts/src/components/members/account-members-table.tsx +++ b/packages/features/team-accounts/src/components/members/account-members-table.tsx @@ -46,6 +46,7 @@ type AccountMembersTableProps = { membersBenefitsUsage: { personal_account_id: string; benefit_amount: number; + benefit_unused_amount: number; }[]; }; @@ -132,6 +133,7 @@ function useGetColumns( membersBenefitsUsage: { personal_account_id: string; benefit_amount: number; + benefit_unused_amount: number; }[]; }, ): ColumnDef[] { @@ -185,11 +187,11 @@ function useGetColumns( { header: t('distributedBenefitsAmount'), cell: ({ row }) => { - const benefitAmount = params.membersBenefitsUsage.find( + let benefitAmount = params.membersBenefitsUsage.find( (usage) => usage.personal_account_id === row.original.id, )?.benefit_amount; if (typeof benefitAmount !== 'number') { - return '-'; + benefitAmount = 0; } return formatCurrency({ @@ -199,6 +201,23 @@ function useGetColumns( }); }, }, + { + header: t('distributedBenefitsUnusedAmount'), + cell: ({ row }) => { + let benefitUnusedAmount = params.membersBenefitsUsage.find( + (usage) => usage.personal_account_id === row.original.id, + )?.benefit_unused_amount; + if (typeof benefitUnusedAmount !== 'number') { + benefitUnusedAmount = 0; + } + + return formatCurrency({ + currencyCode: 'EUR', + locale: language, + value: benefitUnusedAmount, + }); + }, + }, { header: t('roleLabel'), cell: ({ row }) => { diff --git a/packages/supabase/src/database.types.ts b/packages/supabase/src/database.types.ts index 6f03c0b..454e7fb 100644 --- a/packages/supabase/src/database.types.ts +++ b/packages/supabase/src/database.types.ts @@ -2323,6 +2323,7 @@ export type Database = { Returns: { personal_account_id: string benefit_amount: number + benefit_unused_amount: number } } get_config: { diff --git a/public/locales/en/teams.json b/public/locales/en/teams.json index 8af264f..d248e54 100644 --- a/public/locales/en/teams.json +++ b/public/locales/en/teams.json @@ -196,5 +196,6 @@ "specialCharactersError": "This name cannot contain special characters. Please choose a different one.", "personalCode": "Personal Code", "teamOwnerPersonalCodeLabel": "Owner's Personal Code", - "distributedBenefitsAmount": "Assigned benefits" + "distributedBenefitsAmount": "Assigned benefits", + "distributedBenefitsUnusedAmount": "Unused benefits" } diff --git a/public/locales/et/teams.json b/public/locales/et/teams.json index 884923d..48b0281 100644 --- a/public/locales/et/teams.json +++ b/public/locales/et/teams.json @@ -196,5 +196,6 @@ "specialCharactersError": "Nimi ei tohi sisaldada erimärke. Palun vali mõni teine.", "personalCode": "Isikukood", "teamOwnerPersonalCodeLabel": "Omaniku isikukood", - "distributedBenefitsAmount": "Väljastatud toetus" + "distributedBenefitsAmount": "Väljastatud toetus", + "distributedBenefitsUnusedAmount": "Jääk" } diff --git a/public/locales/ru/teams.json b/public/locales/ru/teams.json index 74111f1..c814f7c 100644 --- a/public/locales/ru/teams.json +++ b/public/locales/ru/teams.json @@ -196,5 +196,6 @@ "specialCharactersError": "Это имя не может содержать специальные символы. Пожалуйста, выберите другое.", "personalCode": "Идентификационный код", "teamOwnerPersonalCodeLabel": "Идентификационный код владельца", - "distributedBenefitsAmount": "Распределенные выплаты" + "distributedBenefitsAmount": "Распределенные выплаты", + "distributedBenefitsUnusedAmount": "Неиспользованные выплаты" } diff --git a/supabase/migrations/20251001011316_update_benefits_usage_calculation.sql b/supabase/migrations/20251001011316_update_benefits_usage_calculation.sql new file mode 100644 index 0000000..2e375d5 --- /dev/null +++ b/supabase/migrations/20251001011316_update_benefits_usage_calculation.sql @@ -0,0 +1,30 @@ +DROP FUNCTION IF EXISTS medreport.get_benefits_usages_for_company_members(uuid); + +CREATE OR REPLACE FUNCTION medreport.get_benefits_usages_for_company_members(p_account_id uuid) +returns table ( + personal_account_id uuid, + benefit_amount numeric, + benefit_unused_amount numeric +) +language plpgsql +as $$ +begin + return query + with benefit_recipient_accounts as ( + -- Find all personal accounts that have received benefits from this company + select distinct account_id + from medreport.account_balance_entries + where source_company_id = p_account_id + and entry_type = 'benefit' + ) + select + bra.account_id as personal_account_id, + coalesce(sum(case when abe.entry_type = 'benefit' and abe.source_company_id = p_account_id then abe.amount else 0 end), 0) as benefit_amount, + coalesce(sum(case when abe.entry_type = 'benefit' and abe.source_company_id = p_account_id then abe.amount when abe.entry_type = 'purchase' then abe.amount else 0 end), 0) as benefit_unused_amount + from benefit_recipient_accounts bra + left join medreport.account_balance_entries abe on abe.account_id = bra.account_id + group by bra.account_id; +end; +$$; + +grant execute on function medreport.get_benefits_usages_for_company_members(uuid) to authenticated, service_role; From b4ab02b4efb9fab88c76707b49be2b2bf5cb53a4 Mon Sep 17 00:00:00 2001 From: Karli Date: Wed, 1 Oct 2025 01:47:49 +0300 Subject: [PATCH 2/3] feat(MED-171): move sorting to loader to fix warning --- .../_lib/server/members-page.loader.ts | 15 ++++++- .../members/account-members-table.tsx | 44 +++++++------------ 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/app/home/[account]/members/_lib/server/members-page.loader.ts b/app/home/[account]/members/_lib/server/members-page.loader.ts index b767dcc..0f0c50e 100644 --- a/app/home/[account]/members/_lib/server/members-page.loader.ts +++ b/app/home/[account]/members/_lib/server/members-page.loader.ts @@ -63,7 +63,20 @@ async function loadAccountMembers( throw error; } - return data ?? []; + const members = data ?? []; + + return members + .sort((prev, next) => { + if (prev.primary_owner_user_id === prev.user_id) { + return -1; + } + + if (prev.role_hierarchy_level < next.role_hierarchy_level) { + return -1; + } + + return 1; + }); } export async function loadAccountMembersBenefitsUsage( diff --git a/packages/features/team-accounts/src/components/members/account-members-table.tsx b/packages/features/team-accounts/src/components/members/account-members-table.tsx index d4a68a0..d345ff7 100644 --- a/packages/features/team-accounts/src/components/members/account-members-table.tsx +++ b/packages/features/team-accounts/src/components/members/account-members-table.tsx @@ -83,33 +83,23 @@ export function AccountMembersTable({ membersBenefitsUsage, }); - const filteredMembers = members - .filter((member) => { - const searchString = search.toLowerCase(); + const searchString = search.toLowerCase(); + const filteredMembers = searchString.length > 0 + ? members + .filter((member) => { + const displayName = ( + member.name ?? + member.email.split('@')[0] ?? + '' + ).toLowerCase(); - const displayName = ( - member.name ?? - member.email.split('@')[0] ?? - '' - ).toLowerCase(); - - return ( - displayName.includes(searchString) || - member.role.toLowerCase().includes(searchString) || - (member.personal_code || '').includes(searchString) - ); - }) - .sort((prev, next) => { - if (prev.primary_owner_user_id === prev.user_id) { - return -1; - } - - if (prev.role_hierarchy_level < next.role_hierarchy_level) { - return -1; - } - - return 1; - }); + return ( + displayName.includes(searchString) || + member.role.toLowerCase().includes(searchString) || + (member.personal_code || '').includes(searchString) + ); + }) + : members; return (
@@ -265,7 +255,7 @@ function useGetColumns( ), }, ], - [t, params, permissions], + [t, params, permissions, language], ); } From 68672985ec73293bc8f8f88a444ce43ed9f10c8c Mon Sep 17 00:00:00 2001 From: Karli Date: Wed, 1 Oct 2025 01:48:01 +0300 Subject: [PATCH 3/3] feat(MED-171): show full names for company members in table --- ...51001014022_account_members_full_names.sql | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 supabase/migrations/20251001014022_account_members_full_names.sql diff --git a/supabase/migrations/20251001014022_account_members_full_names.sql b/supabase/migrations/20251001014022_account_members_full_names.sql new file mode 100644 index 0000000..1f50a5d --- /dev/null +++ b/supabase/migrations/20251001014022_account_members_full_names.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 text, + 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, + TRIM(CONCAT(acc.name, ' ', acc.last_name)) as 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;