1 import { useMemo, useState } from 'react';
3 import { c } from 'ttag';
5 import type { IconName } from '@proton/components';
6 import { Dropdown, DropdownMenu, DropdownMenuButton, Icon, ToolbarButton, usePopperAnchor } from '@proton/components';
7 import type { SHARE_MEMBER_PERMISSIONS } from '@proton/shared/lib/drive/permissions';
8 import { getCanAdmin, getCanWrite } from '@proton/shared/lib/drive/permissions';
9 import generateUID from '@proton/utils/generateUID';
11 import type { DecryptedLink } from '../../../../store';
12 import { useActions } from '../../../../store';
13 import { useDetailsModal } from '../../../modals/DetailsModal';
14 import { useFilesDetailsModal } from '../../../modals/FilesDetailsModal';
15 import { useMoveToFolderModal } from '../../../modals/MoveToFolderModal/MoveToFolderModal';
16 import { useRenameModal } from '../../../modals/RenameModal';
17 import { useLinkSharingModal } from '../../../modals/ShareLinkModal/ShareLinkModal';
21 selectedLinks: DecryptedLink[];
22 permissions: SHARE_MEMBER_PERMISSIONS;
25 const ActionsDropdown = ({ shareId, selectedLinks, permissions }: Props) => {
26 const [uid] = useState(generateUID('actions-dropdown'));
27 const { anchorRef, isOpen, toggle, close } = usePopperAnchor<HTMLButtonElement>();
28 const [filesDetailsModal, showFilesDetailsModal] = useFilesDetailsModal();
29 const [detailsModal, showDetailsModal] = useDetailsModal();
30 const [moveToFolderModal, showMoveToFolderModal] = useMoveToFolderModal();
31 const [renameModal, showRenameModal] = useRenameModal();
32 const [linkSharingModal, showLinkSharingModal] = useLinkSharingModal();
33 const isEditor = useMemo(() => getCanWrite(permissions), [permissions]);
34 const isAdmin = useMemo(() => getCanAdmin(permissions), [permissions]);
36 const { trashLinks, renameLink } = useActions();
38 const hasFoldersSelected = selectedLinks.some((item) => !item.isFile);
39 const isMultiSelect = selectedLinks.length > 1;
40 const selectedLinkIds = selectedLinks.map(({ linkId }) => linkId);
50 hidden: isMultiSelect || !isAdmin,
51 name: c('Action').t`Share`,
53 testId: 'actions-dropdown-share-link',
54 action: () => showLinkSharingModal({ shareId: shareId, linkId: selectedLinkIds[0] }),
58 name: c('Action').t`Move to folder`,
60 testId: 'actions-dropdown-move',
61 action: () => showMoveToFolderModal({ shareId, selectedItems: selectedLinks }),
64 hidden: isMultiSelect || !isEditor,
65 name: c('Action').t`Rename`,
67 testId: 'actions-dropdown-rename',
70 isFile: selectedLinks[0].isFile,
71 name: selectedLinks[0].name,
72 onSubmit: (formattedName) =>
74 new AbortController().signal,
75 selectedLinks[0].rootShareId,
76 selectedLinks[0].linkId,
82 hidden: isMultiSelect,
83 name: c('Action').t`Details`,
85 testId: 'actions-dropdown-details',
86 action: () => showDetailsModal({ shareId, linkId: selectedLinkIds[0] }),
89 hidden: !isMultiSelect || hasFoldersSelected,
90 name: c('Action').t`Details`,
92 testId: 'actions-dropdown-details',
93 action: () => showFilesDetailsModal({ selectedItems: selectedLinks }),
97 name: c('Action').t`Move to trash`,
99 testId: 'actions-dropdown-trash',
100 action: () => trashLinks(new AbortController().signal, selectedLinks),
104 const dropdownMenuButtons = menuItems
105 .filter((menuItem) => !menuItem.hidden)
110 onContextMenu={(e) => e.stopPropagation()}
111 className="flex flex-nowrap items-center text-left"
117 data-testid={item.testId}
119 <Icon className="mr-2" name={item.icon} />
121 </DropdownMenuButton>
127 disabled={!selectedLinks.length}
128 aria-describedby={uid}
130 aria-expanded={isOpen}
132 icon={<Icon name="chevron-down-filled" alt={c('Title').t`Show actions`} rotate={isOpen ? 180 : 0} />}
133 data-testid="actions-dropdown"
134 title={c('Title').t`Show actions`}
136 <Dropdown id={uid} isOpen={isOpen} anchorRef={anchorRef} onClose={close} originalPlacement="bottom">
137 <DropdownMenu>{dropdownMenuButtons}</DropdownMenu>
148 export default ActionsDropdown;