Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions app/billing/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { generateMetadata } from "@/src/lib/seo/metadata"
import { breadcrumbListSchema } from "@/src/lib/seo/json-ld"

export const metadata = generateMetadata({
title: "Billing",
description: "View billing history, manage payments, and track usage costs for your utility meters on EquipChain.",
path: "/billing",
})

export default function BillingPage() {
const jsonLd = breadcrumbListSchema([
{ name: "Home", path: "/" },
{ name: "Billing", path: "/billing" },
])

return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
<div className="flex min-h-screen items-center justify-center bg-zinc-50 dark:bg-black">
<main className="flex flex-col items-center gap-8 py-32 px-16">
<h1 className="text-4xl font-bold text-black dark:text-zinc-50">
Billing
</h1>
<p className="text-zinc-600 dark:text-zinc-400">
Billing content coming soon.
</p>
</main>
</div>
</>
)
}
34 changes: 34 additions & 0 deletions app/dashboard/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { generateMetadata } from "@/src/lib/seo/metadata"
import { breadcrumbListSchema } from "@/src/lib/seo/json-ld"

export const metadata = generateMetadata({
title: "Dashboard",
description: "Overview of your utility meters, usage statistics, and recent activity on EquipChain.",
path: "/dashboard",
})

export default function DashboardPage() {
const jsonLd = breadcrumbListSchema([
{ name: "Home", path: "/" },
{ name: "Dashboard", path: "/dashboard" },
])

return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
<div className="flex min-h-screen items-center justify-center bg-zinc-50 dark:bg-black">
<main className="flex flex-col items-center gap-8 py-32 px-16">
<h1 className="text-4xl font-bold text-black dark:text-zinc-50">
Dashboard
</h1>
<p className="text-zinc-600 dark:text-zinc-400">
Dashboard content coming soon.
</p>
</main>
</div>
</>
)
}
41 changes: 39 additions & 2 deletions app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";

const baseUrl = process.env.NEXT_PUBLIC_BASE_URL ?? "http://localhost:3000";

const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"],
Expand All @@ -13,8 +15,43 @@ const geistMono = Geist_Mono({
});

export const metadata: Metadata = {
title: "Equipchain Dashboard",
description: "Next.js frontend dashboard for Equipchain utility management on Stellar Soroban",
metadataBase: new URL(baseUrl),
title: {
default: "EquipChain Dashboard",
template: "%s | EquipChain",
},
description:
"Utility metering and billing dashboard for monitoring meters, managing gas buffers, and tracking usage on Stellar Soroban.",
openGraph: {
title: "EquipChain Dashboard",
description:
"Utility metering and billing dashboard for monitoring meters, managing gas buffers, and tracking usage on Stellar Soroban.",
url: baseUrl,
siteName: "EquipChain",
type: "website",
locale: "en_US",
images: [
{
url: `${baseUrl}/og-image.png`,
width: 1200,
height: 630,
alt: "EquipChain Dashboard",
},
],
},
twitter: {
card: "summary_large_image",
site: "@equipchain",
creator: "@equipchain",
title: "EquipChain Dashboard",
description:
"Utility metering and billing dashboard for monitoring meters, managing gas buffers, and tracking usage on Stellar Soroban.",
images: [`${baseUrl}/og-image.png`],
},
robots: {
index: true,
follow: true,
},
};

export default function RootLayout({
Expand Down
34 changes: 34 additions & 0 deletions app/meters/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { generateMetadata } from "@/src/lib/seo/metadata"
import { breadcrumbListSchema } from "@/src/lib/seo/json-ld"

export const metadata = generateMetadata({
title: "Meters",
description: "View and manage your utility meters, monitor consumption, and configure meter parameters on EquipChain.",
path: "/meters",
})

export default function MetersPage() {
const jsonLd = breadcrumbListSchema([
{ name: "Home", path: "/" },
{ name: "Meters", path: "/meters" },
])

return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
<div className="flex min-h-screen items-center justify-center bg-zinc-50 dark:bg-black">
<main className="flex flex-col items-center gap-8 py-32 px-16">
<h1 className="text-4xl font-bold text-black dark:text-zinc-50">
Meters
</h1>
<p className="text-zinc-600 dark:text-zinc-400">
Meters content coming soon.
</p>
</main>
</div>
</>
)
}
82 changes: 52 additions & 30 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,56 @@
import { generateMetadata } from "@/src/lib/seo/metadata"
import { breadcrumbListSchema, webApplicationSchema, organizationSchema } from "@/src/lib/seo/json-ld"

export const metadata = generateMetadata({
title: "Home",
description:
"Utility metering and billing dashboard for monitoring meters, managing gas buffers, and tracking usage on Stellar Soroban.",
path: "/",
})

export default function Home() {
const jsonLd = {
...webApplicationSchema(),
...organizationSchema(),
...breadcrumbListSchema([{ name: "Home", path: "/" }]),
}

return (
<div className="flex min-h-screen items-center justify-center bg-zinc-50 font-sans dark:bg-black">
<main className="flex min-h-screen w-full max-w-3xl flex-col items-center justify-between py-32 px-16 bg-white dark:bg-black sm:items-start">
<div className="flex flex-col items-center gap-6 text-center sm:items-start sm:text-left">
<h1 className="max-w-xl text-4xl font-bold leading-12 tracking-tight text-black dark:text-zinc-50">
Equipchain Dashboard
</h1>
<p className="max-w-lg text-lg leading-8 text-zinc-600 dark:text-zinc-400">
Utility metering and billing dashboard for monitoring meters, managing gas buffers, and tracking usage on Stellar Soroban.
</p>
</div>
<div className="flex flex-col gap-4 text-base font-medium sm:flex-row">
<a
className="flex h-12 w-full items-center justify-center gap-2 rounded-full bg-foreground px-5 text-background transition-colors hover:bg-[#383838] dark:hover:bg-[#ccc] md:w-[158px]"
href="https://github.com/EquipChain/EquipChain-contracts"
target="_blank"
rel="noopener noreferrer"
>
View Contracts
</a>
<a
className="flex h-12 w-full items-center justify-center rounded-full border border-solid border-black/[.08] px-5 transition-colors hover:border-transparent hover:bg-black/[.04] dark:border-white/[.145] dark:hover:bg-[#1a1a1a] md:w-[158px]"
href="https://github.com/EquipChain/EquipChain-backend"
target="_blank"
rel="noopener noreferrer"
>
Backend API
</a>
</div>
</main>
</div>
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
<div className="flex min-h-screen items-center justify-center bg-zinc-50 font-sans dark:bg-black">
<main className="flex min-h-screen w-full max-w-3xl flex-col items-center justify-between py-32 px-16 bg-white dark:bg-black sm:items-start">
<div className="flex flex-col items-center gap-6 text-center sm:items-start sm:text-left">
<h1 className="max-w-xl text-4xl font-bold leading-12 tracking-tight text-black dark:text-zinc-50">
Equipchain Dashboard
</h1>
<p className="max-w-lg text-lg leading-8 text-zinc-600 dark:text-zinc-400">
Utility metering and billing dashboard for monitoring meters, managing gas buffers, and tracking usage on Stellar Soroban.
</p>
</div>
<div className="flex flex-col gap-4 text-base font-medium sm:flex-row">
<a
className="flex h-12 w-full items-center justify-center gap-2 rounded-full bg-foreground px-5 text-background transition-colors hover:bg-[#383838] dark:hover:bg-[#ccc] md:w-[158px]"
href="https://github.com/EquipChain/EquipChain-contracts"
target="_blank"
rel="noopener noreferrer"
>
View Contracts
</a>
<a
className="flex h-12 w-full items-center justify-center rounded-full border border-solid border-black/[.08] px-5 transition-colors hover:border-transparent hover:bg-black/[.04] dark:border-white/[.145] dark:hover:bg-[#1a1a1a] md:w-[158px]"
href="https://github.com/EquipChain/EquipChain-backend"
target="_blank"
rel="noopener noreferrer"
>
Backend API
</a>
</div>
</main>
</div>
</>
);
}
26 changes: 26 additions & 0 deletions app/robots.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { MetadataRoute } from "next"

const baseUrl = process.env.NEXT_PUBLIC_BASE_URL ?? "http://localhost:3000"
const isProduction = process.env.NODE_ENV === "production"

export default function robots(): MetadataRoute.Robots {
if (isProduction) {
return {
rules: [
{
userAgent: "*",
allow: "/",
disallow: ["/admin/", "/api/"],
},
],
sitemap: `${baseUrl}/sitemap.xml`,
}
}

return {
rules: {
userAgent: "*",
disallow: "/",
},
}
}
38 changes: 38 additions & 0 deletions app/sitemap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import type { MetadataRoute } from "next"

const baseUrl = process.env.NEXT_PUBLIC_BASE_URL ?? "http://localhost:3000"

export default function sitemap(): MetadataRoute.Sitemap {
return [
{
url: baseUrl,
lastModified: new Date(),
changeFrequency: "monthly",
priority: 1,
},
{
url: `${baseUrl}/dashboard`,
lastModified: new Date(),
changeFrequency: "monthly",
priority: 0.9,
},
{
url: `${baseUrl}/meters`,
lastModified: new Date(),
changeFrequency: "weekly",
priority: 0.8,
},
{
url: `${baseUrl}/billing`,
lastModified: new Date(),
changeFrequency: "weekly",
priority: 0.7,
},
{
url: `${baseUrl}/streams`,
lastModified: new Date(),
changeFrequency: "weekly",
priority: 0.6,
},
]
}
34 changes: 34 additions & 0 deletions app/streams/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { generateMetadata } from "@/src/lib/seo/metadata"
import { breadcrumbListSchema } from "@/src/lib/seo/json-ld"

export const metadata = generateMetadata({
title: "Streams",
description: "Monitor real-time data streams from your utility meters and view live usage feeds on EquipChain.",
path: "/streams",
})

export default function StreamsPage() {
const jsonLd = breadcrumbListSchema([
{ name: "Home", path: "/" },
{ name: "Streams", path: "/streams" },
])

return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
<div className="flex min-h-screen items-center justify-center bg-zinc-50 dark:bg-black">
<main className="flex flex-col items-center gap-8 py-32 px-16">
<h1 className="text-4xl font-bold text-black dark:text-zinc-50">
Streams
</h1>
<p className="text-zinc-600 dark:text-zinc-400">
Streams content coming soon.
</p>
</main>
</div>
</>
)
}
Binary file added public/og-image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
50 changes: 50 additions & 0 deletions src/lib/seo/json-ld.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
const baseUrl =
process.env.NEXT_PUBLIC_BASE_URL ?? "http://localhost:3000"

export function webApplicationSchema() {
return {
"@context": "https://schema.org",
"@type": "WebApplication",
name: "EquipChain Dashboard",
url: baseUrl,
applicationCategory: "BusinessApplication",
operatingSystem: "Web",
description:
"Utility metering and billing dashboard for monitoring meters, managing gas buffers, and tracking usage on Stellar Soroban.",
browserRequirements: "Requires modern browser with JavaScript enabled",
}
}

export function organizationSchema() {
return {
"@context": "https://schema.org",
"@type": "Organization",
name: "EquipChain",
url: baseUrl,
description:
"Decentralized utility metering and billing platform on Stellar Soroban",
contactPoint: {
"@type": "ContactPoint",
contactType: "support",
url: `${baseUrl}/contact`,
},
sameAs: [
"https://github.com/EquipChain",
"https://github.com/EquipChain/EquipChain-contracts",
"https://github.com/EquipChain/EquipChain-backend",
],
}
}

export function breadcrumbListSchema(items: { name: string; path: string }[]) {
return {
"@context": "https://schema.org",
"@type": "BreadcrumbList",
itemListElement: items.map((item, index) => ({
"@type": "ListItem",
position: index + 1,
name: item.name,
item: `${baseUrl}${item.path}`,
})),
}
}
Loading
Loading