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';
28 const TVContainer = ({ background = true }: Props) => {
29 const [code, setCode] = useState('');
30 const [step, setStep] = useState(STEP.ENTER_CODE);
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;
39 return VPN_TV_CLIENT_IDS.ANDROID;
42 const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {
43 event.preventDefault();
45 if (loading || !code) {
53 ChildClientID: childClientId,
58 setStep(STEP.DEVICE_CONNECTED);
59 } catch (error: any) {
60 const { data: { Error = '' } = {} } = error;
66 const render = () => {
67 if (step === STEP.ENTER_CODE) {
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} />
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>
81 <div className="flex">
86 className="text-uppercase text-bold mt-8 mb-6 mx-auto"
88 <span className="p-2 inline-flex">
89 {error ? c('Action').t`Verify code again` : c('Action').t`Verify code`}
97 if (step === STEP.DEVICE_CONNECTED) {
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} />
116 ' h-full flex *:min-size-auto flex-column flex-nowrap items-center overflow-auto',
117 background && 'tv-background-container ui-prominent'
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">
126 <h3 className="mb-0 pl-1 text-uppercase text-bold">{c('Title').t`TV sign in`}</h3>
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' }}>
137 export default TVContainer;