From 0dbdeb8c42bc645bc21255afa20746c1cbe71751 Mon Sep 17 00:00:00 2001 From: tomiir Date: Wed, 3 Jan 2024 08:57:42 -0600 Subject: [PATCH] fix: email + UI responsive issues (#1676) --- .../composites/wui-account-button.stories.ts | 6 +- .../src/modal/w3m-account-button/index.ts | 6 ++ .../scaffold/src/modal/w3m-button/index.ts | 6 ++ .../partials/w3m-email-login-widget/index.ts | 35 +++++------ .../partials/w3m-email-login-widget/styles.ts | 2 +- .../scaffold/src/partials/w3m-header/index.ts | 5 +- .../w3m-email-verify-device-view/index.ts | 2 +- .../views/w3m-email-verify-otp-view/index.ts | 58 +++++++++++++++---- .../index.ts | 2 +- .../composites/wui-account-button/index.ts | 19 +++--- .../composites/wui-account-button/styles.ts | 7 ++- .../composites/wui-connect-button/styles.ts | 11 ++++ .../composites/wui-input-numeric/styles.ts | 7 ++- .../ui/src/composites/wui-input-text/index.ts | 2 +- .../src/composites/wui-input-text/styles.ts | 2 +- packages/ui/src/composites/wui-otp/index.ts | 47 ++++++++++----- packages/ui/src/utils/ThemeUtil.ts | 2 +- packages/wallet/src/W3mFrameHelpers.ts | 18 +++++- 18 files changed, 170 insertions(+), 67 deletions(-) diff --git a/apps/gallery/stories/composites/wui-account-button.stories.ts b/apps/gallery/stories/composites/wui-account-button.stories.ts index eb23ce53eb..6d52082e4c 100644 --- a/apps/gallery/stories/composites/wui-account-button.stories.ts +++ b/apps/gallery/stories/composites/wui-account-button.stories.ts @@ -14,7 +14,9 @@ export default { avatarSrc: avatarImageSrc, address, balance: '0.527 ETH', - isProfileName: false + isProfileName: false, + charsStart: 4, + charsEnd: 6 }, argTypes: { disabled: { @@ -35,5 +37,7 @@ export const Default: Component = { .avatarSrc=${args.avatarSrc} .balance=${args.balance} address=${args.address} + .charsStart=${args.charsStart} + .charsEnd=${args.charsEnd} >` } diff --git a/packages/scaffold/src/modal/w3m-account-button/index.ts b/packages/scaffold/src/modal/w3m-account-button/index.ts index d2bb3b3d2c..f2b5741fba 100644 --- a/packages/scaffold/src/modal/w3m-account-button/index.ts +++ b/packages/scaffold/src/modal/w3m-account-button/index.ts @@ -21,6 +21,10 @@ export class W3mAccountButton extends LitElement { @property() public balance?: 'show' | 'hide' = 'show' + @property() public charsStart?: WuiAccountButton['charsStart'] = 4 + + @property() public charsEnd?: WuiAccountButton['charsEnd'] = 6 + @state() private address = AccountController.state.address @state() private balanceVal = AccountController.state.balance @@ -79,6 +83,8 @@ export class W3mAccountButton extends LitElement { : ''} @click=${this.onClick.bind(this)} data-testid="account-button" + .charsStart=${this.charsStart} + .charsEnd=${this.charsEnd} > ` diff --git a/packages/scaffold/src/modal/w3m-button/index.ts b/packages/scaffold/src/modal/w3m-button/index.ts index 5c42549070..bdeb34d3b2 100644 --- a/packages/scaffold/src/modal/w3m-button/index.ts +++ b/packages/scaffold/src/modal/w3m-button/index.ts @@ -22,6 +22,10 @@ export class W3mButton extends LitElement { @property() public loadingLabel?: W3mConnectButton['loadingLabel'] = undefined + @property() public charsStart?: W3mAccountButton['charsStart'] = 4 + + @property() public charsEnd?: W3mAccountButton['charsEnd'] = 6 + @state() private isAccount = AccountController.state.isConnected // -- Lifecycle ----------------------------------------- // @@ -45,6 +49,8 @@ export class W3mButton extends LitElement { ` diff --git a/packages/scaffold/src/partials/w3m-email-login-widget/index.ts b/packages/scaffold/src/partials/w3m-email-login-widget/index.ts index 3aa222b2b9..31ebd44abd 100644 --- a/packages/scaffold/src/partials/w3m-email-login-widget/index.ts +++ b/packages/scaffold/src/partials/w3m-email-login-widget/index.ts @@ -1,4 +1,4 @@ -import { ConnectorController } from '@web3modal/core' +import { ConnectorController, CoreHelperUtil } from '@web3modal/core' import { customElement } from '@web3modal/ui' import { LitElement, html } from 'lit' import { state } from 'lit/decorators.js' @@ -23,6 +23,8 @@ export class W3mEmailLoginWidget extends LitElement { @state() private loading = false + @state() private error = '' + public constructor() { super() this.unsubscribe.push( @@ -57,10 +59,11 @@ export class W3mEmailLoginWidget extends LitElement { - ${showSubmit && multipleConnectors + ${showSubmit ? html` ` : null} - ${this.loading && multipleConnectors + ${this.loading ? html`` : null} - ${multipleConnectors - ? html`` - : html` - Continue - `} + ${multipleConnectors ? html`` : null} ` } // -- Private ------------------------------------------- // private onEmailInputChange(event: CustomEvent) { this.email = event.detail + this.error = '' } private async onSubmitEmail(event: Event) { @@ -103,7 +96,6 @@ export class W3mEmailLoginWidget extends LitElement { if (this.loading) { return } - this.loading = true event.preventDefault() const emailConnector = ConnectorController.getEmailConnector() @@ -111,15 +103,20 @@ export class W3mEmailLoginWidget extends LitElement { if (!emailConnector) { throw new Error('w3m-email-login-widget: Email connector not found') } - const { action } = await emailConnector.provider.connectEmail({ email: this.email }) if (action === 'VERIFY_OTP') { RouterController.push('EmailVerifyOtp', { email: this.email }) } else if (action === 'VERIFY_DEVICE') { RouterController.push('EmailVerifyDevice', { email: this.email }) } - } catch (error) { - SnackController.showError(error) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } catch (error: any) { + const parsedError = CoreHelperUtil.parseError(error) + if (parsedError?.includes('Invalid email')) { + this.error = 'Invalid email. Try again.' + } else { + SnackController.showError(error) + } } finally { this.loading = false } diff --git a/packages/scaffold/src/partials/w3m-email-login-widget/styles.ts b/packages/scaffold/src/partials/w3m-email-login-widget/styles.ts index b1b94cf3d8..24d55138fb 100644 --- a/packages/scaffold/src/partials/w3m-email-login-widget/styles.ts +++ b/packages/scaffold/src/partials/w3m-email-login-widget/styles.ts @@ -24,7 +24,7 @@ export default css` wui-icon-link, wui-loading-spinner { position: absolute; - top: 50%; + top: 20px; transform: translateY(-50%); } diff --git a/packages/scaffold/src/partials/w3m-header/index.ts b/packages/scaffold/src/partials/w3m-header/index.ts index 1290b8b150..656865c384 100644 --- a/packages/scaffold/src/partials/w3m-header/index.ts +++ b/packages/scaffold/src/partials/w3m-header/index.ts @@ -1,6 +1,7 @@ import type { RouterControllerState } from '@web3modal/core' import { ConnectionController, + ConnectorController, EventsController, ModalController, RouterController, @@ -17,9 +18,11 @@ function headings() { const walletName = RouterController.state.data?.wallet?.name const networkName = RouterController.state.data?.network?.name const name = walletName ?? connectorName + const connectors = ConnectorController.getConnectors() + const isEmail = connectors.length === 1 && connectors[0]?.id === 'w3m-email' return { - Connect: 'Connect Wallet', + Connect: `Connect ${isEmail ? 'Email' : ''} Wallet`, Account: undefined, ConnectingExternal: name ?? 'Connect Wallet', ConnectingWalletConnect: name ?? 'WalletConnect', diff --git a/packages/scaffold/src/views/w3m-email-verify-device-view/index.ts b/packages/scaffold/src/views/w3m-email-verify-device-view/index.ts index 4ae51e35f5..f98239228d 100644 --- a/packages/scaffold/src/views/w3m-email-verify-device-view/index.ts +++ b/packages/scaffold/src/views/w3m-email-verify-device-view/index.ts @@ -86,7 +86,7 @@ export class W3mEmailVerifyDeviceView extends LitElement { } this.loading = true await this.emailConnector.provider.connectEmail({ email: this.email }) - SnackController.showSuccess('New Email sent') + SnackController.showSuccess('Code email resent') } } catch (error) { SnackController.showError(error) diff --git a/packages/scaffold/src/views/w3m-email-verify-otp-view/index.ts b/packages/scaffold/src/views/w3m-email-verify-otp-view/index.ts index 54737d8c1f..ad27cff523 100644 --- a/packages/scaffold/src/views/w3m-email-verify-otp-view/index.ts +++ b/packages/scaffold/src/views/w3m-email-verify-otp-view/index.ts @@ -6,10 +6,12 @@ import { ModalController, EventsController, ConnectionController, - ConnectorController + ConnectorController, + CoreHelperUtil } from '@web3modal/core' import { state } from 'lit/decorators.js' import styles from './styles.js' +import { W3mFrameHelpers } from '@web3modal/wallet' // -- Helpers ------------------------------------------- // const OTP_LENGTH = 6 @@ -26,12 +28,28 @@ export class W3mEmailVerifyOtpView extends LitElement { // -- State & Properties -------------------------------- // @state() private loading = false + @state() private timeoutTimeLeft = W3mFrameHelpers.getTimeToNextEmailLogin() + + @state() private error = '' + + private OTPTimeout: NodeJS.Timeout | undefined + + public override firstUpdated() { + this.startOTPTimeout() + } + + public override disconnectedCallback() { + clearTimeout(this.OTPTimeout) + } + // -- Render -------------------------------------------- // public override render() { if (!this.email) { throw new Error('w3m-email-verify-otp-view: No email provided') } + const isResendDisabled = Boolean(this.timeoutTimeLeft) + return html` ` - : html``} + : html` + + ${this.error + ? html`${this.error}. Try Again` + : null} + `} Didn't receive it? - Resend code + + Resend ${isResendDisabled ? `in ${this.timeoutTimeLeft}s` : 'Code'} + ` } // -- Private ------------------------------------------- // + private startOTPTimeout() { + this.OTPTimeout = setInterval(() => { + if (this.timeoutTimeLeft > 0) { + this.timeoutTimeLeft = W3mFrameHelpers.getTimeToNextEmailLogin() + } else { + clearInterval(this.OTPTimeout) + } + }, 1000) + } + private async onOtpInputChange(event: CustomEvent) { try { if (!this.loading) { @@ -80,21 +117,22 @@ export class W3mEmailVerifyOtpView extends LitElement { } } } catch (error) { - SnackController.showError(error) + this.error = CoreHelperUtil.parseError(error) this.loading = false } } private async onResendCode() { try { - if (!this.loading) { + if (!this.loading && !this.timeoutTimeLeft) { const emailConnector = ConnectorController.getEmailConnector() if (!emailConnector || !this.email) { throw new Error('w3m-email-login-widget: Unable to resend email') } this.loading = true await emailConnector.provider.connectEmail({ email: this.email }) - SnackController.showSuccess('New Email sent') + this.startOTPTimeout() + SnackController.showSuccess('Code email resent') } } catch (error) { SnackController.showError(error) diff --git a/packages/scaffold/src/views/w3m-update-email-wallet-waiting-view/index.ts b/packages/scaffold/src/views/w3m-update-email-wallet-waiting-view/index.ts index bdc82cee39..349d290716 100644 --- a/packages/scaffold/src/views/w3m-update-email-wallet-waiting-view/index.ts +++ b/packages/scaffold/src/views/w3m-update-email-wallet-waiting-view/index.ts @@ -88,7 +88,7 @@ export class W3mUpdateEmailWalletWaitingView extends LitElement { this.loading = true await this.emailConnector.provider.updateEmail({ email: this.email }) this.listenForEmailUpdateApproval() - SnackController.showSuccess('New Email sent') + SnackController.showSuccess('Code email resent') } } catch (error) { SnackController.showError(error) diff --git a/packages/ui/src/composites/wui-account-button/index.ts b/packages/ui/src/composites/wui-account-button/index.ts index fc51c28613..cc3f74674d 100644 --- a/packages/ui/src/composites/wui-account-button/index.ts +++ b/packages/ui/src/composites/wui-account-button/index.ts @@ -28,16 +28,19 @@ export class WuiAccountButton extends LitElement { @property() public address = '' + @property() public charsStart = 4 + + @property() public charsEnd = 6 + // -- Render -------------------------------------------- // public override render() { return html` -