From 5199ce099849574c05e3176641c3b6005487901c Mon Sep 17 00:00:00 2001 From: kaladinlight <35275952+kaladinlight@users.noreply.github.com> Date: Fri, 20 Feb 2026 18:01:28 -0700 Subject: [PATCH 1/5] fix issues with railway website-backend interaction and lint --- .github/workflows/lint.yml | 34 +- .prettierrc | 2 +- app/[lang]/(core-products)/README.md | 12 +- .../_components/DownloadButtons.tsx | 4 +- .../_components/ProductFetcher.ts | 44 +- .../_components/ProductFooterBanner.tsx | 5 +- .../_components/ProductHero.tsx | 17 +- .../_components/ProductStats.tsx | 4 +- .../(core-products)/_components/README.md | 2 +- .../(core-products)/_components/TradeHero.tsx | 10 +- .../(core-products)/defi-wallet/page.tsx | 7 +- app/[lang]/(core-products)/earn/page.tsx | 7 +- .../(core-products)/mobile-app/page.tsx | 7 +- app/[lang]/(core-products)/trade/page.tsx | 9 +- .../(resources)/_components/ChainList.tsx | 10 +- .../_components/DiscoverFeature.tsx | 7 +- .../(resources)/_components/FAQContent.tsx | 4 +- .../(resources)/_components/FAQNavigation.tsx | 12 +- .../(resources)/_components/PostList.tsx | 20 +- .../(resources)/_components/ProtocolAbout.tsx | 6 +- .../_components/ProtocolHeader.tsx | 18 +- .../(resources)/_components/ProtocolList.tsx | 10 +- app/[lang]/(resources)/_components/README.md | 10 +- .../(resources)/_components/ResourceCard.tsx | 25 +- .../(resources)/_components/ResourceGrid.tsx | 12 +- .../_components/ResourceHeader.tsx | 28 +- .../(resources)/_components/ResourceHero.tsx | 20 +- .../_components/SupportArticleList.tsx | 16 +- .../SupportArticleListSkeleton.tsx | 4 +- .../_components/SupportedWalletHeader.tsx | 8 +- .../(resources)/_components/WalletList.tsx | 10 +- .../categories/[category]/page.tsx | 2 +- .../blog/(withNavigation)/layout.tsx | 4 +- app/[lang]/(resources)/blog/README.md | 28 +- app/[lang]/(resources)/blog/[slug]/layout.tsx | 6 +- app/[lang]/(resources)/chains/README.md | 4 +- app/[lang]/(resources)/chains/[slug]/page.tsx | 8 +- .../chains/_components/ChainSearchWrapper.tsx | 4 +- app/[lang]/(resources)/discover/README.md | 4 +- .../(resources)/discover/[slug]/page.tsx | 9 +- .../_components/DiscoverSearchWrapper.tsx | 4 +- app/[lang]/(resources)/faq/README.md | 8 +- .../categories/[category]/page.tsx | 2 +- .../newsroom/(withNavigation)/layout.tsx | 4 +- app/[lang]/(resources)/newsroom/README.md | 26 +- .../(resources)/newsroom/[slug]/layout.tsx | 6 +- app/[lang]/(resources)/protocols/README.md | 4 +- .../(resources)/protocols/[slug]/page.tsx | 8 +- .../_components/ProtocolSearchWrapper.tsx | 4 +- app/[lang]/(resources)/wallets/README.md | 4 +- .../(resources)/wallets/[slug]/page.tsx | 8 +- .../_components/WalletSearchWrapper.tsx | 4 +- app/[lang]/(terms)/README.md | 16 +- app/[lang]/(terms)/_components/README.md | 2 +- app/[lang]/(terms)/_components/TermsPage.tsx | 6 +- app/[lang]/(terms)/error.tsx | 6 +- app/[lang]/(terms)/layout.tsx | 4 +- app/[lang]/_components/AnimatedHeight.tsx | 6 +- app/[lang]/_components/BlogPost.tsx | 6 +- app/[lang]/_components/Button.tsx | 16 +- app/[lang]/_components/Carousel.tsx | 10 +- app/[lang]/_components/ChainsBanner.tsx | 10 +- app/[lang]/_components/ChatwootWidget.tsx | 22 +- app/[lang]/_components/Dropdown.tsx | 12 +- app/[lang]/_components/ElementCard.tsx | 23 +- app/[lang]/_components/FooterBanner.tsx | 10 +- app/[lang]/_components/HeaderItem.tsx | 18 +- app/[lang]/_components/LandingInfoCard.tsx | 6 +- app/[lang]/_components/LocalizedLink.tsx | 4 +- app/[lang]/_components/Modal.tsx | 10 +- app/[lang]/_components/NewsPost.tsx | 4 +- app/[lang]/_components/NotificationBar.tsx | 6 +- app/[lang]/_components/Popup.tsx | 10 +- app/[lang]/_components/RoundButton.tsx | 6 +- app/[lang]/_components/SearchBar.tsx | 6 +- app/[lang]/_components/TabItem.tsx | 10 +- app/[lang]/_components/WalletRequestCard.tsx | 12 +- .../_components/header/DesktopHeader.tsx | 8 +- app/[lang]/_components/header/Header.tsx | 4 +- .../_components/header/LanguageExpand.tsx | 4 +- .../_components/header/MobileHeader.tsx | 4 +- .../_components/strapi/cards-row/Card.tsx | 5 +- .../_components/strapi/cards-row/CardsRow.tsx | 4 +- .../strapi/products/CarouselCard.tsx | 15 +- .../strapi/products/ChainBubblesCard.tsx | 23 +- .../_components/strapi/products/Grid.tsx | 3 +- .../strapi/products/GridDisplaced.tsx | 4 +- .../strapi/products/GridLadder.tsx | 3 +- .../strapi/templates/ChainFeatures.tsx | 3 +- app/[lang]/_components/strapi/types.ts | 482 +++++++++--------- .../_components/trading/ChainSelect.tsx | 24 +- .../_components/trading/TokenSelect.tsx | 28 +- .../_components/trading/TradingWidget.tsx | 8 +- .../_contexts/CachedArticlesContext.tsx | 28 +- app/[lang]/_contexts/CachedNewsContext.tsx | 32 +- app/[lang]/_contexts/CachedPostsContext.tsx | 32 +- app/[lang]/_contexts/LanguageContext.tsx | 24 +- app/[lang]/_hooks/useFetchNewsroom.tsx | 26 +- app/[lang]/_hooks/useFetchPosts.tsx | 26 +- app/[lang]/_hooks/useFetchSupportArticles.ts | 22 +- app/[lang]/_utils/README.md | 6 +- app/[lang]/_utils/i18nconfig.ts | 10 +- app/[lang]/_utils/query.ts | 15 + app/[lang]/_utils/schema.ts | 13 +- app/[lang]/dao/fox-token/page.tsx | 13 +- eslint.config.mjs | 151 +++--- next.config.ts | 6 +- package.json | 122 ++--- postcss.config.mjs | 4 +- scripts/release.ts | 20 +- scripts/utils.ts | 4 +- tailwind.config.ts | 4 +- 112 files changed, 999 insertions(+), 957 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index e7f3863..494b8fb 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,26 +1,26 @@ name: Lint on: - pull_request: - branches: [main, develop] - push: - branches: [main, develop] + pull_request: + branches: [main, develop] + push: + branches: [main, develop] jobs: - lint: - runs-on: ubuntu-latest + lint: + runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 + steps: + - name: Checkout code + uses: actions/checkout@v4 - - name: Setup Bun - uses: oven-sh/setup-bun@v2 - with: - bun-version: latest + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: latest - - name: Install dependencies - run: bun install --frozen-lockfile + - name: Install dependencies + run: bun install --frozen-lockfile - - name: Run ESLint - run: bun run lint + - name: Run ESLint + run: bun run lint diff --git a/.prettierrc b/.prettierrc index 19a28d9..ca544ea 100644 --- a/.prettierrc +++ b/.prettierrc @@ -9,4 +9,4 @@ "bracketSameLine": true, "singleAttributePerLine": true, "printWidth": 120 -} \ No newline at end of file +} diff --git a/app/[lang]/(core-products)/README.md b/app/[lang]/(core-products)/README.md index df358e7..ccb7bae 100644 --- a/app/[lang]/(core-products)/README.md +++ b/app/[lang]/(core-products)/README.md @@ -4,17 +4,18 @@ This directory contains all product-related pages and components for ShapeShift' ## Directory Structure -- **_components/**: Shared components used across all core product pages - - Product heroes, stats displays, background images, etc. - - Utility functions and constants for product data fetching +- **\_components/**: Shared components used across all core product pages + - Product heroes, stats displays, background images, etc. + - Utility functions and constants for product data fetching - **defi-wallet/**: DeFi wallet product page - **earn/**: Yield-earning opportunities product page -- **mobile-app/**: Mobile application product page +- **mobile-app/**: Mobile application product page - **trade/**: Trading platform product page ## Route Convention The parentheses in the directory name `(core-products)` indicate a route group in Next.js. This means: + - The folder name itself doesn't affect URL paths - All pages inside share UI layouts and features - It keeps related features organized without affecting the URL structure @@ -22,6 +23,7 @@ The parentheses in the directory name `(core-products)` indicate a route group i ## Component Integration The components in this directory are designed to: + - Integrate with the main layout defined in the app root - Share consistent styling and branding - Leverage common utilities for product data fetching @@ -32,4 +34,4 @@ The components in this directory are designed to: - Follow the design patterns established in the shared components - Maintain consistent UI/UX across all product pages - Use the ProductFetcher utility for data retrieval -- Ensure responsive layouts for all device sizes \ No newline at end of file +- Ensure responsive layouts for all device sizes diff --git a/app/[lang]/(core-products)/_components/DownloadButtons.tsx b/app/[lang]/(core-products)/_components/DownloadButtons.tsx index 4e4c94e..46b7b80 100644 --- a/app/[lang]/(core-products)/_components/DownloadButtons.tsx +++ b/app/[lang]/(core-products)/_components/DownloadButtons.tsx @@ -23,8 +23,8 @@ import type {TDownloadButton} from '@/app/[lang]/_components/strapi/types' import type {ReactNode} from 'react' type TDownloadButtonsProps = { - buttons: TDownloadButton[]; -}; + buttons: TDownloadButton[] +} export function DownloadButtons({buttons}: TDownloadButtonsProps): ReactNode { if (!buttons || buttons.length === 0) { diff --git a/app/[lang]/(core-products)/_components/ProductFetcher.ts b/app/[lang]/(core-products)/_components/ProductFetcher.ts index e7e46af..f3fbbe0 100644 --- a/app/[lang]/(core-products)/_components/ProductFetcher.ts +++ b/app/[lang]/(core-products)/_components/ProductFetcher.ts @@ -53,52 +53,52 @@ import type { * Base type containing properties common to all product pages ************************************************************************************************/ type TBaseProductPage = { - title: string; - description: string; - featuredImg: TStrapiImage; - footer: TFooterSection; -}; + title: string + description: string + featuredImg: TStrapiImage + footer: TFooterSection +} /************************************************************************************************ * DeFi Wallet page data structure * Features card row layout highlighting wallet capabilities ************************************************************************************************/ type TDeFiWalletPage = TBaseProductPage & { - buttonCta: TButton; - buttonDownload: TButton[]; - cardsRow: TCardsRowSection; -}; + buttonCta: TButton + buttonDownload: TButton[] + cardsRow: TCardsRowSection +} /************************************************************************************************ * Earn page data structure * Features grid layout showcasing earning opportunities ************************************************************************************************/ type TEarnPage = TBaseProductPage & { - buttonCta: TButton; - buttonDownload: TButton[]; - grid: TGridSection; -}; + buttonCta: TButton + buttonDownload: TButton[] + grid: TGridSection +} /************************************************************************************************ * Mobile App page data structure * Features step-by-step ladder grid and download buttons ************************************************************************************************/ type TMobileAppPage = TBaseProductPage & { - buttonCta: TButton; - buttonDownload: TDownloadButton[]; - gridLadder: TGridLadderSection; -}; + buttonCta: TButton + buttonDownload: TDownloadButton[] + gridLadder: TGridLadderSection +} /************************************************************************************************ * Trade page data structure * Features statistics, card row, and displaced grid layout ************************************************************************************************/ type TTradePage = TBaseProductPage & { - buttonCta: TButton; - stats: TStat[]; - cardsRow: TCardsRowSection; - gridDisplaced: TGridDisplacedSection; -}; + buttonCta: TButton + stats: TStat[] + cardsRow: TCardsRowSection + gridDisplaced: TGridDisplacedSection +} /************************************************************************************************ * Fetches DeFi Wallet page data from Strapi API diff --git a/app/[lang]/(core-products)/_components/ProductFooterBanner.tsx b/app/[lang]/(core-products)/_components/ProductFooterBanner.tsx index 6ed0ff4..a1d837c 100644 --- a/app/[lang]/(core-products)/_components/ProductFooterBanner.tsx +++ b/app/[lang]/(core-products)/_components/ProductFooterBanner.tsx @@ -1,4 +1,3 @@ - /************************************************************************************************ ** ProductFooterBanner Component: ** @@ -25,8 +24,8 @@ import {PRODUCT_FOOTER_CONFIGS} from './constants' import type {ReactNode} from 'react' type TProductFooterBannerProps = { - productName: keyof typeof PRODUCT_FOOTER_CONFIGS; -}; + productName: keyof typeof PRODUCT_FOOTER_CONFIGS +} export function ProductFooterBanner({productName}: TProductFooterBannerProps): ReactNode { // Get configuration for the specified product diff --git a/app/[lang]/(core-products)/_components/ProductHero.tsx b/app/[lang]/(core-products)/_components/ProductHero.tsx index e19592b..ca7c53c 100644 --- a/app/[lang]/(core-products)/_components/ProductHero.tsx +++ b/app/[lang]/(core-products)/_components/ProductHero.tsx @@ -20,18 +20,19 @@ import Image from 'next/image' import {Button} from '@/app/[lang]/_components/Button' +import {getStrapiImageUrl} from '@/app/[lang]/_utils/query' import type {TButton, TStrapiImage} from '@/app/[lang]/_components/strapi/types' import type {ReactNode} from 'react' type TProductHeroProps = { - title: string; - description: string; - buttonCta?: TButton; // Optional because mobile-app doesn't use it - featuredImg: TStrapiImage; - children?: ReactNode; // Additional content like stats or download buttons - buttonClassName?: string; -}; + title: string + description: string + buttonCta?: TButton // Optional because mobile-app doesn't use it + featuredImg: TStrapiImage + children?: ReactNode // Additional content like stats or download buttons + buttonClassName?: string +} export function ProductHero({ title, @@ -63,7 +64,7 @@ export function ProductHero({
{title { type: 'website', images: [ { - url: `${process.env.NEXT_PUBLIC_STRAPI_URL}${page.featuredImg.url}`, + url: getStrapiImageUrl(page.featuredImg.url), width: 1200, height: 630, alt: page.title @@ -59,7 +60,7 @@ export async function generateMetadata(): Promise { card: 'summary_large_image', title: page.title, description: page.description, - images: [`${process.env.NEXT_PUBLIC_STRAPI_URL}${page.featuredImg.url}`] + images: [getStrapiImageUrl(page.featuredImg.url)] } } } @@ -88,7 +89,7 @@ export default async function DeFiWalletPage(): Promise { const productSchema = generateProductSchema({ title: page.title, description: page.description, - featuredImage: `${process.env.NEXT_PUBLIC_STRAPI_URL}${page.featuredImg.url}`, + featuredImage: getStrapiImageUrl(page.featuredImg.url), pageURL, features }) diff --git a/app/[lang]/(core-products)/earn/page.tsx b/app/[lang]/(core-products)/earn/page.tsx index f2df6f2..49a3f0a 100644 --- a/app/[lang]/(core-products)/earn/page.tsx +++ b/app/[lang]/(core-products)/earn/page.tsx @@ -19,6 +19,7 @@ import {notFound} from 'next/navigation' import Script from 'next/script' import Grid from '@/app/[lang]/_components/strapi/products/Grid' +import {getStrapiImageUrl} from '@/app/[lang]/_utils/query' import {generateProductSchema} from '@/app/[lang]/_utils/schema' import {BackgroundImage} from '../_components/BackgroundImage' @@ -46,7 +47,7 @@ export async function generateMetadata(): Promise { type: 'website', images: [ { - url: `${process.env.NEXT_PUBLIC_STRAPI_URL}${page.featuredImg.url}`, + url: getStrapiImageUrl(page.featuredImg.url), width: 1200, height: 630, alt: page.title @@ -57,7 +58,7 @@ export async function generateMetadata(): Promise { card: 'summary_large_image', title: page.title, description: page.description, - images: [`${process.env.NEXT_PUBLIC_STRAPI_URL}${page.featuredImg.url}`] + images: [getStrapiImageUrl(page.featuredImg.url)] } } } @@ -86,7 +87,7 @@ export default async function EarnPage(): Promise { const productSchema = generateProductSchema({ title: page.title, description: page.description, - featuredImage: `${process.env.NEXT_PUBLIC_STRAPI_URL}${page.featuredImg.url}`, + featuredImage: getStrapiImageUrl(page.featuredImg.url), pageURL, features }) diff --git a/app/[lang]/(core-products)/mobile-app/page.tsx b/app/[lang]/(core-products)/mobile-app/page.tsx index 2625306..d8bd487 100644 --- a/app/[lang]/(core-products)/mobile-app/page.tsx +++ b/app/[lang]/(core-products)/mobile-app/page.tsx @@ -19,6 +19,7 @@ import {notFound} from 'next/navigation' import Script from 'next/script' import GridLadder from '@/app/[lang]/_components/strapi/products/GridLadder' +import {getStrapiImageUrl} from '@/app/[lang]/_utils/query' import {generateProductSchema} from '@/app/[lang]/_utils/schema' import {BackgroundImage} from '../_components/BackgroundImage' @@ -47,7 +48,7 @@ export async function generateMetadata(): Promise { type: 'website', images: [ { - url: `${process.env.NEXT_PUBLIC_STRAPI_URL}${page.featuredImg.url}`, + url: getStrapiImageUrl(page.featuredImg.url), width: 1200, height: 630, alt: page.title @@ -58,7 +59,7 @@ export async function generateMetadata(): Promise { card: 'summary_large_image', title: page.title, description: page.description, - images: [`${process.env.NEXT_PUBLIC_STRAPI_URL}${page.featuredImg.url}`] + images: [getStrapiImageUrl(page.featuredImg.url)] } } } @@ -87,7 +88,7 @@ export default async function MobileAppPage(): Promise { const productSchema = generateProductSchema({ title: page.title, description: page.description, - featuredImage: `${process.env.NEXT_PUBLIC_STRAPI_URL}${page.featuredImg.url}`, + featuredImage: getStrapiImageUrl(page.featuredImg.url), pageURL, features }) diff --git a/app/[lang]/(core-products)/trade/page.tsx b/app/[lang]/(core-products)/trade/page.tsx index 5d30ec6..37810ea 100644 --- a/app/[lang]/(core-products)/trade/page.tsx +++ b/app/[lang]/(core-products)/trade/page.tsx @@ -23,6 +23,7 @@ import Script from 'next/script' import {Card} from '@/app/[lang]/_components/strapi/cards-row/Card' import CardsRow from '@/app/[lang]/_components/strapi/cards-row/CardsRow' import GridDisplaced from '@/app/[lang]/_components/strapi/products/GridDisplaced' +import {getStrapiImageUrl} from '@/app/[lang]/_utils/query' import {generateProductSchema} from '@/app/[lang]/_utils/schema' import {BackgroundImage} from '../_components/BackgroundImage' @@ -52,7 +53,7 @@ export async function generateMetadata(): Promise { type: 'website', images: [ { - url: `${process.env.NEXT_PUBLIC_STRAPI_URL}${page.featuredImg.url}`, + url: getStrapiImageUrl(page.featuredImg.url), width: 1200, height: 630, alt: page.title @@ -63,7 +64,7 @@ export async function generateMetadata(): Promise { card: 'summary_large_image', title: page.title, description: page.description, - images: [`${process.env.NEXT_PUBLIC_STRAPI_URL}${page.featuredImg.url}`] + images: [getStrapiImageUrl(page.featuredImg.url)] } } } @@ -92,7 +93,7 @@ export default async function TradePage(): Promise { const productSchema = generateProductSchema({ title: page.title, description: page.description, - featuredImage: `${process.env.NEXT_PUBLIC_STRAPI_URL}${page.featuredImg.url}`, + featuredImage: getStrapiImageUrl(page.featuredImg.url), pageURL, features }) @@ -115,7 +116,7 @@ export default async function TradePage(): Promise { title={page.title} description={page.description} buttonCta={page.buttonCta} - imageUrl={`${process.env.NEXT_PUBLIC_STRAPI_URL}${page.featuredImg.url}`} + imageUrl={getStrapiImageUrl(page.featuredImg.url)} /> {/* Feature cards section */} diff --git a/app/[lang]/(resources)/_components/ChainList.tsx b/app/[lang]/(resources)/_components/ChainList.tsx index f4a8904..a3fc486 100644 --- a/app/[lang]/(resources)/_components/ChainList.tsx +++ b/app/[lang]/(resources)/_components/ChainList.tsx @@ -21,11 +21,11 @@ import type {TSupportedChainData} from '@/app/[lang]/_components/strapi/types' import type {ReactNode} from 'react' type TChainListProps = { - chains: TSupportedChainData[] | null; - isLoading?: boolean; - className?: string; - isSearchQuery?: boolean; -}; + chains: TSupportedChainData[] | null + isLoading?: boolean + className?: string + isSearchQuery?: boolean +} export function ChainList({chains, isLoading, className, isSearchQuery}: TChainListProps): ReactNode { return ( diff --git a/app/[lang]/(resources)/_components/DiscoverFeature.tsx b/app/[lang]/(resources)/_components/DiscoverFeature.tsx index a3a92a2..674b8ad 100644 --- a/app/[lang]/(resources)/_components/DiscoverFeature.tsx +++ b/app/[lang]/(resources)/_components/DiscoverFeature.tsx @@ -21,6 +21,7 @@ import Image from 'next/image' import {LocalizedLink} from '@/app/[lang]/_components/LocalizedLink' import {cl} from '@/app/[lang]/_utils/cl' +import {getStrapiImageUrl} from '@/app/[lang]/_utils/query' import type {ReactNode} from 'react' @@ -92,11 +93,7 @@ export function DiscoverFeature({ {feature.image?.url && (
{feature.image.alt('') diff --git a/app/[lang]/(resources)/_components/FAQNavigation.tsx b/app/[lang]/(resources)/_components/FAQNavigation.tsx index de1352a..7e306e7 100644 --- a/app/[lang]/(resources)/_components/FAQNavigation.tsx +++ b/app/[lang]/(resources)/_components/FAQNavigation.tsx @@ -24,12 +24,12 @@ import type {ReactNode} from 'react' type TFAQNavigationProps = { sections: { - id: number; - sectionTitle: string; - }[]; - activeSection: string; - onSectionClick: (sectionTitle: string) => void; -}; + id: number + sectionTitle: string + }[] + activeSection: string + onSectionClick: (sectionTitle: string) => void +} export function FAQNavigation({sections, activeSection, onSectionClick}: TFAQNavigationProps): ReactNode { if (!sections || sections.length === 0) { diff --git a/app/[lang]/(resources)/_components/PostList.tsx b/app/[lang]/(resources)/_components/PostList.tsx index 8a88090..9b5c9d7 100644 --- a/app/[lang]/(resources)/_components/PostList.tsx +++ b/app/[lang]/(resources)/_components/PostList.tsx @@ -33,16 +33,16 @@ import type {TBlogPost} from '@/app/[lang]/_components/strapi/types' import type {ReactNode} from 'react' type TPostListProps = { - pageSize?: number; - sort?: 'asc' | 'desc'; - initialPage?: number; - populateContent?: boolean; - cachePosts?: boolean; - emptyMessage?: string; - category?: string; - tag?: string; - gridClassName?: string; -}; + pageSize?: number + sort?: 'asc' | 'desc' + initialPage?: number + populateContent?: boolean + cachePosts?: boolean + emptyMessage?: string + category?: string + tag?: string + gridClassName?: string +} export function PostList({ pageSize = DEFAULT_PAGINATION.PAGE_SIZE, diff --git a/app/[lang]/(resources)/_components/ProtocolAbout.tsx b/app/[lang]/(resources)/_components/ProtocolAbout.tsx index 18bf94b..4ba2a07 100644 --- a/app/[lang]/(resources)/_components/ProtocolAbout.tsx +++ b/app/[lang]/(resources)/_components/ProtocolAbout.tsx @@ -1,9 +1,9 @@ import type {ReactNode} from 'react' type THeaderData = { - name: string; - description: string; -}; + name: string + description: string +} export function ProtocolAbout(data: THeaderData): ReactNode { return (
diff --git a/app/[lang]/(resources)/_components/ProtocolHeader.tsx b/app/[lang]/(resources)/_components/ProtocolHeader.tsx index 05c8fb8..1f0bbfa 100644 --- a/app/[lang]/(resources)/_components/ProtocolHeader.tsx +++ b/app/[lang]/(resources)/_components/ProtocolHeader.tsx @@ -7,13 +7,13 @@ import {IconCheck} from '@/app/[lang]/_icons/IconCheck' import type {ReactNode} from 'react' type THeaderData = { - description: string; - items: string[]; - url: string; - width: number; - height: number; - name: string; -}; + description: string + items: string[] + url: string + width: number + height: number + name: string +} export function ProtocolHeader(data: THeaderData): ReactNode { return ( @@ -33,9 +33,7 @@ export function ProtocolHeader(data: THeaderData): ReactNode { {`Shift into ${data.name}`}

- { - 'Say goodbye to multiple interfaces and hello to ShapeShift.' - } + {'Say goodbye to multiple interfaces and hello to ShapeShift.'}

-
+ return ( +
+
+
+

{title}

+
+

{description}

+ {buttonCta ? ( +
+
-
- {title -
-
-
- ) +
+ {title +
+ + + ) } diff --git a/app/[lang]/(core-products)/_components/ProductStats.tsx b/app/[lang]/(core-products)/_components/ProductStats.tsx index 7f8f3e7..3584ddf 100644 --- a/app/[lang]/(core-products)/_components/ProductStats.tsx +++ b/app/[lang]/(core-products)/_components/ProductStats.tsx @@ -16,35 +16,37 @@ ** - Stats will be arranged in a row (desktop) or column (mobile) ************************************************************************************************/ -import type {TStat} from '@/app/[lang]/_components/strapi/types' -import type {ReactNode} from 'react' +import type { TStat } from '@/app/[lang]/_components/strapi/types' +import type { ReactNode } from 'react' type TProductStatsProps = { - stats: TStat[] + stats: TStat[] } -export function ProductStats({stats = []}: TProductStatsProps): ReactNode { - // Handle case where stats is null, undefined, or empty - if (!stats || stats.length === 0) { - return
{'No statistics available'}
- } +export function ProductStats({ stats = [] }: TProductStatsProps): ReactNode { + // Handle case where stats is null, undefined, or empty + if (!stats || stats.length === 0) { + return
{'No statistics available'}
+ } - return ( -
- {stats.map(stat => ( -
-
- {stat.value} -
-
{stat.title}
-
- ))} -
- ) + return ( +
+ {stats.map((stat) => ( +
+
+ {stat.value} +
+
{stat.title}
+
+ ))} +
+ ) } diff --git a/app/[lang]/(core-products)/_components/TradeHero.tsx b/app/[lang]/(core-products)/_components/TradeHero.tsx index fe66b36..78ad47b 100644 --- a/app/[lang]/(core-products)/_components/TradeHero.tsx +++ b/app/[lang]/(core-products)/_components/TradeHero.tsx @@ -1,6 +1,6 @@ 'use client' -import {Button} from '@/app/[lang]/_components/Button' +import { Button } from '@/app/[lang]/_components/Button' /************************************************************************************************ ** TradeHero Component: ** @@ -19,68 +19,64 @@ import {Button} from '@/app/[lang]/_components/Button' ** - Requires 'use client' directive for client-side interactivity ************************************************************************************************/ -import type {TButton} from '@/app/[lang]/_components/strapi/types' -import type {ReactNode} from 'react' +import type { TButton } from '@/app/[lang]/_components/strapi/types' +import type { ReactNode } from 'react' type TTradeHeroProps = { - title: string - description: string - buttonCta: TButton - imageUrl: string + title: string + description: string + buttonCta: TButton + imageUrl: string } -export function TradeHero({title, description, buttonCta, imageUrl}: TTradeHeroProps): ReactNode { - // Handle button click to open URL in new tab with security precautions - const handleButtonClick = (): void => { - if (buttonCta?.url) { - window.open(buttonCta.url, '_blank', 'noopener,noreferrer') - } - } +export function TradeHero({ title, description, buttonCta, imageUrl }: TTradeHeroProps): ReactNode { + // Handle button click to open URL in new tab with security precautions + const handleButtonClick = (): void => { + if (buttonCta?.url) { + window.open(buttonCta.url, '_blank', 'noopener,noreferrer') + } + } - return ( -
-
- {/* Title, description and CTA button */} -
-

- {title} -

-
-

{description}

- {buttonCta && ( -
-
+ return ( +
+
+ {/* Title, description and CTA button */} +
+

+ {title} +

+
+

{description}

+ {buttonCta && ( +
+
- {/* Featured image with responsive display */} -
- - - {title - -
-
-
- ) + {/* Featured image with responsive display */} +
+ + + {title + +
+
+
+ ) } diff --git a/app/[lang]/(core-products)/_components/constants.ts b/app/[lang]/(core-products)/_components/constants.ts index 7850432..bca2029 100644 --- a/app/[lang]/(core-products)/_components/constants.ts +++ b/app/[lang]/(core-products)/_components/constants.ts @@ -19,28 +19,28 @@ * Contains display text, button text, and target URLs */ export const PRODUCT_FOOTER_CONFIGS = { - 'defi-wallet': { - tag: 'ShapeShift DeFi wallet', - title: 'Everything you need in one place.', - buttonText: 'Get started', - href: 'https://app.shapeshift.com' - }, - earn: { - tag: 'Earn with ShapeShift', - title: 'Everything you need in one place.', - buttonText: 'Start Earning', - href: 'https://app.shapeshift.com/#/earn' - }, - trade: { - tag: 'Trade with ShapeShift', - title: 'Everything you need in one place.', - buttonText: 'Start Trading', - href: 'https://app.shapeshift.com/' - }, - 'mobile-app': { - tag: 'ShapeShift mobile app', - title: 'Everything you need in one place.', - buttonText: 'Start Earning', - href: 'https://app.shapeshift.com/#/earn' - } + 'defi-wallet': { + tag: 'ShapeShift DeFi wallet', + title: 'Everything you need in one place.', + buttonText: 'Get started', + href: 'https://app.shapeshift.com', + }, + earn: { + tag: 'Earn with ShapeShift', + title: 'Everything you need in one place.', + buttonText: 'Start Earning', + href: 'https://app.shapeshift.com/#/earn', + }, + trade: { + tag: 'Trade with ShapeShift', + title: 'Everything you need in one place.', + buttonText: 'Start Trading', + href: 'https://app.shapeshift.com/', + }, + 'mobile-app': { + tag: 'ShapeShift mobile app', + title: 'Everything you need in one place.', + buttonText: 'Start Earning', + href: 'https://app.shapeshift.com/#/earn', + }, } diff --git a/app/[lang]/(core-products)/_components/fetchUtils.ts b/app/[lang]/(core-products)/_components/fetchUtils.ts index 2381ea6..6f643dd 100644 --- a/app/[lang]/(core-products)/_components/fetchUtils.ts +++ b/app/[lang]/(core-products)/_components/fetchUtils.ts @@ -7,29 +7,29 @@ * @returns Properly typed response data or null on error ************************************************************************************************/ export async function fetchWithErrorHandling( - endpoint: string, - queryParams: string, - error: string + endpoint: string, + queryParams: string, + error: string ): Promise { - try { - const response = await fetch(`${process.env.NEXT_PUBLIC_STRAPI_URL}/api/${endpoint}?${queryParams}`, { - headers: { - Authorization: `Bearer ${process.env.NEXT_PUBLIC_STRAPI_API_TOKEN}` - }, - next: { - revalidate: 3600 // Cache for 1 hour - } - }) + try { + const response = await fetch(`${process.env.NEXT_PUBLIC_STRAPI_URL}/api/${endpoint}?${queryParams}`, { + headers: { + Authorization: `Bearer ${process.env.NEXT_PUBLIC_STRAPI_API_TOKEN}`, + }, + next: { + revalidate: 3600, // Cache for 1 hour + }, + }) - if (!response.ok) { - console.error(`Failed to fetch ${error}: Status ${response.status}`) - return null - } + if (!response.ok) { + console.error(`Failed to fetch ${error}: Status ${response.status}`) + return null + } - const data = await response.json() - return data.data - } catch (error) { - console.error(`Error fetching ${error}:`, error instanceof Error ? error.message : String(error)) - return null - } + const data = await response.json() + return data.data + } catch (error) { + console.error(`Error fetching ${error}:`, error instanceof Error ? error.message : String(error)) + return null + } } diff --git a/app/[lang]/(core-products)/defi-wallet/page.tsx b/app/[lang]/(core-products)/defi-wallet/page.tsx index 1f257a3..b1ec4bb 100644 --- a/app/[lang]/(core-products)/defi-wallet/page.tsx +++ b/app/[lang]/(core-products)/defi-wallet/page.tsx @@ -15,114 +15,111 @@ ** - Includes text content, button configurations, and images ************************************************************************************************/ -import {notFound} from 'next/navigation' +import { notFound } from 'next/navigation' import Script from 'next/script' -import {Card} from '@/app/[lang]/_components/strapi/cards-row/Card' +import { Card } from '@/app/[lang]/_components/strapi/cards-row/Card' import CardsRow from '@/app/[lang]/_components/strapi/cards-row/CardsRow' -import {getStrapiImageUrl} from '@/app/[lang]/_utils/query' -import {generateProductSchema} from '@/app/[lang]/_utils/schema' +import { getStrapiImageUrl } from '@/app/[lang]/_utils/query' +import { generateProductSchema } from '@/app/[lang]/_utils/schema' -import {BackgroundImage} from '../_components/BackgroundImage' -import {fetchDeFiWalletPage} from '../_components/ProductFetcher' -import {ProductFooterBanner} from '../_components/ProductFooterBanner' -import {ProductHero} from '../_components/ProductHero' +import { BackgroundImage } from '../_components/BackgroundImage' +import { fetchDeFiWalletPage } from '../_components/ProductFetcher' +import { ProductFooterBanner } from '../_components/ProductFooterBanner' +import { ProductHero } from '../_components/ProductHero' -import type {TCard} from '@/app/[lang]/_components/strapi/types' -import type {Metadata} from 'next' -import type {ReactNode} from 'react' +import type { TCard } from '@/app/[lang]/_components/strapi/types' +import type { Metadata } from 'next' +import type { ReactNode } from 'react' // Generate metadata for SEO export async function generateMetadata(): Promise { - const page = await fetchDeFiWalletPage() - - if (!page) { - return {} - } - - return { - title: page.title, - description: page.description, - openGraph: { - title: page.title, - description: page.description, - type: 'website', - images: [ - { - url: getStrapiImageUrl(page.featuredImg.url), - width: 1200, - height: 630, - alt: page.title - } - ] - }, - twitter: { - card: 'summary_large_image', - title: page.title, - description: page.description, - images: [getStrapiImageUrl(page.featuredImg.url)] - } - } + const page = await fetchDeFiWalletPage() + + if (!page) { + return {} + } + + return { + title: page.title, + description: page.description, + openGraph: { + title: page.title, + description: page.description, + type: 'website', + images: [ + { + url: getStrapiImageUrl(page.featuredImg.url), + width: 1200, + height: 630, + alt: page.title, + }, + ], + }, + twitter: { + card: 'summary_large_image', + title: page.title, + description: page.description, + images: [getStrapiImageUrl(page.featuredImg.url)], + }, + } } export default async function DeFiWalletPage(): Promise { - // Fetch page data from Strapi CMS - const page = await fetchDeFiWalletPage() - - // Handle case where page data is not found - if (!page) { - console.error('DeFi Wallet page data not found') - return notFound() - } - - // Generate structured data for product - const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://shapeshift.com' - const pageURL = `${baseUrl}/defi-wallet` - - // Map card data to features format for schema - const features = page.cardsRow.cards.map(card => ({ - title: card.title, - description: card.description - })) - - // Generate product schema - const productSchema = generateProductSchema({ - title: page.title, - description: page.description, - featuredImage: getStrapiImageUrl(page.featuredImg.url), - pageURL, - features - }) - - return ( -
- {/* Add structured data */} - - + - +