Remove payments API routing initialization
[ProtonMail-WebClient.git] / packages / components / containers / vpn / gateways / ButtonNumberInput.tsx
blob3dfbe3435435f3f88b269b7c3471c4cb24d2847b
1 import { useState } from 'react';
3 import { c } from 'ttag';
5 import Icon from '@proton/components/components/icon/Icon';
6 import Checkbox from '@proton/components/components/input/Checkbox';
7 import Label from '@proton/components/components/label/Label';
8 import type { CountryOptions } from '@proton/components/helpers/countries';
9 import clsx from '@proton/utils/clsx';
11 import { CountryFlagAndName } from './CountryFlagAndName';
12 import type { GatewayLocation } from './GatewayLocation';
13 import { getLocationDisplayName } from './helpers';
15 export const ButtonNumberInput = ({
16     value,
17     onChange,
18     id,
19     min = 0,
20     max = 999,
21     step = 1,
22     disabled = false,
23     location,
24     countryOptions,
25     ownedCount,
26     usedCount,
27 }: {
28     step?: number;
29     id: string;
30     min?: number;
31     max?: number;
32     value: number | undefined;
33     disabled?: boolean;
34     location: GatewayLocation;
35     countryOptions: CountryOptions;
36     ownedCount: number;
37     usedCount: number;
38     onChange?: (newValue: number) => void;
39 }) => {
40     const [tmpValue, setTmpValue] = useState<number | undefined>(value);
42     const getIsValidValue = (newValue?: number) => {
43         return newValue !== undefined && newValue >= min && newValue <= max && newValue % step === 0;
44     };
46     const title = getLocationDisplayName(location, countryOptions);
48     const maxUsable = Math.min(max, ownedCount - usedCount);
49     const isDecDisabled = disabled || tmpValue === undefined || tmpValue <= min;
50     const isIncDisabled = disabled || tmpValue === undefined || tmpValue >= maxUsable;
52     const isValidTmpValue = getIsValidValue(tmpValue);
54     const setTmpNum = (newValue: number) => {
55         if (newValue >= min && newValue <= maxUsable) {
56             setTmpValue(newValue);
57             onChange?.(newValue);
58         }
59     };
61     return (
62         <>
63             <Label className="flex-1" style={{ opacity: disabled ? 0.5 : 1 }}>
64                 <Checkbox
65                     onChange={(e) => {
66                         const newValue = e.target.checked ? 1 : undefined;
67                         setTmpValue(newValue);
68                         onChange?.(newValue || 0);
69                     }}
70                     disabled={disabled}
71                     checked={(tmpValue || 0) > 0}
72                 />{' '}
73                 <CountryFlagAndName countryCode={location.Country} countryName={title} />
74             </Label>
75             <div
76                 className="border rounded shrink-0 flex flex-nowrap"
77                 style={{ visibility: tmpValue === undefined ? 'hidden' : 'visible', opacity: disabled ? 0.5 : 1 }}
78             >
79                 <button
80                     type="button"
81                     title={c('Action').t`Decrease`}
82                     className={clsx(['p-2 flex', isDecDisabled && 'color-disabled'])}
83                     disabled={isDecDisabled}
84                     onClick={() => {
85                         if (!isValidTmpValue || tmpValue === undefined) {
86                             return;
87                         }
88                         const newValue = tmpValue - step;
89                         setTmpNum?.(newValue);
90                         onChange?.(newValue);
91                     }}
92                 >
93                     <Icon name="minus" alt={c('Action').t`Decrease`} className="m-auto" />
94                 </button>
95                 <label htmlFor={id} className="my-2 flex">
96                     <input
97                         autoComplete="off"
98                         min={min}
99                         max={max}
100                         value={tmpValue}
101                         id={id}
102                         className="w-custom border-left border-right text-center"
103                         style={{ '--w-custom': '6em' }}
104                         onBlur={() => {
105                             if (!isValidTmpValue) {
106                                 // Revert to the latest valid value upon blur
107                                 setTmpValue(value);
108                             }
109                         }}
110                         onChange={({ target: { value: newValue } }) => {
111                             if (newValue === '') {
112                                 setTmpValue(undefined);
113                                 return;
114                             }
115                             const newIntValue = parseInt(newValue, 10);
116                             setTmpValue(newIntValue);
117                             if (newIntValue >= min && newIntValue <= maxUsable) {
118                                 onChange?.(newIntValue);
119                             }
120                         }}
121                     />
122                 </label>
123                 <button
124                     type="button"
125                     title={c('Action').t`Increase`}
126                     className={clsx(['p-2 flex', isIncDisabled && 'color-disabled'])}
127                     disabled={isIncDisabled}
128                     onClick={() => {
129                         if (!isValidTmpValue || tmpValue === undefined) {
130                             return;
131                         }
132                         const newValue = tmpValue + step;
133                         setTmpNum?.(newValue);
134                         onChange?.(newValue);
135                     }}
136                 >
137                     <Icon name="plus" alt={c('Action').t`Increase`} className="m-auto" />
138                 </button>
139             </div>
140         </>
141     );