From 48fde638a7306daa071eec1f0ebbbc318d6929fc Mon Sep 17 00:00:00 2001 From: dubemoyibe-star Date: Thu, 26 Mar 2026 09:35:30 +0100 Subject: [PATCH 1/9] added accessibilty changes "Frontend: Add accessibility improvements Fixes #41" --- frontend/components/landing/Navbar.tsx | 28 ++-- frontend/components/layout/Header.tsx | 197 +++++++------------------ frontend/components/layout/Sidebar.tsx | 48 ++++-- frontend/package-lock.json | 60 ++------ frontend/package.json | 2 +- 5 files changed, 125 insertions(+), 210 deletions(-) diff --git a/frontend/components/landing/Navbar.tsx b/frontend/components/landing/Navbar.tsx index 0b1c2097..dbf5cb06 100644 --- a/frontend/components/landing/Navbar.tsx +++ b/frontend/components/landing/Navbar.tsx @@ -5,10 +5,12 @@ import Link from 'next/link'; import { motion, AnimatePresence } from 'framer-motion'; import { Menu, X, Wallet } from 'lucide-react'; import { Button } from '@/components/ui/button'; +import { usePathname } from 'next/navigation'; export function Navbar() { const [isScrolled, setIsScrolled] = useState(false); const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); + const pathname = usePathname(); useEffect(() => { const handleScroll = () => { @@ -35,16 +37,18 @@ export function Navbar() { ? 'bg-white/80 backdrop-blur-md shadow-lg border-b border-gray-200/50' : 'bg-transparent' }`} + role="navigation" + aria-label="Main Navigation" >
{/* Logo */} - + - + AgenticPay @@ -57,7 +61,8 @@ export function Navbar() { {link.name} @@ -68,7 +73,8 @@ export function Navbar() {
@@ -77,8 +83,9 @@ export function Navbar() { {/* Mobile Menu Button */} @@ -135,5 +146,4 @@ export function Navbar() { ); -} - +} \ No newline at end of file diff --git a/frontend/components/layout/Header.tsx b/frontend/components/layout/Header.tsx index 7a0d17db..75b757bd 100644 --- a/frontend/components/layout/Header.tsx +++ b/frontend/components/layout/Header.tsx @@ -16,76 +16,41 @@ import { import { Avatar, AvatarFallback } from '@/components/ui/avatar'; import { Bell, LogOut, User, Settings, Sun, Moon, Clock } from 'lucide-react'; import { toast } from 'sonner'; -<<<<<<< feat/qr-code - -======= ->>>>>>> main -// 1. I added useNetwork to the existing wagmi import import { useDisconnect, useAccount } from 'wagmi'; import { web3auth } from '@/lib/web3auth'; import { ThemeSettingsModal } from '@/components/theme/ThemeSettingsModal'; -// 2. I built the isolated NetworkIndicator component right here -const NetworkIndicator = () => { - // We use useAccount() in Wagmi v2 instead of useNetwork() - const { chain, isConnected } = useAccount(); - - // Hide it if the wallet isn't connected yet - if (!isConnected) return null; - - // In v2, if connected but 'chain' is undefined, it means they are on an unsupported network - if (!chain) { - return ( -
- - Wrong Network -
- ); - } - - // Handle Mainnet (Green) vs Testnet (Yellow) states - const isTestnet = chain.testnet === true; - const bgColor = isTestnet - ? 'bg-yellow-100 text-yellow-800 border-yellow-200' - : 'bg-green-100 text-green-800 border-green-200'; - const dotColor = isTestnet ? 'bg-yellow-500' : 'bg-green-500'; - - return ( -
- - {chain.name} -
- ); -}; - -// 2. I built the isolated NetworkIndicator component right here const NetworkIndicator = () => { - // We use useAccount() in Wagmi v2 instead of useNetwork() const { chain, isConnected } = useAccount(); - // Hide it if the wallet isn't connected yet if (!isConnected) return null; - // In v2, if connected but 'chain' is undefined, it means they are on an unsupported network if (!chain) { return ( -
- +
+ Wrong Network
); } - // Handle Mainnet (Green) vs Testnet (Yellow) states const isTestnet = chain.testnet === true; - const bgColor = isTestnet - ? 'bg-yellow-100 text-yellow-800 border-yellow-200' + const bgColor = isTestnet + ? 'bg-yellow-100 text-yellow-800 border-yellow-200' : 'bg-green-100 text-green-800 border-green-200'; const dotColor = isTestnet ? 'bg-yellow-500' : 'bg-green-500'; return ( -
- +
+ {chain.name}
); @@ -111,7 +76,6 @@ export function Header() { const handleManualToggle = () => { const next = !isDark; setIsDark(next); - // Apply to DOM immediately (ThemeProvider's effect will also fire) document.documentElement.classList.toggle('dark', next); }; @@ -131,25 +95,30 @@ export function Header() { <>
+ {/* Left: Page title */}

Dashboard

-
- - {/* 3. I dropped the new component right here! */} - + {/* Right: Network, notifications, dark mode, user menu */} +
+ {/* Network indicator */} + -
{/* Notifications */} - - {/* Dark mode toggle — only interactive label when manual */} + {/* Dark mode toggle */} -<<<<<<< feat/qr-code -
- - {/* 3. I dropped the new component right here! */} - - - {/* Notifications */} - - - {/* User menu */} - - - - - - -
-

{name || 'User'}

-

{email || 'No email'}

-

{shortAddress}

-
-
- - - - Profile - - - - Settings - - - - - Logout - -
-
-======= - {/* Theme schedule settings */} - - {/* User menu */} - - +

{name || 'User'}

@@ -263,31 +179,30 @@ export function Header() {
- - + + - - + + - - + +
->>>>>>> main
setThemeSettingsOpen(false)} /> ); -<<<<<<< feat/qr-code -} -======= -} ->>>>>>> main +} \ No newline at end of file diff --git a/frontend/components/layout/Sidebar.tsx b/frontend/components/layout/Sidebar.tsx index 03d50622..191ffe37 100644 --- a/frontend/components/layout/Sidebar.tsx +++ b/frontend/components/layout/Sidebar.tsx @@ -27,14 +27,19 @@ export function Sidebar() { size="icon" onClick={() => setIsMobileOpen(!isMobileOpen)} className="bg-white shadow-lg" - aria-label="Toggle menu" + aria-label={isMobileOpen ? 'Close menu' : 'Open menu'} + aria-expanded={isMobileOpen} + aria-controls="sidebar-navigation" > - {isMobileOpen ? : } + {isMobileOpen ?
{/* Sidebar */} ); -} - +} \ No newline at end of file diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 7707d620..234da1e9 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -25,10 +25,11 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "date-fns": "^4.1.0", - "framer-motion": "^12.23.26", + "framer-motion": "^12.38.0", "lucide-react": "^0.562.0", "next": "^16.2.1", "next-themes": "^0.4.6", + "qrcode.react": "^4.2.0", "react": "^19.2.3", "react-day-picker": "^9.13.0", "react-dom": "^19.2.3", @@ -2054,9 +2055,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -9711,31 +9709,14 @@ "node": ">= 6" } }, - "node_modules/form-data": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", - "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", - "dev": true, - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/framer-motion": { - "version": "12.23.26", - "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.26.tgz", - "integrity": "sha512-cPcIhgR42xBn1Uj+PzOyheMtZ73H927+uWPDVhUMqxy8UHt6Okavb6xIz9J/phFUHUj0OncR6UvMfJTXoc/LKA==", + "version": "12.38.0", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.38.0.tgz", + "integrity": "sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g==", "license": "MIT", "dependencies": { - "motion-dom": "^12.23.23", - "motion-utils": "^12.23.6", + "motion-dom": "^12.38.0", + "motion-utils": "^12.36.0", "tslib": "^2.4.0" }, "peerDependencies": { @@ -10208,19 +10189,6 @@ "node": ">=0.10.0" } }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/idb-keyval": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.2.tgz", @@ -11613,18 +11581,18 @@ } }, "node_modules/motion-dom": { - "version": "12.23.23", - "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.23.tgz", - "integrity": "sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA==", + "version": "12.38.0", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.38.0.tgz", + "integrity": "sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA==", "license": "MIT", "dependencies": { - "motion-utils": "^12.23.6" + "motion-utils": "^12.36.0" } }, "node_modules/motion-utils": { - "version": "12.23.6", - "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.23.6.tgz", - "integrity": "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==", + "version": "12.36.0", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.36.0.tgz", + "integrity": "sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg==", "license": "MIT" }, "node_modules/ms": { diff --git a/frontend/package.json b/frontend/package.json index de1af869..8efeacb7 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -28,7 +28,7 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "date-fns": "^4.1.0", - "framer-motion": "^12.23.26", + "framer-motion": "^12.38.0", "lucide-react": "^0.562.0", "next": "^16.2.1", "next-themes": "^0.4.6", From 8c9a16fc9d9bb150760251bde33f6d6031c53b31 Mon Sep 17 00:00:00 2001 From: dubemoyibe-star Date: Sat, 28 Mar 2026 08:04:38 +0100 Subject: [PATCH 2/9] made major fixes --- frontend/app/dashboard/invoices/[id]/page.tsx | 1 + frontend/app/dashboard/invoices/page.tsx | 132 +++++++++--------- frontend/app/dashboard/layout.tsx | 4 + frontend/app/dashboard/payments/page.tsx | 103 ++++++-------- frontend/app/dashboard/projects/[id]/page.tsx | 2 + 5 files changed, 114 insertions(+), 128 deletions(-) diff --git a/frontend/app/dashboard/invoices/[id]/page.tsx b/frontend/app/dashboard/invoices/[id]/page.tsx index 4716728c..f3f4e614 100644 --- a/frontend/app/dashboard/invoices/[id]/page.tsx +++ b/frontend/app/dashboard/invoices/[id]/page.tsx @@ -13,6 +13,7 @@ import { formatTimeInTimeZone, } from '@/lib/utils'; import { useAuthStore } from '@/store/useAuthStore'; +import { PageBreadcrumb } from '@/components/layout/PageBreadcrumb'; export default function InvoiceDetailPage() { const params = useParams(); diff --git a/frontend/app/dashboard/invoices/page.tsx b/frontend/app/dashboard/invoices/page.tsx index 6d0c1676..8fe26db4 100644 --- a/frontend/app/dashboard/invoices/page.tsx +++ b/frontend/app/dashboard/invoices/page.tsx @@ -4,22 +4,35 @@ import { useState } from 'react'; import { useDashboardData } from '@/lib/hooks/useDashboardData'; import { Card, CardContent } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; -import { CheckCircle2, Clock, AlertCircle, Filter, FileText, Loader2 } from 'lucide-react'; +import { + CheckCircle2, + Clock, + AlertCircle, + Filter, + FileText, + Loader2, +} from 'lucide-react'; import { motion } from 'framer-motion'; import Link from 'next/link'; import { InvoiceCardSkeleton } from '@/components/ui/loading-skeletons'; import { EmptyState } from '@/components/empty/EmptyState'; import { formatDateInTimeZone } from '@/lib/utils'; import { useAuthStore } from '@/store/useAuthStore'; +import { useRouter } from 'next/navigation'; export default function InvoicesPage() { const router = useRouter(); const { invoices, loading } = useDashboardData(); const timezone = useAuthStore((state) => state.timezone); - const [filter, setFilter] = useState<'all' | 'paid' | 'pending' | 'overdue'>('all'); + + const [filter, setFilter] = useState< + 'all' | 'paid' | 'pending' | 'overdue' + >('all'); const filteredInvoices = - filter === 'all' ? invoices : invoices.filter((inv) => inv.status === filter); + filter === 'all' + ? invoices + : invoices.filter((inv) => inv.status === filter); const getStatusIcon = (status: string) => { switch (status) { @@ -52,12 +65,15 @@ export default function InvoicesPage() {

Invoices

-

View and manage your invoices

+

+ View and manage your invoices +

Loading invoices...
+
{[1, 2, 3, 4].map((i) => ( @@ -69,83 +85,55 @@ export default function InvoicesPage() { return (
+ {/* Header */}

Invoices

-

View and manage your invoices

+

+ View and manage your invoices +

+ {/* Filters */}
- {(['all', 'paid', 'pending', 'overdue'] as const).map((status) => ( - - ))} + {(['all', 'paid', 'pending', 'overdue'] as const).map( + (status) => ( + + ) + )}
-
- {filteredInvoices.map((invoice, index) => ( - - - - -
-
- {getStatusIcon(invoice.status)} -
-

{invoice.projectTitle}

-

{invoice.milestoneTitle}

-

- Ref #{invoice.id} • {formatDateInTimeZone(invoice.generatedAt, timezone)} -

-
-
-
-

- {invoice.amount} {invoice.currency} -

- - {invoice.status} - -
-
-
-
- -
- ))} -
- - {filteredInvoices.length === 0 && ( + {/* Content */} + {filteredInvoices.length === 0 ? ( { if (filter === 'all') { router.push('/dashboard/projects'); @@ -166,25 +154,39 @@ export default function InvoicesPage() { animate={{ opacity: 1, y: 0 }} transition={{ delay: index * 0.05 }} > - +
{getStatusIcon(invoice.status)} +
-

{invoice.projectTitle}

-

{invoice.milestoneTitle}

+

+ {invoice.projectTitle} +

+ +

+ {invoice.milestoneTitle} +

+

Ref #{invoice.id} •{' '} - {new Date(invoice.generatedAt).toLocaleDateString()} + {formatDateInTimeZone( + invoice.generatedAt, + timezone + )}

+

{invoice.amount} {invoice.currency}

+ (null); + const scrollPositions = React.useRef>({}); + useEffect(() => { if (!isAuthenticated) { router.push('/auth'); diff --git a/frontend/app/dashboard/payments/page.tsx b/frontend/app/dashboard/payments/page.tsx index 3671c645..21ecd600 100644 --- a/frontend/app/dashboard/payments/page.tsx +++ b/frontend/app/dashboard/payments/page.tsx @@ -17,13 +17,18 @@ import { motion } from 'framer-motion'; import { PaymentCardSkeleton } from '@/components/ui/loading-skeletons'; import { EmptyState } from '@/components/empty/EmptyState'; import { formatDateTimeInTimeZone } from '@/lib/utils'; -import { useAuthStore } from '@/store/useAuthStore'; +import { useRouter } from 'next/navigation'; +import { Button } from '@/components/ui/button'; +import { PaymentQRModal } from '@/components/payment/QRCode'; export default function PaymentsPage() { const router = useRouter(); const { payments, loading } = useDashboardData(); const timezone = useAuthStore((state) => state.timezone); + const [isQrModalOpen, setIsQrModalOpen] = useState(false); + const address = useAuthStore((state) => state.address); + const getStatusIcon = (status: string) => { switch (status) { case 'completed': @@ -41,13 +46,18 @@ export default function PaymentsPage() { return (
-

Payment History

-

View all your payment transactions

+

+ Payment History +

+

+ View all your payment transactions +

Loading payments...
+
{[1, 2, 3, 4].map((i) => ( @@ -59,75 +69,30 @@ export default function PaymentsPage() { return (
+ {/* Header */}
-

Payment History

-

View all your payment transactions

+

+ Payment History +

+

+ View all your payment transactions +

{address && ( - )}
- {/* --- PAYMENT LIST --- */} -
- {payments.map((payment, index) => ( - - - -
-
- {getStatusIcon(payment.status)} -
-

{payment.projectTitle}

-

- {payment.type === 'milestone_payment' ? 'Milestone Payment' : 'Full Payment'} -

-

- {formatDateTimeInTimeZone(payment.timestamp, timezone)} -

-
-
-
-

- {payment.amount} {payment.currency} -

- {payment.transactionHash && ( - - View on Explorer - - - )} -
-
- {payment.transactionHash && ( -
-

- {payment.transactionHash} -

-
- )} -
-
-
- ))} -
- - {payments.length === 0 && ( + {/* Content */} + {payments.length === 0 ? (
{getStatusIcon(payment.status)} +
-

{payment.projectTitle}

+

+ {payment.projectTitle} +

+

{payment.type === 'milestone_payment' ? 'Milestone Payment' : 'Full Payment'}

+

- {new Date(payment.timestamp).toLocaleString()} + {formatDateTimeInTimeZone( + payment.timestamp, + timezone + )}

+

{payment.amount} {payment.currency}

+ {payment.transactionHash && (
+ {payment.transactionHash && (

@@ -198,6 +174,7 @@ export default function PaymentsPage() {

)} + {/* QR Modal */} {address && ( Date: Sat, 28 Mar 2026 08:34:20 +0100 Subject: [PATCH 3/9] implemeted another fix --- frontend/components/landing/Navbar.tsx | 1 + .../settings/TimezoneSettingsModal.tsx | 88 ++++++--- frontend/components/ui/breadcrumb.tsx | 169 +++++++++--------- 3 files changed, 153 insertions(+), 105 deletions(-) diff --git a/frontend/components/landing/Navbar.tsx b/frontend/components/landing/Navbar.tsx index aaed2c60..12975de7 100644 --- a/frontend/components/landing/Navbar.tsx +++ b/frontend/components/landing/Navbar.tsx @@ -6,6 +6,7 @@ import { motion, AnimatePresence } from 'framer-motion'; import { Menu, X, Wallet } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { usePathname } from 'next/navigation'; +import { LanguageSwitcher } from '../language/LanguageSwitcher'; export function Navbar() { const [isScrolled, setIsScrolled] = useState(false); diff --git a/frontend/components/settings/TimezoneSettingsModal.tsx b/frontend/components/settings/TimezoneSettingsModal.tsx index ecb5b1cb..cf4f3a2f 100644 --- a/frontend/components/settings/TimezoneSettingsModal.tsx +++ b/frontend/components/settings/TimezoneSettingsModal.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useEffect, useMemo, useState } from 'react'; +import { useMemo, useState } from 'react'; import { Clock3, LocateFixed } from 'lucide-react'; import { toast } from 'sonner'; import { Button } from '@/components/ui/button'; @@ -37,19 +37,28 @@ function getSupportedTimeZones() { return Intl.supportedValuesOf('timeZone'); } -export function TimezoneSettingsModal({ open, onClose }: TimezoneSettingsModalProps) { +export function TimezoneSettingsModal({ + open, + onClose, +}: TimezoneSettingsModalProps) { const storedTimeZone = useAuthStore((state) => state.timezone); const setTimezone = useAuthStore((state) => state.setTimezone); const browserTimeZone = getBrowserTimeZone(); - const [localTimeZone, setLocalTimeZone] = useState(resolveTimeZone(storedTimeZone)); - useEffect(() => { - if (open) { - setLocalTimeZone(resolveTimeZone(storedTimeZone)); - } - }, [open, storedTimeZone]); + // ✅ derive initial value safely + const initialTimeZone = useMemo( + () => resolveTimeZone(storedTimeZone), + [storedTimeZone] + ); + + const [localTimeZone, setLocalTimeZone] = + useState(initialTimeZone); + + const supportedTimeZones = useMemo( + () => getSupportedTimeZones(), + [] + ); - const supportedTimeZones = useMemo(() => getSupportedTimeZones(), []); const previewTimeZone = resolveTimeZone(localTimeZone); const handleDetectTimezone = () => { @@ -60,7 +69,9 @@ export function TimezoneSettingsModal({ open, onClose }: TimezoneSettingsModalPr const handleSave = () => { if (!isValidTimeZone(localTimeZone)) { - toast.error('Enter a valid IANA timezone such as Europe/London'); + toast.error( + 'Enter a valid IANA timezone such as Europe/London' + ); return; } @@ -70,7 +81,12 @@ export function TimezoneSettingsModal({ open, onClose }: TimezoneSettingsModalPr }; return ( - !nextOpen && onClose()}> + + !nextOpen && onClose() + } + > @@ -78,25 +94,33 @@ export function TimezoneSettingsModal({ open, onClose }: TimezoneSettingsModalPr Timezone Settings - Choose how dates and times are shown across your dashboard. + Choose how dates and times are shown across your + dashboard.
-

Detected timezone

+

+ Detected timezone +

- {browserTimeZone ?? 'Unavailable in this browser'} + {browserTimeZone ?? + 'Unavailable in this browser'}

- + setLocalTimeZone(event.target.value)} + onChange={(event) => + setLocalTimeZone(event.target.value) + } placeholder="e.g. America/New_York" /> @@ -105,28 +129,46 @@ export function TimezoneSettingsModal({ open, onClose }: TimezoneSettingsModalPr ))}

- Use a valid IANA timezone, like `Africa/Lagos` or `America/Los_Angeles`. + Use a valid IANA timezone, like `Africa/Lagos` + or `America/Los_Angeles`.

-

Preview

+

+ Preview +

- {formatDateTimeInTimeZone(new Date(), previewTimeZone)} + {formatDateTimeInTimeZone( + new Date(), + previewTimeZone + )} +

+

+ {previewTimeZone}

-

{previewTimeZone}

- +
- + @@ -135,4 +177,4 @@ export function TimezoneSettingsModal({ open, onClose }: TimezoneSettingsModalPr
); -} +} \ No newline at end of file diff --git a/frontend/components/ui/breadcrumb.tsx b/frontend/components/ui/breadcrumb.tsx index d9d55031..38c3eaab 100644 --- a/frontend/components/ui/breadcrumb.tsx +++ b/frontend/components/ui/breadcrumb.tsx @@ -1,15 +1,16 @@ -import * as React from "react" -import { Slot } from "@radix-ui/react-slot" -import { cva, type VariantProps } from "class-variance-authority" -import { ChevronRight } from "lucide-react" -import { cn } from "@/lib/utils" -import Link from "next/link" +'use client'; -const breadcrumbVariants = cva("flex items-center gap-1.5") +import * as React from 'react'; +import { Slot } from '@radix-ui/react-slot'; +import { cva, type VariantProps } from 'class-variance-authority'; +import { ChevronRight } from 'lucide-react'; +import { cn } from '@/lib/utils'; +import Link from 'next/link'; -interface BreadcrumbProps - extends React.HTMLAttributes, - VariantProps {} +const breadcrumbVariants = cva('flex items-center gap-1.5'); + +type BreadcrumbProps = React.HTMLAttributes & + VariantProps; const Breadcrumb = React.forwardRef( ({ className, ...props }, ref) => ( @@ -20,90 +21,93 @@ const Breadcrumb = React.forwardRef( {...props} /> ) -) -Breadcrumb.displayName = "Breadcrumb" +); +Breadcrumb.displayName = 'Breadcrumb'; -interface BreadcrumbListProps extends React.HTMLAttributes {} +type BreadcrumbListProps = React.HTMLAttributes; -const BreadcrumbList = React.forwardRef( - ({ className, ...props }, ref) => ( -
    - ) -) -BreadcrumbList.displayName = "BreadcrumbList" +const BreadcrumbList = React.forwardRef< + HTMLOListElement, + BreadcrumbListProps +>(({ className, ...props }, ref) => ( +
      +)); +BreadcrumbList.displayName = 'BreadcrumbList'; -interface BreadcrumbItemProps extends React.HTMLAttributes {} +type BreadcrumbItemProps = React.HTMLAttributes; -const BreadcrumbItem = React.forwardRef( - ({ className, ...props }, ref) => ( -
    1. - ) -) -BreadcrumbItem.displayName = "BreadcrumbItem" - -interface BreadcrumbLinkProps - extends React.AnchorHTMLAttributes { - asChild?: boolean - href: string -} - -const BreadcrumbLink = React.forwardRef( - ({ className, href, asChild = false, ...props }, ref) => { - const Comp = asChild ? Slot : Link - - return ( - - ) - } -) -BreadcrumbLink.displayName = "BreadcrumbLink" - -interface BreadcrumbPageProps - extends React.HTMLAttributes {} - -const BreadcrumbPage = React.forwardRef( - ({ className, ...props }, ref) => ( - (({ className, ...props }, ref) => ( +
    2. +)); +BreadcrumbItem.displayName = 'BreadcrumbItem'; + +type BreadcrumbLinkProps = React.AnchorHTMLAttributes & { + asChild?: boolean; + href: string; +}; + +const BreadcrumbLink = React.forwardRef< + HTMLAnchorElement, + BreadcrumbLinkProps +>(({ className, href, asChild = false, ...props }, ref) => { + const Comp: any = asChild ? Slot : Link; + + return ( + - ) -) -BreadcrumbPage.displayName = "BreadcrumbPage" + ); +}); +BreadcrumbLink.displayName = 'BreadcrumbLink'; + +type BreadcrumbPageProps = React.HTMLAttributes; + +const BreadcrumbPage = React.forwardRef< + HTMLSpanElement, + BreadcrumbPageProps +>(({ className, ...props }, ref) => ( + +)); +BreadcrumbPage.displayName = 'BreadcrumbPage'; -interface BreadcrumbSeparatorProps - extends React.HTMLAttributes { - icon?: React.ReactNode -} +type BreadcrumbSeparatorProps = + React.HTMLAttributes & { + icon?: React.ReactNode; + }; -const BreadcrumbSeparator = ({ className, icon, ...props }: BreadcrumbSeparatorProps) => +const BreadcrumbSeparator = ({ + className, + icon, + ...props +}: BreadcrumbSeparatorProps) => icon ? ( ); -} +} \ No newline at end of file diff --git a/frontend/lib/web3auth.ts b/frontend/lib/web3auth.ts index ee82049a..f546e528 100644 --- a/frontend/lib/web3auth.ts +++ b/frontend/lib/web3auth.ts @@ -12,16 +12,15 @@ const chainConfig = { tickerName: "Stellar Lumens", }; -const privateKeyProvider = new EthereumPrivateKeyProvider({ - config: { chainConfig }, -}); +// Cast to any to satisfy TypeScript +const privateKeyProvider = new EthereumPrivateKeyProvider({ config: { chainConfig } }) as any; // Get client ID from environment or use a placeholder for development const clientId = process.env.NEXT_PUBLIC_WEB3AUTH_CLIENT_ID; if (!clientId) { console.warn( - 'NEXT_PUBLIC_WEB3AUTH_CLIENT_ID is not set. Web3Auth will not work until you add your client ID to .env.local' + "NEXT_PUBLIC_WEB3AUTH_CLIENT_ID is not set. Web3Auth will not work until you add your client ID to .env.local" ); } @@ -30,15 +29,12 @@ export const web3auth: IWeb3AuthModal | null = clientId ? new Web3Auth({ clientId, web3AuthNetwork: "testnet", - chainConfig, - privateKeyProvider, + privateKeyProvider, // keep here uiConfig: { appName: "AgenticPay", - theme: { - primary: "#0052FF", - }, + theme: { primary: "#0052FF" }, mode: "light", loginMethodsOrder: ["google", "twitter", "email_passwordless"], }, }) - : null; + : null; \ No newline at end of file