From b33b95c847d918faa065b77763856757355fc660 Mon Sep 17 00:00:00 2001 From: Joel Date: Tue, 24 Mar 2026 16:56:19 +0800 Subject: [PATCH] fix: ps not recorded when not login --- .../__tests__/cookie-recorder.spec.tsx | 28 +++++++++++++++++++ .../billing/partner-stack/cookie-recorder.tsx | 16 +++++++++++ .../billing/partner-stack/use-ps-info.ts | 7 +++-- web/app/layout.tsx | 2 ++ web/app/signin/page.tsx | 7 ----- 5 files changed, 50 insertions(+), 10 deletions(-) create mode 100644 web/app/components/billing/partner-stack/__tests__/cookie-recorder.spec.tsx create mode 100644 web/app/components/billing/partner-stack/cookie-recorder.tsx diff --git a/web/app/components/billing/partner-stack/__tests__/cookie-recorder.spec.tsx b/web/app/components/billing/partner-stack/__tests__/cookie-recorder.spec.tsx new file mode 100644 index 0000000000..a9f5983ec3 --- /dev/null +++ b/web/app/components/billing/partner-stack/__tests__/cookie-recorder.spec.tsx @@ -0,0 +1,28 @@ +import { render } from '@testing-library/react' +import PartnerStackCookieRecorder from '../cookie-recorder' + +const saveOrUpdate = vi.fn() + +vi.mock('../use-ps-info', () => ({ + default: () => ({ + saveOrUpdate, + }), +})) + +describe('PartnerStackCookieRecorder', () => { + beforeEach(() => { + vi.clearAllMocks() + }) + + it('should call saveOrUpdate once on mount', () => { + render() + + expect(saveOrUpdate).toHaveBeenCalledTimes(1) + }) + + it('should render null', () => { + const { container } = render() + + expect(container.innerHTML).toBe('') + }) +}) diff --git a/web/app/components/billing/partner-stack/cookie-recorder.tsx b/web/app/components/billing/partner-stack/cookie-recorder.tsx new file mode 100644 index 0000000000..a95099f7e0 --- /dev/null +++ b/web/app/components/billing/partner-stack/cookie-recorder.tsx @@ -0,0 +1,16 @@ +'use client' + +import { useEffect } from 'react' +import usePSInfo from './use-ps-info' + +const PartnerStackCookieRecorder = () => { + const { saveOrUpdate } = usePSInfo() + + useEffect(() => { + saveOrUpdate() + }, [saveOrUpdate]) + + return null +} + +export default PartnerStackCookieRecorder diff --git a/web/app/components/billing/partner-stack/use-ps-info.ts b/web/app/components/billing/partner-stack/use-ps-info.ts index 7c45d7ef87..043115d90f 100644 --- a/web/app/components/billing/partner-stack/use-ps-info.ts +++ b/web/app/components/billing/partner-stack/use-ps-info.ts @@ -24,13 +24,14 @@ const usePSInfo = () => { }] = useBoolean(false) const { mutateAsync } = useBindPartnerStackInfo() // Save to top domain. cloud.dify.ai => .dify.ai - const domain = globalThis.location.hostname.replace('cloud', '') + const domain = globalThis.location?.hostname.replace('cloud', '') const saveOrUpdate = useCallback(() => { if (!psPartnerKey || !psClickId) return if (!isPSChanged) return + // console.log('set cookie') Cookies.set(PARTNER_STACK_CONFIG.cookieName, JSON.stringify({ partnerKey: psPartnerKey, clickId: psClickId, @@ -39,7 +40,7 @@ const usePSInfo = () => { path: '/', domain, }) - }, [psPartnerKey, psClickId, isPSChanged]) + }, [psPartnerKey, psClickId, isPSChanged, domain]) const bind = useCallback(async () => { if (psPartnerKey && psClickId && !hasBind) { @@ -59,7 +60,7 @@ const usePSInfo = () => { Cookies.remove(PARTNER_STACK_CONFIG.cookieName, { path: '/', domain }) setBind() } - }, [psPartnerKey, psClickId, mutateAsync, hasBind, setBind]) + }, [psPartnerKey, psClickId, hasBind, domain, setBind, mutateAsync]) return { psPartnerKey, psClickId, diff --git a/web/app/layout.tsx b/web/app/layout.tsx index be51c76f2e..0319a83da1 100644 --- a/web/app/layout.tsx +++ b/web/app/layout.tsx @@ -11,6 +11,7 @@ import { getLocaleOnServer } from '@/i18n-config/server' import { ToastProvider } from './components/base/toast' import { ToastHost } from './components/base/ui/toast' import { TooltipProvider } from './components/base/ui/tooltip' +import PartnerStackCookieRecorder from './components/billing/partner-stack/cookie-recorder' import BrowserInitializer from './components/browser-initializer' import { ReactScanLoader } from './components/devtools/react-scan/loader' import { I18nServerProvider } from './components/provider/i18n-server' @@ -72,6 +73,7 @@ const LocaleLayout = async ({ + diff --git a/web/app/signin/page.tsx b/web/app/signin/page.tsx index 7fad92fe5d..3f893b12fa 100644 --- a/web/app/signin/page.tsx +++ b/web/app/signin/page.tsx @@ -1,18 +1,11 @@ 'use client' -import { useEffect } from 'react' import { useSearchParams } from '@/next/navigation' -import usePSInfo from '../components/billing/partner-stack/use-ps-info' import NormalForm from './normal-form' import OneMoreStep from './one-more-step' const SignIn = () => { const searchParams = useSearchParams() const step = searchParams.get('step') - const { saveOrUpdate } = usePSInfo() - - useEffect(() => { - saveOrUpdate() - }, []) if (step === 'next') return