'use client';
import { useMemo, useState } from 'react';
import { ColumnDef } from '@tanstack/react-table';
import { Ellipsis } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { formatCurrency } from '@kit/shared/utils';
import { Database } from '@kit/supabase/database';
import { Badge } from '@kit/ui/badge';
import { Button } from '@kit/ui/button';
import { DataTable } from '@kit/ui/data-table';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@kit/ui/dropdown-menu';
import { If } from '@kit/ui/if';
import { Input } from '@kit/ui/input';
import { ProfileAvatar } from '@kit/ui/profile-avatar';
import { Trans } from '@kit/ui/trans';
import { RemoveMemberDialog } from './remove-member-dialog';
import { RoleBadge } from './role-badge';
import { TransferOwnershipDialog } from './transfer-ownership-dialog';
import UpdateEmployeeBenefitDialog from './update-employee-benefit-dialog';
import { UpdateMemberRoleDialog } from './update-member-role-dialog';
type Members =
Database['medreport']['Functions']['get_account_members']['Returns'];
interface Permissions {
canUpdateRole: (roleHierarchy: number) => boolean;
canRemoveFromAccount: (roleHierarchy: number) => boolean;
canTransferOwnership: boolean;
canUpdateBenefit: boolean;
}
type AccountMembersTableProps = {
members: Members;
currentUserId: string;
currentAccountId: string;
userRoleHierarchy: number;
isPrimaryOwner: boolean;
canManageRoles: boolean;
canUpdateBenefit: boolean;
membersBenefitsUsage: {
personal_account_id: string;
benefit_amount: number;
benefit_unused_amount: number;
}[];
};
export function AccountMembersTable({
members,
currentUserId,
currentAccountId,
isPrimaryOwner,
userRoleHierarchy,
canManageRoles,
canUpdateBenefit,
membersBenefitsUsage,
}: AccountMembersTableProps) {
const [search, setSearch] = useState('');
const { t } = useTranslation('teams');
const permissions = {
canUpdateRole: (targetRole: number) => {
return (
isPrimaryOwner || (canManageRoles && userRoleHierarchy < targetRole)
);
},
canRemoveFromAccount: (targetRole: number) => {
return (
isPrimaryOwner || (canManageRoles && userRoleHierarchy < targetRole)
);
},
canTransferOwnership: isPrimaryOwner,
canUpdateBenefit,
};
const columns = useGetColumns(permissions, {
currentUserId,
currentAccountId,
currentRoleHierarchy: userRoleHierarchy,
membersBenefitsUsage,
});
const searchString = search.toLowerCase();
const filteredMembers =
searchString.length > 0
? members.filter((member) => {
const displayName = (
member.name ??
member.email.split('@')[0] ??
''
).toLowerCase();
return (
displayName.includes(searchString) ||
member.role.toLowerCase().includes(searchString) ||
(member.personal_code || '').includes(searchString)
);
})
: members;
return (
setSearch((e.target as HTMLInputElement).value)}
placeholder={t(`searchMembersPlaceholder`)}
/>
);
}
function useGetColumns(
permissions: Permissions,
params: {
currentUserId: string;
currentAccountId: string;
currentRoleHierarchy: number;
membersBenefitsUsage: {
personal_account_id: string;
benefit_amount: number;
benefit_unused_amount: number;
}[];
},
): ColumnDef[] {
const {
t,
i18n: { language },
} = useTranslation('teams');
return useMemo(
() => [
{
header: t('memberName'),
size: 200,
cell: ({ row }) => {
const member = row.original;
const displayName = member.name ?? member.email.split('@')[0];
const isSelf = member.user_id === params.currentUserId;
return (
{displayName}
{t('youLabel')}
);
},
},
{
header: t('emailLabel'),
accessorKey: 'email',
cell: ({ row }) => {
return row.original.email ?? '-';
},
},
{
header: t('personalCode'),
accessorKey: 'personal_code',
cell: ({ row }) => {
return row.original.personal_code ?? '-';
},
},
{
header: t('distributedBenefitsAmount'),
cell: ({ row }) => {
let benefitAmount = params.membersBenefitsUsage.find(
(usage) => usage.personal_account_id === row.original.id,
)?.benefit_amount;
if (typeof benefitAmount !== 'number') {
benefitAmount = 0;
}
return formatCurrency({
currencyCode: 'EUR',
locale: language,
value: benefitAmount,
});
},
},
{
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 }) => {
const { role } = row.original;
return (
);
},
},
{
header: t('joinedAtLabel'),
cell: ({ row }) => {
return new Date(row.original.created_at).toLocaleDateString();
},
},
{
header: '',
id: 'actions',
cell: ({ row }) => (
),
},
],
[t, params, permissions, language],
);
}
function ActionsDropdown({
permissions,
member,
currentTeamAccountId,
currentRoleHierarchy,
}: {
permissions: Permissions;
member: Members[0];
currentTeamAccountId: string;
currentRoleHierarchy: number;
}) {
const [isRemoving, setIsRemoving] = useState(false);
const [isTransferring, setIsTransferring] = useState(false);
const [isUpdatingRole, setIsUpdatingRole] = useState(false);
const [isUpdatingBenefit, setIsUpdatingBenefit] = useState(false);
const isPrimaryOwner = member.primary_owner_user_id === member.user_id;
const memberRoleHierarchy = member.role_hierarchy_level;
const canUpdateRole = permissions.canUpdateRole(memberRoleHierarchy);
const canRemoveFromAccount =
permissions.canRemoveFromAccount(memberRoleHierarchy);
// if has no permission to update role, transfer ownership or remove from account
// do not render the dropdown menu
if (
!canUpdateRole &&
!permissions.canTransferOwnership &&
!canRemoveFromAccount
) {
return null;
}
return (
<>
setIsUpdatingRole(true)}>
setIsTransferring(true)}>
setIsRemoving(true)}>
setIsUpdatingBenefit(true)}>
>
);
}