1 import type { MutableRefObject } from 'react';
2 import { useEffect, useState } from 'react';
4 import { c, msgid } from 'ttag';
6 import { useAddresses } from '@proton/account/addresses/hooks';
7 import { useMembers } from '@proton/account/members/hooks';
8 import { useOrganization } from '@proton/account/organization/hooks';
9 import { getPrivatizeError } from '@proton/account/organizationKey/actions';
10 import { useOrganizationKey } from '@proton/account/organizationKey/hooks';
11 import { useUser } from '@proton/account/user/hooks';
12 import { Button, Href } from '@proton/atoms';
13 import useModalState from '@proton/components/components/modalTwo/useModalState';
14 import { MemberListBanner, MembersList } from '@proton/components/containers/organization/MemberListBanner';
15 import useNotifications from '@proton/components/hooks/useNotifications';
16 import { MEMBER_ROLE } from '@proton/shared/lib/constants';
17 import { getKnowledgeBaseUrl } from '@proton/shared/lib/helpers/url';
18 import type { Member } from '@proton/shared/lib/interfaces';
22 getMemberHasAccessToOrgKey,
23 getMemberHasMissingOrgKey,
25 getOrganizationKeyInfo,
26 } from '@proton/shared/lib/organization/helper';
28 import ActivatePasswordlessOrganizationKey from './ActivatePasswordlessOrganizationKey';
29 import ChangeOrganizationKeysModal from './ChangeOrganizationKeysModal';
30 import ChangeOrganizationKeysPasswordlessModal from './ChangeOrganizationKeysPasswordlessModal';
31 import ChangeOrganizationPasswordModal from './ChangeOrganizationPasswordModal';
32 import InviteOrganizationKeysModal from './InviteOrganizationKeysModal';
33 import ReactivateOrganizationKeysModal from './ReactivateOrganizationKeysModal';
34 import ReactivatePasswordlessOrganizationKey from './ReactivatePasswordlessOrganizationKey';
35 import { getActivationText, getReactivationText } from './helper';
37 const UserNeedsToInvite = ({
38 onRestorePrivilegesClick,
39 otherAdminsWithMissingOrgKeys,
41 onRestorePrivilegesClick: () => void;
42 otherAdminsWithMissingOrgKeys: Member[];
44 const n = otherAdminsWithMissingOrgKeys.length;
51 {c('Restore administrator panel').ngettext(
52 msgid`${n} administrator in your organization need access to the organization key.`,
53 `${n} administrators in your organization need access to the organization key.`,
57 <Href href={getKnowledgeBaseUrl('/restore-administrator')} className="inline-block">
58 {c('Link').t`Learn more`}
60 <MembersList members={otherAdminsWithMissingOrgKeys} />
64 <Button size="small" color="norm" onClick={onRestorePrivilegesClick}>
65 {c('Title').t`Restore administrator privileges`}
72 const UserNeedsToReactivatePasswordless = ({ onRestorePrivilegesClick }: { onRestorePrivilegesClick: () => void }) => {
78 <div>{getReactivationText()}</div>
79 <Href href={getKnowledgeBaseUrl('/restore-administrator')} className="inline-block">
80 {c('Link').t`Learn more`}
85 <Button size="small" color="norm" onClick={onRestorePrivilegesClick}>
86 {c('Title').t`Restore administrator privileges`}
93 const UserNeedsToReactivate = ({ onRestorePrivilegesClick }: { onRestorePrivilegesClick: () => void }) => {
100 {c('Restore administrator panel')
101 .t`Due to a password change, your organization administrator privileges have been restricted. The following actions are no longer permitted:`}
103 <ul className="mb-0">
104 <li>{c('Restore administrator panel').t`Creating or accessing non-private user accounts`}</li>
105 <li>{c('Restore administrator panel').t`Changing organization password`}</li>
106 <li>{c('Restore administrator panel').t`Changing organization keys`}</li>
108 <Href href={getKnowledgeBaseUrl('/restore-administrator')} className="inline-block">
109 {c('Link').t`Learn more`}
114 <Button size="small" color="norm" onClick={onRestorePrivilegesClick}>
115 {c('Title').t`Restore administrator privileges`}
122 const UserNeedsToActivate = ({ onActiveOrganizationKeyClick }: { onActiveOrganizationKeyClick: () => void }) => {
126 members={getActivationText()}
128 <Button size="small" color="norm" onClick={onActiveOrganizationKeyClick}>
129 {c('Action').t`Activate organization key`}
136 const useOrganizationModals = (onceRef: MutableRefObject<boolean>) => {
137 const [user] = useUser();
138 const [organization] = useOrganization();
139 const [organizationKey, loadingOrganizationKey] = useOrganizationKey();
140 const [addresses] = useAddresses();
141 const [members, loadingMembers] = useMembers();
142 const { createNotification } = useNotifications();
143 const [reactivateModalProps, setReactivateModal, reactivateModalRender] = useModalState();
144 const [reactivatePasswordlessModalProps, setReactivatePasswordlessModal, renderReactivatePasswordlessModal] =
146 const [activateModalProps, setActivateModal, renderActivateModal] = useModalState();
147 const [activatePasswordlessModalProps, setActivatePasswordlessModal, renderActivatePasswordless] = useModalState();
148 const [changeOrganizationKeysProps, setChangeOrganizationKeys, renderChangeOrganizationKeys] = useModalState();
150 changePasswordlessOrganizationKeysProps,
151 setChangePasswordlessOrganizationKeys,
152 renderChangePasswordlessOrganizationKeys,
155 invitePasswordlessOrganizationKeys,
156 setInvitePasswordlessOrganizationKeys,
157 renderInvitePasswordlessOrganizationKeys,
159 const [changeOrganizationPasswordProps, setChangeOrganizationPassword, renderChangeOrganizationPassword] =
161 const [changeMode, setChangeMode] = useState<'reset' | undefined>();
163 const organizationKeyInfo = getOrganizationKeyInfo(organization, organizationKey, addresses);
164 const otherAdmins = (members || []).filter(
165 (member) => member.Role === MEMBER_ROLE.ORGANIZATION_ADMIN && !member.Self
167 const otherAdminsWithKeyAccess = otherAdmins.filter(getMemberHasAccessToOrgKey);
168 const otherAdminsWithMissingOrgKey = otherAdmins.filter(getMemberHasMissingOrgKey);
169 const hasOtherAdmins = otherAdmins.length > 0;
170 const publicMembers = getNonPrivateMembers(members || []);
172 const disableResetOrganizationKeys = publicMembers.length > 0 && !organizationKey?.privateKey;
174 const handleChangeOrganizationKeys = (mode?: 'reset') => {
175 if (!organizationKey) {
176 throw new Error('Organization key not loaded');
178 if (disableResetOrganizationKeys) {
179 return createNotification({
180 text: getPrivatizeError(),
185 if (organizationKeyInfo.mode === OrganizationKeyMode.Passwordless) {
186 setChangePasswordlessOrganizationKeys(true);
188 setChangeOrganizationKeys(true);
192 const handleResetOrganizationKeys = () => {
193 handleChangeOrganizationKeys('reset');
196 const handleChangeOrganizationPassword = () => {
197 if (!organizationKey?.privateKey) {
198 return createNotification({ text: c('Error').t`Organization key is not decrypted`, type: 'error' });
201 setChangeOrganizationPassword(true);
207 loadingOrganizationKey ||
210 !organization?.HasKeys;
213 if (onceRef.current || disabled) {
217 if (organizationKeyInfo.mode === OrganizationKeyMode.Passwordless) {
218 if (organizationKeyInfo.state === OrganizationKeyState.Activate) {
219 setActivatePasswordlessModal(true);
220 onceRef.current = true;
221 } else if (organizationKeyInfo.state === OrganizationKeyState.Inactive) {
222 setReactivatePasswordlessModal(true);
223 onceRef.current = true;
226 if (organizationKeyInfo.state === OrganizationKeyState.Activate) {
227 setActivateModal(true);
228 onceRef.current = true;
229 } else if (organizationKeyInfo.state === OrganizationKeyState.Inactive) {
230 setReactivateModal(true);
231 onceRef.current = true;
238 {reactivateModalRender && (
239 <ReactivateOrganizationKeysModal
241 onResetKeys={handleResetOrganizationKeys}
242 {...reactivateModalProps}
245 {renderActivateModal && (
246 <ReactivateOrganizationKeysModal
248 onResetKeys={handleResetOrganizationKeys}
249 {...activateModalProps}
252 {renderActivatePasswordless && (
253 <ActivatePasswordlessOrganizationKey
254 onResetKeys={handleResetOrganizationKeys}
255 {...activatePasswordlessModalProps}
258 {renderReactivatePasswordlessModal && (
259 <ReactivatePasswordlessOrganizationKey
261 onResetKeys={handleResetOrganizationKeys}
262 disableResetOrganizationKeys={disableResetOrganizationKeys}
263 otherAdminsWithKeyAccess={otherAdminsWithKeyAccess}
264 {...reactivatePasswordlessModalProps}
267 {renderChangeOrganizationKeys && organizationKey && (
268 <ChangeOrganizationKeysModal
270 hasOtherAdmins={hasOtherAdmins}
271 organizationKey={organizationKey}
272 {...changeOrganizationKeysProps}
275 {renderChangePasswordlessOrganizationKeys && (
276 <ChangeOrganizationKeysPasswordlessModal
278 {...changePasswordlessOrganizationKeysProps}
281 {renderInvitePasswordlessOrganizationKeys && (
282 <InviteOrganizationKeysModal
283 members={otherAdminsWithMissingOrgKey}
284 {...invitePasswordlessOrganizationKeys}
287 {renderChangeOrganizationPassword && organizationKey?.privateKey && (
288 <ChangeOrganizationPasswordModal
289 hasOtherAdmins={hasOtherAdmins}
290 organizationKey={organizationKey.privateKey}
291 {...changeOrganizationPasswordProps}
297 const handleActivatePasswordless = () => {
298 setActivatePasswordlessModal(true);
300 const handleReActivatePasswordless = () => {
301 setReactivatePasswordlessModal(true);
304 const handleActivate = () => {
305 if (organizationKeyInfo.mode === OrganizationKeyMode.Passwordless) {
306 handleActivatePasswordless();
308 setActivateModal(true);
311 const handleReactivate = () => {
312 if (organizationKeyInfo.mode === OrganizationKeyMode.Passwordless) {
313 handleReActivatePasswordless();
315 setActivateModal(true);
319 const info = (() => {
320 if (disabled || organizationKeyInfo.state === OrganizationKeyState.NoKey) {
323 if (organizationKeyInfo.mode === OrganizationKeyMode.Passwordless) {
324 if (organizationKeyInfo.state === OrganizationKeyState.Activate) {
325 return <UserNeedsToActivate onActiveOrganizationKeyClick={handleActivatePasswordless} />;
327 if (organizationKeyInfo.state === OrganizationKeyState.Inactive) {
328 return <UserNeedsToReactivatePasswordless onRestorePrivilegesClick={handleReActivatePasswordless} />;
330 if (otherAdminsWithMissingOrgKey.length) {
333 onRestorePrivilegesClick={() => {
334 setInvitePasswordlessOrganizationKeys(true);
336 otherAdminsWithMissingOrgKeys={otherAdminsWithMissingOrgKey}
341 if (organizationKeyInfo.state === OrganizationKeyState.Activate) {
342 return <UserNeedsToActivate onActiveOrganizationKeyClick={handleActivate} />;
344 if (organizationKeyInfo.state === OrganizationKeyState.Inactive) {
345 return <UserNeedsToReactivate onRestorePrivilegesClick={handleReactivate} />;
353 handleChangeOrganizationPassword,
354 handleChangeOrganizationKeys,
355 handleResetOrganizationKeys,
356 handleActivatePasswordless,
362 export default useOrganizationModals;