Skip to content

Commit 82322ce

Browse files
authored
Merge pull request #1863 from internxt/feature/cello-date-exp
[_]: Add 30-day expiration for Cello referral attribution
2 parents 0840ff0 + 5e4a33b commit 82322ce

4 files changed

Lines changed: 63 additions & 10 deletions

File tree

src/lib/auth.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import axios from 'axios';
22
import { PromoCodeProps } from './types';
33
import { PASSWORD_REGEX } from '@/components/cloud-object-storage/integrated-checkout/components/InputsComponent';
4+
import { isCelloExpired } from '@/lib/cookies';
45

56
export const IFRAME_AUTH_ENABLED = false;
67
export const REDIRECT_AUTH_ENABLED = true;
@@ -265,13 +266,15 @@ export function checkout({ planId, promoCodeId, planType, mode, currency, gclid
265266
mode && params.set('mode', mode ? mode : 'subscription');
266267
gclid && params.set('gclid', gclid);
267268

268-
const currentParams = new URLSearchParams(globalThis.location.search);
269-
const celloProductId = currentParams.get('productId');
270-
const celloUcc = currentParams.get('ucc');
271-
const celloN = currentParams.get('celloN');
272-
if (celloProductId) params.set('productId', celloProductId);
273-
if (celloUcc) params.set('ucc', celloUcc);
274-
if (celloN) params.set('celloN', celloN);
269+
if (!isCelloExpired()) {
270+
const currentParams = new URLSearchParams(globalThis.location.search);
271+
const celloProductId = currentParams.get('productId');
272+
const celloUcc = currentParams.get('ucc');
273+
const celloN = currentParams.get('celloN');
274+
if (celloProductId) params.set('productId', celloProductId);
275+
if (celloUcc) params.set('ucc', celloUcc);
276+
if (celloN) params.set('celloN', celloN);
277+
}
275278

276279
window.location.href = AUTH_FLOW_URL + `${pathname}?${params.toString()}`;
277280
}

src/lib/cookies.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const url = require('url');
66
const queryString = require('querystring');
77

88
const GCLID_COOKIE_LIFESPAN_DAYS = 90;
9+
const CELLO_EXPIRATION_DAYS = 30;
910
const MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
1011

1112
function parseUri(ctx: GetServerSidePropsContext) {
@@ -88,10 +89,31 @@ export const getGclidFromURL = (): string | null => {
8889
return params.get('gclid');
8990
};
9091

92+
export const saveCelloFirstVisit = (): void => {
93+
if (typeof window === 'undefined') return;
94+
if (localStorage.getItem('cello_first_visit') === null) {
95+
localStorage.setItem('cello_first_visit', new Date().toISOString());
96+
}
97+
};
98+
99+
export const getCelloFirstVisitDate = (): string | null => {
100+
if (typeof window === 'undefined') return null;
101+
return localStorage.getItem('cello_first_visit');
102+
};
103+
104+
export const isCelloExpired = (): boolean => {
105+
const storedDate = getCelloFirstVisitDate();
106+
if (!storedDate) return false;
107+
return Date.now() - new Date(storedDate).getTime() > CELLO_EXPIRATION_DAYS * MILLISECONDS_PER_DAY;
108+
};
109+
91110
export default {
92111
parseUri,
93112
setCookie,
94113
getCookie,
95114
setReferralCookie,
96115
setPublicCookie,
116+
saveCelloFirstVisit,
117+
getCelloFirstVisitDate,
118+
isCelloExpired,
97119
};

src/pages/specialoffer.tsx

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import { useEffect, useState } from 'react';
12
import Layout from '@/components/layout/Layout';
23
import Script from 'next/script';
34

45
import { PromoCodeName } from '@/lib/types';
6+
import { saveCelloFirstVisit, isCelloExpired } from '@/lib/cookies';
57
import Footer from '@/components/layout/footers/Footer';
68
import usePricing from '@/hooks/usePricing';
79

@@ -30,6 +32,13 @@ function SpecialOffer({
3032
footerLang,
3133
navbarLang,
3234
}: SpecialOfferProps): JSX.Element {
35+
const [isCelloAttributionExpired, setIsCelloAttributionExpired] = useState(true);
36+
37+
useEffect(() => {
38+
saveCelloFirstVisit();
39+
setIsCelloAttributionExpired(isCelloExpired());
40+
}, []);
41+
3342
const metatags = metatagsDescriptions.filter((desc) => desc.id === 'special-offer');
3443

3544
const {
@@ -84,7 +93,13 @@ function SpecialOffer({
8493

8594
return (
8695
<Layout title={metatags[0].title} description={metatags[0].description} segmentName="Partners" lang={lang}>
87-
<Script src={process.env.NEXT_PUBLIC_CELLO_ATTRIBUTION_URL} type="module" strategy="afterInteractive" />
96+
{!isCelloAttributionExpired && (
97+
<Script
98+
src="https://assets.cello.so/attribution/latest/cello-attribution.js"
99+
type="module"
100+
strategy="afterInteractive"
101+
/>
102+
)}
88103
<Navbar lang={lang} textContent={navbarLang} cta={['payment']} isLinksHidden hideCTA />
89104

90105
<HeroSection textContent={langJson.HeroSection} percentOff={percentOff} image={'internxt-private-cloud'} />

src/pages/specialoffer/[filename].tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
/* eslint-disable @typescript-eslint/no-non-null-assertion */
2-
import { useEffect } from 'react';
2+
import { useEffect, useState } from 'react';
33
import { useRouter } from 'next/router';
44
import Layout from '@/components/layout/Layout';
55
import Script from 'next/script';
66
import { PromoCodeName } from '@/lib/types';
7+
import { saveCelloFirstVisit, isCelloExpired } from '@/lib/cookies';
78
import Footer from '@/components/layout/footers/Footer';
89
import usePricing from '@/hooks/usePricing';
910
import Navbar from '@/components/layout/navbars/Navbar';
@@ -65,6 +66,7 @@ function CombinedSpecialOffer({
6566
pathname,
6667
}: CombinedSpecialOfferProps): JSX.Element {
6768
const router = useRouter();
69+
const [isCelloAttributionExpired, setIsCelloAttributionExpired] = useState(true);
6870
const selectedPathname = ALLOWED_PATHS.find((p) => p === pathname);
6971
const isDarkMode = selectedPathname ? DARK_MODE_PATHS.includes(selectedPathname) : false;
7072
const isValentinesMode = selectedPathname === 'love';
@@ -79,6 +81,11 @@ function CombinedSpecialOffer({
7981
}
8082
}, [selectedPathname, router]);
8183

84+
useEffect(() => {
85+
saveCelloFirstVisit();
86+
setIsCelloAttributionExpired(isCelloExpired());
87+
}, []);
88+
8289
const couponCode = COUPON_CODES[pathname];
8390
const metatags = metatagsDescriptions.find((desc) => desc.id === 'special-offer');
8491

@@ -148,7 +155,13 @@ function CombinedSpecialOffer({
148155
lang={lang}
149156
robots="noindex, follow"
150157
>
151-
<Script src={process.env.NEXT_PUBLIC_CELLO_ATTRIBUTION_URL} type="module" strategy="afterInteractive" />
158+
{!isCelloAttributionExpired && (
159+
<Script
160+
src="https://assets.cello.so/attribution/latest/cello-attribution.js"
161+
type="module"
162+
strategy="afterInteractive"
163+
/>
164+
)}
152165
<Navbar lang={lang} textContent={navbarLang} cta={['payment']} isLinksHidden hideLogoLink hideCTA />
153166

154167
<HeroSection

0 commit comments

Comments
 (0)