Cleanup - unused files / unused exports / duplicate exports
[ProtonMail-WebClient.git] / applications / drive / src / app / components / modals / SignupFlowModal / SignupFlowModal.tsx
blob34fe8e9bd9f3904ddd5925865b447eb65090cbbf
1 import { useEffect, useState } from 'react';
3 import { c } from 'ttag';
5 import { Button } from '@proton/atoms';
6 import type { ModalStateProps } from '@proton/components';
7 import {
8     DriveLogo,
9     Form,
10     Icon,
11     InputFieldTwo,
12     ModalTwo,
13     ModalTwoContent,
14     ModalTwoFooter,
15     ModalTwoHeader,
16     useApi,
17     useModalTwoStatic,
18 } from '@proton/components';
19 import { PLANS } from '@proton/payments';
20 import { getApiError } from '@proton/shared/lib/api/helpers/apiErrorHelper';
21 import { queryCheckEmailAvailability } from '@proton/shared/lib/api/user';
22 import { getAppHref } from '@proton/shared/lib/apps/helper';
23 import { APPS, DRIVE_APP_NAME, SSO_PATHS } from '@proton/shared/lib/constants';
24 import { DRIVE_SIGNIN } from '@proton/shared/lib/drive/urls';
25 import { API_CUSTOM_ERROR_CODES } from '@proton/shared/lib/errors';
26 import { replaceUrl } from '@proton/shared/lib/helpers/browser';
27 import { emailValidator } from '@proton/shared/lib/helpers/formValidators';
28 import { getUrlWithReturnUrl } from '@proton/shared/lib/helpers/url';
30 import usePublicToken from '../../../hooks/drive/usePublicToken';
31 import { RedirectionReason, drivePublicRedirectionReasonKey } from '../../../hooks/util/useRedirectToPublicPage';
32 import { Actions, countActionWithTelemetry, traceTelemetry } from '../../../utils/telemetry';
33 import { deleteStoredUrlPassword, saveUrlPasswordForRedirection } from '../../../utils/url/password';
35 interface Props {
36     customPassword?: string;
38 export const SignupFlowModal = ({ customPassword, onClose, ...modalProps }: Props & ModalStateProps) => {
39     const [email, setEmail] = useState('');
40     const [error, setError] = useState('');
41     const api = useApi();
42     const { token, urlPassword } = usePublicToken();
44     useEffect(() => {
45         deleteStoredUrlPassword();
46         countActionWithTelemetry(Actions.ViewSignUpFlowModal);
47     }, []);
49     const handleChangeEmail = (e: React.ChangeEvent<HTMLInputElement>) => {
50         setEmail(e.target.value);
51         setError(emailValidator(e.target.value));
52     };
54     /*
55      * Sign-up flow: Redirect to /shared-with-me, then auto-add bookmarks in MainContainer.tsx
56      * Sign-in flow: Auto-add bookmarks in MainContainer.tsx and redirect back to public page
57      */
58     const handleSubmit = async () => {
59         try {
60             countActionWithTelemetry(Actions.SubmitSignUpFlowModal);
61             const { Code } = await api({
62                 ...queryCheckEmailAvailability(email),
63                 silence: [API_CUSTOM_ERROR_CODES.ALREADY_USED, API_CUSTOM_ERROR_CODES.NOT_ALLOWED],
64             });
65             // Email is verified and available to use
66             // We redirect to DRIVE_SIGNUP
67             // If user pass proton domain we redirect him to signin page in all case
68             if (Code === 1000) {
69                 saveUrlPasswordForRedirection(urlPassword + (customPassword ?? ''));
70                 await Promise.all([
71                     countActionWithTelemetry(Actions.SignUpFlowModal),
72                     traceTelemetry(Actions.SignUpFlowAndRedirectCompleted).start(),
73                 ]);
74                 const returnUrlSearchParams = new URLSearchParams();
75                 returnUrlSearchParams.append('token', token);
76                 const returnUrl = `/shared-with-me?`.concat(returnUrlSearchParams.toString());
78                 const url = new URL(getAppHref(SSO_PATHS.SIGNUP, APPS.PROTONACCOUNT));
79                 // This autofill the sign-up email input
80                 url.searchParams.append('email', email);
81                 url.searchParams.append('plan', PLANS.FREE);
82                 url.searchParams.append('product', 'drive');
83                 replaceUrl(
84                     getUrlWithReturnUrl(url.toString(), {
85                         returnUrl,
86                         context: 'private',
87                     })
88                 );
89             }
90         } catch (err) {
91             const { code, message } = getApiError(err);
92             // Email is already in use or if user pass proton domain we redirect him to, we redirect to SIGN_IN
93             if (API_CUSTOM_ERROR_CODES.ALREADY_USED === code || API_CUSTOM_ERROR_CODES.NOT_ALLOWED === code) {
94                 saveUrlPasswordForRedirection(urlPassword + (customPassword ?? ''));
95                 await countActionWithTelemetry(Actions.SignInFlowModal);
96                 const returnUrlSearchParams = new URLSearchParams();
97                 returnUrlSearchParams.append('token', token);
98                 returnUrlSearchParams.append(drivePublicRedirectionReasonKey, RedirectionReason.SIGNIN);
99                 // Always return to public page in case of signin. This will be done in MainContainer.tsx on page loading
100                 const returnUrl = `/?`.concat(returnUrlSearchParams.toString());
101                 const url = new URL(DRIVE_SIGNIN);
102                 // This autofill the sign-in email input
103                 url.searchParams.append('username', email);
104                 url.searchParams.append('product', 'drive');
105                 replaceUrl(
106                     getUrlWithReturnUrl(url.toString(), {
107                         returnUrl,
108                         context: 'private',
109                     })
110                 );
111                 return;
112             }
113             // Other errors we show the error message
114             setError(message || c('Error').t`Email is not valid`);
115         }
116     };
118     return (
119         <ModalTwo
120             as={Form}
121             onSubmit={handleSubmit}
122             enableCloseWhenClickOutside
123             onClose={() => {
124                 countActionWithTelemetry(Actions.DismissSignUpFlowModal);
125                 onClose();
126             }}
127             size="small"
128             {...modalProps}
129             data-testid="download-page-sign-in"
130         >
131             <ModalTwoHeader
132                 title={
133                     <div className="flex flex-column mb-1">
134                         <DriveLogo variant="glyph-only" size={12} />
135                         {c('Title').t`Save it for later in ${DRIVE_APP_NAME}`}
136                     </div>
137                 }
138                 subline={c('Info').t`Keep your files secure with end-to-end encryption.`}
139             />
140             <ModalTwoContent className="mt-4">
141                 <InputFieldTwo
142                     data-testid="public-share-signup-modal-email"
143                     id="public-share-signup-modal-email"
144                     label={c('Label').t`Log in or sign up `}
145                     onChange={handleChangeEmail}
146                     placeholder={c('Placeholder').t`Email`}
147                     type="email"
148                     error={error}
149                     value={email}
150                 />
151                 <span className="flex items-center gap-1">
152                     <Icon className="color-primary" name="gift" />
153                     {c('Info').t`Free 5GB encrypted storage to get started`}
154                 </span>
155             </ModalTwoContent>
156             <ModalTwoFooter className="flex flex-column items-center">
157                 <Button color="norm" size="large" type="submit" fullWidth={true}>{c('Action').t`Continue`}</Button>
158             </ModalTwoFooter>
159         </ModalTwo>
160     );
163 export const useSignupFlowModal = () => {
164     return useModalTwoStatic(SignupFlowModal);