From c12332cd6dca14551c92fbfe40ab1bdc2af8385a Mon Sep 17 00:00:00 2001 From: ajulaybeeb Date: Thu, 18 Jun 2026 07:43:54 +0100 Subject: [PATCH] feat: wire bills page to live endpoints and fix ui build errors --- app/api/docs/SwaggerUIWrapper.tsx | 2 +- app/bills/page.tsx | 104 +++++++++++++++++++-- app/settings/page.tsx | 43 +++------ app/split/page.tsx | 5 + app/transactions/page.tsx | 2 +- components/Bills/BillsCard.tsx | 31 ++---- components/Bills/RecentPaymentsSection.tsx | 36 ++++--- components/Bills/UnpaidBillsSection.tsx | 26 +++--- components/ui/WidgetStates.tsx | 27 ++++++ 9 files changed, 181 insertions(+), 95 deletions(-) create mode 100644 components/ui/WidgetStates.tsx diff --git a/app/api/docs/SwaggerUIWrapper.tsx b/app/api/docs/SwaggerUIWrapper.tsx index e01affa..8b5c289 100644 --- a/app/api/docs/SwaggerUIWrapper.tsx +++ b/app/api/docs/SwaggerUIWrapper.tsx @@ -113,7 +113,7 @@ export default function SwaggerUIWrapper({ specUrl }: SwaggerUIWrapperProps) { RemitWise API Documentation

- Complete reference for integrating with RemitWise's remittance and financial planning services. + Complete reference for integrating with RemitWise's remittance and financial planning services. Build secure, scalable applications with our comprehensive API.

diff --git a/app/bills/page.tsx b/app/bills/page.tsx index 6e9b693..205fc2b 100644 --- a/app/bills/page.tsx +++ b/app/bills/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useRef } from "react"; +import { useRef, useState, useEffect } from "react"; import { Loader2, Layers3, ShieldCheck, Wallet, Clock3 } from "lucide-react"; import { UnpaidBillsSection } from "@/components/Bills/UnpaidBillsSection"; import PageHeader from "@/components/PageHeader"; @@ -10,6 +10,10 @@ import { ActionState } from "@/lib/auth/middleware"; import { useFormAction } from "@/lib/hooks/useFormAction"; import AsyncOperationsPanel from "@/components/AsyncOperationsPanel"; import AsyncSubmissionStatus from "@/components/AsyncSubmissionStatus"; +import { apiClient } from "@/lib/client/apiClient"; +import { Bill } from "@/lib/contracts/bill-payments"; +import { WidgetErrorState } from "@/components/ui/WidgetStates"; +import { SkeletonList } from "@/components/ui/Skeleton"; type AddBillResponse = ActionState & { name?: string; @@ -80,6 +84,57 @@ export default function Bills() { const formSectionRef = useRef(null); const [state, formAction, pending] = useFormAction("/api/bills"); + const [bills, setBills] = useState([]); + const [stats, setStats] = useState(null); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(null); + + const fetchBillsData = async () => { + setIsLoading(true); + setError(null); + try { + const [billsRes, statsRes] = await Promise.all([ + apiClient.get('/api/bills'), + apiClient.get('/api/bills/total-unpaid') + ]); + + if (!billsRes || !statsRes) throw new Error("Session expired"); + if (!billsRes.ok || !statsRes.ok) throw new Error("Failed to load bills data"); + + const billsJson = await billsRes.json(); + const statsJson = await statsRes.json(); + + const fetchedBills: Bill[] = billsJson.data?.bills || []; + const fetchedStats = statsJson.data; + + setBills(fetchedBills); + + const paidBills = fetchedBills.filter((b: Bill) => b.status === 'paid'); + const paidAmount = paidBills.reduce((acc: number, b: Bill) => acc + b.amount, 0); + const overdueCount = fetchedBills.filter((b: Bill) => b.status === 'overdue' || b.status === 'urgent').length; + + setStats({ + totalUnpaid: { + amount: fetchedStats?.totalUnpaid?.toLocaleString() || '0', + pendingCount: fetchedStats?.count || 0 + }, + overdueCount, + paidThisMonth: { + amount: paidAmount.toLocaleString(), + paymentCount: paidBills.length + } + }); + } catch (err) { + setError(err instanceof Error ? err : new Error("Unknown error")); + } finally { + setIsLoading(false); + } + }; + + useEffect(() => { + fetchBillsData(); + }, []); + function handleAddBill() { formSectionRef.current?.scrollIntoView({ behavior: "smooth", @@ -98,17 +153,34 @@ export default function Bills() { />
-
- -
+ {error ? ( +
+ +
+ ) : isLoading ? ( +
+ + +
+ ) : ( + <> +
+ +
-
- -
+
+ +
-
- -
+
+ +
+ + )}
+

This bill request is built as an on-chain USDC payment payload. Your wallet signs and submits the transaction; RemitWise only prepares the payload.

+ +
+
+ + diff --git a/app/settings/page.tsx b/app/settings/page.tsx index 833389f..4c40258 100644 --- a/app/settings/page.tsx +++ b/app/settings/page.tsx @@ -23,14 +23,7 @@ import PreferencesRow from "@/components/PreferencesRow"; import SecuritySection from "@/components/SecuritySection"; import { useDensity } from "@/lib/context/DensityContext"; -export default function SettingsPage() { - const { density, setDensity } = useDensity(); - const [notifications, setNotifications] = useState({ - billReminders: true, - paymentConfirmations: true, - goalUpdates: false, - securityAlerts: true, - }); + const SECTIONS = [ { id: "profile", label: "Profile", icon: User }, @@ -209,30 +202,18 @@ function SaveButton({ label = "Save changes" }: { label?: string }) { stroke="currentColor" strokeWidth="4" /> - - {/* Density Row */} - } - title="Display Density" - subtitle="Adjust the spacing of tables and lists" - rightContent={ -
- -
- -
-
- } + -
-
+ + )} + {state === "saving" ? "Saving…" : state === "saved" ? "Saved!" : label} + +
+ ); +} type InsuranceReminder = { policyId: string; diff --git a/app/split/page.tsx b/app/split/page.tsx index c11274f..a1e1081 100644 --- a/app/split/page.tsx +++ b/app/split/page.tsx @@ -89,6 +89,11 @@ export default function SplitConfiguration() {

Allocation changes are saved as a USDC smart contract action. The payload is prepared in-app and the wallet signs it locally.

+ + + diff --git a/app/transactions/page.tsx b/app/transactions/page.tsx index 9e2af17..25a3bdd 100644 --- a/app/transactions/page.tsx +++ b/app/transactions/page.tsx @@ -196,7 +196,7 @@ export default function TransactionsPage() { )) ) : (
- No transactions found matching "{searchQuery}" + No transactions found matching "{searchQuery}"
)} diff --git a/components/Bills/BillsCard.tsx b/components/Bills/BillsCard.tsx index 2acb6dc..ec7eb04 100644 --- a/components/Bills/BillsCard.tsx +++ b/components/Bills/BillsCard.tsx @@ -1,5 +1,6 @@ -import { CalendarClock, CheckCircle, Repeat, Zap } from "lucide-react"; +import { CalendarClock, CheckCircle, CheckCircle2, Clock4, AlertCircle, Repeat, Zap } from "lucide-react"; import { getBillStatusPresentation } from "@/lib/ui/status-semantics"; +import { Bill } from "@/lib/contracts/bill-payments"; const getStatusStyles = (status: Bill['status']) => { switch (status) { @@ -38,7 +39,7 @@ const getStatusStyles = (status: Bill['status']) => { // ─── Status badge ───────────────────────────────────────────────────────────── function StatusBadge({ status }: { status: Bill["status"] }) { - const s = STATUS_STYLES[status]; + const s = getStatusStyles(status)!; const label: Record = { overdue: "Overdue", urgent: "Due Soon", @@ -54,7 +55,7 @@ function StatusBadge({ status }: { status: Bill["status"] }) { return (