diff --git a/apps/frontend/src/app/layout.tsx b/apps/frontend/src/app/layout.tsx
index c645acad..c143d959 100644
--- a/apps/frontend/src/app/layout.tsx
+++ b/apps/frontend/src/app/layout.tsx
@@ -12,6 +12,7 @@ import clsx from 'clsx';
import { VariableContextComponent } from '@gitroom/react/helpers/variable.context';
import { Fragment } from 'react';
import { PHProvider } from '@gitroom/react/helpers/posthog';
+import UtmSaver from '@gitroom/helpers/utils/utm.saver';
const chakra = Chakra_Petch({ weight: '400', subsets: ['latin'] });
@@ -49,6 +50,7 @@ export default async function AppLayout({ children }: { children: ReactNode }) {
phkey={process.env.NEXT_PUBLIC_POSTHOG_KEY}
host={process.env.NEXT_PUBLIC_POSTHOG_HOST}
>
+
{children}
diff --git a/apps/frontend/src/components/billing/main.billing.component.tsx b/apps/frontend/src/components/billing/main.billing.component.tsx
index 69c49ab0..d528ceaa 100644
--- a/apps/frontend/src/components/billing/main.billing.component.tsx
+++ b/apps/frontend/src/components/billing/main.billing.component.tsx
@@ -22,6 +22,7 @@ import { useModals } from '@mantine/modals';
import { TopTitle } from '@gitroom/frontend/components/launches/helpers/top.title.component';
import { Textarea } from '@gitroom/react/form/textarea';
import { useFireEvents } from '@gitroom/helpers/utils/use.fire.events';
+import { useUtmUrl } from '@gitroom/helpers/utils/utm.saver';
export interface Tiers {
month: Array<{
@@ -219,6 +220,7 @@ export const MainBillingComponent: FC<{
const user = useUser();
const modal = useModals();
const router = useRouter();
+ const utm = useUtmUrl();
const [subscription, setSubscription] = useState(
sub
@@ -344,6 +346,7 @@ export const MainBillingComponent: FC<{
method: 'POST',
body: JSON.stringify({
period: monthlyOrYearly === 'on' ? 'YEARLY' : 'MONTHLY',
+ utm,
billing,
}),
})
diff --git a/libraries/helpers/src/utils/utm.saver.tsx b/libraries/helpers/src/utils/utm.saver.tsx
index 656ca9c6..df280f71 100644
--- a/libraries/helpers/src/utils/utm.saver.tsx
+++ b/libraries/helpers/src/utils/utm.saver.tsx
@@ -1,47 +1,38 @@
-import {FC, useCallback, useEffect} from "react";
-import {useSearchParams} from "next/navigation";
+'use client';
+
+import { FC, useCallback, useEffect } from 'react';
+import { useSearchParams } from 'next/navigation';
+import { useLocalStorage } from '@mantine/hooks';
const UtmSaver: FC = () => {
- const query = useSearchParams();
- useEffect(() => {
- const landingUrl = localStorage.getItem('landingUrl');
- if (landingUrl) {
- return ;
- }
+ const query = useSearchParams();
+ const [value, setValue] = useLocalStorage({ key: 'utm', defaultValue: '' });
- localStorage.setItem('landingUrl', window.location.href);
- localStorage.setItem('referrer', document.referrer);
- }, []);
+ useEffect(() => {
+ const landingUrl = localStorage.getItem('landingUrl');
+ if (landingUrl) {
+ return;
+ }
- useEffect(() => {
- const utm = query.get('utm_source') || query.get('utm');
- const utmMedium = query.get('utm_medium');
- const utmCampaign = query.get('utm_campaign');
+ localStorage.setItem('landingUrl', window.location.href);
+ localStorage.setItem('referrer', document.referrer);
+ }, []);
- if (utm) {
- localStorage.setItem('utm', utm);
- }
- if (utmMedium) {
- localStorage.setItem('utm_medium', utmMedium);
- }
- if (utmCampaign) {
- localStorage.setItem('utm_campaign', utmCampaign);
- }
- }, [query]);
+ useEffect(() => {
+ const utm = query.get('utm_source') || query.get('utm') || query.get('ref');
+ if (utm && !value) {
+ setValue(utm);
+ }
+ }, [query, value]);
- return <>>;
-}
+ return <>>;
+};
-export const useUtmSaver = () => {
- return useCallback(() => {
- return {
- utm: localStorage.getItem('utm'),
- utmMedium: localStorage.getItem('utm_medium'),
- utmCampaign: localStorage.getItem('utm_campaign'),
- landingUrl: localStorage.getItem('landingUrl'),
- referrer: localStorage.getItem('referrer'),
- }
- }, []);
-}
-
-export default UtmSaver;
\ No newline at end of file
+export const useUtmUrl = () => {
+ const [value] = useLocalStorage({ key: 'utm', defaultValue: '' });
+ if (value) {
+ return `utm_source=${value}`;
+ }
+ return '';
+};
+export default UtmSaver;
diff --git a/libraries/nestjs-libraries/src/dtos/billing/billing.subscribe.dto.ts b/libraries/nestjs-libraries/src/dtos/billing/billing.subscribe.dto.ts
index 7544d722..1cbde147 100644
--- a/libraries/nestjs-libraries/src/dtos/billing/billing.subscribe.dto.ts
+++ b/libraries/nestjs-libraries/src/dtos/billing/billing.subscribe.dto.ts
@@ -6,4 +6,6 @@ export class BillingSubscribeDto {
@IsIn(['STANDARD', 'PRO', 'TEAM', 'ULTIMATE'])
billing: 'STANDARD' | 'PRO' | 'TEAM' | 'ULTIMATE';
+
+ utm: string;
}
diff --git a/libraries/nestjs-libraries/src/services/stripe.service.ts b/libraries/nestjs-libraries/src/services/stripe.service.ts
index 5464a7a8..64837eea 100644
--- a/libraries/nestjs-libraries/src/services/stripe.service.ts
+++ b/libraries/nestjs-libraries/src/services/stripe.service.ts
@@ -270,12 +270,13 @@ export class StripeService {
body: BillingSubscribeDto,
price: string
) {
+ const isUtm = body.utm ? `&utm_source=${body.utm}` : '';
const { url } = await stripe.checkout.sessions.create({
customer,
- cancel_url: process.env['FRONTEND_URL'] + `/billing`,
+ cancel_url: process.env['FRONTEND_URL'] + `/billing?cancel=true${isUtm}`,
success_url:
process.env['FRONTEND_URL'] +
- `/launches?onboarding=true&check=${uniqueId}`,
+ `/launches?onboarding=true&check=${uniqueId}${isUtm}`,
mode: 'subscription',
subscription_data: {
trial_period_days: 7,