From e8c55f57a38358afcf2135f98dc4bd898ab43df2 Mon Sep 17 00:00:00 2001 From: Kamil Pyszkowski Date: Tue, 1 Oct 2024 20:02:05 +0200 Subject: [PATCH] Implement basic hooks Based on Threshold Dashboard implementation (WIP) --- dapp/src/hooks/posthog/index.ts | 4 ++ dapp/src/hooks/posthog/usePostHog.ts | 7 ++ dapp/src/hooks/posthog/usePostHogCapture.ts | 15 ++++ .../posthog/usePostHogCapturePageView.ts | 7 ++ dapp/src/hooks/posthog/usePostHogIdentify.ts | 70 +++++++++++++++++++ dapp/src/posthog.tsx | 26 +++++++ dapp/src/utils/hash.ts | 17 +++++ 7 files changed, 146 insertions(+) create mode 100644 dapp/src/hooks/posthog/index.ts create mode 100644 dapp/src/hooks/posthog/usePostHog.ts create mode 100644 dapp/src/hooks/posthog/usePostHogCapture.ts create mode 100644 dapp/src/hooks/posthog/usePostHogCapturePageView.ts create mode 100644 dapp/src/hooks/posthog/usePostHogIdentify.ts create mode 100644 dapp/src/posthog.tsx create mode 100644 dapp/src/utils/hash.ts diff --git a/dapp/src/hooks/posthog/index.ts b/dapp/src/hooks/posthog/index.ts new file mode 100644 index 000000000..ec6fc1609 --- /dev/null +++ b/dapp/src/hooks/posthog/index.ts @@ -0,0 +1,4 @@ +export * from "./usePostHogIdentify" +export * from "./usePostHog" +export * from "./usePostHogCapture" +export * from "./usePostHogCapturePageView" diff --git a/dapp/src/hooks/posthog/usePostHog.ts b/dapp/src/hooks/posthog/usePostHog.ts new file mode 100644 index 000000000..7f3343762 --- /dev/null +++ b/dapp/src/hooks/posthog/usePostHog.ts @@ -0,0 +1,7 @@ +import { usePostHogCapturePageView } from "./usePostHogCapturePageView" +import { usePostHogIdentify } from "./usePostHogIdentify" + +export const usePostHog = () => { + usePostHogCapturePageView() + usePostHogIdentify() +} diff --git a/dapp/src/hooks/posthog/usePostHogCapture.ts b/dapp/src/hooks/posthog/usePostHogCapture.ts new file mode 100644 index 000000000..ab8e530bd --- /dev/null +++ b/dapp/src/hooks/posthog/usePostHogCapture.ts @@ -0,0 +1,15 @@ +import { featureFlags } from "#/constants" +import { PostHog } from "posthog-js" +import { usePostHog as usePostHogClient } from "posthog-js/react" +import { useEffect } from "react" + +export const usePostHogCapture = ( + ...captureArgs: Parameters +) => { + const postHog = usePostHogClient() + + useEffect(() => { + if (!featureFlags.POSTHOG_ENABLED) return + postHog.capture(...captureArgs) + }, [postHog, captureArgs]) +} diff --git a/dapp/src/hooks/posthog/usePostHogCapturePageView.ts b/dapp/src/hooks/posthog/usePostHogCapturePageView.ts new file mode 100644 index 000000000..6812a4e18 --- /dev/null +++ b/dapp/src/hooks/posthog/usePostHogCapturePageView.ts @@ -0,0 +1,7 @@ +import { usePostHogCapture } from "./usePostHogCapture" + +export const usePostHogCapturePageView = () => { + const { pathname } = window.location + + usePostHogCapture("$pageview", { pathname }) +} diff --git a/dapp/src/hooks/posthog/usePostHogIdentify.ts b/dapp/src/hooks/posthog/usePostHogIdentify.ts new file mode 100644 index 000000000..d4a65a4f8 --- /dev/null +++ b/dapp/src/hooks/posthog/usePostHogIdentify.ts @@ -0,0 +1,70 @@ +import { featureFlags } from "#/constants" +import { usePostHog } from "posthog-js/react" +import { useCallback, useEffect } from "react" +import { hashString, isSameETHAddress, logPromiseFailure } from "#/utils" +import { EventCallback, useSubscribeToConnectorEvent } from "@orangekit/react" +import { getAddress } from "ethers" +import { useConfig } from "wagmi" +import { useWallet } from "../useWallet" +import { useConnector } from "../orangeKit" + +export const usePostHogIdentify = () => { + const postHog = usePostHog() + const connector = useConnector() + const { address } = useWallet() + const wagmiConfig = useConfig() + + useEffect(() => { + if (!featureFlags.POSTHOG_ENABLED || !address) return + + const handleIdentify = async () => { + const hashedAccountAddress = await hashString({ + value: address.toUpperCase(), + }) + + postHog.identify(hashedAccountAddress) + } + + logPromiseFailure(handleIdentify()) + }, [postHog, address]) + + const handleConnectorChange = useCallback>( + (updated) => { + const [updatedAddress] = updated.accounts || [] + + if (!updatedAddress) { + postHog.reset() + return + } + + const isChanged = + updatedAddress && address && !isSameETHAddress(updatedAddress, address) + + if (isChanged) { + postHog.reset() + postHog.identify(getAddress(updatedAddress)) + } + }, + [postHog, address], + ) + + const handleConnectorDisconnect = useCallback< + EventCallback<"disconnect"> + >(() => { + postHog.reset() + }, [postHog]) + + useSubscribeToConnectorEvent( + wagmiConfig, + connector!.name, + "change", + handleConnectorChange, + ) + + useSubscribeToConnectorEvent( + wagmiConfig, + connector!.name, + "disconnect", + handleConnectorDisconnect, + ) +} diff --git a/dapp/src/posthog.tsx b/dapp/src/posthog.tsx new file mode 100644 index 000000000..2bb5c957e --- /dev/null +++ b/dapp/src/posthog.tsx @@ -0,0 +1,26 @@ +import React, { PropsWithChildren } from "react" +import { PostHogProvider as Provider } from "posthog-js/react" +import { PostHogConfig } from "posthog-js" +import { featureFlags, env } from "./constants" + +const options: Partial = { + api_host: env.POSTHOG_API_HOST, + capture_pageview: false, + persistence: "memory", +} + +function PostHogProvider(props: PropsWithChildren) { + const { children } = props + + if (!featureFlags.POSTHOG_ENABLED) { + return children + } + + return ( + + {children} + + ) +} + +export default PostHogProvider diff --git a/dapp/src/utils/hash.ts b/dapp/src/utils/hash.ts new file mode 100644 index 000000000..b59c5f976 --- /dev/null +++ b/dapp/src/utils/hash.ts @@ -0,0 +1,17 @@ +type HashAlgorithm = "SHA-1" | "SHA-256" | "SHA-384" | "SHA-512" + +export const hashString = async ({ + algorithm = "SHA-256", + value, +}: { + algorithm?: HashAlgorithm + value: string +}) => + Array.prototype.map + .call( + new Uint8Array( + await crypto.subtle.digest(algorithm, new TextEncoder().encode(value)), + ), + (x: number) => `0${x.toString(16)}`.slice(-2), + ) + .join("")