Skip to content

Commit 37f55f4

Browse files
committed
Merge branch 'frontend-ts-rule'
2 parents fe300d7 + 551ca5d commit 37f55f4

File tree

95 files changed

+535
-418
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

95 files changed

+535
-418
lines changed

frontends/web/src/api/account.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@
1515
*/
1616

1717
import type { LineData } from 'lightweight-charts';
18-
import { apiGet, apiPost } from '@/utils/request';
18+
import type { Slip24 } from 'request-address';
1919
import type { TDetailStatus } from './bitsurance';
2020
import type { SuccessResponse } from './response';
21-
import { Slip24 } from 'request-address';
21+
import type { NonEmptyArray } from '@/utils/types';
22+
import { apiGet, apiPost } from '@/utils/request';
2223

2324
export type NativeCoinCode = 'btc' | 'tbtc' | 'rbtc' | 'ltc' | 'tltc' | 'eth' | 'sepeth';
2425

@@ -304,11 +305,11 @@ export interface IReceiveAddress {
304305

305306
export interface ReceiveAddressList {
306307
scriptType: ScriptType | null;
307-
addresses: IReceiveAddress[];
308+
addresses: NonEmptyArray<IReceiveAddress>;
308309
}
309310

310311
export const getReceiveAddressList = (code: AccountCode) => {
311-
return (): Promise<ReceiveAddressList[] | null> => {
312+
return (): Promise<NonEmptyArray<ReceiveAddressList> | null> => {
312313
return apiGet(`account/${code}/receive-addresses`);
313314
};
314315
};

frontends/web/src/app.tsx

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ export const App = () => {
5858

5959
const prevDevices = usePrevious(devices);
6060

61+
const deviceIDs = Object.keys(devices);
62+
const firstDevice = deviceIDs[0];
63+
6164
useEffect(() => {
6265
return syncNewTxs((meta) => {
6366
notifyUser(t('notification.newTxs', {
@@ -71,7 +74,6 @@ export const App = () => {
7174
const currentURL = window.location.hash.replace(/^#/, '');
7275
const isIndex = currentURL === '' || currentURL === '/';
7376
const inAccounts = currentURL.startsWith('/account/');
74-
const deviceIDs = Object.keys(devices);
7577

7678
// QT and Android start their apps in '/index.html' and '/android_asset/web/index.html' respectively
7779
// This re-routes them to '/' so we have a simpler uri structure
@@ -106,9 +108,10 @@ export const App = () => {
106108
// if device is connected route to device settings
107109
if (
108110
deviceIDs.length === 1
111+
&& firstDevice
109112
&& currentURL === '/settings/no-device-connected'
110113
) {
111-
navigate(`/settings/device-settings/${deviceIDs[0]}`);
114+
navigate(`/settings/device-settings/${firstDevice}`);
112115
return;
113116
}
114117
// if on an account that isn't registered route to /
@@ -138,7 +141,7 @@ export const App = () => {
138141
return;
139142
}
140143

141-
}, [accounts, devices, navigate]);
144+
}, [accounts, deviceIDs, firstDevice, navigate]);
142145

143146
useEffect(() => {
144147
const oldDeviceIDList = Object.keys(prevDevices || {});
@@ -155,10 +158,13 @@ export const App = () => {
155158
// We don't bother implementing the same for the bitbox01.
156159
// The bb02 bootloader screen is not full screen, so we don't mount it globally and instead
157160
// route to it.
158-
const productName = devices[newDeviceIDList[0]];
159-
if (productName === 'bitbox' || productName === 'bitbox02-bootloader') {
160-
navigate(`settings/device-settings/${newDeviceIDList[0]}`);
161-
return;
161+
const firstNewDevice = newDeviceIDList[0];
162+
if (firstNewDevice) {
163+
const productName = devices[firstNewDevice];
164+
if (productName === 'bitbox' || productName === 'bitbox02-bootloader') {
165+
navigate(`settings/device-settings/${firstNewDevice}`);
166+
return;
167+
}
162168
}
163169
}
164170
maybeRoute();
@@ -170,10 +176,9 @@ export const App = () => {
170176
return prefix + ':' + JSON.stringify(devices, Object.keys(devices).sort());
171177
};
172178

173-
const deviceIDs: string[] = Object.keys(devices);
174179
const activeAccounts = accounts.filter(acct => acct.active);
175180

176-
const isBitboxBootloader = devices[deviceIDs[0]] === 'bitbox02-bootloader';
181+
const isBitboxBootloader = firstDevice && devices[firstDevice] === 'bitbox02-bootloader';
177182
const showBottomNavigation = (deviceIDs.length > 0 || activeAccounts.length > 0) && !isBitboxBootloader;
178183

179184

@@ -187,7 +192,10 @@ export const App = () => {
187192
accounts={activeAccounts}
188193
devices={devices}
189194
/>
190-
<div className={`${styles.appContent} ${showBottomNavigation ? styles.hasBottomNavigation : ''}`}>
195+
<div className={`
196+
${styles.appContent || ''}
197+
${showBottomNavigation && styles.hasBottomNavigation || ''}
198+
`}>
191199
<WCSigningRequest />
192200
<Aopp />
193201
<KeystoreConnectPrompt />

frontends/web/src/components/actionable-item/actionable-item.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,14 @@ export const ActionableItem = ({
3838
return (
3939
<>
4040
{notButton ? (
41-
<div className={`${styles.container} ${className}`}>
41+
<div className={`${styles.container || ''} ${className}`}>
4242
{children}
4343
{icon && icon}
4444
</div>
4545
) : (
4646
<button
4747
type="button"
48-
className={`${styles.container} ${styles.isButton} ${className}`}
48+
className={`${styles.container || ''} ${styles.isButton || ''} ${className}`}
4949
onClick={onClick}>
5050
{children}
5151
{icon ? icon : (

frontends/web/src/components/amount/amount-with-unit.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,10 @@ export const AmountWithUnit = ({
8383
);
8484
}
8585
return (
86-
<span className={ `${style.rates} ${!displayedAmount ? style.notAvailable : ''}`}>
86+
<span className={`
87+
${style.rates || ''}
88+
${!displayedAmount && style.notAvailable || ''}
89+
`.trim()}>
8790
{!!displayedAmount ? sign : ''}
8891
{formattedAmount}
8992
{' '}
@@ -98,7 +101,11 @@ type TAmountUnitProps = {
98101
}
99102

100103
export const AmountUnit = ({ rotateUnit, unit }: TAmountUnitProps) => {
101-
const classRototable = rotateUnit ? style.rotatable : '';
102-
const textStyle = `${style.unit} ${classRototable}`;
103-
return <span className={textStyle} onClick={rotateUnit}>{unit}</span>;
104+
const classRototable = rotateUnit ? (style.rotatable || '') : '';
105+
const textStyle = `${style.unit || ''} ${classRototable}`;
106+
return (
107+
<span className={textStyle} onClick={rotateUnit}>
108+
{unit}
109+
</span>
110+
);
104111
};

frontends/web/src/components/anchor/anchor.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,10 @@ export const A = ({
4949
}: TProps) => {
5050
return (
5151
<span
52-
className={`${runningInIOS() ? style.linkIos : style.link} ${className || ''}`}
52+
className={`
53+
${(runningInIOS() ? style.linkIos : style.link) || ''}
54+
${className || ''}
55+
`}
5356
title={props.title || href}
5457
onClick={(e: SyntheticEvent) => {
5558
e.preventDefault();

frontends/web/src/components/aopp/vasp.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,14 @@ export const Vasp = ({
6363
);
6464
}
6565

66-
const logoClasses = prominent ? `${styles.logo} ${styles.prominent}` : styles.logo;
66+
const logoClasses = prominent ? `
67+
${styles.logo || ''}
68+
${styles.prominent || ''}
69+
` : styles.logo as string;
6770
return (
6871
<div>
6972
<img className={logoClasses} src={VASPLogoMap[knownVasp]} alt={knownVasp} />
70-
<p className={`${styles.hostname} ${styles.capitalized}`}>
73+
<p className={`${styles.hostname as string} ${styles.capitalized as string}`}>
7174
{knownVasp in VASPHostnameMap ? VASPHostnameMap[knownVasp] : knownVasp}
7275
</p>
7376
{withLogoText ? (<p>{withLogoText}</p>) : null}

frontends/web/src/components/badge/badge.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,17 @@ export const Badge = ({
3636
const iconOnlyStyle = (children === undefined && icon) ? style.iconOnly : '';
3737
return (
3838
<span
39-
className={`${style.badge} ${style[type]} ${withChildrenStyle} ${iconOnlyStyle} ${className || ''}`}
39+
className={`
40+
${style.badge || ''}
41+
${style[type] || ''}
42+
${withChildrenStyle || ''}
43+
${iconOnlyStyle || ''}
44+
${className || ''}
45+
`}
4046
{...props}>
41-
{icon && icon({ className: style.badgeIcon })}
47+
{icon && style.badgeIcon && icon({
48+
className: style.badgeIcon || ''
49+
})}
4250
{children}
4351
</span>
4452
);

frontends/web/src/components/banners/backup.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,13 @@ export const BackupReminder = ({ keystore, accountsBalanceSummary }: BackupRemin
5858
const connectResult = await connectKeystore(keystore.rootFingerprint);
5959
if (connectResult.success) {
6060
const devices = await getDeviceList();
61-
if (Object.keys(devices).length === 0) {
61+
const firstDevice = Object.keys(devices)[0];
62+
if (!firstDevice) {
6263
// If no devices are connected, we cannot navigate to settings.
6364
// This shouldn't happen in theory, as the connectKeystore functions has succeeded.
6465
return;
6566
}
66-
const deviceSettingsURL = `/settings/device-settings/recovery-words/${Object.keys(devices)[0]}`;
67+
const deviceSettingsURL = `/settings/device-settings/recovery-words/${firstDevice}`;
6768
// Proceed to the setting screen if the keystore was connected.
6869
navigate(deviceSettingsURL);
6970
}

frontends/web/src/components/banners/banner.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ type TBannerProps = {
2828

2929
export const Banner = ({ msgKey }: TBannerProps) => {
3030
const { i18n, t } = useTranslation();
31+
const { fallbackLng } = i18n.options;
3132
const [banner, setBanner] = useState<TBannerInfo>();
3233

3334
useEffect(() => {
@@ -37,18 +38,24 @@ export const Banner = ({ msgKey }: TBannerProps) => {
3738

3839
if (
3940
!banner
40-
|| !i18n.options.fallbackLng
41+
|| !fallbackLng
4142
|| !i18n.resolvedLanguage
4243
) {
4344
return null;
4445
}
4546
const { message, link } = banner;
4647

48+
const maybeFallbackLng: string = (
49+
Array.isArray(fallbackLng) && fallbackLng.length > 0
50+
? fallbackLng[0]
51+
: fallbackLng
52+
);
53+
4754
return (
4855
<Status
4956
dismissible={banner.dismissible ? `banner-${msgKey}-${banner.id}` : ''}
5057
type={banner.type ? banner.type : 'warning'}>
51-
{message[i18n.resolvedLanguage] || message[(i18n.options.fallbackLng as string[])[0]]}
58+
{message[i18n.resolvedLanguage] || message[maybeFallbackLng || 'en']}
5259
&nbsp;
5360
{link && (
5461
<A href={link.href} className={style.link}>

frontends/web/src/components/bottom-navigation/bottom-navigation.tsx

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export const BottomNavigation = ({ activeAccounts, devices }: Props) => {
3333
const { t } = useTranslation();
3434
const { pathname } = useLocation();
3535
const deviceID = Object.keys(devices)[0];
36-
const isBitBox02 = devices[deviceID] === 'bitbox02';
36+
const isBitBox02 = deviceID && devices[deviceID] === 'bitbox02';
3737
const versionInfo = useLoad(isBitBox02 ? () => getVersion(deviceID) : null, [deviceID]);
3838
const canUpgrade = versionInfo ? versionInfo.canUpgrade : false;
3939

@@ -43,14 +43,20 @@ export const BottomNavigation = ({ activeAccounts, devices }: Props) => {
4343
return (
4444
<div className={styles.container}>
4545
<Link
46-
className={`${styles.link} ${pathname.startsWith('/account-summary') ? styles.active : ''}`}
46+
className={`
47+
${styles.link || ''}
48+
${pathname.startsWith('/account-summary') && styles.active || ''}
49+
`}
4750
to="/account-summary"
4851
>
4952
<PortfolioIconSVG />
5053
{t('accountSummary.portfolio')}
5154
</Link>
5255
<Link
53-
className={`${styles.link} ${pathname.startsWith('/account/') || pathname.startsWith('/accounts/') ? styles.active : ''}`}
56+
className={`
57+
${styles.link || ''}
58+
${pathname.startsWith('/account/') || pathname.startsWith('/accounts/') ? (styles.active || '') : ''}
59+
`}
5460
to={
5561
onlyHasOneAccount && accountCode ?
5662
`/account/${accountCode}` :
@@ -61,14 +67,20 @@ export const BottomNavigation = ({ activeAccounts, devices }: Props) => {
6167
{onlyHasOneAccount ? t('account.account') : t('account.accounts')}
6268
</Link>
6369
<Link
64-
className={`${styles.link} ${pathname.startsWith('/market/') ? styles.active : ''}`}
70+
className={`
71+
${styles.link || ''}
72+
${pathname.startsWith('/market/') && styles.active || ''}
73+
`}
6574
to="/market/info"
6675
>
6776
<MarketIconSVG />
6877
{t('generic.buySell')}
6978
</Link>
7079
<Link
71-
className={`${styles.link} ${pathname.startsWith('/settings') || pathname.startsWith('/bitsurance/') ? styles.active : ''}`}
80+
className={`
81+
${styles.link || ''}
82+
${pathname.startsWith('/settings') || pathname.startsWith('/bitsurance/') ? (styles.active || '') : ''}
83+
`}
7284
to="/settings/more"
7385
>
7486
<MoreIconSVG />

0 commit comments

Comments
 (0)