Skip to content

Commit 61849b9

Browse files
1.23.0-0.1.0: [feature] Adds optional terms agreement (#531)
* Adds optional terms agreement
1 parent a4bce1b commit 61849b9

File tree

11 files changed

+139
-21
lines changed

11 files changed

+139
-21
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "bnc-onboard",
3-
"version": "1.23.0",
3+
"version": "1.23.0-0.1.0",
44
"description": "Onboard users to web3 by allowing them to select a wallet, get that wallet ready to transact and have access to synced wallet state.",
55
"keywords": [
66
"ethereum",

src/components/Wallets.svelte

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import { onDestroy } from 'svelte'
33
import Button from '../elements/Button.svelte'
44
import IconButton from '../elements/IconButton.svelte'
5-
import { wallet } from '../stores'
5+
import { app, wallet } from '../stores'
66
import {
77
WalletSelectModalData,
88
WalletModule,
@@ -68,6 +68,7 @@
6868
{#each modalData.primaryWallets as wallet, i (wallet.name)}
6969
<li>
7070
<IconButton
71+
disabled={!$app.termsAgreed}
7172
onclick={() => handleWalletSelect(wallet)}
7273
iconSrc={wallet.iconSrc}
7374
iconSrcSet={wallet.iconSrcSet}
@@ -80,14 +81,15 @@
8081

8182
{#if modalData.secondaryWallets && modalData.secondaryWallets.length && !showingAllWalletModules}
8283
<div>
83-
<Button onclick={showAllWallets}>Show More</Button>
84+
<Button disabled={!$app.termsAgreed} onclick={showAllWallets}>Show More</Button>
8485
</div>
8586
{/if}
8687

8788
{#if showingAllWalletModules}
8889
{#each modalData.secondaryWallets as wallet, i (wallet.name)}
8990
<li>
9091
<IconButton
92+
disabled={!$app.termsAgreed}
9193
onclick={() => handleWalletSelect(wallet)}
9294
iconSrc={wallet.iconSrc}
9395
iconSrcSet={wallet.iconSrcSet}

src/constants.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { StorageKeys } from './interfaces'
2+
3+
export const STORAGE_KEYS: StorageKeys = {
4+
TERMS_AGREED: 'onboard.js:termsAgreed'
5+
}

src/elements/Button.svelte

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { app } from '../stores'
33
export let onclick: () => void = () => {}
44
export let position: string
5+
export let disabled: boolean = false
56
</script>
67

78
<style>
@@ -17,6 +18,8 @@
1718
font-family: inherit;
1819
transition: background 150ms ease-in-out;
1920
line-height: 1.15;
21+
opacity: 1;
22+
transition: opacity 200ms;
2023
}
2124
2225
button:focus {
@@ -35,10 +38,18 @@
3538
position: absolute;
3639
left: 0;
3740
}
41+
42+
.disabled {
43+
cursor: inherit;
44+
pointer-events: none;
45+
opacity: .4;
46+
}
3847
</style>
3948

4049
<button
4150
on:click={onclick}
51+
{disabled}
52+
class:disabled
4253
class="bn-onboard-custom bn-onboard-prepare-button"
4354
class:bn-onboard-prepare-button-right={position === 'right'}
4455
class:bn-onboard-prepare-button-left={position === 'left'}

src/elements/IconButton.svelte

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
export let text: string
99
export let loadingWallet: string | undefined
1010
export let currentlySelected: boolean = false
11+
export let disabled: boolean = false
1112
</script>
1213

1314
<style>
@@ -27,6 +28,14 @@
2728
color: inherit;
2829
line-height: 1.15;
2930
font-family: inherit;
31+
opacity: 1;
32+
transition: opacity 200ms;
33+
}
34+
35+
.disabled {
36+
cursor: inherit;
37+
pointer-events: none;
38+
opacity: .4;
3039
}
3140
3241
button:hover {
@@ -86,6 +95,8 @@
8695

8796
<button
8897
on:click={onclick}
98+
{disabled}
99+
class:disabled
89100
class="bn-onboard-custom bn-onboard-icon-button"
90101
class:bn-onboard-dark-mode-background-hover={$app.darkMode}
91102
class:bn-onboard-selected-wallet={currentlySelected}>

src/interfaces.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,17 @@ export interface WalletSelectModuleOptions {
2323
description?: string
2424
wallets?: Array<WalletModule | WalletInitOptions>
2525
explanation?: string
26+
termsOfServiceUrl?: string
27+
privacyPolicyUrl?: string
2628
}
2729

2830
export interface WalletSelectModule {
2931
heading: string
3032
description: string
3133
wallets: Array<WalletModule | WalletInitOptions>
3234
explanation?: string
35+
termsOfServiceUrl: string
36+
privacyPolicyUrl: string
3337
}
3438

3539
export interface WalletCheckModule {
@@ -480,8 +484,13 @@ export interface AppState {
480484
walletSelectDisplayedUI: boolean
481485
walletCheckDisplayedUI: boolean
482486
displayBranding: boolean
487+
termsAgreed: boolean
483488
}
484489

485490
export interface CancelablePromise extends Promise<any> {
486491
cancel: () => void
487492
}
493+
494+
export interface StorageKeys {
495+
TERMS_AGREED: string
496+
}

src/modules/index.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,32 @@ const defaultWalletExplanation = `Wallets are used to send, receive, and store d
1212

1313
export default function initializeModules(
1414
networkId: number,
15-
walletSelect: WalletSelectModuleOptions | undefined,
15+
walletSelectOptions: WalletSelectModuleOptions | undefined,
1616
walletCheck: Array<WalletCheckModule | WalletCheckInit> | undefined,
1717
isMobile: boolean
1818
) {
1919
const wallets = select(
20-
walletSelect && walletSelect.wallets,
20+
walletSelectOptions && walletSelectOptions.wallets,
2121
networkId,
2222
isMobile
2323
)
2424

25+
const {
26+
heading = defaultHeading,
27+
description = defaultDescription,
28+
explanation = defaultWalletExplanation,
29+
termsOfServiceUrl = '',
30+
privacyPolicyUrl = ''
31+
} = walletSelectOptions || {}
32+
2533
return {
2634
walletSelect: {
27-
heading: (walletSelect && walletSelect.heading) || defaultHeading,
28-
description:
29-
(walletSelect && walletSelect.description) || defaultDescription,
35+
heading,
36+
description,
3037
wallets,
31-
explanation:
32-
(walletSelect && walletSelect.explanation) || defaultWalletExplanation
38+
explanation,
39+
termsOfServiceUrl,
40+
privacyPolicyUrl
3341
},
3442
walletCheck: check(walletCheck, networkId)
3543
}

src/onboard.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
} from './interfaces'
3232

3333
import initializeModules from './modules'
34+
import { STORAGE_KEYS } from './constants'
3435

3536
let onboard: any
3637

@@ -77,6 +78,13 @@ function init(initialization: Initialization): API {
7778
displayBranding = false
7879
}
7980
}
81+
const { termsOfServiceUrl, privacyPolicyUrl } =
82+
initialization.walletSelect || {}
83+
84+
const termsAgreed =
85+
termsOfServiceUrl || privacyPolicyUrl
86+
? localStorage.getItem(STORAGE_KEYS.TERMS_AGREED) == 'true'
87+
: true
8088

8189
app.update((store: AppState) => ({
8290
...store,
@@ -91,7 +99,8 @@ function init(initialization: Initialization): API {
9199
darkMode,
92100
displayBranding,
93101
checkModules: initializedModules.walletCheck,
94-
blockPollingInterval
102+
blockPollingInterval,
103+
termsAgreed
95104
}))
96105

97106
initializeStores()

src/stores.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ export const app: WritableStore = writable({
3434
walletSelectDisplayedUI: false,
3535
walletCheckDisplayedUI: false,
3636
displayBranding: false,
37-
blockPollingInterval: 4000
37+
blockPollingInterval: 4000,
38+
termsAgreed: false
3839
})
3940

4041
export const stateSyncStatus: {

src/validation.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,12 +202,21 @@ function validateWalletSelect(
202202
description,
203203
explanation,
204204
wallets,
205+
termsOfServiceUrl,
206+
privacyPolicyUrl,
205207
...otherParams
206208
} = walletSelect
207209

208210
invalidParams(
209211
otherParams,
210-
['heading', 'description', 'explanation', 'wallets'],
212+
[
213+
'heading',
214+
'description',
215+
'explanation',
216+
'termsOfServiceUrl',
217+
'privacyPolicyUrl',
218+
'wallets'
219+
],
211220
'walletSelect'
212221
)
213222

@@ -232,6 +241,20 @@ function validateWalletSelect(
232241
optional: true
233242
})
234243

244+
validateType({
245+
name: 'termsOfServiceUrl',
246+
value: termsOfServiceUrl,
247+
type: 'string',
248+
optional: true
249+
})
250+
251+
validateType({
252+
name: 'privacyPolicyUrl',
253+
value: privacyPolicyUrl,
254+
type: 'string',
255+
optional: true
256+
})
257+
235258
if (Array.isArray(wallets)) {
236259
wallets.forEach(validateWallet)
237260
}

src/views/WalletSelect.svelte

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,22 +29,42 @@
2929
WalletSelectModule,
3030
WalletInterface
3131
} from '../interfaces'
32+
import { STORAGE_KEYS } from '../constants'
3233
3334
export let module: WalletSelectModule = {
3435
heading: '',
3536
description: '',
37+
termsOfServiceUrl: '',
38+
privacyPolicyUrl: '',
3639
wallets: []
3740
}
3841
3942
let modalData: WalletSelectModalData | null
4043
let showWalletDefinition: boolean
4144
let walletAlreadyInstalled: string | undefined
42-
let installMessage: string | undefined
45+
let installMessage: string
4346
4447
let selectedWalletModule: WalletModule
4548
4649
const { mobileDevice, os } = get(app)
47-
let { heading, description, explanation, wallets } = module
50+
let {
51+
heading,
52+
description,
53+
explanation,
54+
termsOfServiceUrl,
55+
privacyPolicyUrl,
56+
wallets
57+
} = module
58+
59+
let showTermsOfService: boolean = !!(termsOfServiceUrl || privacyPolicyUrl) && !get(app).termsAgreed
60+
61+
$: {
62+
if ($app.termsAgreed) {
63+
localStorage.setItem(STORAGE_KEYS.TERMS_AGREED, 'true')
64+
} else {
65+
localStorage.removeItem(STORAGE_KEYS.TERMS_AGREED)
66+
}
67+
}
4868
4969
let primaryWallets: WalletModule[]
5070
let secondaryWallets: WalletModule[] | undefined
@@ -159,12 +179,12 @@
159179
160180
walletAlreadyInstalled = provider && getProviderName(provider)
161181
162-
installMessage =
163-
module.installMessage &&
164-
module.installMessage({
165-
currentWallet: walletAlreadyInstalled,
166-
selectedWallet: selectedWalletModule.name
167-
})
182+
installMessage = module.installMessage
183+
? module.installMessage({
184+
currentWallet: walletAlreadyInstalled,
185+
selectedWallet: selectedWalletModule.name
186+
})
187+
: ''
168188
169189
// if it was autoSelected then we need to add modalData to show the modal
170190
if (autoSelected) {
@@ -236,11 +256,30 @@
236256
margin-top: 0.66em;
237257
cursor: pointer;
238258
}
259+
.terms-of-service {
260+
display: flex;
261+
align-items: center;
262+
}
263+
.terms-of-service-check-box {
264+
margin-right: 7px;
265+
}
239266
</style>
240267

241268
{#if modalData}
242269
<Modal closeModal={() => finish({ completed: false })}>
243270
<ModalHeader icon={walletIcon} heading={modalData.heading} />
271+
{#if showTermsOfService}
272+
<p>
273+
<label class="terms-of-service">
274+
<input class="terms-of-service-check-box" type="checkbox" bind:checked={$app.termsAgreed} />
275+
<span>
276+
I agree to the
277+
{#if termsOfServiceUrl}<a href={termsOfServiceUrl} target="_blank">Terms & Conditions</a>{privacyPolicyUrl ? ' and' : '.'} {/if}
278+
{#if privacyPolicyUrl}<a href={privacyPolicyUrl} target="_blank">Privacy Policy</a>.{/if}
279+
</span>
280+
</label>
281+
</p>
282+
{/if}
244283
{#if !selectedWalletModule}
245284
<p class="bn-onboard-custom bn-onboard-select-description">
246285
{@html modalData.description}

0 commit comments

Comments
 (0)