From 968674e0095b826841da24804724a0dcdb116405 Mon Sep 17 00:00:00 2001 From: Rahman Lawal Date: Thu, 23 Apr 2026 10:01:32 +0100 Subject: [PATCH 1/5] style: fix accessibility (a11y) issues in Transaction History Table --- frontend/src/components/RecentPayments.tsx | 108 +++++++++++++-------- 1 file changed, 67 insertions(+), 41 deletions(-) diff --git a/frontend/src/components/RecentPayments.tsx b/frontend/src/components/RecentPayments.tsx index 97424be1..7709f0c1 100644 --- a/frontend/src/components/RecentPayments.tsx +++ b/frontend/src/components/RecentPayments.tsx @@ -150,7 +150,8 @@ function SortBtn({ + )} @@ -506,8 +525,8 @@ export default function RecentPayments({

{t("showingResults", { shown: sortedPayments.length, total: totalCount })} {hasActiveFilters ? t("filteredSuffix") : ""}

- @@ -515,15 +534,16 @@ export default function RecentPayments({ {/* Table */}
- +
+ - - - - - - + + + + + + @@ -532,7 +552,9 @@ export default function RecentPayments({ ) : sortedPayments.map(payment => ( { setSelectedPayment(payment.id); setIsSheetOpen(true); }} - className={`group cursor-pointer transition-all duration-200 ease-in-out hover:bg-[#F9F9F9] hover:shadow-sm hover:border-l-2 hover:border-l-[var(--pluto-500)] active:bg-[#F5F5F5] active:scale-[0.995] ${flashedIds.has(payment.id) ? "bg-emerald-50" : ""}`} + tabIndex={0} + onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); setSelectedPayment(payment.id); setIsSheetOpen(true); } }} + className={`group cursor-pointer transition-all duration-200 ease-in-out hover:bg-[#F9F9F9] hover:shadow-sm hover:border-l-2 hover:border-l-[var(--pluto-500)] focus-visible:outline-none focus-visible:bg-[#F9F9F9] focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--pluto-500)] active:bg-[#F5F5F5] active:scale-[0.995] ${flashedIds.has(payment.id) ? "bg-emerald-50" : ""}`} > @@ -564,13 +587,15 @@ export default function RecentPayments({ {totalCount > 0 && (
- Rows: +
- @@ -595,7 +620,8 @@ export default function RecentPayments({ ); From b9decb536fd443fd0275a99bfb5fae37f2aa1f58 Mon Sep 17 00:00:00 2001 From: Rahman Lawal Date: Thu, 23 Apr 2026 10:13:58 +0100 Subject: [PATCH 4/5] style: improve mobile responsiveness of Wallet Connection Modal --- frontend/src/components/WalletSelector.tsx | 28 +++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/frontend/src/components/WalletSelector.tsx b/frontend/src/components/WalletSelector.tsx index 6b13decf..5b07c3a8 100644 --- a/frontend/src/components/WalletSelector.tsx +++ b/frontend/src/components/WalletSelector.tsx @@ -157,10 +157,10 @@ export default function WalletSelector({ networkPassphrase, onConnected }: Walle } return ( -
+
-

{t("chooseWallet")}

-

{t("description")}

+

{t("chooseWallet")}

+

{t("description")}

@@ -177,13 +177,13 @@ export default function WalletSelector({ networkPassphrase, onConnected }: Walle disabled={isDisabled || connecting !== null} onClick={() => handleSelect(p.id)} aria-busy={isConnecting} - className="group relative flex h-16 w-full items-center gap-4 rounded-2xl border border-[#E8E8E8] bg-white px-5 text-left shadow-sm transition-[border-color,box-shadow,transform] duration-200 hover:-translate-y-px hover:border-[var(--pluto-400)] hover:shadow-[0_6px_22px_rgba(74,111,165,0.12)] active:translate-y-0 active:scale-[0.99] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--pluto-300)] disabled:cursor-not-allowed disabled:opacity-40" - className="group relative flex h-16 w-full items-center gap-4 rounded-2xl border border-[#E8E8E8] bg-white px-5 text-left shadow-sm transition-[border-color,box-shadow,transform] duration-200 hover:-translate-y-px hover:border-[var(--pluto-400)] hover:shadow-[0_6px_22px_rgba(74,111,165,0.12)] active:translate-y-0 active:scale-[0.99] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--pluto-300)] disabled:cursor-not-allowed disabled:opacity-40" + className="group relative flex h-14 sm:h-16 w-full items-center gap-3 sm:gap-4 rounded-xl sm:rounded-2xl border border-[#E8E8E8] bg-white px-4 sm:px-5 text-left shadow-sm transition-[border-color,box-shadow,transform] duration-200 hover:-translate-y-px hover:border-[var(--pluto-400)] hover:shadow-[0_6px_22px_rgba(74,111,165,0.12)] active:translate-y-0 active:scale-[0.99] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--pluto-500)] disabled:cursor-not-allowed disabled:opacity-40" + > {/* Icon */}
{ICONS[p.id] ?? ( - + )} @@ -192,14 +192,14 @@ export default function WalletSelector({ networkPassphrase, onConnected }: Walle {/* Label */}
{isConnecting ? ( - + {isWc ? t("walletConnectWaiting") : "Connecting…"} ) : ( <> - {p.name} - + {p.name} + {isDisabled ? (isWc ? t("noProjectId") : t("notInstalled")) : SUBTITLES[p.id] ?? t("tapToConnect")} @@ -221,12 +221,12 @@ export default function WalletSelector({ networkPassphrase, onConnected }: Walle {/* WalletConnect QR */} {wcUri && ( -
-

{t("scanTitle")}

-
- +
+

{t("scanTitle")}

+
+
-

{t("scanDescription")}

+

{t("scanDescription")}

)} From cabc4909762f0379a20e557694527aa9f101ff41 Mon Sep 17 00:00:00 2001 From: Rahman Lawal Date: Thu, 23 Apr 2026 10:41:23 +0100 Subject: [PATCH 5/5] fix: resolve all ESLint warnings and errors --- .../app/(authenticated)/dashboard/page.tsx | 9 +--- frontend/src/components/PaymentMetrics.tsx | 15 +++++- frontend/src/components/WalletSelector.tsx | 53 ------------------- 3 files changed, 15 insertions(+), 62 deletions(-) diff --git a/frontend/src/app/(authenticated)/dashboard/page.tsx b/frontend/src/app/(authenticated)/dashboard/page.tsx index 03cbca63..bc124ec1 100644 --- a/frontend/src/app/(authenticated)/dashboard/page.tsx +++ b/frontend/src/app/(authenticated)/dashboard/page.tsx @@ -1,17 +1,14 @@ "use client"; import React, { useState, useEffect } from "react"; -import AnalyticsCards from "@/components/AnalyticsCards"; -import ActivityFeed from "@/components/ActivityFeed"; + import DashboardSkeleton from "@/components/DashboardSkeleton"; import Link from "next/link"; import { useMerchantHydrated, useHydrateMerchantStore, useMerchantApiKey, - useMerchantMetadata, } from "@/lib/merchant-store"; -import { useTranslations } from "next-intl"; import FirstApiKeyModal from "@/components/FirstApiKeyModal"; import PaymentMetrics from "@/components/PaymentMetrics"; import RecentPayments from "@/components/RecentPayments"; @@ -19,12 +16,10 @@ import WithdrawModal from "@/components/WithdrawModal"; import FirstPaymentCelebration from "@/components/FirstPaymentCelebration"; export default function DashboardPage() { - const t = useTranslations("dashboardPage"); const [isFirstKeyModalOpen, setIsFirstKeyModalOpen] = useState(false); const [isWithdrawOpen, setIsWithdrawOpen] = useState(false); const hydrated = useMerchantHydrated(); const apiKey = useMerchantApiKey(); - const merchant = useMerchantMetadata(); const [loading, setLoading] = useState(true); useHydrateMerchantStore(); @@ -138,7 +133,7 @@ export default function DashboardPage() { setIsFirstKeyModalOpen(false)} /> - setIsWithdrawOpen(false)} /> + setIsWithdrawOpen(false)} />
); } diff --git a/frontend/src/components/PaymentMetrics.tsx b/frontend/src/components/PaymentMetrics.tsx index de227d1f..d8da78d2 100644 --- a/frontend/src/components/PaymentMetrics.tsx +++ b/frontend/src/components/PaymentMetrics.tsx @@ -26,7 +26,6 @@ import { DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { localeToLanguageTag } from "@/i18n/config"; -import MetricsSkeleton from "@/components/MetricsSkeleton"; import DensityGrid from "@/components/DensityGrid"; type TimeRange = "7D" | "30D" | "1Y"; @@ -268,6 +267,18 @@ export default function PaymentMetrics({ const hydrated = useMerchantHydrated(); const chartContainerRef = useRef(null); + const handleExport = async (format: ExportFormat) => { + if (!chartContainerRef.current) return; + try { + setExporting(true); + await exportChart(chartContainerRef, format, `metrics-export-${new Date().getTime()}`); + } catch (err) { + toast.error(err instanceof Error ? err.message : t("exportFailed")); + } finally { + setExporting(false); + } + }; + useHydrateMerchantStore(); useEffect(() => { @@ -343,7 +354,7 @@ export default function PaymentMetrics({ }); }; - if (loading || !hydrated) { + if (showSkeleton || loading || !hydrated) { return (
diff --git a/frontend/src/components/WalletSelector.tsx b/frontend/src/components/WalletSelector.tsx index a12372a7..f81eabfe 100644 --- a/frontend/src/components/WalletSelector.tsx +++ b/frontend/src/components/WalletSelector.tsx @@ -153,60 +153,7 @@ export default function WalletSelector({ networkPassphrase, onConnected }: Walle } }, [networkPassphrase, onConnected, selectProvider, providers, t]); - const providerButtons = useMemo(() => { - return providers.map((p) => { - const isWc = p.id === "walletconnect"; - const isConnecting = connecting === p.id; - const isInstalled = installed[p.id] ?? false; - const isDisabled = !isInstalled; - return ( - - ); - }); - }, [providers, connecting, installed, handleSelect, t]); if (activeProvider) return null;
Recent payments transaction history
handleSort("status")}>{t("tableStatus")} handleSort("amount")}>{t("tableAmount")} handleSort("recipient")}>{t("tableRecipient")}Description handleSort("created_at")}>{t("tableDate")}Actions handleSort("status")}>{t("tableStatus")} handleSort("amount")}>{t("tableAmount")} handleSort("recipient")}>{t("tableRecipient")}Description handleSort("created_at")}>{t("tableDate")}Actions
@@ -550,7 +572,8 @@ export default function RecentPayments({