From ebacb8a0e813b7cecc7d2e03f9c3f7278eb21fe1 Mon Sep 17 00:00:00 2001 From: Marvell69 Date: Thu, 28 May 2026 13:14:59 +0100 Subject: [PATCH 1/2] Add UTM parameter support for share links and update environment configuration --- .env.example | 8 +++ .../common/CreatorProfileHeader.tsx | 6 ++- src/utils/env.utils.ts | 11 ++++ src/utils/utm.utils.ts | 50 +++++++++++++++++++ 4 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 src/utils/utm.utils.ts diff --git a/.env.example b/.env.example index 2ac4b85..dad5681 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,11 @@ +VITE_BACKEND_URL=/api +# UTM settings for shared profile links (optional) +# Set any of these to enable UTM parameters on shared profile URLs. +VITE_UTM_SOURCE=twitter +VITE_UTM_MEDIUM=social +VITE_UTM_CAMPAIGN=share_profile +#VITE_UTM_TERM= +#VITE_UTM_CONTENT= VITE_BACKEND_URL=http://localhost:3000/api/v1 VITE_DEFAULT_CHAIN_ID=84532 VITE_ANVIL_RPC_URL=http://127.0.0.1:8545 diff --git a/src/components/common/CreatorProfileHeader.tsx b/src/components/common/CreatorProfileHeader.tsx index a9d94cc..84bbc4e 100644 --- a/src/components/common/CreatorProfileHeader.tsx +++ b/src/components/common/CreatorProfileHeader.tsx @@ -1,6 +1,7 @@ import React, { useState } from 'react'; import { Copy, Check, Share2 } from 'lucide-react'; import showToast from '@/utils/toast.util'; +import appendUtmParams from '@/utils/utm.utils'; import { Button } from '@/components/ui/button'; import { cn } from '@/lib/utils'; import VerifiedBadge from '@/components/common/VerifiedBadge'; @@ -32,7 +33,10 @@ const CreatorProfileHeader: React.FC = ({ const [copied, setCopied] = useState(false); const handleShare = async () => { - const url = window.location.href; + let url = window.location.href; + + // Append UTM params when configured (no-op if none configured) + url = appendUtmParams(url); if (navigator.share) { try { diff --git a/src/utils/env.utils.ts b/src/utils/env.utils.ts index 29f0422..4d7a338 100644 --- a/src/utils/env.utils.ts +++ b/src/utils/env.utils.ts @@ -7,6 +7,12 @@ const envSchema = z.object({ VITE_BASE_SEPOLIA_RPC_URL: z.string().default('https://sepolia.base.org'), VITE_SEPOLIA_RPC_URL: z.string().optional(), VITE_MAINNET_RPC_URL: z.string().optional(), + // UTM configuration for share links. Optional — when not provided, share URLs remain unchanged. + VITE_UTM_SOURCE: z.string().optional(), + VITE_UTM_MEDIUM: z.string().optional(), + VITE_UTM_CAMPAIGN: z.string().optional(), + VITE_UTM_TERM: z.string().optional(), + VITE_UTM_CONTENT: z.string().optional(), }); export const env = envSchema.parse({ @@ -16,4 +22,9 @@ export const env = envSchema.parse({ VITE_BASE_SEPOLIA_RPC_URL: import.meta.env.VITE_BASE_SEPOLIA_RPC_URL, VITE_SEPOLIA_RPC_URL: import.meta.env.VITE_SEPOLIA_RPC_URL, VITE_MAINNET_RPC_URL: import.meta.env.VITE_MAINNET_RPC_URL, + VITE_UTM_SOURCE: import.meta.env.VITE_UTM_SOURCE, + VITE_UTM_MEDIUM: import.meta.env.VITE_UTM_MEDIUM, + VITE_UTM_CAMPAIGN: import.meta.env.VITE_UTM_CAMPAIGN, + VITE_UTM_TERM: import.meta.env.VITE_UTM_TERM, + VITE_UTM_CONTENT: import.meta.env.VITE_UTM_CONTENT, }); diff --git a/src/utils/utm.utils.ts b/src/utils/utm.utils.ts new file mode 100644 index 0000000..93ccb43 --- /dev/null +++ b/src/utils/utm.utils.ts @@ -0,0 +1,50 @@ +import { env } from '@/utils/env.utils'; + +export interface UtmParams { + utm_source?: string; + utm_medium?: string; + utm_campaign?: string; + utm_term?: string; + utm_content?: string; +} + +export const getConfiguredUtmParams = (): UtmParams => { + const params: UtmParams = {}; + + if (env.VITE_UTM_SOURCE) params.utm_source = env.VITE_UTM_SOURCE; + if (env.VITE_UTM_MEDIUM) params.utm_medium = env.VITE_UTM_MEDIUM; + if (env.VITE_UTM_CAMPAIGN) params.utm_campaign = env.VITE_UTM_CAMPAIGN; + if (env.VITE_UTM_TERM) params.utm_term = env.VITE_UTM_TERM; + if (env.VITE_UTM_CONTENT) params.utm_content = env.VITE_UTM_CONTENT; + + return params; +}; + +export const appendUtmParams = (inputUrl: string, overrideParams?: UtmParams): string => { + const configured = overrideParams ?? getConfiguredUtmParams(); + + // If no UTM params configured, return original URL unchanged + const keys = Object.keys(configured) as Array; + const hasAny = keys.some((k) => !!configured[k]); + if (!hasAny) return inputUrl; + + try { + const url = new URL(inputUrl); + + const search = url.searchParams; + + if (configured.utm_source) search.set('utm_source', configured.utm_source); + if (configured.utm_medium) search.set('utm_medium', configured.utm_medium); + if (configured.utm_campaign) search.set('utm_campaign', configured.utm_campaign); + if (configured.utm_term) search.set('utm_term', configured.utm_term); + if (configured.utm_content) search.set('utm_content', configured.utm_content); + + // Preserve hash and other parts — URL.toString() keeps them + return url.toString(); + } catch (e) { + // If URL parsing fails, fall back to original input + return inputUrl; + } +}; + +export default appendUtmParams; From 548499edaa3b8314c095d23a5788af53bb1d60b3 Mon Sep 17 00:00:00 2001 From: Marvell69 Date: Thu, 28 May 2026 17:59:52 +0100 Subject: [PATCH 2/2] feat: add utility functions to retrieve and append UTM parameters to URLs --- .husky/pre-commit | 2 +- src/utils/utm.utils.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index ec281ac..e65f5e7 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,3 +1,3 @@ #!/usr/bin/env sh sh ./scripts/check-no-package-lock.sh -pnpm lint-staged +npx lint-staged diff --git a/src/utils/utm.utils.ts b/src/utils/utm.utils.ts index 93ccb43..32d319e 100644 --- a/src/utils/utm.utils.ts +++ b/src/utils/utm.utils.ts @@ -41,7 +41,7 @@ export const appendUtmParams = (inputUrl: string, overrideParams?: UtmParams): s // Preserve hash and other parts — URL.toString() keeps them return url.toString(); - } catch (e) { + } catch { // If URL parsing fails, fall back to original input return inputUrl; }