From 768fb63b8886ba7cd79ce56978ea85ab267286c2 Mon Sep 17 00:00:00 2001 From: Zeng Qingwen <143274079+fishwww-ww@users.noreply.github.com> Date: Fri, 12 Sep 2025 09:54:36 +0800 Subject: [PATCH] feat: scan QRCode auto redeem coupon (#5616) * feat: scan QRCode auto redeem coupon * feat: use hook to auto redeem, instead of modify auth --- .../components/Layout/hooks/checkCoupon.ts | 23 +++++++++++++++++++ projects/app/src/components/Layout/index.tsx | 3 +++ projects/app/src/web/context/useInitApp.ts | 12 ++++++++-- .../app/src/web/support/marketing/utils.ts | 13 +++++++++++ 4 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 projects/app/src/components/Layout/hooks/checkCoupon.ts diff --git a/projects/app/src/components/Layout/hooks/checkCoupon.ts b/projects/app/src/components/Layout/hooks/checkCoupon.ts new file mode 100644 index 000000000..fb38039f3 --- /dev/null +++ b/projects/app/src/components/Layout/hooks/checkCoupon.ts @@ -0,0 +1,23 @@ +import { useEffect, useRef } from 'react'; +import { getCouponCode, removeCouponCode } from '@/web/support/marketing/utils'; +import type { UserType } from '@fastgpt/global/support/user/type.d'; +import { redeemCoupon } from '@/web/support/user/team/api'; + +export const useCheckCoupon = (userInfo: UserType | null) => { + const hasCheckedCouponRef = useRef(false); + + useEffect(() => { + if (!userInfo || hasCheckedCouponRef.current) return; + + const couponCode = getCouponCode(); + if (!couponCode) return; + + hasCheckedCouponRef.current = true; + + redeemCoupon(couponCode) + .catch(() => {}) + .finally(removeCouponCode); + }, [userInfo]); +}; + +export default useCheckCoupon; diff --git a/projects/app/src/components/Layout/index.tsx b/projects/app/src/components/Layout/index.tsx index 1859a0997..559381e96 100644 --- a/projects/app/src/components/Layout/index.tsx +++ b/projects/app/src/components/Layout/index.tsx @@ -15,6 +15,7 @@ import { useDebounceEffect, useMount } from 'ahooks'; import { useTranslation } from 'next-i18next'; import { useToast } from '@fastgpt/web/hooks/useToast'; import WorkorderButton from './WorkorderButton'; +import { useCheckCoupon } from './hooks/checkCoupon'; const Navbar = dynamic(() => import('./navbar')); const NavbarPhone = dynamic(() => import('./navbarPhone')); @@ -74,6 +75,8 @@ const Layout = ({ children }: { children: JSX.Element }) => { const { userInfo, isUpdateNotification, setIsUpdateNotification } = useUserStore(); const { setUserDefaultLng } = useI18nLng(); + useCheckCoupon(userInfo); + const isChatPage = useMemo( () => router.pathname === '/chat' && Object.values(router.query).join('').length !== 0, [router.pathname, router.query] diff --git a/projects/app/src/web/context/useInitApp.ts b/projects/app/src/web/context/useInitApp.ts index 0f8c7e837..5d81c09dc 100644 --- a/projects/app/src/web/context/useInitApp.ts +++ b/projects/app/src/web/context/useInitApp.ts @@ -17,6 +17,7 @@ import { setUtmWorkflow } from '../support/marketing/utils'; import { type ShortUrlParams } from '@fastgpt/global/support/marketing/type'; +import { setCouponCode } from '@/web/support/marketing/utils'; type MarketingQueryParams = { hiId?: string; @@ -29,6 +30,7 @@ type MarketingQueryParams = { utm_medium?: string; utm_content?: string; utm_workflow?: string; + couponCode?: string; }; const MARKETING_PARAMS: (keyof MarketingQueryParams)[] = [ @@ -40,7 +42,8 @@ const MARKETING_PARAMS: (keyof MarketingQueryParams)[] = [ 'utm_source', 'utm_medium', 'utm_content', - 'utm_workflow' + 'utm_workflow', + 'couponCode' ]; export const useInitApp = () => { @@ -55,7 +58,8 @@ export const useInitApp = () => { utm_source, utm_medium, utm_content, - utm_workflow + utm_workflow, + couponCode } = router.query as MarketingQueryParams; const { loadGitStar, setInitd, feConfigs } = useSystemStore(); @@ -149,6 +153,10 @@ export const useInitApp = () => { } setFastGPTSem({ keyword: k, search, ...utmParams }); + if (couponCode) { + setCouponCode(couponCode); + } + const newPath = getPathWithoutMarketingParams(); router.replace(newPath); }); diff --git a/projects/app/src/web/support/marketing/utils.ts b/projects/app/src/web/support/marketing/utils.ts index 17a0f6f63..df9f8f784 100644 --- a/projects/app/src/web/support/marketing/utils.ts +++ b/projects/app/src/web/support/marketing/utils.ts @@ -90,3 +90,16 @@ export const setSourceDomain = (sourceDomain?: string) => { if (!formatSourceDomain || getSourceDomain()) return; sessionStorage.setItem('sourceDomain', formatSourceDomain); }; + +export const setCouponCode = (couponCode?: string) => { + if (!couponCode) return; + localStorage.setItem('couponCode', couponCode); +}; + +export const getCouponCode = () => { + return localStorage.getItem('couponCode') || undefined; +}; + +export const removeCouponCode = () => { + localStorage.removeItem('couponCode'); +};