From 0fdad1498d5a82636347bc715210d273bfe074de Mon Sep 17 00:00:00 2001 From: Jordan Ribbink Date: Tue, 29 Oct 2024 23:54:37 -0700 Subject: [PATCH] trim and cleanup for prod --- packages/fcl-wc/src/fcl-wc.ts | 3 + packages/fcl-wc/src/request-notification.ts | 25 ------ packages/fcl-wc/src/service.ts | 53 ++++-------- packages/fcl-wc/src/types/types.ts | 2 +- .../fcl-wc/src/ui/components/Notification.tsx | 4 +- packages/fcl-wc/src/ui/hooks/useBreakpoint.ts | 17 ---- packages/fcl-wc/src/ui/notifications.tsx | 84 +++++++++++++------ packages/fcl-wc/src/ui/styles.css | 76 ----------------- 8 files changed, 78 insertions(+), 186 deletions(-) delete mode 100644 packages/fcl-wc/src/request-notification.ts delete mode 100644 packages/fcl-wc/src/ui/hooks/useBreakpoint.ts diff --git a/packages/fcl-wc/src/fcl-wc.ts b/packages/fcl-wc/src/fcl-wc.ts index 875e34131..63fe902d0 100644 --- a/packages/fcl-wc/src/fcl-wc.ts +++ b/packages/fcl-wc/src/fcl-wc.ts @@ -12,6 +12,7 @@ export interface FclWalletConnectConfig { wcRequestHook?: any pairingModalOverride?: any wallets?: any[] + showNotifications?: boolean } const DEFAULT_RELAY_URL = "wss://relay.walletconnect.com" @@ -76,6 +77,7 @@ const initHelper = ({ wcRequestHook = null, pairingModalOverride = null, wallets = [], + showNotifications = true, }: FclWalletConnectConfig) => { if (typeof window === "undefined") { throw new Error( @@ -111,6 +113,7 @@ const initHelper = ({ wcRequestHook, pairingModalOverride, wallets, + showNotifications, }) return { diff --git a/packages/fcl-wc/src/request-notification.ts b/packages/fcl-wc/src/request-notification.ts deleted file mode 100644 index b448b7712..000000000 --- a/packages/fcl-wc/src/request-notification.ts +++ /dev/null @@ -1,25 +0,0 @@ -import {showNotification} from "./ui/notifications" -import {isMobile} from "./utils" -import mobileIcon from "./ui/assets/mobile.png" - -export async function withRequestNotification( - service: any, - user: any, - openDeeplink: (uid: string) => void -) { - const authnService = user?.services?.find((s: any) => s.type === "authn") - const walletProvider = authnService?.provider - - const {close: closePrompt} = showNotification({ - title: walletProvider?.name || "Mobile Wallet", - message: isMobile() - ? "Tap to view request in app" - : "Pending request on your mobile device", - icon: walletProvider?.icon || mobileIcon, - onClick: service.uid - ? () => { - openDeeplink(service.uid) - } - : undefined, - }) -} diff --git a/packages/fcl-wc/src/service.ts b/packages/fcl-wc/src/service.ts index b443a6fbf..c5447db5b 100644 --- a/packages/fcl-wc/src/service.ts +++ b/packages/fcl-wc/src/service.ts @@ -4,10 +4,8 @@ import {isMobile, openDeeplink, shouldDeepLink} from "./utils" import {REQUEST_TYPES} from "./constants" import {SignClient} from "@walletconnect/sign-client/dist/types/client" import {createSessionProposal, request} from "./session" -import {showNotification} from "./ui/notifications" - -import mobileIcon from "./ui/assets/mobile.png" import {ModalCtrlState} from "@walletconnect/modal-core/dist/_types/src/types/controllerTypes" +import {showWcRequestNotification} from "./ui/notifications" type WalletConnectModalType = import("@walletconnect/modal").WalletConnectModal @@ -24,12 +22,14 @@ export const makeServicePlugin = ( wallets: any[] wcRequestHook: any pairingModalOverride: any + showNotifications: boolean } = { projectId: "", includeBaseWC: false, wallets: [], wcRequestHook: null, pairingModalOverride: null, + showNotifications: true, } ) => ({ name: SERVICE_PLUGIN_NAME, @@ -117,21 +117,24 @@ const makeExec = ( openDeeplink(appLink) } - // Wrap the request function with a notification - const requestWithNotification = withRequestNotification(request, { - method, - user, - openDeeplink: () => openDeeplink(appLink), - }) + // Show notification to the user + let dismissNotification = () => {} + if (opts.showNotifications) { + const {dismiss} = showWcRequestNotification({ + user, + service, + }) + dismissNotification = dismiss + } // Make request to the WalletConnect client and return the result - return await requestWithNotification({ + return await request({ method, body, session, client, abortSignal, - }) + }).finally(dismissNotification) function validateAppLink({uid}: {uid: string}) { if (!(uid && /^(ftp|http|https):\/\/[^ "]+$/.test(uid))) { @@ -258,31 +261,3 @@ function connectWc( } } } - -export function withRequestNotification< - T extends (...args: any[]) => Promise, ->( - fn: T, - params: { - method: string - user: any - openDeeplink?: () => void - } -) { - return async (...args: Parameters) => { - const {method, user, openDeeplink} = params - const authnService = user?.services?.find((s: any) => s.type === "authn") - const walletProvider = authnService?.provider - - const {close: dismissNotification} = showNotification({ - title: walletProvider?.name || "Mobile Wallet", - message: isMobile() - ? "Tap to view request in app" - : "Pending request on your mobile device", - icon: walletProvider?.icon || mobileIcon, - onClick: openDeeplink, - }) - - return await fn(...args).finally(dismissNotification) - } -} diff --git a/packages/fcl-wc/src/types/types.ts b/packages/fcl-wc/src/types/types.ts index 4d5382bc2..def2efca5 100644 --- a/packages/fcl-wc/src/types/types.ts +++ b/packages/fcl-wc/src/types/types.ts @@ -3,5 +3,5 @@ export type NotificationInfo = { message: string icon?: string onClick?: () => void - onClose?: () => void + onDismiss?: () => void } diff --git a/packages/fcl-wc/src/ui/components/Notification.tsx b/packages/fcl-wc/src/ui/components/Notification.tsx index db6093657..c53272814 100644 --- a/packages/fcl-wc/src/ui/components/Notification.tsx +++ b/packages/fcl-wc/src/ui/components/Notification.tsx @@ -5,7 +5,7 @@ export function Notification({ message, icon, onClick, - onClose, + onDismiss, }: NotificationInfo) { return (
{ e.stopPropagation() - onClose?.() + onDismiss?.() }} > Close diff --git a/packages/fcl-wc/src/ui/hooks/useBreakpoint.ts b/packages/fcl-wc/src/ui/hooks/useBreakpoint.ts deleted file mode 100644 index bcaacf1c5..000000000 --- a/packages/fcl-wc/src/ui/hooks/useBreakpoint.ts +++ /dev/null @@ -1,17 +0,0 @@ -import {useEffect, useState} from "preact/hooks" - -export function useBreakpoint(breakpoint: number) { - const [matches, setMatches] = useState(false) - - useEffect(() => { - const mediaQuery = window.matchMedia(`(min-width: ${breakpoint}px)`) - const listener = () => setMatches(mediaQuery.matches) - - mediaQuery.addEventListener("change", listener) - listener() - - return () => mediaQuery.removeEventListener("change", listener) - }, [breakpoint]) - - return matches -} diff --git a/packages/fcl-wc/src/ui/notifications.tsx b/packages/fcl-wc/src/ui/notifications.tsx index 4059a370d..e74d115b6 100644 --- a/packages/fcl-wc/src/ui/notifications.tsx +++ b/packages/fcl-wc/src/ui/notifications.tsx @@ -2,16 +2,44 @@ import {render} from "preact" import styles from "./styles.css" import {Notification} from "./components/Notification" import {NotificationInfo} from "../types/types" +import {isMobile, openDeeplink} from "../utils" +import mobileIcon from "./assets/mobile.png" let renderRoot: HTMLElement | null = null let id = 0 -export function showNotification({ +function createRenderRoot() { + const shadowHost = document.createElement("div") + const shadowRoot = shadowHost.attachShadow({mode: "open"}) + const container = document.createElement("div") + + shadowRoot.appendChild(container) + document.body.appendChild(shadowHost) + + const style = document.createElement("style") + style.textContent = styles + shadowRoot.appendChild(style) + + // Subscribe to root dark mode changes to inherit the theme + const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)") + const listener = () => { + container.classList.toggle("dark", mediaQuery.matches) + } + mediaQuery.addEventListener("change", listener) + listener() + + return container +} + +/** + * Show a notification to the user. Only one notification can be shown at a time and will replace any existing notification. + */ +function showNotification({ title, message, icon, onClick, - onClose, + onDismiss, }: NotificationInfo) { if (!renderRoot) { renderRoot = createRenderRoot() @@ -24,43 +52,47 @@ export function showNotification({ message={message} icon={icon} onClick={onClick} - onClose={() => { + onDismiss={() => { close() - onClose?.() + onDismiss?.() }} />, renderRoot ) - function close() { + function dismiss() { if (!renderRoot) return render(null, renderRoot) } return { - close, + dismiss, } } -function createRenderRoot() { - const shadowHost = document.createElement("div") - const shadowRoot = shadowHost.attachShadow({mode: "open"}) - const container = document.createElement("div") +/** + * Show a notification for a WalletConnect request. + * @param service - The service that is requesting the user's attention. + * @param user - The user that is being requested to sign a transaction. + * @param openDeeplink - A function to open the wallet app deeplink. + * @returns A close function to dismiss the notification. + */ +export function showWcRequestNotification({ + service, + user, +}: { + service: any + user: any +}) { + const authnService = user?.services?.find((s: any) => s.type === "authn") + const walletProvider = authnService?.provider - shadowRoot.appendChild(container) - document.body.appendChild(shadowHost) - - const style = document.createElement("style") - style.textContent = styles - shadowRoot.appendChild(style) - - // Subscribe to root dark mode changes to inherit the theme - const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)") - const listener = () => { - container.classList.toggle("dark", mediaQuery.matches) - } - mediaQuery.addEventListener("change", listener) - listener() - - return container + return showNotification({ + title: walletProvider?.name || "Mobile Wallet", + message: isMobile() + ? "Tap to view request in app" + : "Pending request on your mobile device", + icon: walletProvider?.icon || mobileIcon, + onClick: service.uid ? () => openDeeplink(service.uid) : undefined, + }) } diff --git a/packages/fcl-wc/src/ui/styles.css b/packages/fcl-wc/src/ui/styles.css index 0ee1aeff5..76fcadcc0 100644 --- a/packages/fcl-wc/src/ui/styles.css +++ b/packages/fcl-wc/src/ui/styles.css @@ -1,79 +1,3 @@ @import "tailwindcss/base"; @import "tailwindcss/components"; @import "tailwindcss/utilities"; - -:root { - --dot-color: lightgray; -} - -.dot-pulse { - position: relative; - left: -9999px; - width: 10px; - height: 10px; - border-radius: 5px; - background-color: var(--dot-color); - color: var(--dot-color); - box-shadow: 9999px 0 0 -5px; - animation: dot-pulse 1.5s infinite linear; - animation-delay: 0.25s; -} -.dot-pulse::before, -.dot-pulse::after { - content: ""; - display: inline-block; - position: absolute; - top: 0; - width: 10px; - height: 10px; - border-radius: 5px; - background-color: var(--dot-color); - color: var(--dot-color); -} -.dot-pulse::before { - box-shadow: 9984px 0 0 -5px; - animation: dot-pulse-before 1.5s infinite linear; - animation-delay: 0s; -} -.dot-pulse::after { - box-shadow: 10014px 0 0 -5px; - animation: dot-pulse-after 1.5s infinite linear; - animation-delay: 0.5s; -} - -@keyframes dot-pulse-before { - 0% { - box-shadow: 9984px 0 0 -5px; - } - 30% { - box-shadow: 9984px 0 0 2px; - } - 60%, - 100% { - box-shadow: 9984px 0 0 -5px; - } -} -@keyframes dot-pulse { - 0% { - box-shadow: 9999px 0 0 -5px; - } - 30% { - box-shadow: 9999px 0 0 2px; - } - 60%, - 100% { - box-shadow: 9999px 0 0 -5px; - } -} -@keyframes dot-pulse-after { - 0% { - box-shadow: 10014px 0 0 -5px; - } - 30% { - box-shadow: 10014px 0 0 2px; - } - 60%, - 100% { - box-shadow: 10014px 0 0 -5px; - } -}