diff --git a/app/layout.tsx b/app/layout.tsx index 17dff8b..bd51ac4 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -19,7 +19,7 @@ export const viewport: Viewport = { export async function generateMetadata(): Promise { return buildMetadata( 'Ratio1 Explorer', - 'Experience the power of Ratio1 AI OS, built on Ratio1 Protocol and powered by blockchain, democratizing AI to empower limitless innovation.', + 'Explore the Ratio1 network with Ratio1 Explorer - a real-time explorer providing transparent insights, analytics, and live network metrics.', config.publicUrl, ); } @@ -45,7 +45,7 @@ export default async function RootLayout({ diff --git a/app/manifest.ts b/app/manifest.ts index 0b9dd3f..357460b 100644 --- a/app/manifest.ts +++ b/app/manifest.ts @@ -1,15 +1,15 @@ import { MetadataRoute } from 'next'; export default async function manifest(): Promise { - return { - name: 'Ratio1 Explorer', - short_name: 'Ratio1 Explorer', - description: - 'Experience the power of Ratio1 AI OS, built on Ratio1 Protocol and powered by blockchain, democratizing AI to empower limitless innovation.', - icons: [ - { src: '/android-chrome-192x192.png', sizes: '192x192', type: 'image/png' }, - { src: '/android-chrome-512x512.png', sizes: '512x512', type: 'image/png' }, - ], + return { + name: 'Ratio1 Explorer', + short_name: 'Ratio1 Explorer', + description: + 'Explore the Ratio1 network with Ratio1 Explorer - a real-time explorer providing transparent insights, analytics, and live network metrics.', + icons: [ + { src: '/android-chrome-192x192.png', sizes: '192x192', type: 'image/png' }, + { src: '/android-chrome-512x512.png', sizes: '512x512', type: 'image/png' }, + ], start_url: '/', theme_color: '#1b47f7', background_color: '#1b47f7', diff --git a/app/server-components/main-cards/LicenseCard.tsx b/app/server-components/main-cards/LicenseCard.tsx index 949b586..05da158 100644 --- a/app/server-components/main-cards/LicenseCard.tsx +++ b/app/server-components/main-cards/LicenseCard.tsx @@ -1,160 +1,155 @@ -import LicenseRewardsPoA from '@/app/server-components/Licenses/LicenseRewardsPoA'; -import { BorderedCard } from '@/app/server-components/shared/cards/BorderedCard'; -import { CardHorizontal } from '@/app/server-components/shared/cards/CardHorizontal'; -import ClientWrapper from '@/components/shared/ClientWrapper'; -import { CopyableAddress } from '@/components/shared/CopyableValue'; -import config from '@/config'; -import { routePath } from '@/lib/routes'; -import { fBI } from '@/lib/utils'; -import * as types from '@/typedefs/blockchain'; -import { Skeleton } from '@heroui/skeleton'; -import clsx from 'clsx'; -import Link from 'next/link'; -import { Suspense } from 'react'; -import { formatUnits } from 'viem'; -import PoA from '../Licenses/PoA'; -import TreasuryWallets from '../Licenses/TreasuryWallets'; -import { CardTitle } from '../shared/CardTitle'; -import { LargeTag } from '../shared/LargeTag'; -import UsageStats from '../shared/Licenses/UsageStats'; - -interface Props { - license: types.License; - licenseType: 'ND' | 'MND' | 'GND'; - licenseId: string; - owner: types.EthAddress; - getNodeAvailability: () => Promise<(types.OraclesAvailabilityResult & types.OraclesDefaultResult) | undefined>; - hasLink?: boolean; // If it has a link to it, it means it's not the main card (displayed on top of the page) -} - -export default async function LicenseCard({ license, licenseType, licenseId, owner, getNodeAvailability, hasLink }: Props) { - const environment = config.environment; - const awbBalance = license.awbBalance; - - const getTitle = () => License #{licenseId}; - - return ( - -
- {!hasLink ? ( - getTitle() - ) : ( - - {getTitle()} - - )} - - {license.isBanned && Banned} -
- -
- {!!licenseType && ( - - {licenseType} -
- } - isSmall - isFlexible - /> - )} - - {!!owner && ( - - - - } - isSmall - isFlexible - /> - )} - - {!!license.assignTimestamp && ( - - )} - - {!!license.lastClaimEpoch && ( - - )} - - - - - } - isSmall - isFlexible - /> - - - - {licenseType !== 'ND' && ( - {fBI(awbBalance, 18)} $R1} - isSmall - isFlexible - widthClasses="min-w-[360px]" - /> - )} - - }> - - - - {licenseType === 'ND' && ( - - {license.r1PoaiRewards === undefined - ? '...' - : parseFloat( - Number(formatUnits(license.r1PoaiRewards ?? 0n, 18)).toFixed(2), - ).toLocaleString()} - {!!license.r1PoaiRewards ? ' $R1' : ''} - - } - isSmall - /> - )} - - - {environment === 'mainnet' && licenseId === '1' && licenseType === 'GND' && } -
- ); -} +import LicenseRewardsPoA from '@/app/server-components/Licenses/LicenseRewardsPoA'; +import { BorderedCard } from '@/app/server-components/shared/cards/BorderedCard'; +import { CardHorizontal } from '@/app/server-components/shared/cards/CardHorizontal'; +import ClientWrapper from '@/components/shared/ClientWrapper'; +import { CopyableAddress } from '@/components/shared/CopyableValue'; +import { routePath } from '@/lib/routes'; +import { fBI } from '@/lib/utils'; +import * as types from '@/typedefs/blockchain'; +import { Skeleton } from '@heroui/skeleton'; +import clsx from 'clsx'; +import Link from 'next/link'; +import { Suspense } from 'react'; +import { formatUnits } from 'viem'; +import PoA from '../Licenses/PoA'; +import { CardTitle } from '../shared/CardTitle'; +import { LargeTag } from '../shared/LargeTag'; +import UsageStats from '../shared/Licenses/UsageStats'; + +interface Props { + license: types.License; + licenseType: 'ND' | 'MND' | 'GND'; + licenseId: string; + owner: types.EthAddress; + getNodeAvailability: () => Promise<(types.OraclesAvailabilityResult & types.OraclesDefaultResult) | undefined>; + hasLink?: boolean; // If it has a link to it, it means it's not the main card (displayed on top of the page) +} + +export default async function LicenseCard({ license, licenseType, licenseId, owner, getNodeAvailability, hasLink }: Props) { + const awbBalance = license.awbBalance; + + const getTitle = () => License #{licenseId}; + + return ( + +
+ {!hasLink ? ( + getTitle() + ) : ( + + {getTitle()} + + )} + + {license.isBanned && Banned} +
+ +
+ {!!licenseType && ( + + {licenseType} +
+ } + isSmall + isFlexible + /> + )} + + {!!owner && ( + + + + } + isSmall + isFlexible + /> + )} + + {!!license.assignTimestamp && ( + + )} + + {!!license.lastClaimEpoch && ( + + )} + + + + + } + isSmall + isFlexible + /> + + + + {licenseType !== 'ND' && ( + {fBI(awbBalance, 18)} $R1} + isSmall + isFlexible + widthClasses="min-w-[360px]" + /> + )} + + }> + + + + {licenseType === 'ND' && ( + + {license.r1PoaiRewards === undefined + ? '...' + : parseFloat( + Number(formatUnits(license.r1PoaiRewards ?? 0n, 18)).toFixed(2), + ).toLocaleString()} + {!!license.r1PoaiRewards ? ' $R1' : ''} + + } + isSmall + /> + )} + +
+ ); +} diff --git a/app/stats/page.tsx b/app/stats/page.tsx index 690dd0a..d9bf0d4 100644 --- a/app/stats/page.tsx +++ b/app/stats/page.tsx @@ -4,10 +4,14 @@ import DailyStatsAreaChart from '@/components/charts/DailyStatsAreaChart'; import NodesMap from '@/components/charts/NodesMap'; import ClientWrapper from '@/components/shared/ClientWrapper'; import { ChartConfig } from '@/components/ui/chart'; +import config from '@/config'; +import { getLicense } from '@/lib/api/blockchain'; import { getTokenSupply } from '@/lib/api/general'; import { fN } from '@/lib/utils'; +import { License } from '@/typedefs/blockchain'; import { TokenSupplyResponse } from '@/typedefs/general'; import Link from 'next/link'; +import TreasuryWallets from '../server-components/Licenses/TreasuryWallets'; import { BorderedCard } from '../server-components/shared/cards/BorderedCard'; import { CardHorizontal } from '../server-components/shared/cards/CardHorizontal'; @@ -59,6 +63,7 @@ export async function generateMetadata() { export default async function StatsPage() { let tokenSupply: TokenSupplyResponse; + let gndLicense: License | undefined; try { tokenSupply = await getTokenSupply(); @@ -67,6 +72,14 @@ export default async function StatsPage() { return ; } + if (config.environment === 'mainnet') { + try { + gndLicense = await getLicense('GND', 1); + } catch (error) { + console.error(error); + } + } + const getLegendEntries = (config: ChartConfig) => Object.values(config).map((entry, index) => (
@@ -109,7 +122,7 @@ export default async function StatsPage() {
-
Daily PoAI
+
PoAI
{getLegendEntries(chartConfig)} @@ -148,6 +161,12 @@ export default async function StatsPage() { + {gndLicense && ( + + + + )} +
Nodes