Cleanup - unused files / unused exports / duplicate exports
[ProtonMail-WebClient.git] / applications / drive / src / app / components / modals / ShareLinkModal / DirectSharing / DirectSharingListing.tsx
blob36e9b9372f61888aaf2e5dfe0457446bb78a0f47
1 import { useMemo } from 'react';
3 import { c } from 'ttag';
5 import { useUser } from '@proton/account/user/hooks';
6 import { Avatar, CircleLoader } from '@proton/atoms';
7 import { useSortedList } from '@proton/components';
8 import useLoading from '@proton/hooks/useLoading';
9 import { useContactEmails } from '@proton/mail/contactEmails/hooks';
10 import { SORT_DIRECTION } from '@proton/shared/lib/constants';
11 import type { SHARE_MEMBER_PERMISSIONS } from '@proton/shared/lib/drive/permissions';
12 import { canonicalizeEmailByGuess } from '@proton/shared/lib/helpers/email';
13 import { getInitials } from '@proton/shared/lib/helpers/string';
14 import type { ContactEmail } from '@proton/shared/lib/interfaces/contacts';
16 import type { ShareExternalInvitation, ShareInvitation, ShareMember } from '../../../../store';
17 import { DirectSharingListInvitation } from './DirectSharingListInvitation';
18 import { MemberDropdownMenu } from './MemberDropdownMenu';
20 interface Props {
21     volumeId?: string;
22     linkId: string;
23     members: ShareMember[];
24     invitations: ShareInvitation[];
25     externalInvitations: ShareExternalInvitation[];
26     isLoading: boolean;
27     onPermissionsChange: (member: ShareMember, permission: SHARE_MEMBER_PERMISSIONS) => Promise<void>;
28     onInvitationPermissionsChange: (invitationId: string, permission: SHARE_MEMBER_PERMISSIONS) => Promise<void>;
29     onExternalInvitationPermissionsChange: (
30         externalInvitationId: string,
31         permission: SHARE_MEMBER_PERMISSIONS
32     ) => Promise<void>;
33     onMemberRemove: (member: ShareMember) => Promise<void>;
34     onInvitationRemove: (invitationId: string) => Promise<void>;
35     onExternalInvitationRemove: (externalInvitationId: string) => Promise<void>;
36     onResendInvitationEmail: (invitationId: string) => Promise<void>;
37     onResendExternalInvitationEmail: (externaInvitationId: string) => Promise<void>;
40 const getContactNameAndEmail = (email: string, contactEmails?: ContactEmail[]) => {
41     const canonicalizedEmail = canonicalizeEmailByGuess(email);
42     const { Name: contactName, Email: contactEmail } = contactEmails?.find(
43         (contactEmail) => canonicalizeEmailByGuess(contactEmail.Email) === canonicalizedEmail
44     ) || {
45         Name: '',
46         Email: email,
47     };
49     return {
50         contactName,
51         contactEmail,
52     };
55 const MemberItem = ({
56     member,
57     contactName,
58     contactEmail,
59     onPermissionsChange,
60     onMemberRemove,
61 }: {
62     member: ShareMember;
63     contactName?: string;
64     contactEmail: string;
65     onPermissionsChange: (member: ShareMember, permission: SHARE_MEMBER_PERMISSIONS) => Promise<void>;
66     onMemberRemove: (member: ShareMember) => Promise<void>;
67 }) => {
68     const [isLoading, withIsLoading] = useLoading(false);
69     const { memberId, permissions } = member;
70     const handlePermissionChange = (value: SHARE_MEMBER_PERMISSIONS) =>
71         withIsLoading(onPermissionsChange(member, value));
73     const handleMemberRemove = () => withIsLoading(onMemberRemove(member));
75     return (
76         <div
77             key={memberId}
78             className="flex my-4 justify-space-between items-center"
79             data-testid="share-accepted-members"
80         >
81             <div className={'flex items-center'}>
82                 <Avatar color="weak" className="mr-2">
83                     {getInitials(contactName || contactEmail)}
84                 </Avatar>
85                 <p className="flex flex-column p-0 m-0">
86                     <span className="text-semibold">{contactName ? contactName : contactEmail}</span>
87                     {contactName && <span className="color-weak">{contactEmail}</span>}
88                 </p>
89             </div>
90             <MemberDropdownMenu
91                 isLoading={isLoading}
92                 selectedPermissions={permissions}
93                 onChangePermissions={handlePermissionChange}
94                 onRemoveAccess={handleMemberRemove}
95             />
96         </div>
97     );
100 export const DirectSharingListing = ({
101     volumeId,
102     linkId,
103     members,
104     invitations,
105     externalInvitations,
106     isLoading,
107     onPermissionsChange,
108     onMemberRemove,
109     onInvitationRemove,
110     onInvitationPermissionsChange,
111     onExternalInvitationRemove,
112     onExternalInvitationPermissionsChange,
113     onResendInvitationEmail,
114     onResendExternalInvitationEmail,
115 }: Props) => {
116     const [user] = useUser();
117     const [contactEmails] = useContactEmails();
119     const displayName = user.DisplayName || user.Name;
121     const membersWithName = useMemo(
122         () =>
123             members.map((member) => {
124                 const { contactName, contactEmail } = getContactNameAndEmail(member.email, contactEmails);
125                 return { member, contactName, contactEmail };
126             }),
127         [members, contactEmails]
128     );
129     const { sortedList: sortedMembersWithName } = useSortedList(membersWithName, {
130         key: 'contactName',
131         direction: SORT_DIRECTION.ASC,
132     });
134     if (isLoading) {
135         return <CircleLoader size="medium" className="mx-auto my-6 w-full" />;
136     }
137     return (
138         <>
139             <div className="flex my-4 justify-space-between items-center" data-testid="share-owner">
140                 <div className={'flex items-center'}>
141                     <Avatar color="weak" className="mr-2">
142                         {getInitials(displayName || user.Email)}
143                     </Avatar>
144                     <p className="flex flex-column p-0 m-0">
145                         <span className="text-semibold">
146                             {displayName} ({c('Info').t`you`})
147                         </span>
148                         <span className="color-weak">{user.Email}</span>
149                     </p>
150                 </div>
151                 <div className="mr-8">{c('Info').t`Owner`}</div>
152             </div>
154             {volumeId &&
155                 externalInvitations.map((externalInvitation) => {
156                     const { contactName, contactEmail } = getContactNameAndEmail(
157                         externalInvitation.inviteeEmail,
158                         contactEmails
159                     );
160                     return (
161                         <DirectSharingListInvitation
162                             key={externalInvitation.externalInvitationId}
163                             invitationId={externalInvitation.externalInvitationId}
164                             volumeId={volumeId}
165                             linkId={linkId}
166                             contactName={contactName}
167                             contactEmail={contactEmail}
168                             selectedPermissions={externalInvitation.permissions}
169                             onInvitationRemove={onExternalInvitationRemove}
170                             onInvitationPermissionsChange={onExternalInvitationPermissionsChange}
171                             onResendInvitationEmail={onResendExternalInvitationEmail}
172                             externalInvitationState={externalInvitation.state}
173                         />
174                     );
175                 })}
176             {volumeId &&
177                 invitations.map((invitation) => {
178                     const { contactName, contactEmail } = getContactNameAndEmail(
179                         invitation.inviteeEmail,
180                         contactEmails
181                     );
182                     return (
183                         <DirectSharingListInvitation
184                             key={invitation.invitationId}
185                             invitationId={invitation.invitationId}
186                             volumeId={volumeId}
187                             linkId={linkId}
188                             contactName={contactName}
189                             contactEmail={contactEmail}
190                             selectedPermissions={invitation.permissions}
191                             onInvitationRemove={onInvitationRemove}
192                             onInvitationPermissionsChange={onInvitationPermissionsChange}
193                             onResendInvitationEmail={onResendInvitationEmail}
194                         />
195                     );
196                 })}
198             {sortedMembersWithName.map(({ member, contactName, contactEmail }) => {
199                 return (
200                     <MemberItem
201                         key={member.memberId}
202                         member={member}
203                         contactName={contactName}
204                         contactEmail={contactEmail}
205                         onPermissionsChange={onPermissionsChange}
206                         onMemberRemove={onMemberRemove}
207                     />
208                 );
209             })}
210         </>
211     );