Skip to content

Commit e55b3d2

Browse files
committed
feat: added the API status on the navba
1 parent 8c9184a commit e55b3d2

4 files changed

Lines changed: 30 additions & 100 deletions

File tree

frontend/src/app/(authenticated)/dashboard/page.tsx

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import React, { useState, useEffect } from "react";
44
import AnalyticsCards from "@/components/AnalyticsCards";
55
import ActivityFeed from "@/components/ActivityFeed";
6-
import WithdrawalModal from "@/components/WithdrawalModal";
76
import DashboardSkeleton from "@/components/DashboardSkeleton";
87
import Link from "next/link";
98
import {
@@ -18,7 +17,6 @@ import FirstPaymentCelebration from "@/components/FirstPaymentCelebration";
1817

1918
export default function DashboardPage() {
2019
const t = useTranslations("dashboardPage");
21-
const [isWithdrawOpen, setIsWithdrawOpen] = useState(false);
2220
const [isFirstKeyModalOpen, setIsFirstKeyModalOpen] = useState(false);
2321
const hydrated = useMerchantHydrated();
2422
const apiKey = useMerchantApiKey();
@@ -86,16 +84,6 @@ export default function DashboardPage() {
8684
</svg>
8785
{t("createPaymentLink")}
8886
</Link>
89-
<button
90-
type="button"
91-
onClick={() => setIsWithdrawOpen(true)}
92-
className="flex items-center gap-3 rounded-xl border border-[#E8E8E8] bg-[#F9F9F9] px-4 py-3 text-sm font-bold text-[#0A0A0A] transition-all hover:bg-[#0A0A0A] hover:text-white hover:border-[#0A0A0A]"
93-
>
94-
<svg className="h-4 w-4 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
95-
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" />
96-
</svg>
97-
{t("withdrawFunds")}
98-
</button>
9987
<Link
10088
href="/settings"
10189
className="flex items-center gap-3 rounded-xl border border-[#E8E8E8] bg-[#F9F9F9] px-4 py-3 text-sm font-bold text-[#0A0A0A] transition-all hover:bg-[#0A0A0A] hover:text-white hover:border-[#0A0A0A]"
@@ -135,31 +123,23 @@ export default function DashboardPage() {
135123
</section>
136124

137125
<section className="rounded-2xl border border-[#E8E8E8] bg-white p-6">
138-
<h3 className="mb-4 text-xs font-bold uppercase tracking-[0.2em] text-[#6B6B6B]">Integration Modes</h3>
126+
<h3 className="mb-4 text-xs font-bold uppercase tracking-[0.2em] text-[#6B6B6B]">x402 Integration</h3>
139127
<p className="mb-4 text-xs text-[#6B6B6B]">
140-
Use one merchant account, then choose your pricing/integration path.
128+
Build pay-per-request flows with the production x402 setup guide.
141129
</p>
142130
<div className="flex flex-col gap-2">
143-
<Link
144-
href="/docs/api-guide"
145-
className="flex items-center justify-between rounded-xl border border-[#E8E8E8] bg-[#F9F9F9] px-4 py-3 text-sm font-bold text-[#0A0A0A] transition-colors hover:bg-[#F2F2F2]"
146-
>
147-
<span>Subscription Mode</span>
148-
<span className="text-[10px] uppercase tracking-widest text-[#6B6B6B]">Path 01</span>
149-
</Link>
150131
<Link
151132
href="/docs/x402-agentic-payments"
152133
className="flex items-center justify-between rounded-xl border border-[var(--pluto-200)] bg-[var(--pluto-50)] px-4 py-3 text-sm font-bold text-[var(--pluto-700)] transition-colors hover:bg-[var(--pluto-100)]"
153134
>
154-
<span>x402 Pay-per-request</span>
155-
<span className="text-[10px] uppercase tracking-widest text-[var(--pluto-600)]">Path 02</span>
135+
<span>Open x402 Integration Guide</span>
136+
<span className="text-[10px] uppercase tracking-widest text-[var(--pluto-600)]">Docs</span>
156137
</Link>
157138
</div>
158139
</section>
159140
</aside>
160141
</div>
161142

162-
<WithdrawalModal isOpen={isWithdrawOpen} onClose={() => setIsWithdrawOpen(false)} />
163143
<FirstApiKeyModal isOpen={isFirstKeyModalOpen} onClose={() => setIsFirstKeyModalOpen(false)} />
164144
<FirstPaymentCelebration />
165145
</div>

frontend/src/app/(authenticated)/settings/page.tsx

Lines changed: 1 addition & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const DEFAULT_BRANDING = {
2626
logo_url: null as string | null,
2727
};
2828

29-
type SettingsTab = "api" | "billing" | "branding" | "display" | "webhooks" | "danger";
29+
type SettingsTab = "api" | "branding" | "display" | "webhooks" | "danger";
3030

3131
interface WebhookDomainVerification {
3232
status: "verified" | "unverified";
@@ -82,7 +82,6 @@ function EyeIcon({ open }: { open: boolean }) {
8282

8383
const NAV_ITEMS: { id: SettingsTab; label: string; icon: React.ReactNode; danger?: boolean }[] = [
8484
{ id: "api", label: "API Keys", icon: <svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z" /></svg> },
85-
{ id: "billing", label: "Billing & Plans", icon: <svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" /></svg> },
8685
{ id: "branding", label: "Branding", icon: <svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4a2 2 0 012 2v12a4 4 0 01-4 4zm0 0h12a2 2 0 002-2v-4a2 2 0 00-2-2h-2.343M11 7.343l1.657-1.657a2 2 0 012.828 0l2.829 2.829a2 2 0 010 2.828l-8.486 8.485M7 17h.01" /></svg> },
8786
{ id: "display", label: "Display", icon: <svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" /></svg> },
8887
{ id: "webhooks", label: "Webhooks", icon: <svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" /></svg> },
@@ -337,56 +336,6 @@ export default function SettingsPage() {
337336
{/* Right content panel */}
338337
<div className="flex-1 min-w-0">
339338

340-
{/* Billing Tab */}
341-
{activeTab === "billing" && (
342-
<div className="rounded-2xl border border-[#E8E8E8] bg-white p-8 flex flex-col gap-8 animate-in fade-in duration-300">
343-
<div>
344-
<h2 className="text-lg font-bold text-[#0A0A0A] mb-1">Billing & Plans</h2>
345-
<p className="text-sm text-[#6B6B6B]">Select your monetization strategy and configure your active plans.</p>
346-
</div>
347-
348-
<div className="grid gap-6 lg:grid-cols-2">
349-
{/* Traditional Subscription Card */}
350-
<div className="flex flex-col rounded-2xl border border-[#E8E8E8] bg-[#F9F9F9] p-6 transition-all hover:border-[#0A0A0A] hover:shadow-[0_8px_30px_rgba(0,0,0,0.04)]">
351-
<span className="self-start rounded-full border border-[#E8E8E8] bg-white px-3 py-1 text-[9px] font-bold uppercase tracking-widest text-[#6B6B6B]">Path 01</span>
352-
<h3 className="mt-4 text-xl font-bold tracking-tight text-[#0A0A0A]">Pro Subscription</h3>
353-
<div className="mt-2 flex items-baseline gap-1">
354-
<span className="text-3xl font-bold tracking-tighter text-[#0A0A0A]">$49</span>
355-
<span className="text-xs font-medium text-[#6B6B6B]">/mo</span>
356-
</div>
357-
<p className="mt-3 text-sm text-[#6B6B6B]">Traditional flat-rate billing. Unlimited manual webhook setups, priority support, and high rate limits.</p>
358-
<button type="button" onClick={() => toast.success("Redirecting to Stripe...")} className="mt-6 inline-flex items-center justify-center rounded-xl bg-[#0A0A0A] px-4 py-3 text-[10px] font-bold uppercase tracking-widest text-white transition-colors hover:bg-black">
359-
Subscribe Now
360-
</button>
361-
</div>
362-
363-
{/* x402 Agentic Card */}
364-
<div className="flex flex-col bg-[var(--pluto-50)] rounded-2xl border border-[var(--pluto-200)] p-6 transition-all hover:border-[var(--pluto-400)] hover:shadow-[0_8px_30px_rgba(33,206,153,0.1)]">
365-
<span className="self-start rounded-full border border-[var(--pluto-200)] bg-[var(--pluto-100)] px-3 py-1 text-[9px] font-bold uppercase tracking-widest text-[var(--pluto-800)]">Path 02</span>
366-
<h3 className="mt-4 text-xl font-bold tracking-tight text-[var(--pluto-900)]">x402 Agentic</h3>
367-
<div className="mt-2 flex items-baseline gap-1">
368-
<span className="text-3xl font-bold tracking-tighter text-[var(--pluto-900)]">Pay-per-use</span>
369-
</div>
370-
<p className="mt-3 text-sm text-[var(--pluto-700)]">Set custom XLM pricing metrics. Perfect for automated AI agents solving X402 challenges natively.</p>
371-
<button type="button" onClick={() => toast.success("x402 Configured")} className="mt-6 inline-flex items-center justify-center rounded-xl bg-[var(--pluto-500)] px-4 py-3 text-[10px] font-bold uppercase tracking-widest text-white transition-colors hover:bg-[var(--pluto-600)]">
372-
Enable x402
373-
</button>
374-
</div>
375-
</div>
376-
377-
<div className="h-px bg-[#E8E8E8]" />
378-
379-
<div className="flex flex-col gap-4">
380-
<div>
381-
<h3 className="text-sm font-bold text-[#0A0A0A] mb-1">x402 Wallet Configuration</h3>
382-
<p className="text-xs text-[#6B6B6B]">Account address where your HTTP 402 challenge funds should settle.</p>
383-
</div>
384-
<input type="text" placeholder="G..." className="max-w-md rounded-xl border border-[#E8E8E8] bg-[#F9F9F9] px-4 py-3 font-mono text-sm text-[#0A0A0A] focus:border-[#0A0A0A] focus:bg-white focus:outline-none transition-all" />
385-
<button type="button" onClick={() => toast.success("Wallet Address saved")} className="self-start rounded-xl bg-white border border-[#E8E8E8] px-5 py-2.5 text-[10px] font-bold uppercase tracking-widest text-[#0A0A0A] hover:bg-[#F5F5F5] transition-all">Save Wallet</button>
386-
</div>
387-
</div>
388-
)}
389-
390339
{/* API Keys Tab */}
391340
{activeTab === "api" && (
392341
<div className="rounded-2xl border border-[#E8E8E8] bg-white p-8 flex flex-col gap-8">

frontend/src/components/ApiHealthBadge.tsx

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,40 @@
22

33
import { useEffect, useState } from "react";
44

5-
type HealthStatus = "loading" | "healthy" | "error";
5+
type ExtendedHealthStatus = "loading" | "healthy" | "error";
66

77
export default function ApiHealthBadge() {
8-
const [status, setStatus] = useState<HealthStatus>("loading");
8+
const [status, setStatus] = useState<ExtendedHealthStatus>("loading");
99
const [errorMsg, setErrorMsg] = useState<string | null>(null);
1010

1111
useEffect(() => {
1212
let mounted = true;
1313
const checkHealth = async () => {
1414
try {
1515
const apiUrl = process.env.NEXT_PUBLIC_API_URL || "http://localhost:4000";
16-
const res = await fetch(`${apiUrl}/health`);
17-
const data = await res.json();
18-
16+
const res = await fetch(`${apiUrl}/health`, { cache: "no-store" });
17+
const data = await res.json().catch(() => ({}));
18+
1919
if (mounted) {
20-
if (res.ok && data.ok && data.horizon_reachable) {
20+
const services = data?.services ?? {};
21+
const dbOk = services.database === "ok";
22+
const horizonOk = services.horizon === "ok";
23+
const apiReachable = true; // If we got an HTTP response, backend is reachable.
24+
const healthy = apiReachable;
25+
26+
if (healthy) {
2127
setStatus("healthy");
22-
setErrorMsg("Dashboard & Stellar Network Online");
28+
const missing: string[] = [];
29+
if (!dbOk) missing.push("database");
30+
if (!horizonOk) missing.push("horizon");
31+
setErrorMsg(
32+
missing.length > 0
33+
? `Degraded dependency: ${missing.join(" + ")} unavailable`
34+
: null,
35+
);
2336
} else {
2437
setStatus("error");
25-
setErrorMsg(data.error || "Service Disruption Detected");
38+
setErrorMsg(data?.error || "Backend unavailable");
2639
}
2740
}
2841
} catch {
@@ -53,13 +66,13 @@ export default function ApiHealthBadge() {
5366
color: "bg-green-500",
5467
pulse: "bg-green-500/20",
5568
text: "text-[#6B6B6B]",
56-
label: "All Systems Operational",
69+
label: "Pluto API Online",
5770
},
5871
error: {
5972
color: "bg-red-500",
6073
pulse: "bg-red-500/20",
6174
text: "text-red-500",
62-
label: "Service Disruption",
75+
label: "Pluto API Offline",
6376
},
6477
}[status];
6578

@@ -74,13 +87,13 @@ export default function ApiHealthBadge() {
7487
<span className={`relative inline-flex h-1.5 w-1.5 rounded-full ${config.color}`} />
7588
</div>
7689
<span className={`text-[10px] font-bold uppercase tracking-widest ${config.text}`}>
77-
{status === "error" ? "Degraded" : "API"}
90+
{status === "healthy" ? "API Active" : status === "error" ? "API Down" : "Checking"}
7891
</span>
7992

8093
{/* Tooltip */}
8194
<div className="pointer-events-none absolute left-1/2 top-full z-50 mt-3 -translate-x-1/2 whitespace-nowrap rounded-xl border border-[#E8E8E8] bg-white px-4 py-3 text-[10px] font-bold uppercase tracking-widest text-[#0A0A0A] opacity-0 shadow-[0_10px_30px_rgb(0,0,0,0.08)] transition-all group-hover:opacity-100 group-hover:translate-y-1">
8295
<p className="text-center">{config.label}</p>
83-
{(status === "error" && errorMsg) && (
96+
{(errorMsg && status !== "loading") && (
8497
<p className="mt-1.5 text-[9px] text-[#6B6B6B] lowercase tracking-normal font-medium text-center">{errorMsg}</p>
8598
)}
8699
</div>

frontend/src/components/Sidebar.tsx

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -155,18 +155,6 @@ export default function Sidebar({
155155
t={t}
156156
onNavigate={() => onMobileOpenChange(false)}
157157
/>
158-
159-
<div className="p-4">
160-
<div className="rounded-lg bg-[var(--pluto-50)] border border-[var(--pluto-100)] p-5">
161-
<p className="text-[10px] font-bold uppercase tracking-widest text-[var(--pluto-600)]">
162-
{t("network")}
163-
</p>
164-
<div className="mt-2 flex items-center gap-2 text-xs font-medium text-[var(--pluto-800)]">
165-
<span className="h-2 w-2 rounded-full bg-[var(--pluto-500)]" />
166-
Stellar Mainnet
167-
</div>
168-
</div>
169-
</div>
170158
</>
171159
);
172160

0 commit comments

Comments
 (0)