'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)}> ); }