Merge branch 'feat/inda-383-daily-stat' into 'main'
[ProtonMail-WebClient.git] / applications / drive / src / app / components / sections / Drive / ToolbarButtons / ActionsDropdown.tsx
blobda1ed5f3ba1111278c3add87cf5852d6a24170a9
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';
19 interface Props {
20     shareId: string;
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);
42     const menuItems: {
43         hidden: boolean;
44         name: string;
45         icon: IconName;
46         testId: string;
47         action: () => void;
48     }[] = [
49         {
50             hidden: isMultiSelect || !isAdmin,
51             name: c('Action').t`Share`,
52             icon: 'user-plus',
53             testId: 'actions-dropdown-share-link',
54             action: () => showLinkSharingModal({ shareId: shareId, linkId: selectedLinkIds[0] }),
55         },
56         {
57             hidden: !isEditor,
58             name: c('Action').t`Move to folder`,
59             icon: 'arrows-cross',
60             testId: 'actions-dropdown-move',
61             action: () => showMoveToFolderModal({ shareId, selectedItems: selectedLinks }),
62         },
63         {
64             hidden: isMultiSelect || !isEditor,
65             name: c('Action').t`Rename`,
66             icon: 'pen-square',
67             testId: 'actions-dropdown-rename',
68             action: () =>
69                 showRenameModal({
70                     isFile: selectedLinks[0].isFile,
71                     name: selectedLinks[0].name,
72                     onSubmit: (formattedName) =>
73                         renameLink(
74                             new AbortController().signal,
75                             selectedLinks[0].rootShareId,
76                             selectedLinks[0].linkId,
77                             formattedName
78                         ),
79                 }),
80         },
81         {
82             hidden: isMultiSelect,
83             name: c('Action').t`Details`,
84             icon: 'info-circle',
85             testId: 'actions-dropdown-details',
86             action: () => showDetailsModal({ shareId, linkId: selectedLinkIds[0] }),
87         },
88         {
89             hidden: !isMultiSelect || hasFoldersSelected,
90             name: c('Action').t`Details`,
91             icon: 'info-circle',
92             testId: 'actions-dropdown-details',
93             action: () => showFilesDetailsModal({ selectedItems: selectedLinks }),
94         },
95         {
96             hidden: !isEditor,
97             name: c('Action').t`Move to trash`,
98             icon: 'trash',
99             testId: 'actions-dropdown-trash',
100             action: () => trashLinks(new AbortController().signal, selectedLinks),
101         },
102     ];
104     const dropdownMenuButtons = menuItems
105         .filter((menuItem) => !menuItem.hidden)
106         .map((item) => (
107             <DropdownMenuButton
108                 key={item.name}
109                 hidden={item.hidden}
110                 onContextMenu={(e) => e.stopPropagation()}
111                 className="flex flex-nowrap items-center text-left"
112                 onClick={(e) => {
113                     e.stopPropagation();
114                     item.action();
115                     close();
116                 }}
117                 data-testid={item.testId}
118             >
119                 <Icon className="mr-2" name={item.icon} />
120                 {item.name}
121             </DropdownMenuButton>
122         ));
124     return (
125         <>
126             <ToolbarButton
127                 disabled={!selectedLinks.length}
128                 aria-describedby={uid}
129                 ref={anchorRef}
130                 aria-expanded={isOpen}
131                 onClick={toggle}
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`}
135             />
136             <Dropdown id={uid} isOpen={isOpen} anchorRef={anchorRef} onClose={close} originalPlacement="bottom">
137                 <DropdownMenu>{dropdownMenuButtons}</DropdownMenu>
138             </Dropdown>
139             {filesDetailsModal}
140             {detailsModal}
141             {moveToFolderModal}
142             {renameModal}
143             {linkSharingModal}
144         </>
145     );
148 export default ActionsDropdown;