From eb7e03b0ceccdeb4d219a83416205395def47f4c Mon Sep 17 00:00:00 2001 From: CodingOnStar Date: Wed, 15 Oct 2025 16:30:00 +0800 Subject: [PATCH] feat: integrate Google Analytics event tracking utility --- .../components/app/workflow-log/filter.tsx | 5 ++++ web/app/components/base/ga/index.tsx | 20 +++++++------- .../components/billing/upgrade-btn/index.tsx | 5 ++-- web/global.d.ts | 21 ++++++++++++++- web/utils/gtag.ts | 26 +++++++++++++++++++ 5 files changed, 65 insertions(+), 12 deletions(-) create mode 100644 web/utils/gtag.ts diff --git a/web/app/components/app/workflow-log/filter.tsx b/web/app/components/app/workflow-log/filter.tsx index 1ef1bd7a29..c75c058c68 100644 --- a/web/app/components/app/workflow-log/filter.tsx +++ b/web/app/components/app/workflow-log/filter.tsx @@ -8,6 +8,7 @@ import quarterOfYear from 'dayjs/plugin/quarterOfYear' import type { QueryParam } from './index' import Chip from '@/app/components/base/chip' import Input from '@/app/components/base/input' +import { sendGAEvent } from '@/utils/gtag' dayjs.extend(quarterOfYear) const today = dayjs() @@ -36,6 +37,10 @@ const Filter: FC = ({ queryParams, setQueryParams }: IFilterProps) { + sendGAEvent('filter_workflow_status', { + status: item.value, + status_name: item.name, + }) setQueryParams({ ...queryParams, status: item.value as string }) }} onClear={() => setQueryParams({ ...queryParams, status: 'all' })} diff --git a/web/app/components/base/ga/index.tsx b/web/app/components/base/ga/index.tsx index 81d84a85d3..a33b6546e4 100644 --- a/web/app/components/base/ga/index.tsx +++ b/web/app/components/base/ga/index.tsx @@ -28,14 +28,10 @@ const GA: FC = ({ return ( <> - + {/* Initialize dataLayer first */} + /> + {/* Load GA script */} + + /> ) diff --git a/web/app/components/billing/upgrade-btn/index.tsx b/web/app/components/billing/upgrade-btn/index.tsx index f3ae95a10b..aabc7db3a5 100644 --- a/web/app/components/billing/upgrade-btn/index.tsx +++ b/web/app/components/billing/upgrade-btn/index.tsx @@ -6,6 +6,7 @@ import PremiumBadge from '../../base/premium-badge' import Button from '@/app/components/base/button' import { SparklesSoft } from '@/app/components/base/icons/src/public/common' import { useModalContext } from '@/context/modal-context' +import { sendGAEvent } from '@/utils/gtag' type Props = { className?: string @@ -33,8 +34,8 @@ const UpgradeBtn: FC = ({ } const onClick = () => { handleClick() - if (loc && (window as any).gtag) { - (window as any).gtag('event', 'click_upgrade_btn', { + if (loc) { + sendGAEvent('click_upgrade_btn', { loc, }) } diff --git a/web/global.d.ts b/web/global.d.ts index 20b84a5327..e286b14647 100644 --- a/web/global.d.ts +++ b/web/global.d.ts @@ -12,4 +12,23 @@ declare module '*.mdx' { export default MDXComponent } -export {} +// Google Analytics gtag types +type GtagEventParams = { + [key: string]: any +} + +type Gtag = { + (command: 'config', targetId: string, config?: GtagEventParams): void + (command: 'event', eventName: string, eventParams?: GtagEventParams): void + (command: 'js', date: Date): void + (command: 'set', config: GtagEventParams): void +} + +declare global { + interface Window { + gtag?: Gtag + dataLayer?: any[] + } +} + +import './types/i18n' diff --git a/web/utils/gtag.ts b/web/utils/gtag.ts new file mode 100644 index 0000000000..2f00e83b0c --- /dev/null +++ b/web/utils/gtag.ts @@ -0,0 +1,26 @@ +/** + * Google Analytics event tracking utility function + * Wraps gtag calls and automatically handles the case where gtag is not available + */ + +type GtagEventParams = { + [key: string]: any +} + +/** + * Send Google Analytics event + * @param eventName - event name + * @param eventParams - event params + * @example + * sendGAEvent('filter_workflow_status', { + * status: 'succeeded', + * status_name: 'Success' + * }) + */ +export const sendGAEvent = ( + eventName: string, + eventParams?: GtagEventParams, +): void => { + if (typeof window !== 'undefined' && window.gtag) + window.gtag('event', eventName, eventParams) +}