Cleanup - unused files / unused exports / duplicate exports
[ProtonMail-WebClient.git] / packages / components / containers / members / ChangeMemberPasswordModal.tsx
blobd4648d74573051f2c559f998f9b72a1e2e02ce0c
1 import { useState } from 'react';
3 import { c } from 'ttag';
5 import { changeMemberPassword } from '@proton/account/organizationKey/memberPasswordAction';
6 import { Button } from '@proton/atoms';
7 import Form from '@proton/components/components/form/Form';
8 import type { ModalProps } from '@proton/components/components/modalTwo/Modal';
9 import Modal from '@proton/components/components/modalTwo/Modal';
10 import ModalContent from '@proton/components/components/modalTwo/ModalContent';
11 import ModalFooter from '@proton/components/components/modalTwo/ModalFooter';
12 import ModalHeader from '@proton/components/components/modalTwo/ModalHeader';
13 import InputFieldTwo from '@proton/components/components/v2/field/InputField';
14 import PasswordInputTwo from '@proton/components/components/v2/input/PasswordInput';
15 import useFormErrors from '@proton/components/components/v2/useFormErrors';
16 import AuthModal from '@proton/components/containers/password/AuthModal';
17 import useApi from '@proton/components/hooks/useApi';
18 import useBeforeUnload from '@proton/components/hooks/useBeforeUnload';
19 import useErrorHandler from '@proton/components/hooks/useErrorHandler';
20 import useNotifications from '@proton/components/hooks/useNotifications';
21 import { useDispatch } from '@proton/redux-shared-store';
22 import { revoke } from '@proton/shared/lib/api/auth';
23 import { authMember } from '@proton/shared/lib/api/members';
24 import { lockSensitiveSettings } from '@proton/shared/lib/api/user';
25 import { withUIDHeaders } from '@proton/shared/lib/fetch/headers';
26 import {
27     confirmPasswordValidator,
28     passwordLengthValidator,
29     requiredValidator,
30 } from '@proton/shared/lib/helpers/formValidators';
31 import type { Member } from '@proton/shared/lib/interfaces/Member';
32 import noop from '@proton/utils/noop';
34 import GenericError from '../error/GenericError';
36 interface Inputs {
37     newPassword: string;
38     confirmPassword: string;
41 interface Props extends ModalProps {
42     member: Member;
45 const ChangeMemberPasswordModal = ({ member, onClose, ...rest }: Props) => {
46     const normalApi = useApi();
47     const dispatch = useDispatch();
48     const silentApi = <T,>(config: any) => normalApi<T>({ ...config, silence: true });
49     const [memberAuthData, setMemberAuthData] = useState<{ UID: string }>();
50     const handleError = useErrorHandler();
52     const { createNotification } = useNotifications();
53     const { validator, onFormSubmit } = useFormErrors();
55     const lockAndClose = () => {
56         if (memberAuthData?.UID) {
57             Promise.all([
58                 silentApi(withUIDHeaders(memberAuthData.UID, revoke())),
59                 silentApi(lockSensitiveSettings()),
60             ]).catch(noop);
61         }
62         onClose?.();
63     };
65     const [inputs, setInputs] = useState<Inputs>({
66         newPassword: '',
67         confirmPassword: '',
68     });
69     const [loading, setLoading] = useState<boolean>(false);
70     const [error, setError] = useState(false);
72     useBeforeUnload(loading ? c('Info').t`By leaving now, changes may not be saved` : '');
74     const setPartialInput = (object: Partial<Inputs>) => setInputs((oldState) => ({ ...oldState, ...object }));
76     const newPasswordError = passwordLengthValidator(inputs.newPassword);
77     const confirmPasswordError =
78         passwordLengthValidator(inputs.confirmPassword) ||
79         confirmPasswordValidator(inputs.newPassword, inputs.confirmPassword);
81     if (!memberAuthData) {
82         return (
83             <AuthModal
84                 scope="password"
85                 config={authMember(member.ID, { Unlock: true })}
86                 {...rest}
87                 onCancel={onClose}
88                 onSuccess={async (result) => {
89                     const { response } = result;
91                     const data = await response.json();
92                     const UID = data?.UID;
93                     if (!UID) {
94                         throw new Error('Failed to get auth data');
95                     }
96                     setMemberAuthData({ UID });
97                 }}
98             />
99         );
100     }
102     if (error) {
103         const handleClose = () => {
104             lockAndClose();
105         };
106         return (
107             <Modal {...rest} onClose={handleClose}>
108                 <ModalHeader title={c('Title').t`Change password`} />
109                 <ModalContent>
110                     <GenericError />
111                 </ModalContent>
112                 <ModalFooter>
113                     <div />
114                     <Button color="norm" onClick={handleClose}>
115                         {c('Action').t`OK`}
116                     </Button>
117                 </ModalFooter>
118             </Modal>
119         );
120     }
122     const onSubmit = async () => {
123         if (!onFormSubmit()) {
124             return;
125         }
126         if (newPasswordError || confirmPasswordError) {
127             return;
128         }
130         try {
131             setLoading(true);
133             await dispatch(
134                 changeMemberPassword({
135                     api: silentApi,
136                     memberUID: memberAuthData.UID,
137                     password: inputs.newPassword,
138                     member,
139                 })
140             );
142             createNotification({ text: c('Success').t`Password updated` });
143             lockAndClose();
144         } catch (e: any) {
145             handleError(e);
146             setError(true);
147         } finally {
148             setLoading(false);
149         }
150     };
152     const handleClose = loading ? noop : lockAndClose;
154     const userName = (
155         <b key="user" className="text-break">
156             {member.Name} ({(member?.Addresses || [])[0]?.Email ?? ''})
157         </b>
158     );
160     return (
161         <Modal as={Form} onClose={handleClose} {...rest} onSubmit={onSubmit}>
162             <ModalHeader title={c('Title').t`Change password`} />
163             <ModalContent>
164                 <div className="mb-4">{c('Info').jt`Enter new password for user ${userName}.`}</div>
165                 <InputFieldTwo
166                     id="newPassword"
167                     label={c('Label').t`User's new password`}
168                     error={validator([
169                         requiredValidator(inputs.newPassword),
170                         passwordLengthValidator(inputs.newPassword),
171                     ])}
172                     as={PasswordInputTwo}
173                     autoFocus
174                     autoComplete="new-password"
175                     value={inputs.newPassword}
176                     onValue={(value: string) => setPartialInput({ newPassword: value })}
177                     disabled={loading}
178                 />
180                 <InputFieldTwo
181                     id="confirmPassword"
182                     label={c('Label').t`Confirm new password`}
183                     error={validator([
184                         requiredValidator(inputs.confirmPassword),
185                         passwordLengthValidator(inputs.confirmPassword),
186                         confirmPasswordValidator(inputs.newPassword, inputs.confirmPassword),
187                     ])}
188                     as={PasswordInputTwo}
189                     autoComplete="new-password"
190                     value={inputs.confirmPassword}
191                     onValue={(value: string) => setPartialInput({ confirmPassword: value })}
192                     disabled={loading}
193                 />
194             </ModalContent>
195             <ModalFooter>
196                 <Button onClick={handleClose} disabled={loading}>
197                     {c('Action').t`Cancel`}
198                 </Button>
199                 <Button loading={loading} type="submit" color="norm">
200                     {c('Action').t`Change password`}
201                 </Button>
202             </ModalFooter>
203         </Modal>
204     );
207 export default ChangeMemberPasswordModal;