Remove payments API routing initialization
[ProtonMail-WebClient.git] / packages / components / containers / vpn / tv / TVContainer.tsx
blob8496861b5bb522b236717e93ec2bd06d364059ef
1 import type { FormEvent } from 'react';
2 import { useState } from 'react';
3 import { useLocation } from 'react-router-dom';
5 import { c } from 'ttag';
7 import { Href } from '@proton/atoms';
8 import PrimaryButton from '@proton/components/components/button/PrimaryButton';
9 import Icon from '@proton/components/components/icon/Icon';
10 import VpnLogo from '@proton/components/components/logo/VpnLogo';
11 import useApi from '@proton/components/hooks/useApi';
12 import { useLoading } from '@proton/hooks';
13 import { pushForkSession } from '@proton/shared/lib/api/auth';
14 import { VPN_TV_CLIENT_IDS, VPN_TV_PATHS_MAP } from '@proton/shared/lib/constants';
15 import clsx from '@proton/utils/clsx';
17 import TVCodeInputs from './TVCodeInputs';
19 enum STEP {
20     ENTER_CODE,
21     DEVICE_CONNECTED,
24 interface Props {
25     background?: boolean;
28 const TVContainer = ({ background = true }: Props) => {
29     const [code, setCode] = useState('');
30     const [step, setStep] = useState(STEP.ENTER_CODE);
31     const api = useApi();
32     const [loading, withLoading] = useLoading();
33     const location = useLocation();
34     const [error, setError] = useState('');
35     const childClientId = (() => {
36         if (VPN_TV_PATHS_MAP.apple.includes(location.pathname)) {
37             return VPN_TV_CLIENT_IDS.APPLE;
38         }
39         return VPN_TV_CLIENT_IDS.ANDROID;
40     })();
42     const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {
43         event.preventDefault();
45         if (loading || !code) {
46             return;
47         }
49         try {
50             setError('');
51             await api(
52                 pushForkSession({
53                     ChildClientID: childClientId,
54                     Independent: 1,
55                     UserCode: code,
56                 })
57             );
58             setStep(STEP.DEVICE_CONNECTED);
59         } catch (error: any) {
60             const { data: { Error = '' } = {} } = error;
61             setError(Error);
62             throw error;
63         }
64     };
66     const render = () => {
67         if (step === STEP.ENTER_CODE) {
68             return (
69                 <form onSubmit={(event) => withLoading(handleSubmit(event))}>
70                     <label className="h3 text-center mb-3" htmlFor="code-input">{c('Label')
71                         .t`Enter the code displayed on your TV`}</label>
72                     <TVCodeInputs value={code} setValue={setCode} />
73                     {error ? (
74                         <>
75                             <p className="mt-8 mb-0 pl-4 text-center color-danger">{c('Error')
76                                 .t`Code wrong or not valid anymore`}</p>
77                             <p className="m-0 text-center border-none">{c('Error')
78                                 .t`If the time on your TV has expired, click on Refresh on your TV and enter your code again.`}</p>
79                         </>
80                     ) : null}
81                     <div className="flex">
82                         <PrimaryButton
83                             loading={loading}
84                             type="submit"
85                             pill
86                             className="text-uppercase text-bold mt-8 mb-6 mx-auto"
87                         >
88                             <span className="p-2 inline-flex">
89                                 {error ? c('Action').t`Verify code again` : c('Action').t`Verify code`}
90                             </span>
91                         </PrimaryButton>
92                     </div>
93                 </form>
94             );
95         }
97         if (step === STEP.DEVICE_CONNECTED) {
98             return (
99                 <>
100                     <h2>{c('Title').t`Device connected!`}</h2>
101                     <div className="flex justify-center my-8">
102                         <span className="inline-flex bg-success rounded-50 p-7">
103                             <Icon name="checkmark" size={15} />
104                         </span>
105                     </div>
106                 </>
107             );
108         }
110         return null;
111     };
113     return (
114         <div
115             className={clsx(
116                 ' h-full flex *:min-size-auto flex-column flex-nowrap items-center overflow-auto',
117                 background && 'tv-background-container ui-prominent'
118             )}
119         >
120             <div className="flex justify-center items-center pt-7">
121                 <div className="w-custom" style={{ '--w-custom': '9.375rem' }}>
122                     <Href href="https://protonvpn.com" target="_self">
123                         <VpnLogo />
124                     </Href>
125                 </div>
126                 <h3 className="mb-0 pl-1 text-uppercase text-bold">{c('Title').t`TV sign in`}</h3>
127             </div>
128             <div className="flex flex-column flex-1 flex-nowrap shrink-0">
129                 <div className="m-auto p-7 shrink-0 max-w-custom" style={{ '--max-w-custom': '30em' }}>
130                     {render()}
131                 </div>
132             </div>
133         </div>
134     );
137 export default TVContainer;