Skip to content

Commit

Permalink
feat: add tracker
Browse files Browse the repository at this point in the history
  • Loading branch information
Innei committed Jul 12, 2023
1 parent 4adf672 commit 1cfd22c
Show file tree
Hide file tree
Showing 11 changed files with 181 additions and 39 deletions.
55 changes: 34 additions & 21 deletions src/app/analyze.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,15 @@

import { useRef } from 'react'
import { useServerInsertedHTML } from 'next/navigation'
import type { TrackerAction } from '~/constants/tracker'

import { apiClient } from '~/lib/request'
declare global {
interface Window {
umami?: {
track: (event: string, data?: any) => void
}
}
}

export const Analyze = () => {
const onceRef = useRef(false)
Expand All @@ -13,33 +20,39 @@ export const Analyze = () => {
}

onceRef.current = true
const apiBase = apiClient.proxy.fn.utils.analyze.toString(true)
// const apiBase = apiClient.proxy.fn.utils.analyze.toString(true)

return (
<script
dangerouslySetInnerHTML={{
__html:
`var apiBase = "${apiBase}";
${function run() {
document.addEventListener('click', async (e) => {
const $ = e.target as HTMLElement
const event = $.dataset.event
if (event) {
await fetch(apiBase, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
`${function run() {
document.addEventListener(
'click',
async (e) => {
const $ = e.target as HTMLElement
const event = $.dataset.event
if (event) {
window.umami?.track(event, {
type: 'click',
})
}
},
body: JSON.stringify({
key: 'mx',
event,
type: 'inc',
}),
true,
)
document.addEventListener('impression', async (e: any) => {
const detail = e.detail as {
action: TrackerAction
label: string
}
window.umami?.track(detail.label, {
type: 'impression',
})
})
}
})
}.toString()}\n` + `run();`,
}.toString()}\n` + `run();`,
}}
/>
)
Expand Down
11 changes: 11 additions & 0 deletions src/app/config.d.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
import type { ScriptProps } from 'next/script'

export interface AppConfig {
site: Site
hero: Hero
module: Module

custom: Custom
}
export interface Custom {
css: string[]
styles: any[]
js: string[]
scripts: ScriptProps[]
}

export interface Site {
favicon: string
}
Expand Down
57 changes: 57 additions & 0 deletions src/components/common/ImpressionTracker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { memo, useState } from 'react'
import { useInView } from 'react-intersection-observer'

import { useIsLogged } from '~/atoms'
import { TrackerAction } from '~/constants/tracker'

type ImpressionProps = {
trackerMessage?: string
action?: TrackerAction
onTrack?: () => any
}
export const ImpressionView: Component<
{ shouldTrack?: boolean } & ImpressionProps
> = (props) => {
const { shouldTrack = true, ...rest } = props
if (!shouldTrack) {
return <>{props.children}</>
}
return <ImpressionViewImpl {...rest} />
}

const ImpressionViewImpl: Component<ImpressionProps> = memo((props) => {
const [impression, setImpression] = useState(false)
const isLogged = useIsLogged()
const { ref } = useInView({
initialInView: false,
triggerOnce: true,
onChange(inView) {
if (inView) {
setImpression(true)

if (isLogged) {
return
}
document.dispatchEvent(
new CustomEvent('impression', {
detail: {
action: props.action ?? TrackerAction.Impression,
label: props.trackerMessage,
},
}),
)

props.onTrack?.()
}
},
})

return (
<>
{props.children}
{!impression && <span ref={ref} />}
</>
)
})

ImpressionViewImpl.displayName = 'ImpressionView'
15 changes: 11 additions & 4 deletions src/components/layout/header/internal/Activity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ import {
setActivityProcessName,
useActivity,
} from '~/atoms/activity'
import { ImpressionView } from '~/components/common/ImpressionTracker'
import { FloatPopover } from '~/components/ui/float-popover'
import { softBouncePrest } from '~/constants/spring'
import { TrackerAction } from '~/constants/tracker'
import useDebounceValue from '~/hooks/common/use-debounce-value'
import { usePageIsActive } from '~/hooks/common/use-is-active'
import { apiClient } from '~/lib/request'
Expand Down Expand Up @@ -163,10 +165,15 @@ export const Activity = memo(() => {
type="tooltip"
strategy="fixed"
>
{ownerName} 正在使用 {processName}
{appDescrption[processName]
? ` ${appDescrption[processName]}`
: ''}
<ImpressionView
action={TrackerAction.Impression}
trackerMessage="Activity"
>
{ownerName} 正在使用 {processName}
{appDescrption[processName]
? ` ${appDescrption[processName]}`
: ''}
</ImpressionView>
</FloatPopover>
</m.div>
)}
Expand Down
2 changes: 1 addition & 1 deletion src/components/widgets/peek/PeekLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const PeekLink: FC<
)

return (
<Link href={href} onClick={handlePeek} data-event="peek" {...rest}>
<Link href={href} onClick={handlePeek} {...rest}>
{children}
</Link>
)
Expand Down
6 changes: 6 additions & 0 deletions src/components/widgets/peek/PeekModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import { m } from 'framer-motion'
import Link from 'next/link'
import type { PropsWithChildren } from 'react'

import { ImpressionView } from '~/components/common/ImpressionTracker'
import { microReboundPreset } from '~/constants/spring'
import { TrackerAction } from '~/constants/tracker'
import { useModalStack } from '~/providers/root/modal-stack-provider'

export const PeekModal = (
Expand All @@ -14,6 +16,10 @@ export const PeekModal = (

return (
<div>
<ImpressionView
action={TrackerAction.Impression}
trackerMessage="Peek Modal"
/>
<m.div
initial={{ opacity: 0.5, y: 50 }}
animate={{ opacity: 1, y: 0 }}
Expand Down
33 changes: 20 additions & 13 deletions src/components/widgets/shared/AsideDonateButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import { AnimatePresence, m } from 'framer-motion'
import { atom, useAtomValue, useSetAtom } from 'jotai'
import type { HTMLMotionProps } from 'framer-motion'

import { ImpressionView } from '~/components/common/ImpressionTracker'
import { MotionButtonBase } from '~/components/ui/button'
import { DialogOverlay } from '~/components/ui/dlalog/DialogOverlay'
import { TrackerAction } from '~/constants/tracker'
import { useIsClient } from '~/hooks/common/use-is-client'
import { clsxm } from '~/lib/helper'
import { useAppConfigSelector } from '~/providers/root/aggregation-data-provider'
Expand Down Expand Up @@ -80,19 +82,24 @@ const DonateButtonTop = () => {
const setOverlayShow = useSetAtom(overlayShowAtom)
const buttonPos = useAtomValue(positionAtom)
return (
<DonateButtonInternal
className="focus-visible:text-uk-brown-light focus-visible:!shadow-none"
style={{
position: 'fixed',
left: buttonPos.x,
top: buttonPos.y,
zIndex: 999,
margin: 0,
}}
onMouseLeave={() => {
setOverlayShow(false)
}}
/>
<ImpressionView
trackerMessage="Donate Show"
action={TrackerAction.Impression}
>
<DonateButtonInternal
className="focus-visible:text-uk-brown-light focus-visible:!shadow-none"
style={{
position: 'fixed',
left: buttonPos.x,
top: buttonPos.y,
zIndex: 999,
margin: 0,
}}
onMouseLeave={() => {
setOverlayShow(false)
}}
/>
</ImpressionView>
)
}

Expand Down
1 change: 1 addition & 0 deletions src/components/widgets/shared/AutoResizeHeight.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export const AutoResizeHeight: React.FC<AnimateChangeInHeightProps> = ({
<m.div
className={clsxm('overflow-hidden', className)}
style={{ height }}
initial={false}
animate={{ height }}
transition={{ duration }}
>
Expand Down
2 changes: 2 additions & 0 deletions src/providers/root/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { EventProvider } from './event-provider'
import { JotaiStoreProvider } from './jotai-provider'
import { ModalStackProvider } from './modal-stack-provider'
import { PageScrollInfoProvider } from './page-scroll-info-provider'
import { ScriptInjectProvider } from './script-inject-provider'
import { SentryProvider } from './sentry-provider'
import { SocketContainer } from './socket-provider'

Expand All @@ -41,6 +42,7 @@ export function Providers({ children }: PropsWithChildren) {
<PageScrollInfoProvider key="PageScrollInfoProvider" />
<DebugProvider key="debugProvider" />
<AccentColorProvider />
<ScriptInjectProvider />
</ProviderComposer>
</>
)
Expand Down
17 changes: 17 additions & 0 deletions src/providers/root/script-inject-provider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
'use client'

import Script from 'next/script'

import { useAppConfigSelector } from './aggregation-data-provider'

export const ScriptInjectProvider = () => {
const scripts = useAppConfigSelector((config) => config.custom.scripts)
if (!scripts) return null
return (
<>
{scripts.map((props) => (
<Script key={props.src} {...props} />
))}
</>
)
}
Loading

1 comment on commit 1cfd22c

@vercel
Copy link

@vercel vercel bot commented on 1cfd22c Jul 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

shiro – ./

innei.in
shiro-innei.vercel.app
springtide.vercel.app
shiro-git-main-innei.vercel.app

Please sign in to comment.