Skip to content

Commit e7caab9

Browse files
committed
Merge branch 'frontend-bip85-route-back'
2 parents c2c2186 + 3a2b80f commit e7caab9

File tree

5 files changed

+216
-181
lines changed

5 files changed

+216
-181
lines changed
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
/**
2+
* Copyright 2024 Shift Crypto AG
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { useState } from 'react';
18+
import { useNavigate } from 'react-router-dom';
19+
import { useTranslation } from 'react-i18next';
20+
import { View, ViewButtons, ViewContent, ViewHeader } from '@/components/view/view';
21+
import { Button, Checkbox } from '@/components/forms';
22+
import { PointToBitBox02 } from '@/components/icon';
23+
import { invokeBIP85 } from '@/api/bitbox02';
24+
import { SimpleMarkup } from '@/utils/markup';
25+
import { A } from '@/components/anchor/anchor';
26+
import { Column, Grid } from '@/components/layout';
27+
import { useDarkmode } from '@/hooks/darkmode';
28+
import { UseDisableBackButton } from '@/hooks/backbutton';
29+
import { BackButton } from '@/components/backbutton/backbutton';
30+
import bip85Graphic from './assets/bip85-graphic.svg';
31+
import bip85GraphicLight from './assets/bip85-graphic-light.svg';
32+
33+
type Status = 'info-what' | 'info-how' | 'info-recover' | 'info-security' | 'progress';
34+
35+
type TProps = {
36+
deviceID: string;
37+
}
38+
39+
export const Bip85 = ({
40+
deviceID,
41+
}: TProps) => {
42+
const navigate = useNavigate();
43+
const { t } = useTranslation();
44+
const { isDarkMode } = useDarkmode();
45+
const [status, setStatus] = useState<Status>('info-what');
46+
const [disclaimer, setDisclaimer] = useState(false);
47+
48+
switch (status) {
49+
case 'info-what':
50+
return (
51+
<View
52+
key="bip85-info-what"
53+
fullscreen
54+
verticallyCentered>
55+
<ViewHeader title={t('deviceSettings.expert.bip85.what.title')} />
56+
<ViewContent minHeight="280px">
57+
<Grid>
58+
<Column>
59+
<p>
60+
{t('deviceSettings.expert.bip85.what.description')}
61+
<br />
62+
<A href="https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki">
63+
{t('deviceSettings.expert.bip85.what.link')}
64+
</A>
65+
<br />
66+
<br />
67+
</p>
68+
</Column>
69+
<Column textCenter>
70+
<img
71+
src={isDarkMode ? bip85GraphicLight : bip85Graphic}
72+
style={{ height: 'auto', width: '100%' }}
73+
width="320"
74+
height="147"
75+
/>
76+
</Column>
77+
</Grid>
78+
</ViewContent>
79+
<ViewButtons>
80+
<Button
81+
primary
82+
onClick={() => setStatus('info-how')}>
83+
{t('button.continue')}
84+
</Button>
85+
<BackButton>
86+
{t('button.back')}
87+
</BackButton>
88+
</ViewButtons>
89+
</View>
90+
);
91+
case 'info-how':
92+
return (
93+
<View
94+
key="bip85-info-how"
95+
fullscreen
96+
verticallyCentered>
97+
<ViewHeader title={t('deviceSettings.expert.bip85.how.title')} />
98+
<ViewContent minHeight="280px">
99+
<SimpleMarkup
100+
tagName="p"
101+
markup={t('deviceSettings.expert.bip85.how.description')} />
102+
</ViewContent>
103+
<ViewButtons>
104+
<Button
105+
primary
106+
onClick={() => setStatus('info-recover')}>
107+
{t('button.continue')}
108+
</Button>
109+
<Button
110+
secondary
111+
onClick={() => setStatus('info-what')}>
112+
{t('button.back')}
113+
</Button>
114+
</ViewButtons>
115+
</View>
116+
);
117+
case 'info-recover':
118+
return (
119+
<View
120+
key="bip85-info-recover"
121+
fullscreen
122+
verticallyCentered>
123+
<ViewHeader title={t('deviceSettings.expert.bip85.recover.title')} />
124+
<ViewContent minHeight="280px">
125+
<SimpleMarkup
126+
tagName="p"
127+
markup={t('deviceSettings.expert.bip85.recover.description')} />
128+
</ViewContent>
129+
<ViewButtons>
130+
<Button
131+
primary
132+
onClick={() => {
133+
setDisclaimer(false);
134+
setStatus('info-security');
135+
}}>
136+
{t('button.continue')}
137+
</Button>
138+
<Button
139+
secondary
140+
onClick={() => setStatus('info-how')}>
141+
{t('button.back')}
142+
</Button>
143+
</ViewButtons>
144+
</View>
145+
);
146+
case 'info-security':
147+
return (
148+
<View
149+
key="bip85-info-security"
150+
fullscreen
151+
verticallyCentered>
152+
<ViewHeader title={t('deviceSettings.expert.bip85.security.title')} />
153+
<ViewContent minHeight="280px">
154+
<p>
155+
{t('deviceSettings.expert.bip85.security.description')}
156+
</p>
157+
<Checkbox
158+
id="understood"
159+
onClick={(e) => setDisclaimer((e.target as HTMLInputElement).checked)}
160+
>
161+
{t('deviceSettings.expert.bip85.disclaimer')}
162+
</Checkbox>
163+
</ViewContent>
164+
<ViewButtons>
165+
<Button
166+
primary
167+
disabled={!disclaimer}
168+
onClick={async () => {
169+
setStatus('progress');
170+
await invokeBIP85(deviceID);
171+
navigate(-1);
172+
}}>
173+
{t('button.proceedOnBitBox')}
174+
</Button>
175+
<Button
176+
secondary
177+
onClick={() => setStatus('info-recover')}>
178+
{t('button.back')}
179+
</Button>
180+
</ViewButtons>
181+
</View>
182+
);
183+
case 'progress':
184+
return (
185+
<View
186+
key="bip85-progress"
187+
fullscreen
188+
textCenter
189+
verticallyCentered>
190+
<UseDisableBackButton />
191+
<ViewHeader title={t('deviceSettings.expert.bip85.title')} />
192+
<ViewContent minHeight="280px">
193+
<PointToBitBox02 />
194+
</ViewContent>
195+
<ViewButtons>
196+
{/* Empty ViewButtons to avoid layout shift when changing between 'info' and 'progress' steps */}
197+
</ViewButtons>
198+
</View>
199+
);
200+
}
201+
};

frontends/web/src/routes/router.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import { ManageBackups } from './device/manage-backups/manage-backups';
3232
import { ManageAccounts } from './settings/manage-accounts';
3333
import { ElectrumSettings } from './settings/electrum';
3434
import { Passphrase } from './device/bitbox02/passphrase';
35+
import { Bip85 } from './device/bitbox02/bip85';
3536
import { Account } from './account/account';
3637
import { ReceiveAccountsSelector } from './accounts/select-receive';
3738
import { General } from './settings/general';
@@ -164,6 +165,7 @@ export const AppRouter = ({ devices, deviceIDs, devicesKey, accounts, activeAcco
164165
</InjectParams>;
165166

166167
const PassphraseEl = <InjectParams><Passphrase deviceID={''} /></InjectParams>;
168+
const Bip85El = <InjectParams><Bip85 deviceID={''} /></InjectParams>;
167169

168170
const ManageBackupsEl = <InjectParams><ManageBackups
169171
key={devicesKey('manage-backups')}
@@ -244,6 +246,7 @@ export const AppRouter = ({ devices, deviceIDs, devicesKey, accounts, activeAcco
244246
<Route path="about" element={AboutEl} />
245247
<Route path="device-settings/:deviceID" element={Device} />
246248
<Route path="device-settings/passphrase/:deviceID" element={PassphraseEl} />
249+
<Route path="device-settings/bip85/:deviceID" element={Bip85El} />
247250
<Route path="advanced-settings" element={AdvancedSettingsEl} />
248251
<Route path="electrum" element={<ElectrumSettings />} />
249252
<Route path="manage-accounts" element={

0 commit comments

Comments
 (0)