diff --git a/src/app/(auth)/register/page.tsx b/src/app/(auth)/register/page.tsx index 8094de9..7d29fbb 100644 --- a/src/app/(auth)/register/page.tsx +++ b/src/app/(auth)/register/page.tsx @@ -1,6 +1,8 @@ import { redirect } from "next/navigation"; +import { cookies } from "next/headers"; import { getSettings } from "@/lib/settings"; import { RegisterForm } from "./register-form"; +import { UTM_COOKIE, parseUtmCookie, pickUtm } from "@/lib/utm-cookie"; export default async function RegisterPage({ searchParams, @@ -15,6 +17,11 @@ export default async function RegisterPage({ const sp = await searchParams; const str = (v: string | string[] | undefined) => (Array.isArray(v) ? v[0] : v) ?? ""; + // Метки: из адреса, а если их нет — из cookie лендинга (src/lib/utm-cookie.ts). + const utm = pickUtm( + { utmSource: str(sp.utm_source), utmMedium: str(sp.utm_medium), utmCampaign: str(sp.utm_campaign) }, + parseUtmCookie((await cookies()).get(UTM_COOKIE)?.value), + ); return (
@@ -34,9 +41,9 @@ export default async function RegisterPage({ termsUrl={settings.termsUrl} offerUrl={settings.offerUrl} archetype={str(sp.archetype)} - utmSource={str(sp.utm_source)} - utmMedium={str(sp.utm_medium)} - utmCampaign={str(sp.utm_campaign)} + utmSource={utm.utmSource} + utmMedium={utm.utmMedium} + utmCampaign={utm.utmCampaign} gclid={str(sp.gclid)} />
diff --git a/src/lib/__tests__/utm-cookie.test.ts b/src/lib/__tests__/utm-cookie.test.ts new file mode 100644 index 0000000..b29a909 --- /dev/null +++ b/src/lib/__tests__/utm-cookie.test.ts @@ -0,0 +1,40 @@ +import { describe, it, expect } from "vitest"; +import { cleanUtm, parseUtmCookie, pickUtm } from "../utm-cookie"; + +describe("utm-cookie", () => { + it("разбирает сырую строку запроса из cookie", () => { + expect(parseUtmCookie("utm_source=youtube&utm_medium=video&utm_campaign=test-20261103&fbclid=x")).toEqual({ + utmSource: "youtube", + utmMedium: "video", + utmCampaign: "test-20261103", + }); + }); + + it("понимает percent-кодирование", () => { + expect(parseUtmCookie("utm_campaign=a%2Db_c.d").utmCampaign).toBe("a-b_c.d"); + }); + + it("пустая и битая cookie — пустые метки", () => { + expect(parseUtmCookie(undefined)).toEqual({ utmSource: "", utmMedium: "", utmCampaign: "" }); + expect(parseUtmCookie("")).toEqual({ utmSource: "", utmMedium: "", utmCampaign: "" }); + expect(parseUtmCookie("%%%")).toEqual({ utmSource: "", utmMedium: "", utmCampaign: "" }); + }); + + it("отбрасывает значения не из белого списка символов и слишком длинные", () => { + expect(cleanUtm("ok-1")).toBe("ok-1"); + expect(cleanUtm("