import { useCallback, useState } from 'react'; import { useLingui } from '@lingui/react/macro'; import { Trans } from '@lingui/react/macro'; import type { Field, Recipient } from '@prisma/client'; import { RecipientRole, SendStatus } from '@prisma/client'; import { Check, ChevronsUpDown, Info } from 'lucide-react'; import { sortBy } from 'remeda'; import { RECIPIENT_ROLES_DESCRIPTION } from '@documenso/lib/constants/recipient-roles'; import { canRecipientFieldsBeModified } from '@documenso/lib/utils/recipients'; import { getRecipientColorStyles } from '@documenso/ui/lib/recipient-colors'; import { cn } from '@documenso/ui/lib/utils'; import { Button } from '@documenso/ui/primitives/button'; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, } from '@documenso/ui/primitives/command'; import { Popover, PopoverContent, PopoverTrigger } from '@documenso/ui/primitives/popover'; import { Tooltip, TooltipContent, TooltipTrigger } from '@documenso/ui/primitives/tooltip'; export interface EnvelopeRecipientSelectorProps { className?: string; selectedRecipient: Recipient | null; onSelectedRecipientChange: (recipient: Recipient) => void; recipients: Recipient[]; fields: Field[]; align?: 'center' | 'end' | 'start'; } export const EnvelopeRecipientSelector = ({ className, selectedRecipient, onSelectedRecipientChange, recipients, fields, align = 'start', }: EnvelopeRecipientSelectorProps) => { const [showRecipientsSelector, setShowRecipientsSelector] = useState(false); return ( { onSelectedRecipientChange(recipient); setShowRecipientsSelector(false); }} recipients={recipients} /> ); }; interface EnvelopeRecipientSelectorCommandProps { className?: string; selectedRecipient: Recipient | null; onSelectedRecipientChange: (recipient: Recipient) => void; recipients: Recipient[]; fields: Field[]; placeholder?: string; } export const EnvelopeRecipientSelectorCommand = ({ className, selectedRecipient, onSelectedRecipientChange, recipients, fields, placeholder, }: EnvelopeRecipientSelectorCommandProps) => { const { t } = useLingui(); const recipientsByRole = useCallback(() => { const recipientsByRole: Record = { CC: [], VIEWER: [], SIGNER: [], APPROVER: [], ASSISTANT: [], }; recipients.forEach((recipient) => { recipientsByRole[recipient.role].push(recipient); }); return recipientsByRole; }, [recipients]); const recipientsByRoleToDisplay = useCallback(() => { return Object.entries(recipientsByRole()) .filter( ([role]) => role !== RecipientRole.CC && role !== RecipientRole.VIEWER && role !== RecipientRole.ASSISTANT, ) .map( ([role, roleRecipients]) => [ role, sortBy( roleRecipients, [(r) => r.signingOrder || Number.MAX_SAFE_INTEGER, 'asc'], [(r) => r.id, 'asc'], ), ] as [RecipientRole, Recipient[]], ); }, [recipientsByRole]); const isRecipientDisabled = useCallback( (recipientId: number) => { const recipient = recipients.find((r) => r.id === recipientId); const recipientFields = fields.filter((f) => f.recipientId === recipientId); return !recipient || !canRecipientFieldsBeModified(recipient, recipientFields); }, [fields, recipients], ); return ( No recipient matching this description was found. {recipientsByRoleToDisplay().map(([role, roleRecipients], roleIndex) => (
{t(RECIPIENT_ROLES_DESCRIPTION[role].roleNamePlural)}
{roleRecipients.length === 0 && (
No recipients with this role
)} {roleRecipients.map((recipient) => ( r.id === recipient.id), 0, ), ).comboxBoxItem, { 'text-muted-foreground': recipient.sendStatus === SendStatus.SENT, 'cursor-not-allowed': isRecipientDisabled(recipient.id), }, )} onSelect={() => { if (!isRecipientDisabled(recipient.id)) { onSelectedRecipientChange(recipient); } }} > {recipient.name && ( {recipient.name} ({recipient.email}) )} {!recipient.name && {recipient.email}}
{!isRecipientDisabled(recipient.id) ? ( ) : ( This document has already been sent to this recipient. You can no longer edit this recipient. )}
))}
))}
); };