diff --git a/src/app/(main)/links/LinkEditForm.tsx b/src/app/(main)/links/LinkEditForm.tsx index 8b8f476bee..2b5c9f4c18 100644 --- a/src/app/(main)/links/LinkEditForm.tsx +++ b/src/app/(main)/links/LinkEditForm.tsx @@ -21,6 +21,22 @@ import { isValidUrl } from '@/lib/url'; const generateId = () => getRandomChars(9); +const parseUtm = (url: string) => { + if (!url) return {}; + try { + const u = new URL(url); + return { + utmSource: u.searchParams.get('utm_source') || '', + utmMedium: u.searchParams.get('utm_medium') || '', + utmCampaign: u.searchParams.get('utm_campaign') || '', + utmContent: u.searchParams.get('utm_content') || '', + utmTerm: u.searchParams.get('utm_term') || '', + }; + } catch { + return {}; + } +}; + export function LinkEditForm({ linkId, teamId, @@ -46,9 +62,15 @@ export function LinkEditForm({ const hostUrl = linksUrl || LINKS_URL; const { data, isLoading } = useLinkQuery(linkId); const [defaultSlug] = useState(generateId()); + const [showUtm, setShowUtm] = useState(() => { + const utm = parseUtm(data?.url); + return !!(utm.utmSource || utm.utmMedium || utm.utmCampaign || utm.utmContent || utm.utmTerm); + }); const handleSubmit = async (data: any) => { - await mutateAsync(data, { + const { utmSource, utmMedium, utmCampaign, utmContent, utmTerm, ...payload } = data; + + await mutateAsync(payload, { onSuccess: async () => { toast(t(messages.saved)); touch('links'); @@ -74,7 +96,7 @@ export function LinkEditForm({
{({ setValue, watch }) => { const slug = watch('slug'); @@ -85,13 +107,105 @@ export function LinkEditForm({ - - - + + + + + + + + {showUtm && ( + + + { + const url = watch('url'); + try { + const u = new URL(url); + if (val) u.searchParams.set('utm_source', val); + else u.searchParams.delete('utm_source'); + setValue('url', u.toString(), { shouldDirty: true }); + } catch { + // ignore + } + }} + /> + + + { + const url = watch('url'); + try { + const u = new URL(url); + if (val) u.searchParams.set('utm_medium', val); + else u.searchParams.delete('utm_medium'); + setValue('url', u.toString(), { shouldDirty: true }); + } catch { + // ignore + } + }} + /> + + + { + const url = watch('url'); + try { + const u = new URL(url); + if (val) u.searchParams.set('utm_campaign', val); + else u.searchParams.delete('utm_campaign'); + setValue('url', u.toString(), { shouldDirty: true }); + } catch { + // ignore + } + }} + /> + + + { + const url = watch('url'); + try { + const u = new URL(url); + if (val) u.searchParams.set('utm_content', val); + else u.searchParams.delete('utm_content'); + setValue('url', u.toString(), { shouldDirty: true }); + } catch { + // ignore + } + }} + /> + + + { + const url = watch('url'); + try { + const u = new URL(url); + if (val) u.searchParams.set('utm_term', val); + else u.searchParams.delete('utm_term'); + setValue('url', u.toString(), { shouldDirty: true }); + } catch { + // ignore + } + }} + /> + + + )} {cloudMode ? (