Skip to content

Commit 055d22a

Browse files
authored
fix: try to reduce cold-load latency for missions/earn (#2856)
1 parent 4930d36 commit 055d22a

17 files changed

Lines changed: 108 additions & 140 deletions

File tree

.storybook/main.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ const config: StorybookConfig = {
3131
}),
3232
];
3333

34+
config.resolve = {
35+
...config.resolve,
36+
dedupe: [...(config.resolve?.dedupe ?? []), 'debug'],
37+
};
38+
3439
return config;
3540
},
3641
};

next.config.mjs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,6 @@ const nextConfig = {
1111
experimental: {
1212
serverSourceMaps: false,
1313
optimizePackageImports: [],
14-
staleTimes: {
15-
dynamic: 30,
16-
static: 180,
17-
},
1814
},
1915
webpack: (config) => {
2016
config.resolve.extensionAlias = {

src/app/[lng]/earn/[slug]/page.tsx

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,42 @@ import {
33
pageOpenGraph,
44
pageTwitter,
55
} from '@/app/lib/metadata';
6+
import { getOpportunitiesFiltered } from '@/app/lib/getOpportunitiesFiltered';
67
import { EarnPage, EarnPageSkeleton } from '@/app/ui/earn';
78
import { AppPaths, getSiteUrl } from '@/const/urls';
89
import { notFound } from 'next/navigation';
910
import type { Metadata } from 'next/types';
1011
import { Suspense } from 'react';
12+
import envConfig from '@/config/env-config';
1113

1214
type Params = Promise<{ slug: string }>;
1315

1416
export const dynamicParams = true;
1517
export const revalidate = 300;
1618

17-
export async function generateStaticParams(): Promise<Params[]> {
18-
console.log('21. Earn page generateStaticParams');
19-
20-
// TODO: LF-14853: list available opportunities
21-
return [];
19+
export async function generateStaticParams(): Promise<{ slug: string }[]> {
20+
if (envConfig.NEXT_PUBLIC_ENVIRONMENT !== 'production') {
21+
return [];
22+
}
23+
const res = await getOpportunitiesFiltered({});
24+
const rows = res.data?.data ?? [];
25+
const slugs = [
26+
...new Set(
27+
rows
28+
.map(({ slug }) => slug)
29+
.filter(
30+
(slug): slug is string => typeof slug === 'string' && slug.length > 0,
31+
),
32+
),
33+
];
34+
return slugs.map((slug) => ({ slug }));
2235
}
2336

2437
export async function generateMetadata({
2538
params,
2639
}: {
2740
params: Params;
2841
}): Promise<Metadata> {
29-
console.log('20. Earn page metadata');
3042
const { slug } = await params;
3143

3244
const openGraph: Metadata['openGraph'] = {
@@ -49,24 +61,15 @@ export async function generateMetadata({
4961
}
5062

5163
export default async function Page({ params }: { params: Params }) {
52-
console.log('22. Earn page');
5364
const { slug } = await params;
5465

55-
console.log('24. Earn page slug', slug);
56-
5766
if (!slug) {
58-
console.log('23. Earn page not found');
5967
return notFound();
6068
}
6169

62-
try {
63-
return (
64-
<Suspense fallback={<EarnPageSkeleton />}>
65-
<EarnPage slug={slug} />
66-
</Suspense>
67-
);
68-
} catch (error) {
69-
console.error('26. Failed to fetch earn page', error);
70-
throw error;
71-
}
70+
return (
71+
<Suspense fallback={<EarnPageSkeleton />}>
72+
<EarnPage slug={slug} />
73+
</Suspense>
74+
);
7275
}

src/app/[lng]/earn/loading.tsx

Lines changed: 0 additions & 5 deletions
This file was deleted.

src/app/[lng]/missions/[slug]/page.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { AppPaths, getSiteUrl } from 'src/const/urls';
1111
import { MissionPageSkeleton } from 'src/app/ui/mission/MissionPageSkeleton';
1212
import { MissionPage } from 'src/app/ui/mission/MissionPage';
1313
import { UPCOMING_DAYS_AHEAD } from 'src/const/quests';
14+
import envConfig from '@/config/env-config';
1415

1516
type Params = Promise<{ slug: string }>;
1617

@@ -23,6 +24,10 @@ const getPageTitle = (title: string) => {
2324
const formatSlugToTitle = (slug: string) => slug.replaceAll('-', ' ');
2425

2526
export async function generateStaticParams() {
27+
if (envConfig.NEXT_PUBLIC_ENVIRONMENT !== 'production') {
28+
return [];
29+
}
30+
2631
const pageSize = 25;
2732

2833
const { data: firstPage } = await getQuestsWithNoCampaignAttached(
@@ -115,7 +120,7 @@ export async function generateMetadata({
115120
}
116121

117122
export const dynamicParams = true;
118-
export const revalidate = 300;
123+
export const revalidate = 3600;
119124

120125
export default async function Page({ params }: { params: Params }) {
121126
const { slug } = await params;

src/app/[lng]/missions/loading.tsx

Lines changed: 0 additions & 5 deletions
This file was deleted.

src/app/[lng]/quests/[slug]/page.tsx

Lines changed: 21 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,39 @@
11
import { questSlugSchema } from '@/utils/validation-schemas';
22
import type { Metadata } from 'next';
33
import { redirect, RedirectType } from 'next/navigation';
4-
import { getQuestsWithNoCampaignAttached } from 'src/app/lib/getQuestsWithNoCampaignAttached';
5-
import { siteName } from 'src/app/lib/metadata';
6-
import { AppPaths, getSiteUrl, JUMPER_QUESTS_PATH } from 'src/const/urls';
4+
import { AppPaths, getSiteUrl } from 'src/const/urls';
75
import { sliceStrToXChar } from 'src/utils/splitStringToXChar';
8-
import { getStrapiBaseUrl } from 'src/utils/strapi/strapiHelper';
9-
import { getQuestBySlug } from '../../../lib/getQuestBySlug';
106

117
type Params = Promise<{ slug: string }>;
128

9+
/**
10+
* Legacy `/quests/:slug` URLs redirect to `/missions/:slug`.
11+
* Keep metadata cheap (no Strapi): canonical points at missions so crawlers
12+
* and previews prefer the real URL; avoid indexing the redirect hop.
13+
*/
1314
export async function generateMetadata({
1415
params,
1516
}: {
1617
params: Params;
1718
}): Promise<Metadata> {
1819
const { slug } = await params;
19-
20-
try {
21-
// Validate slug
22-
const slugResult = questSlugSchema.safeParse(slug);
23-
if (!slugResult.success) {
24-
throw new Error('Invalid quest slug');
25-
}
26-
27-
const quest = await getQuestBySlug(slugResult.data);
28-
if (!quest || !quest.data) {
29-
throw new Error();
30-
}
31-
32-
const questData = quest.data;
33-
const baseUrl = getStrapiBaseUrl();
34-
35-
const openGraph: Metadata['openGraph'] = {
36-
title: `Jumper Quest | ${sliceStrToXChar(questData.Title, 45)}`,
37-
description: `${sliceStrToXChar(questData.Information || 'Quest description', 60)}`,
38-
siteName: siteName,
39-
url: `${getSiteUrl()}${JUMPER_QUESTS_PATH}/${slug}`,
40-
images: [
41-
{
42-
url: `${baseUrl}${questData.Image?.url}`,
43-
width: 900,
44-
height: 450,
45-
alt: 'banner image',
46-
},
47-
],
48-
type: 'article',
49-
};
50-
51-
return {
52-
title: `Jumper Quest | ${sliceStrToXChar(questData.Title, 45)}`,
53-
description: questData.Subtitle,
54-
alternates: {
55-
canonical: `${getSiteUrl()}${JUMPER_QUESTS_PATH}/${slug}`,
56-
},
57-
twitter: openGraph,
58-
openGraph,
59-
};
60-
} catch (err) {
61-
return {
62-
title: `Jumper Quest | ${sliceStrToXChar(slug.replaceAll('-', ' '), 45)}`,
63-
description: `This is the description for the quest "${slug.replaceAll('-', ' ')}".`,
64-
};
65-
}
20+
const slugResult = questSlugSchema.safeParse(slug);
21+
const pathSlug = slugResult.success ? slugResult.data : slug;
22+
const missionUrl = `${getSiteUrl()}${AppPaths.Missions}/${pathSlug}`;
23+
const titleFromSlug = sliceStrToXChar(pathSlug.replaceAll('-', ' '), 45);
24+
25+
return {
26+
title: `Jumper Mission | ${titleFromSlug}`,
27+
alternates: {
28+
canonical: missionUrl,
29+
},
30+
robots: {
31+
index: false,
32+
follow: true,
33+
},
34+
};
6635
}
6736

68-
export async function generateStaticParams() {
69-
const { data } = await getQuestsWithNoCampaignAttached();
70-
71-
return data.data.map((quest) => ({ slug: quest.Slug }));
72-
}
73-
74-
export const dynamicParams = true;
75-
export const revalidate = 300;
76-
7737
export default async function Page({ params }: { params: Params }) {
7838
const { slug } = await params;
7939

src/app/ui/earn/EarnPage.tsx

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ interface EarnPageProps {
2020
}
2121

2222
export const EarnPage: FC<EarnPageProps> = async ({ slug }) => {
23-
console.log('27. EarnPage');
24-
2523
// TODO: LF-14853: Opportunity Details
2624
const [opportunity, relatedMarkets] = await Promise.all([
2725
getOpportunityBySlug(slug).catch((error) => {
@@ -32,8 +30,6 @@ export const EarnPage: FC<EarnPageProps> = async ({ slug }) => {
3230
}),
3331
]);
3432

35-
console.log('28. EarnPage opportunity', opportunity);
36-
3733
if (opportunity.error || !opportunity.data) {
3834
return notFound();
3935
}
@@ -46,8 +42,6 @@ export const EarnPage: FC<EarnPageProps> = async ({ slug }) => {
4642
const relatedMarketsData =
4743
relatedMarkets.data?.filter(Boolean).slice(0, 3) ?? [];
4844

49-
console.log('29. EarnPage relatedMarkets', relatedMarketsData);
50-
5145
const { tags, protocol } = opportunity.data;
5246

5347
return (

src/app/ui/gatekeeper/useGatekeeperStatus.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,6 @@ export const useGatekeeperStatus = (flag: string): GatekeeperData => {
6363

6464
const hasAccess = Boolean(data?.[flag]);
6565

66-
console.log('8. useGatekeeperStatus done', hasAccess);
67-
6866
return {
6967
status: hasAccess ? GatekeeperStatus.SUCCESS : GatekeeperStatus.NOT_ALLOWED,
7068
};

src/app/ui/mission/MissionDetails.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import { useAccount } from '@lifi/wallet-management';
1212
import { Badge } from 'src/components/Badge/Badge';
1313
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
1414
import { AppPaths } from 'src/const/urls';
15-
import { useGoBack } from 'src/hooks/routing/useGoBack';
1615
import {
1716
MissionDetailsColumnContainer,
1817
MissionDetailsCardContainer,
@@ -26,6 +25,7 @@ import { BadgeSize, BadgeVariant } from 'src/components/Badge/Badge.styles';
2625
import { BaseAlertVariant } from 'src/components/Alerts/BaseAlert/BaseAlert.styles';
2726
import { SectionCardContainer } from 'src/components/Cards/SectionCard/SectionCard.style';
2827
import { useResetCurrentActiveTask } from 'src/hooks/tasksVerification/useResetCurrentActiveTask';
28+
import { useGoBack } from '@/hooks/routing/useGoBack';
2929

3030
interface MissionDetailsProps {
3131
mission: Quest;

0 commit comments

Comments
 (0)