Skip to content

Commit

Permalink
Merge branch 'develop' into LF-9574-jumper-frontend-make-superfest-re…
Browse files Browse the repository at this point in the history
…usable
  • Loading branch information
dennyscode committed Oct 1, 2024
2 parents 150e1ce + 176753a commit 1f1e128
Show file tree
Hide file tree
Showing 44 changed files with 1,385 additions and 1,563 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"react-error-boundary": "^4.0.13",
"react-i18next": "^15.0.2",
"react-router-dom": "^6.26.2",
"shallow-equal": "^3.1.0",
"sharp": "^0.33.5",
"siwe": "^2.3.2",
"typescript": "^5.6.2",
Expand Down
6 changes: 5 additions & 1 deletion src/app/[lng]/(infos)/learn/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { getArticles } from '@/app/lib/getArticles';
import { getFeaturedArticle } from '@/app/lib/getFeaturedArticle';
import LearnPage from '@/app/ui/learn/LearnPage';
import type { Metadata } from 'next';
import { getTags } from 'src/app/lib/getTags';

export async function generateMetadata(): Promise<Metadata> {
return {
Expand All @@ -18,9 +19,12 @@ export async function generateMetadata(): Promise<Metadata> {
export default async function Page() {
// TODO: make this component client side by removing async, a hook should do the job, will permit us to pre-render the pages
const featuredArticle = await getFeaturedArticle();
const carouselArticles = await getArticles(featuredArticle.data.id);
const carouselArticles = await getArticles(featuredArticle.data.id, 5);
const tags = await getTags();

return (
<LearnPage
tags={tags}
carouselArticles={carouselArticles}
featuredArticle={featuredArticle.data}
url={carouselArticles.url}
Expand Down
96 changes: 87 additions & 9 deletions src/app/[lng]/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,95 @@
import initTranslations from '@/app/i18n';
import TranslationsProvider from '@/providers/TranslationProvider';
import i18nConfig from 'i18nconfig';
import type { ReactNode } from 'react';
import React from 'react';
import { defaultNS, fallbackLng, namespaces } from 'src/i18n';
import { fonts } from '@/fonts/fonts';
import Script from 'next/script';
import { PixelBg } from '@/components/illustrations/PixelBg';
import { fonts } from '@/fonts/fonts';
import { ReactQueryProvider } from '@/providers/ReactQueryProvider';
import TranslationsProvider from '@/providers/TranslationProvider';
import { WalletProvider } from '@/providers/WalletProvider';
import { AppRouterCacheProvider } from '@mui/material-nextjs/v14-appRouter';
import i18nConfig from 'i18nconfig';
import Script from 'next/script';
import type { Viewport } from 'next/types';
import { metadata as JumperMetadata } from '../lib/metadata';
export const metadata = JumperMetadata;
import type { ReactNode } from 'react';
import { defaultNS, fallbackLng, namespaces } from 'src/i18n';
import { description, siteName, title } from '../lib/metadata';
import type { Metadata } from 'next';

interface RootLayoutProps {
children: ReactNode;
params: { lng: string };
}

export function generateMetadata({ params }: RootLayoutProps): Metadata {
return {
title,
description,
alternates: {
canonical: `${process.env.NEXT_PUBLIC_SITE_URL}/${params.lng === 'en' ? '' : params.lng}`,
},
openGraph: {
title: title,
description,
siteName,
url: `${process.env.NEXT_PUBLIC_SITE_URL}/${params.lng === 'en' ? '' : params.lng}`,
images: [
{
url: 'https://jumper.exchange/preview.png', // Default image
width: 900,
height: 450,
},
],
type: 'website', // Override type
},
twitter: {
// Twitter metadata
// cardType: 'summary_large_image',
site: '@JumperExchange',
title: title, // Twitter title
description,
images: 'https://jumper.exchange/preview.png', // Twitter image
},
icons: {
// Icons metadata
icon: [
{
url: '/favicon_DT.svg',
sizes: 'any',
media: '(prefers-color-scheme: dark)',
},
{ url: '/favicon_DT.png', media: '(prefers-color-scheme: dark)' },
{ url: '/favicon_DT.ico', media: '(prefers-color-scheme: dark)' },
{
url: '/favicon.svg',
sizes: 'any',
media: '(prefers-color-scheme: light)',
},
{ url: '/favicon.png', media: '(prefers-color-scheme: light)' },
{ url: '/favicon.ico', media: '(prefers-color-scheme: light)' },
],
shortcut: [
{
url: '/apple-touch-icon-57x57.png',
sizes: '57x57',
media: '(prefers-color-scheme: light)',
},
{
url: '/apple-touch-icon-180x180.png',
sizes: '180x180',
media: '(prefers-color-scheme: light)',
},
{
url: '/apple-touch-icon-57x57_DT.png',
sizes: '57x57',
media: '(prefers-color-scheme: dark)',
},
{
url: '/apple-touch-icon-180x180_DT.png',
sizes: '180x180',
media: '(prefers-color-scheme: dark)',
},
],
},
};
}

export const viewport: Viewport = {
initialScale: 1,
Expand All @@ -33,6 +110,7 @@ export default async function RootLayout({
lang={lng || fallbackLng}
suppressHydrationWarning
className={fonts.map((f) => f.variable).join(' ')}
style={{ scrollBehavior: 'smooth' }}
>
<head>
<link rel="icon" href="/favicon.ico" sizes="any" />
Expand Down
9 changes: 6 additions & 3 deletions src/app/lib/getArticles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ export interface GetArticlesResponse extends StrapiResponse<BlogArticleData> {

export async function getArticles(
excludeId?: number,
pageSize?: number,
): Promise<GetArticlesResponse> {
const urlParams = new ArticleStrapiApi()
.sort('desc')
.addPaginationParams({ page: 1, pageSize: 20, withCount: false });
const urlParams = new ArticleStrapiApi().sort('desc').addPaginationParams({
page: 1,
pageSize: pageSize || 20,
withCount: false,
});
const apiBaseUrl = urlParams.getApiBaseUrl();
const apiUrl = urlParams.getApiUrl();
const accessToken = urlParams.getApiAccessToken();
Expand Down
88 changes: 88 additions & 0 deletions src/app/lib/getTags.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import type { StrapiResponse, TagAttributes } from '@/types/strapi';
import { TagStrapiApi } from '@/utils/strapi/StrapiApi';

export interface GetTagsResponse extends StrapiResponse<TagAttributes> {
url: string;
}

const predefinedOrder = ['Announcement', 'Partner', 'Bridge'];

// Helper function to sort tags based on predefined order
const sortTagsByPredefinedOrder = (tags: TagAttributes[]) => {
return tags.sort((a, b) => {
const titleA = a.attributes.Title;
const titleB = b.attributes.Title;

const indexA = predefinedOrder.indexOf(titleA);
const indexB = predefinedOrder.indexOf(titleB);

if (indexA === -1 && indexB === -1) {
return 0;
}
if (indexA === -1) {
return 1;
}
if (indexB === -1) {
return -1;
}
return indexA - indexB;
});
};

// Helper function to sort blog articles by `publishedAt` date
const sortBlogArticlesByPublishedDate = (tags: TagAttributes[]) => {
return tags.map((tag) => {
tag.attributes.blog_articles.data = tag.attributes.blog_articles.data.sort(
(a, b) => {
const dateA = a.attributes.publishedAt
? Date.parse(a.attributes.publishedAt)
: -Infinity; // Default to oldest if undefined
const dateB = b.attributes.publishedAt
? Date.parse(b.attributes.publishedAt)
: -Infinity; // Default to oldest if undefined

return dateB - dateA;
},
);
return tag;
});
};

export async function getTags(): Promise<GetTagsResponse> {
const urlParams = new TagStrapiApi().addPaginationParams({
page: 1,
pageSize: 20,
withCount: false,
});
const apiBaseUrl = urlParams.getApiBaseUrl();
const apiUrl = urlParams.getApiUrl();
const accessToken = urlParams.getApiAccessToken();

const res = await fetch(decodeURIComponent(apiUrl), {
cache: 'force-cache',
headers: {
Authorization: `Bearer ${accessToken}`,
},
});

if (!res.ok) {
throw new Error('Failed to fetch data');
}

const data = await res.json().then((output) => {
let filteredData = output.data;

// Sort blog_articles by published date first
filteredData = sortBlogArticlesByPublishedDate(filteredData);

// Then sort tags by predefined order
filteredData = sortTagsByPredefinedOrder(filteredData);

return {
meta: output.meta,
data: filteredData,
};
});

return { ...data, url: apiBaseUrl };
}
75 changes: 1 addition & 74 deletions src/app/lib/metadata.ts
Original file line number Diff line number Diff line change
@@ -1,77 +1,4 @@
import type { Metadata } from 'next';

export const siteName = 'Jumper.Exchange';
export const title = 'Jumper | Multi-Chain Bridging & Swapping';
const description =
export const description =
'Jumper is Crypto’s Everything Exchange, enabling seamless swap and bridge transactions across 25 blockchains. By aggregating all of DeFi liquidity, Jumper ensures the best routes for any token transaction.';

export const metadata: Metadata = {
title,
description,
alternates: {
canonical: `${process.env.NEXT_PUBLIC_SITE_URL}/`,
},
openGraph: {
title: title,
description,
siteName,
url: `${process.env.NEXT_PUBLIC_SITE_URL}/`,
images: [
{
url: 'https://jumper.exchange/preview.png', // Default image
width: 900,
height: 450,
},
],
type: 'website', // Override type
},
twitter: {
// Twitter metadata
// cardType: 'summary_large_image',
site: '@JumperExchange',
title: title, // Twitter title
description,
images: 'https://jumper.exchange/preview.png', // Twitter image
},
icons: {
// Icons metadata
icon: [
{
url: '/favicon_DT.svg',
sizes: 'any',
media: '(prefers-color-scheme: dark)',
},
{ url: '/favicon_DT.png', media: '(prefers-color-scheme: dark)' },
{ url: '/favicon_DT.ico', media: '(prefers-color-scheme: dark)' },
{
url: '/favicon.svg',
sizes: 'any',
media: '(prefers-color-scheme: light)',
},
{ url: '/favicon.png', media: '(prefers-color-scheme: light)' },
{ url: '/favicon.ico', media: '(prefers-color-scheme: light)' },
],
shortcut: [
{
url: '/apple-touch-icon-57x57.png',
sizes: '57x57',
media: '(prefers-color-scheme: light)',
},
{
url: '/apple-touch-icon-180x180.png',
sizes: '180x180',
media: '(prefers-color-scheme: light)',
},
{
url: '/apple-touch-icon-57x57_DT.png',
sizes: '57x57',
media: '(prefers-color-scheme: dark)',
},
{
url: '/apple-touch-icon-180x180_DT.png',
sizes: '180x180',
media: '(prefers-color-scheme: dark)',
},
],
},
};
7 changes: 3 additions & 4 deletions src/app/sitemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,15 @@ function generateAlternates(path: string) {
return {
languages: {
...locales.reduce((acc, loc) => {
return {
const pages = {
...acc,
[loc]: withoutTrailingSlash(
`${process.env.NEXT_PUBLIC_SITE_URL}${loc !== 'en' ? `/${loc}` : ''}${path}`,
),
};

return pages;
}, {}),
'x-default': withoutTrailingSlash(
`${process.env.NEXT_PUBLIC_SITE_URL}${path}`,
),
},
};
}
Expand Down
6 changes: 5 additions & 1 deletion src/app/ui/learn/LearnPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,20 @@ import { BlogCarousel } from '@/components/Blog/BlogCarousel/BlogCarousel';
import { FeaturedArticle } from '@/components/Blog/FeaturedArticle/FeaturedArticle';
import { JoinDiscordBanner } from '@/components/JoinDiscordBanner/JoinDiscordBanner';
import type { BlogArticleData, StrapiResponse } from '@/types/strapi';
import type { GetTagsResponse } from 'src/app/lib/getTags';
import { BlogArticlesCollections } from 'src/components/Blog/BlogArticlesCollections/BlogArticlesCollections';

interface LearnPageProps {
carouselArticles: GetArticlesResponse;
featuredArticle: StrapiResponse<BlogArticleData>;
url: string;
tags: GetTagsResponse;
}

const LearnPage = ({
carouselArticles,
featuredArticle,
tags,
url,
}: LearnPageProps) => {
return (
Expand All @@ -28,7 +32,7 @@ const LearnPage = ({
)}
<BlogCarousel url={url} data={carouselArticles?.data} />
<JoinDiscordBanner />
{/* <BlogArticlesBoard /> */}
<BlogArticlesCollections tags={tags} data={carouselArticles?.data} />
</div>
);
};
Expand Down
Loading

0 comments on commit 1f1e128

Please sign in to comment.