Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

91 feat add a persistence layer to store the address #102

Merged
2 changes: 1 addition & 1 deletion apps/sample-angular-app/src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<vwk-connect-button-with-modal mode="DARK"></vwk-connect-button-with-modal>
<vwk-vechain-dapp-connect-kit mode="DARK"></vwk-vechain-dapp-connect-kit>
4 changes: 2 additions & 2 deletions apps/sample-vanilla-app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
<script crossorigin type="module" src="index.js"></script>
</head>
<body>
<vwk-connect-button-with-modal
<vwk-vechain-dapp-connect-kit
mode="DARK"
></vwk-connect-button-with-modal>
></vwk-vechain-dapp-connect-kit>
</body>
</html>
4 changes: 2 additions & 2 deletions apps/sample-vue-app/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
<ConnexProvider>
<img alt="Vue logo" src="./assets/logo.png" />
<div id="app">
<vwk-connect-button-with-modal
<vwk-vechain-dapp-connect-kit
mode="DARK"
></vwk-connect-button-with-modal>
></vwk-vechain-dapp-connect-kit>
</div>
</ConnexProvider>
</template>
Expand Down
1 change: 1 addition & 0 deletions packages/dapp-kit-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"watch": "tsup --watch"
},
"dependencies": {
"@lit/context": "^1.1.0",
"@vechain/picasso": "2.1.1",
"@vechainfoundation/dapp-kit": "*",
"@wagmi/core": "^1.4.5",
Expand Down
4 changes: 4 additions & 0 deletions packages/dapp-kit-ui/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import './base';
import './provider';
import './vwk-connect-modal';
import './vwk-connect-button';
import './vwk-connect-button-with-modal';
Expand All @@ -8,8 +9,10 @@ import './vwk-connected-address-badge-with-modal';
import './vwk-source-card';
import './vwk-fonts';
import './vwk-wallet-connect-qrcode';
import './vwk-vechain-dapp-connect-kit';

export * from './base';
export * from './provider';
export * from './vwk-connect-modal';
export * from './vwk-connect-button';
export * from './vwk-connect-button-with-modal';
Expand All @@ -19,3 +22,4 @@ export * from './vwk-connected-address-badge-with-modal';
export * from './vwk-source-card';
export * from './vwk-fonts';
export * from './vwk-wallet-connect-qrcode';
export * from './vwk-vechain-dapp-connect-kit';
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { provide } from '@lit/context';
import { LitElement, type TemplateResult, html } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import {
type DappKitContext,
dappKitContext,
getDappKitContext,
} from '../dapp-kit-context';

@customElement('dapp-kit-context-provider')
export class DappKitContextProvider extends LitElement {
@provide({ context: dappKitContext })
@property({ attribute: false })
dappKitContext: DappKitContext = {
options: {
notPersistentContext: false,
},
address: '',
};

@property({ type: Boolean })
notPersistentContext = false;

// Use the `connectedCallback` lifecycle hook to retrieve the stored address
connectedCallback(): void {
super.connectedCallback();
this.dappKitContext = getDappKitContext(this.notPersistentContext);
}

render(): TemplateResult {
return html`<slot></slot>`;
}
}

declare global {
interface HTMLElementTagNameMap {
'dapp-kit-context-provider': DappKitContextProvider;
}
}
44 changes: 44 additions & 0 deletions packages/dapp-kit-ui/src/components/provider/dapp-kit-context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { createContext } from '@lit/context';

interface DappKitContextOptions {
notPersistentContext: boolean;
}

interface DappKitContext {
options: DappKitContextOptions;
address: string;
}

const dappKitContext = createContext<DappKitContext>(
Symbol('dapp-kit-context'),
);

const storeDappKitContext = function (context: DappKitContext): void {
localStorage.setItem('dapp-kit-context-object', JSON.stringify(context));
};

const getDappKitContext = function (
notPersistentContext = false,
): DappKitContext {
const dappKitContextObject = localStorage.getItem(
'dapp-kit-context-object',
);

if (notPersistentContext || !dappKitContextObject) {
return {
options: {
notPersistentContext,
},
address: '',
};
}

return JSON.parse(dappKitContextObject) as DappKitContext;
};

export {
dappKitContext,
type DappKitContext,
storeDappKitContext,
getDappKitContext,
};
2 changes: 2 additions & 0 deletions packages/dapp-kit-ui/src/components/provider/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './dapp-kit-context';
export * from './dapp-kit-context-provider';
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import type { TemplateResult } from 'lit';
import { html, LitElement } from 'lit';
import { consume } from '@lit/context';
import { LitElement, type TemplateResult, html } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import type { WalletManager } from '@vechainfoundation/dapp-kit';
import type { SourceInfo, Theme, ThemeMode } from '../../constants';
import { dappKitContext, storeDappKitContext } from '../provider';
import { DAppKit } from '../../client';
import type { SourceInfo, Theme, ThemeMode } from '../../constants';

@customElement('vwk-connect-button-with-modal')
export class ConnectButtonWithModal extends LitElement {
@consume({ context: dappKitContext })
@property({ attribute: false })
dappKitContext = {
options: {
notPersistentContext: false,
},
address: '',
};

@property()
override title = 'Connect Wallet';

Expand All @@ -19,9 +29,6 @@ export class ConnectButtonWithModal extends LitElement {
@property({ type: Boolean })
open = false;

@property({ type: String })
address?: string;

private get wallet(): WalletManager {
return DAppKit.connex.wallet;
}
Expand All @@ -32,8 +39,9 @@ export class ConnectButtonWithModal extends LitElement {
this.wallet.setSource(source.id);
this.wallet
.connect()
// eslint-disable-next-line no-console
.then((res) => (this.address = res.account))
.then((res) => {
this.updateAddress(res.account);
})
.finally(() => {
this.open = false;
});
Expand All @@ -43,20 +51,19 @@ export class ConnectButtonWithModal extends LitElement {
@property({ type: Function })
onDisconnectClick = (): void => {
this.wallet.disconnect().finally(() => {
this.address = undefined;
this.updateAddress('');
});
};

override render(): TemplateResult {
return html`
<div>
<vwk-fonts></vwk-fonts>

${this.address
${this.dappKitContext.address
? html`<vwk-connected-address-badge-with-modal
.mode=${this.mode}
.theme=${this.theme}
.address=${this.address}
.address=${this.dappKitContext.address}
.onDisconnectClick=${this.onDisconnectClick}
></vwk-connected-address-badge-with-modal>`
: html`<vwk-connect-button
Expand All @@ -76,6 +83,17 @@ export class ConnectButtonWithModal extends LitElement {
`;
}

private updateAddress = (address: string): void => {
this.dappKitContext.address = address;

// store the context object in local storage if the context is persistent
if (!this.dappKitContext.options.notPersistentContext) {
storeDappKitContext(this.dappKitContext);
}
// render the component again after the address is updated
this.requestUpdate();
};

private handleOpen = (): void => {
DAppKit.connex.wallet.disconnect().finally(() => {
this.open = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,19 @@ export class ConnectModal extends LitElement {
color: ${Colors.LightGrey};
}
`;

@property({ type: Boolean })
open = false;

@property({ type: Function })
onSourceClick?: (source?: SourceInfo) => void = undefined;

@property()
mode: ThemeMode = 'LIGHT';

@property()
theme: Theme = 'DEFAULT';

@property()
walletConnectQRcode?: string = undefined;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { LitElement, css, html } from 'lit';
import { LitElement, type TemplateResult, css, html } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { Colors, ThemeMode } from '../../constants';
import { Colors, type ThemeMode } from '../../constants';
import { friendlyAddress, getPicassoImage } from '../../utils/account';

@customElement('vwk-connected-address-badge')
Expand Down Expand Up @@ -57,7 +57,7 @@ export class ConnectedAddressBadge extends LitElement {
@property({ type: Function })
onClick? = undefined;

render() {
render(): TemplateResult {
return html` <div
class="wallet-badge ${this.mode}"
@click=${this.onClick}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { LitElement, type TemplateResult, html } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import type { Theme, ThemeMode } from '../../constants';

@customElement('vwk-vechain-dapp-connect-kit')
export class VechainDappConnectKit extends LitElement {
@property({ type: String })
mode: ThemeMode = 'LIGHT';

@property({ type: String })
theme: Theme = 'DEFAULT';

@property({ type: Boolean })
notPersistentContext = false;

render(): TemplateResult {
return html`<dapp-kit-context-provider
?notPersistentContext=${this.notPersistentContext}
><vwk-connect-button-with-modal
mode="DARK"
></vwk-connect-button-with-modal
></dapp-kit-context-provider>`;
}
}

declare global {
interface HTMLElementTagNameMap {
'vwk-vechain-dapp-connect-kit': VechainDappConnectKit;
}
}
5 changes: 3 additions & 2 deletions packages/dapp-kit-ui/test/connect-button-with-modal.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ describe('connect-button-with-modal', () => {
// testing the connected address badge

// mock a connection to the wallet by setting the address
element.address = '0x00000';
element.dappKitContext.address = '0x00000';
element.requestUpdate();

const connectedAddressBadgeWithModal =
(await elementQueries.getConnectedAddressBadgeWithModal()) as ConnectedAddressBadgeWithModal;
Expand All @@ -87,6 +88,6 @@ describe('connect-button-with-modal', () => {

await element.updateComplete;

expect(element.address).toBeUndefined();
expect(element.dappKitContext.address).toBe('');
});
});
12 changes: 12 additions & 0 deletions packages/dapp-kit-ui/test/helpers/element-queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
ConnectedAddressBadge,
ConnectedAddressBadgeWithModal,
ConnectedAddressModal,
DappKitContextProvider,
SourceCard,
} from '../../src';

Expand Down Expand Up @@ -53,6 +54,16 @@ const getConnectedAddressBadgeWithModal = (
);
};

const getDappKitContextProvider = (): Promise<
DappKitContextProvider | undefined | null
> => {
return performQueryWithTimeout(2000, () =>
window.document.body
.querySelector('vwk-vechain-dapp-connect-kit')
?.shadowRoot?.querySelector('dapp-kit-context-provider'),
);
};

const getConnectedAddressBadge = (
timeout = 2000,
): Promise<ConnectedAddressBadge | undefined | null> => {
Expand Down Expand Up @@ -115,4 +126,5 @@ export const elementQueries = {
getConnectedAddressBadgeWithModal,
getConnectedAddressBadge,
getConnectedAddressModal,
getDappKitContextProvider,
};
34 changes: 34 additions & 0 deletions packages/dapp-kit-ui/test/vechain-dapp-connect-kit.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { beforeEach, describe, expect, it } from 'vitest';

import { DAppKit, DappKitContextProvider, VechainDappConnectKit } from '../src';
import { elementQueries } from './helpers/element-queries';

describe('connect-button-with-modal', () => {
beforeEach(() => {
DAppKit.configure({ nodeUrl: 'https://mainnet.vechain.org/' });
});

it('Should callback with source when user clicks a wallet and should render the connected address badge once connected', async () => {
const element: VechainDappConnectKit = window.document.createElement(
'vwk-vechain-dapp-connect-kit',
);

window.document.body.appendChild(element);

// testing the dapp kit context provider

// set a not persistent context
element.notPersistentContext = true;

const dappKitContextProvider =
(await elementQueries.getDappKitContextProvider()) as DappKitContextProvider;

expect(dappKitContextProvider).toBeDefined();

// check if the context is not persistent
expect(dappKitContextProvider.notPersistentContext).toBe(true);

expect(dappKitContextProvider.dappKitContext).toBeDefined();
expect(dappKitContextProvider.dappKitContext.address).toBe('');
});
});
Loading
Loading