feat(MED-97): show benefits amount for each member
This commit is contained in:
@@ -5,6 +5,7 @@ import { SupabaseClient } from '@supabase/supabase-js';
|
|||||||
import { Database } from '@/packages/supabase/src/database.types';
|
import { Database } from '@/packages/supabase/src/database.types';
|
||||||
|
|
||||||
import { loadTeamWorkspace } from '~/home/[account]/_lib/server/team-account-workspace.loader';
|
import { loadTeamWorkspace } from '~/home/[account]/_lib/server/team-account-workspace.loader';
|
||||||
|
import { getSupabaseServerAdminClient } from '@/packages/supabase/src/clients/server-admin-client';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load data for the members page
|
* Load data for the members page
|
||||||
@@ -15,11 +16,13 @@ export async function loadMembersPageData(
|
|||||||
client: SupabaseClient<Database>,
|
client: SupabaseClient<Database>,
|
||||||
slug: string,
|
slug: string,
|
||||||
) {
|
) {
|
||||||
|
const workspace = await loadTeamWorkspace(slug);
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
loadAccountMembers(client, slug),
|
loadAccountMembers(client, slug),
|
||||||
loadInvitations(client, slug),
|
loadInvitations(client, slug),
|
||||||
canAddMember,
|
canAddMember,
|
||||||
loadTeamWorkspace(slug),
|
workspace,
|
||||||
|
loadAccountMembersBenefitsUsage(getSupabaseServerAdminClient(), workspace.account.id),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,6 +63,27 @@ async function loadAccountMembers(
|
|||||||
return data ?? [];
|
return data ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function loadAccountMembersBenefitsUsage(
|
||||||
|
client: SupabaseClient<Database>,
|
||||||
|
accountId: string,
|
||||||
|
): Promise<{
|
||||||
|
personal_account_id: string;
|
||||||
|
benefit_amount: number;
|
||||||
|
}[]> {
|
||||||
|
const { data, error } = await client
|
||||||
|
.schema('medreport')
|
||||||
|
.rpc('get_benefits_usages_for_company_members', {
|
||||||
|
p_account_id: accountId,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
console.error('Failed to load account members benefits usage', error);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return data ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load account invitations
|
* Load account invitations
|
||||||
* @param client
|
* @param client
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ async function TeamAccountMembersPage({ params }: TeamAccountMembersPageProps) {
|
|||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const slug = (await params).account;
|
const slug = (await params).account;
|
||||||
|
|
||||||
const [members, invitations, canAddMember, { user, account }] =
|
const [members, invitations, canAddMember, { user, account }, membersBenefitsUsage] =
|
||||||
await loadMembersPageData(client, slug);
|
await loadMembersPageData(client, slug);
|
||||||
|
|
||||||
const canManageRoles = account.permissions.includes('roles.manage');
|
const canManageRoles = account.permissions.includes('roles.manage');
|
||||||
@@ -96,6 +96,7 @@ async function TeamAccountMembersPage({ params }: TeamAccountMembersPageProps) {
|
|||||||
members={members}
|
members={members}
|
||||||
isPrimaryOwner={isPrimaryOwner}
|
isPrimaryOwner={isPrimaryOwner}
|
||||||
canManageRoles={canManageRoles}
|
canManageRoles={canManageRoles}
|
||||||
|
membersBenefitsUsage={membersBenefitsUsage}
|
||||||
/>
|
/>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import { If } from '@kit/ui/if';
|
|||||||
import { Input } from '@kit/ui/input';
|
import { Input } from '@kit/ui/input';
|
||||||
import { ProfileAvatar } from '@kit/ui/profile-avatar';
|
import { ProfileAvatar } from '@kit/ui/profile-avatar';
|
||||||
import { Trans } from '@kit/ui/trans';
|
import { Trans } from '@kit/ui/trans';
|
||||||
|
import { formatCurrency } from '@kit/shared/utils';
|
||||||
|
|
||||||
import { RemoveMemberDialog } from './remove-member-dialog';
|
import { RemoveMemberDialog } from './remove-member-dialog';
|
||||||
import { RoleBadge } from './role-badge';
|
import { RoleBadge } from './role-badge';
|
||||||
@@ -42,6 +43,10 @@ type AccountMembersTableProps = {
|
|||||||
userRoleHierarchy: number;
|
userRoleHierarchy: number;
|
||||||
isPrimaryOwner: boolean;
|
isPrimaryOwner: boolean;
|
||||||
canManageRoles: boolean;
|
canManageRoles: boolean;
|
||||||
|
membersBenefitsUsage: {
|
||||||
|
personal_account_id: string;
|
||||||
|
benefit_amount: number;
|
||||||
|
}[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export function AccountMembersTable({
|
export function AccountMembersTable({
|
||||||
@@ -51,6 +56,7 @@ export function AccountMembersTable({
|
|||||||
isPrimaryOwner,
|
isPrimaryOwner,
|
||||||
userRoleHierarchy,
|
userRoleHierarchy,
|
||||||
canManageRoles,
|
canManageRoles,
|
||||||
|
membersBenefitsUsage,
|
||||||
}: AccountMembersTableProps) {
|
}: AccountMembersTableProps) {
|
||||||
const [search, setSearch] = useState('');
|
const [search, setSearch] = useState('');
|
||||||
const { t } = useTranslation('teams');
|
const { t } = useTranslation('teams');
|
||||||
@@ -73,6 +79,7 @@ export function AccountMembersTable({
|
|||||||
currentUserId,
|
currentUserId,
|
||||||
currentAccountId,
|
currentAccountId,
|
||||||
currentRoleHierarchy: userRoleHierarchy,
|
currentRoleHierarchy: userRoleHierarchy,
|
||||||
|
membersBenefitsUsage,
|
||||||
});
|
});
|
||||||
|
|
||||||
const filteredMembers = members
|
const filteredMembers = members
|
||||||
@@ -122,9 +129,13 @@ function useGetColumns(
|
|||||||
currentUserId: string;
|
currentUserId: string;
|
||||||
currentAccountId: string;
|
currentAccountId: string;
|
||||||
currentRoleHierarchy: number;
|
currentRoleHierarchy: number;
|
||||||
|
membersBenefitsUsage: {
|
||||||
|
personal_account_id: string;
|
||||||
|
benefit_amount: number;
|
||||||
|
}[];
|
||||||
},
|
},
|
||||||
): ColumnDef<Members[0]>[] {
|
): ColumnDef<Members[0]>[] {
|
||||||
const { t } = useTranslation('teams');
|
const { t, i18n: { language } } = useTranslation('teams');
|
||||||
|
|
||||||
return useMemo(
|
return useMemo(
|
||||||
() => [
|
() => [
|
||||||
@@ -168,6 +179,23 @@ function useGetColumns(
|
|||||||
return row.original.personal_code ?? '-';
|
return row.original.personal_code ?? '-';
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
header: t('distributedBenefitsAmount'),
|
||||||
|
cell: ({ row }) => {
|
||||||
|
const benefitAmount = params.membersBenefitsUsage.find(
|
||||||
|
(usage) => usage.personal_account_id === row.original.id
|
||||||
|
)?.benefit_amount;
|
||||||
|
if (typeof benefitAmount !== 'number') {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
return formatCurrency({
|
||||||
|
currencyCode: 'EUR',
|
||||||
|
locale: language,
|
||||||
|
value: benefitAmount,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
header: t('roleLabel'),
|
header: t('roleLabel'),
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
@@ -175,7 +203,7 @@ function useGetColumns(
|
|||||||
const isPrimaryOwner = primary_owner_user_id === user_id;
|
const isPrimaryOwner = primary_owner_user_id === user_id;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className={'flex items-center space-x-1'}>
|
<span className={'flex items-center space-x-1 flex-wrap space-y-1 sm:space-y-0 sm:flex-nowrap'}>
|
||||||
<RoleBadge role={role} />
|
<RoleBadge role={role} />
|
||||||
|
|
||||||
<If condition={isPrimaryOwner}>
|
<If condition={isPrimaryOwner}>
|
||||||
|
|||||||
@@ -160,5 +160,6 @@
|
|||||||
"leaveTeamInputDescription": "By leaving the company, you will no longer have access to it.",
|
"leaveTeamInputDescription": "By leaving the company, you will no longer have access to it.",
|
||||||
"reservedNameError": "This name is reserved. Please choose a different one.",
|
"reservedNameError": "This name is reserved. Please choose a different one.",
|
||||||
"specialCharactersError": "This name cannot contain special characters. Please choose a different one.",
|
"specialCharactersError": "This name cannot contain special characters. Please choose a different one.",
|
||||||
"personalCode": "Personal Code"
|
"personalCode": "Personal Code",
|
||||||
|
"distributedBenefitsAmount": "Assigned benefits"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -193,5 +193,6 @@
|
|||||||
"reservedNameError": "See nimi on reserveeritud. Palun vali mõni teine.",
|
"reservedNameError": "See nimi on reserveeritud. Palun vali mõni teine.",
|
||||||
"specialCharactersError": "Nimi ei tohi sisaldada erimärke. Palun vali mõni teine.",
|
"specialCharactersError": "Nimi ei tohi sisaldada erimärke. Palun vali mõni teine.",
|
||||||
"personalCode": "Isikukood",
|
"personalCode": "Isikukood",
|
||||||
"teamOwnerPersonalCodeLabel": "Omaniku isikukood"
|
"teamOwnerPersonalCodeLabel": "Omaniku isikukood",
|
||||||
|
"distributedBenefitsAmount": "Väljastatud toetus"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -193,5 +193,6 @@
|
|||||||
"reservedNameError": "Это имя зарезервировано. Пожалуйста, выберите другое.",
|
"reservedNameError": "Это имя зарезервировано. Пожалуйста, выберите другое.",
|
||||||
"specialCharactersError": "Это имя не может содержать специальные символы. Пожалуйста, выберите другое.",
|
"specialCharactersError": "Это имя не может содержать специальные символы. Пожалуйста, выберите другое.",
|
||||||
"personalCode": "Идентификационный код",
|
"personalCode": "Идентификационный код",
|
||||||
"teamOwnerPersonalCodeLabel": "Идентификационный код владельца"
|
"teamOwnerPersonalCodeLabel": "Идентификационный код владельца",
|
||||||
|
"distributedBenefitsAmount": "Распределенные выплаты"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user