Skip to content

Commit 8bd473f

Browse files
committed
Merge branch 'frontend-can-update-dot'
2 parents e1c4483 + e0c952b commit 8bd473f

File tree

6 files changed

+87
-8
lines changed

6 files changed

+87
-8
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
- Add Satoshi as an option in active currencies
1212
- Show address re-use warning and group UTXOs with the same address together in coin control.
1313
- Fix encoding of transaction notes on Windows
14+
- Add red dot in sidebar and on device settings tab to indicate that there is a firmware upgrade
1415

1516
## 4.42.1
1617
- BitBox02: fix missing button to re-install firmware, fixing interrupted installs ("invalid firmware").

frontends/web/src/app.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ export const App = () => {
152152
<Sidebar
153153
accounts={activeAccounts}
154154
deviceIDs={deviceIDs}
155+
devices={devices}
155156
/>
156157
<div className="appContent flex flex-column flex-1" style={{ minWidth: 0 }}>
157158
<Update />

frontends/web/src/components/sidebar/sidebar.module.css

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,3 +223,13 @@ a.sidebarActive .single img,
223223
text-align: left;
224224
width: 100%;
225225
}
226+
227+
.canUpgradeDot {
228+
height: 8px;
229+
left: 2px;
230+
max-width: 8px;
231+
position: relative;
232+
top: -2px;
233+
vertical-align: top;
234+
width: 8px;
235+
}

frontends/web/src/components/sidebar/sidebar.tsx

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@
1515
* limitations under the License.
1616
*/
1717

18-
import React, { useContext, useEffect } from 'react';
18+
import React, { useContext, useEffect, useState } from 'react';
1919
import { useLocation } from 'react-router';
2020
import { Link, NavLink } from 'react-router-dom';
2121
import { useTranslation } from 'react-i18next';
2222
import { useKeystores } from '../../hooks/backend';
23-
import { IAccount } from '../../api/account';
23+
import type { TDevices } from '../../api/devices';
24+
import type { IAccount } from '../../api/account';
2425
import { deregisterTest } from '../../api/keystores';
26+
import { getVersion } from '../../api/bitbox02';
2527
import coins from '../../assets/icons/coins.svg';
2628
import ejectIcon from '../../assets/icons/eject.svg';
2729
import shieldIcon from '../../assets/icons/shield_grey.svg';
@@ -31,7 +33,7 @@ import settingsGrey from '../../assets/icons/settings-alt_disabled.svg';
3133
import deviceSettings from '../../assets/icons/wallet-light.svg';
3234
import { debug } from '../../utils/env';
3335
import { AppLogoInverted, Logo } from '../icon/logo';
34-
import { CloseXWhite, USBSuccess } from '../icon';
36+
import { CloseXWhite, RedDot, USBSuccess } from '../icon';
3537
import { getAccountsByKeystore, isAmbiguiousName, isBitcoinOnly } from '../../routes/account/utils';
3638
import { SkipForTesting } from '../../routes/device/components/skipfortesting';
3739
import { Badge } from '../badge/badge';
@@ -41,6 +43,7 @@ import style from './sidebar.module.css';
4143

4244
type SidebarProps = {
4345
deviceIDs: string[];
46+
devices: TDevices;
4447
accounts: IAccount[];
4548
};
4649

@@ -75,12 +78,32 @@ const eject = (e: React.SyntheticEvent): void => {
7578

7679
const Sidebar = ({
7780
deviceIDs,
81+
devices,
7882
accounts,
7983
}: SidebarProps) => {
8084
const { t } = useTranslation();
8185
const { pathname } = useLocation();
86+
const [ canUpgrade, setCanUpgrade ] = useState(false);
8287
const { activeSidebar, sidebarStatus, toggleSidebar } = useContext(AppContext);
8388

89+
useEffect(() => {
90+
const checkUpgradableDevices = async () => {
91+
setCanUpgrade(false);
92+
const bitbox02Devices = Object.keys(devices).filter(deviceID => devices[deviceID] === 'bitbox02');
93+
94+
for (const deviceID of bitbox02Devices) {
95+
const { canUpgrade } = await getVersion(deviceID);
96+
if (canUpgrade) {
97+
setCanUpgrade(true);
98+
// exit early as we found an upgradable device
99+
return;
100+
}
101+
}
102+
};
103+
104+
checkUpgradableDevices();
105+
}, [devices]);
106+
84107
useEffect(() => {
85108
const swipe = {
86109
active: false,
@@ -243,7 +266,12 @@ const Sidebar = ({
243266
<img draggable={false} src={settingsGrey} alt={t('sidebar.settings')} />
244267
<img draggable={false} src={settings} alt={t('sidebar.settings')} />
245268
</div>
246-
<span className={style.sidebarLabel}>{t('sidebar.settings')}</span>
269+
<span className={style.sidebarLabel}>
270+
{t('sidebar.settings')}
271+
{canUpgrade && (
272+
<RedDot className={style.canUpgradeDot} width={8} height={8} />
273+
)}
274+
</span>
247275
</NavLink>
248276
</div>
249277

frontends/web/src/routes/settings/components/tabs.module.css

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,6 @@
2323
}
2424
}
2525

26+
.canUpgradeDot {
27+
vertical-align: top;
28+
}

frontends/web/src/routes/settings/components/tabs.tsx

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@
1616

1717
import { ReactNode } from 'react';
1818
import { NavLink } from 'react-router-dom';
19+
import { useTranslation } from 'react-i18next';
20+
import { useLoad } from '../../../hooks/api';
21+
import { getVersion } from '../../../api/bitbox02';
1922
import { route } from '../../../utils/route';
2023
import { SettingsItem } from './settingsItem/settingsItem';
21-
import { ChevronRightDark } from '../../../components/icon';
22-
import { useTranslation } from 'react-i18next';
24+
import { ChevronRightDark, RedDot } from '../../../components/icon';
2325
import styles from './tabs.module.css';
2426

2527
type TWithSettingsTabsProps = {
@@ -33,6 +35,7 @@ type TTab = {
3335
name: string;
3436
url: string;
3537
hideMobileMenu?: boolean;
38+
canUpgrade?: boolean;
3639
}
3740

3841
type TTabs = {
@@ -57,7 +60,16 @@ export const WithSettingsTabs = ({
5760
);
5861
};
5962

60-
export const Tab = ({ name, url, hideMobileMenu }: TTab) => {
63+
export const Tab = ({
64+
name,
65+
url,
66+
hideMobileMenu,
67+
canUpgrade,
68+
}: TTab) => {
69+
70+
const upgradeDot = canUpgrade ? (
71+
<RedDot className={styles.canUpgradeDot} width={8} height={8} />
72+
) : null;
6173

6274
if (!hideMobileMenu) {
6375
// Will only be shown on mobile (index/general settings page)
@@ -67,6 +79,7 @@ export const Tab = ({ name, url, hideMobileMenu }: TTab) => {
6779
settingName={name}
6880
onClick={() => route(url)}
6981
extraComponent={<ChevronRightDark/>} />
82+
{upgradeDot}
7083
</div>
7184
);
7285
}
@@ -77,18 +90,41 @@ export const Tab = ({ name, url, hideMobileMenu }: TTab) => {
7790
to={url}
7891
key={url}>
7992
{name}
93+
{upgradeDot}
8094
</NavLink>
8195
);
8296
};
8397

98+
type TTabWithVersionCheck = TTab & {
99+
deviceID: string;
100+
}
101+
102+
const TabWithVersionCheck = ({ deviceID, ...props }: TTabWithVersionCheck) => {
103+
104+
const versionInfo = useLoad(() => getVersion(deviceID), [deviceID]);
105+
106+
return (
107+
<Tab
108+
canUpgrade={versionInfo ? versionInfo.canUpgrade : false}
109+
{...props}
110+
/>
111+
);
112+
};
113+
84114
export const Tabs = ({ deviceIDs, hideMobileMenu, hasAccounts }: TTabs) => {
85115
const { t } = useTranslation();
86116
return (
87117
<div className={styles.container}>
88118
<Tab key="appearance" hideMobileMenu={hideMobileMenu} name={t('settings.appearance')} url="/settings/appearance" />
89119
{hasAccounts ? <Tab key="manage-accounts" hideMobileMenu={hideMobileMenu} name={t('manageAccounts.title')} url="/settings/manage-accounts" /> : null}
90120
{deviceIDs.map(id => (
91-
<Tab hideMobileMenu={hideMobileMenu} name={t('sidebar.device')} key={`device-${id}`} url={`/settings/device-settings/${id}`} />
121+
<TabWithVersionCheck
122+
key={`device-${id}`}
123+
deviceID={id}
124+
hideMobileMenu={hideMobileMenu}
125+
name={t('sidebar.device')}
126+
url={`/settings/device-settings/${id}`}
127+
/>
92128
)) }
93129
<Tab key="advanced-settings" hideMobileMenu={hideMobileMenu} name={t('settings.advancedSettings')} url="/settings/advanced-settings" />
94130
<Tab key="about" hideMobileMenu={hideMobileMenu} name={t('settings.about')} url="/settings/about" />

0 commit comments

Comments
 (0)