From c10227bb420a291221960c6d8f548de5c8ad8c08 Mon Sep 17 00:00:00 2001 From: Ayoazeez26 Date: Wed, 2 Jul 2025 12:22:04 +0100 Subject: [PATCH 1/3] feat: resolving build failure --- app/dashboard/layout.tsx | 5 +- app/dashboard/page.tsx | 8 +- app/dashboard/transactions/page.tsx | 4 +- .../Landing-page/Hero/ExchangePreviewCard.tsx | 2 +- components/Landing-page/Hero/HeroCTA.tsx | 5 +- components/auth/sign-in-form.tsx | 86 ++-- components/auth/sign-up-form.tsx | 8 +- .../dashboard/convert/currency-selector.tsx | 17 +- .../dashboard/modals/confirmation-modal.tsx | 20 +- .../dashboard/modals/processing-modal.tsx | 8 +- components/dashboard/modals/success-modal.tsx | 8 +- .../dashboard/transaction/TransactionList.tsx | 413 ++++++++++++------ components/header/LandingNavbar.tsx | 14 +- components/header/Navbar.tsx | 39 +- components/ui/{button.tsx => but.tsx} | 0 hooks/transaction/useTransaction.ts | 24 + package-lock.json | 132 +++++- package.json | 2 + services/README.md | 99 +++++ services/api/axiosClient.ts | 42 ++ services/api/client.ts | 156 +++++++ services/api/config.ts | 33 ++ services/api/index.ts | 11 + services/api/transactionService.ts | 19 + services/api/types.ts | 16 + services/api/userService.ts | 39 ++ 26 files changed, 941 insertions(+), 269 deletions(-) rename components/ui/{button.tsx => but.tsx} (100%) create mode 100644 hooks/transaction/useTransaction.ts create mode 100644 services/README.md create mode 100644 services/api/axiosClient.ts create mode 100644 services/api/client.ts create mode 100644 services/api/config.ts create mode 100644 services/api/index.ts create mode 100644 services/api/transactionService.ts create mode 100644 services/api/types.ts create mode 100644 services/api/userService.ts diff --git a/app/dashboard/layout.tsx b/app/dashboard/layout.tsx index e538640..cb0795e 100644 --- a/app/dashboard/layout.tsx +++ b/app/dashboard/layout.tsx @@ -27,7 +27,7 @@ export default function Layout({ children }: LayoutProps) { const { isCollapsed } = useSidebarStore(); return ( -
+
@@ -35,8 +35,7 @@ export default function Layout({ children }: LayoutProps) {
+ } pt-20`}>
{children}
diff --git a/app/dashboard/page.tsx b/app/dashboard/page.tsx index 8e0b506..e7c6e32 100644 --- a/app/dashboard/page.tsx +++ b/app/dashboard/page.tsx @@ -1,5 +1,5 @@ import { ArrowDown, ArrowUp, ChevronRight } from "lucide-react"; -import { Button } from "@/components/ui/button"; +import { Button } from "@/components/ui/but"; import { BalanceCard } from "@/components/dashboard/home/balance-card"; import { PortfolioCard } from "@/components/dashboard/convert/portfolio-card"; import { TransactionsTable } from "@/components/dashboard/transaction/transactions-table"; @@ -76,8 +76,7 @@ export default function Dashboard() { @@ -107,8 +106,7 @@ export default function Dashboard() { diff --git a/app/dashboard/transactions/page.tsx b/app/dashboard/transactions/page.tsx index 5da9105..de86892 100644 --- a/app/dashboard/transactions/page.tsx +++ b/app/dashboard/transactions/page.tsx @@ -84,8 +84,8 @@ const dummyTransactions: Transaction[] = [ export default function TransactionsPage() { return ( -
- +
+ diff --git a/components/Landing-page/Hero/ExchangePreviewCard.tsx b/components/Landing-page/Hero/ExchangePreviewCard.tsx index 8889128..a2dbfed 100644 --- a/components/Landing-page/Hero/ExchangePreviewCard.tsx +++ b/components/Landing-page/Hero/ExchangePreviewCard.tsx @@ -1,5 +1,5 @@ import { RefreshCw } from "lucide-react"; -import { Button } from "../../ui/button"; +import { Button } from "../../ui/but"; export default function ExchangePreviewCard() { return ( diff --git a/components/Landing-page/Hero/HeroCTA.tsx b/components/Landing-page/Hero/HeroCTA.tsx index 36be8dd..50670b7 100644 --- a/components/Landing-page/Hero/HeroCTA.tsx +++ b/components/Landing-page/Hero/HeroCTA.tsx @@ -1,5 +1,5 @@ import { ArrowRight } from "lucide-react"; -import { Button } from "../../ui/button"; +import { Button } from "../../ui/but"; import Link from "next/link"; export default function HeroCTA() { @@ -8,8 +8,7 @@ export default function HeroCTA() { diff --git a/components/auth/sign-in-form.tsx b/components/auth/sign-in-form.tsx index fba50c5..1d34037 100644 --- a/components/auth/sign-in-form.tsx +++ b/components/auth/sign-in-form.tsx @@ -1,13 +1,13 @@ -"use client" +"use client"; -import { useFormik } from "formik" -import Link from "next/link" -import { FormInput } from "../ui/form-input" -import { Mail } from "lucide-react" -import { PasswordInput } from "../ui/passwor-input" -import { Button } from "../ui/button" -import { Separator } from "../ui/separator" -import { signInSchema } from "@/utils/authValidationSchema" +import { useFormik } from "formik"; +import Link from "next/link"; +import { FormInput } from "../ui/form-input"; +import { Mail } from "lucide-react"; +import { PasswordInput } from "../ui/passwor-input"; +import { Button } from "../ui/but"; +import { Separator } from "../ui/separator"; +import { signInSchema } from "@/utils/authValidationSchema"; export default function SignInForm() { const formik = useFormik({ @@ -20,14 +20,14 @@ export default function SignInForm() { onSubmit: async (values) => { try { // Here you would typically call an API endpoint - console.log("Form submitted:", values) + console.log("Form submitted:", values); // Simulate successful signin // router.push("/dashboard"); } catch (error) { - console.error("Signin error:", error) + console.error("Signin error:", error); } }, - }) + }); return (
@@ -46,10 +46,14 @@ export default function SignInForm() {
-
@@ -60,7 +64,11 @@ export default function SignInForm() { placeholder="••••••••" value={formik.values.password} onChange={formik.handleChange} - error={formik.touched.password && formik.errors.password ? formik.errors.password : undefined} + error={ + formik.touched.password && formik.errors.password + ? formik.errors.password + : undefined + } />
@@ -86,15 +94,16 @@ export default function SignInForm() { type="submit" size={"lg"} className="w-full bg-gradient-to-r from-[#3B82F6] to-[#EAB308] hover:opacity-90 shadow-sm font-medium" - disabled={formik.isSubmitting} - > + disabled={formik.isSubmitting}> Sign In
- Or continue with + + Or continue with +
@@ -106,50 +115,48 @@ export default function SignInForm() { preserveAspectRatio="xMidYMid" fill="#000000" stroke="#000000" - strokeWidth="0.00262" - > + strokeWidth="0.00262"> + strokeWidth="0.524"> + fill="#000000000"> + fill="#0000000"> + fill="#000"> + fill="#00000"> {" "} Google
- ) + ); } - diff --git a/components/auth/sign-up-form.tsx b/components/auth/sign-up-form.tsx index d621864..df65cdf 100644 --- a/components/auth/sign-up-form.tsx +++ b/components/auth/sign-up-form.tsx @@ -5,7 +5,7 @@ import Link from "next/link"; import { User, Mail } from "lucide-react"; import { FormInput } from "../ui/form-input"; import { PasswordInput } from "../ui/passwor-input"; -import { Button } from "../ui/button"; +import { Button } from "../ui/but"; import { signUpSchema } from "@/utils/authValidationSchema"; export default function SignUpForm() { @@ -112,8 +112,7 @@ export default function SignUpForm() { type="submit" size={"lg"} className="w-full bg-gradient-to-r from-[#3B82F6] to-[#EAB308] hover:opacity-90 shadow-sm font-medium" - disabled={formik.isSubmitting} - > + disabled={formik.isSubmitting}> Create Account @@ -122,8 +121,7 @@ export default function SignUpForm() { Already have an account?{" "} + className="text-blue-500 hover:underline font-medium"> Sign in

diff --git a/components/dashboard/convert/currency-selector.tsx b/components/dashboard/convert/currency-selector.tsx index a873322..b326517 100644 --- a/components/dashboard/convert/currency-selector.tsx +++ b/components/dashboard/convert/currency-selector.tsx @@ -11,7 +11,7 @@ import { import { Currency } from "@/types"; import { useState } from "react"; -import { Button } from "@/components/ui/button"; +import { Button } from "@/components/ui/but"; import { Input } from "@/components/ui/input"; interface CurrencySelectorProps { currency: string; @@ -41,8 +41,7 @@ export function CurrencySelector({ variant === "default" ? "bg-blue-500 text-lg hover:bg-blue-600 text-white rounded-full" : "" - } ${className}`} - > + } ${className}`}> {currency} @@ -50,16 +49,14 @@ export function CurrencySelector({ onFocusOutside={() => { setOpen(false); }} - className="sm:max-w-[611px] h-[223px] px-6 py-3 overflow-hidden mt-1 -ml-64" - > + className="sm:max-w-[611px] h-[223px] px-6 py-3 overflow-hidden mt-1 -ml-64">
Select Token
@@ -79,8 +76,7 @@ export function CurrencySelector({ onSelect(currency); setOpen(false); }} - className="flex bg-[#EBEBEB] cursor-pointer flex-col items-center px-3 py-1 rounded-lg border border-gray-200 hover:border-gray-300 transition-colors" - > + className="flex bg-[#EBEBEB] cursor-pointer flex-col items-center px-3 py-1 rounded-lg border border-gray-200 hover:border-gray-300 transition-colors">
{/* {currency.icon} */}
@@ -93,8 +89,7 @@ export function CurrencySelector({
diff --git a/components/dashboard/modals/confirmation-modal.tsx b/components/dashboard/modals/confirmation-modal.tsx index 9d7eb2c..1a88f80 100644 --- a/components/dashboard/modals/confirmation-modal.tsx +++ b/components/dashboard/modals/confirmation-modal.tsx @@ -1,4 +1,4 @@ -import { Button } from "@/components/ui/button"; +import { Button } from "@/components/ui/but"; import { Dialog, DialogClose, @@ -71,8 +71,7 @@ export function ConfirmationModal(Props: ConfirmationModalProp) { height="25" viewBox="0 0 25 25" fill="none" - xmlns="http://www.w3.org/2000/svg" - > + xmlns="http://www.w3.org/2000/svg"> + className="flex-1 bg-yellow-400 hover:bg-yellow-500 h-10 text-md text-black"> Proceed
@@ -144,8 +142,7 @@ export function ConfirmationModal(Props: ConfirmationModalProp) { height="131" viewBox="0 0 130 131" fill="none" - xmlns="http://www.w3.org/2000/svg" - > + xmlns="http://www.w3.org/2000/svg"> + className="absolute cursor-pointer right-4 top-4">

@@ -204,8 +200,7 @@ export function ConfirmationModal(Props: ConfirmationModalProp) { setModalScene("confirm"); }, 1000); }} - className="flex-1 h-12 cursor-pointer border rounded-md " - > + className="flex-1 h-12 cursor-pointer border rounded-md "> Close + className="flex-1 h-12 cursor-pointer rounded-md bg-yellow-400 hover:bg-yellow-500 text-black"> View wallet

diff --git a/components/dashboard/modals/processing-modal.tsx b/components/dashboard/modals/processing-modal.tsx index af77af3..3053b08 100644 --- a/components/dashboard/modals/processing-modal.tsx +++ b/components/dashboard/modals/processing-modal.tsx @@ -1,6 +1,6 @@ "use client"; -import { Button } from "@/components/ui/button"; +import { Button } from "@/components/ui/but"; import { Dialog, DialogContent, @@ -30,8 +30,7 @@ export function ProcessingModal({ variant="ghost" size="sm" className="absolute right-4 top-4" - onClick={onCancel} - > + onClick={onCancel}> @@ -69,8 +68,7 @@ export function ProcessingModal({
diff --git a/components/dashboard/modals/success-modal.tsx b/components/dashboard/modals/success-modal.tsx index e2fd1c8..6a42f71 100644 --- a/components/dashboard/modals/success-modal.tsx +++ b/components/dashboard/modals/success-modal.tsx @@ -1,6 +1,6 @@ "use client"; -import { Button } from "@/components/ui/button"; +import { Button } from "@/components/ui/but"; import { Dialog, DialogContent } from "@/components/ui/dialog"; import { Check, X } from "lucide-react"; import type { ConversionData } from "@/types"; @@ -25,8 +25,7 @@ export function SuccessModal({ variant="ghost" size="sm" className="absolute right-4 top-4" - onClick={onClose} - > + onClick={onClose}>
@@ -51,8 +50,7 @@ export function SuccessModal({
diff --git a/components/dashboard/transaction/TransactionList.tsx b/components/dashboard/transaction/TransactionList.tsx index 4185749..45707be 100644 --- a/components/dashboard/transaction/TransactionList.tsx +++ b/components/dashboard/transaction/TransactionList.tsx @@ -1,14 +1,14 @@ "use client"; -import { useState } from "react"; +import { useState, useEffect, useCallback } from "react"; +import axios from "axios"; import { Check, X, ChevronDown, ChevronUp } from "lucide-react"; import Image from "next/image"; -import { +import type { Transaction, TransactionFilter, TransactionType, } from "@/types/transaction"; - import { Table, TableBody, @@ -19,12 +19,14 @@ import { } from "@/components/ui/table"; import { Badge } from "@/components/ui/badge"; import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { Button } from "@/components/ui/but"; +import { fetchTransactions } from "@/lib/api/transactions"; import React from "react"; import { EmptyTransaction } from "./EmptyTransaction"; -interface TransactionListProps { - transactions: Transaction[]; -} +// interface TransactionListProps { +// transactions: Transaction[]; +// } function getTransactionIcon(type: TransactionType) { switch (type) { @@ -76,9 +78,8 @@ function StatusBadge({ status }: { status: "Success" | "Failed" }) { return ( - + className="bg-[#1BB72D]/20 text-[#009411]/90 font-bold flex items-center gap-1 rounded-full px-2 py-1.5 min-w-[106px] hover:bg-green-100"> + Success ); @@ -87,9 +88,8 @@ function StatusBadge({ status }: { status: "Success" | "Failed" }) { return ( - + className="bg-[#C80808]/20 text-[#C80808]/90 border-red-200 font-bold flex items-center gap-1 rounded-full min-w-[106px] px-2 py-1.5 hover:bg-red-100"> + Failed ); @@ -103,8 +103,7 @@ function MobileAccordionRow({ transaction }: { transaction: Transaction }) { <> setIsOpen(!isOpen)} - > + onClick={() => setIsOpen(!isOpen)}> {/* TYPE */}
@@ -179,59 +178,187 @@ function MobileAccordionRow({ transaction }: { transaction: Transaction }) { ); } -export function TransactionList({ transactions }: TransactionListProps) { +// Pagination Component +function Pagination({ + currentPage, + totalPages, + totalItems, + itemsPerPage, + onPageChange, +}: { + currentPage: number; + totalPages: number; + totalItems: number; + itemsPerPage: number; + onPageChange: (page: number) => void; +}) { + const startItem = (currentPage - 1) * itemsPerPage + 1; + const endItem = Math.min(currentPage * itemsPerPage, totalItems); + + // Generate page numbers to show + const getPageNumbers = () => { + const pages = []; + const maxVisiblePages = 6; + + if (totalPages <= maxVisiblePages) { + for (let i = 1; i <= totalPages; i++) { + pages.push(i); + } + } else { + if (currentPage <= 3) { + for (let i = 1; i <= maxVisiblePages; i++) { + pages.push(i); + } + } else if (currentPage >= totalPages - 2) { + for (let i = totalPages - maxVisiblePages + 1; i <= totalPages; i++) { + pages.push(i); + } + } else { + for (let i = currentPage - 2; i <= currentPage + 3; i++) { + pages.push(i); + } + } + } + + return pages; + }; + + const pageNumbers = getPageNumbers(); + + return ( +
+ {/* Left side - Showing entries text */} +
+ Showing {startItem} to {endItem} of {totalItems} entries +
+ + {/* Right side - Navigation */} +
+ {/* Previous Button */} + + + {/* Page Numbers */} + {pageNumbers.map((pageNum) => ( + + ))} + + {/* Next Button */} + +
+
+ ); +} + +export function TransactionList() { const [activeFilter, setActiveFilter] = useState("All"); + const [currentPage, setCurrentPage] = useState(1); + const itemsPerPage = 5; + const [loading, setLoading] = useState(true); + const [transactionsData, setTransactionsData] = useState([]); + + useEffect(() => { + const fetchTransactions = async () => { + try { + setLoading(true); + const data = await fetchTransactions(); + setTransactionsData(data); + } catch (error) { + console.error("Error fetching transactions:", error); + } finally { + setLoading(false); + } + }; + fetchTransactions(); + }, [fetchTransactions]); // Filter transactions based on active filter - const filteredTransactions = transactions.filter((transaction) => { + const filteredTransactions = transactionsData.filter((transaction) => { if (activeFilter === "All") return true; if (activeFilter === "Withdrawal") return transaction.type === "Withdraw"; return transaction.type === activeFilter; }); + // Calculate pagination + const totalPages = Math.ceil(filteredTransactions.length / itemsPerPage); + const startIndex = (currentPage - 1) * itemsPerPage; + const endIndex = startIndex + itemsPerPage; + const currentTransactions = filteredTransactions.slice(startIndex, endIndex); + + // Reset to first page when filter changes + useEffect(() => { + setCurrentPage(1); + }, [activeFilter]); + // Count transactions for each filter const counts = { - All: transactions.length, - Deposit: transactions.filter((t) => t.type === "Deposit").length, - Withdrawal: transactions.filter((t) => t.type === "Withdraw").length, - Convert: transactions.filter((t) => t.type === "Convert").length, + All: transactionsData.length, + Deposit: transactionsData.filter((t) => t.type === "Deposit").length, + Withdrawal: transactionsData.filter((t) => t.type === "Withdraw").length, + Convert: transactionsData.filter((t) => t.type === "Convert").length, }; return (
-
-

Transactions

+
+ {/* Search bar */} +
+ +
setActiveFilter(value as TransactionFilter)} - className="w-auto" - > - + className="w-auto"> + + className="data-[state=active]:bg-[#FFD552] data-[state=active]:text-black/70 text-black/60 px-5 py-3 text-xs rounded-xl"> All {counts.All > 0 && {counts.All}} + className="data-[state=active]:bg-[#FFD552] data-[state=active]:text-black/70 + text-black/60 px-5 py-3 text-xs rounded-xl"> Deposit + className="data-[state=active]:bg-[#FFD552] data-[state=active]:text-black/70 + text-black/60 px-5 py-3 text-xs rounded-xl"> Withdrawal + className="data-[state=active]:bg-[#FFD552] data-[state=active]:text-black/70 text-black/60 px-5 py-3 text-xs rounded-xl"> Convert @@ -239,107 +366,123 @@ export function TransactionList({ transactions }: TransactionListProps) {
{/* Transactions Table or Empty State */} - {filteredTransactions.length === 0 ? ( - - ) : ( -
- - - - {/* Desktop Headers */} - - TYPE - - - CURRENCY - - - DATE - - - STATUS - - - AMOUNT - - - {/* Mobile Headers - 3 columns properly aligned */} - - TYPE - - - AMOUNT - - - STATUS - - - - - {filteredTransactions.map((transaction) => ( - - {/* Desktop Row */} - - {/* Type */} - -
- {getTransactionIcon(transaction.type)} - - {transaction.type} - -
-
- - {/* Currency */} - -
- {transaction.toCurrency ? ( -
+
+ {loading ? ( +
+ Loading transactions... +
+ ) : filteredTransactions.length === 0 ? ( + + ) : ( +
+
+ + + {/* Desktop Headers */} + + TYPE + + + CURRENCY + + + DATE + + + STATUS + + + AMOUNT + + + {/* Mobile Headers - 3 columns properly aligned */} + + TYPE + + + AMOUNT + + + STATUS + + + + + {currentTransactions.map((transaction) => ( + + {/* Desktop Row */} + + {/* Type */} + +
+ {getTransactionIcon(transaction.type)} + + {transaction.type} + +
+
+ + {/* Currency */} + +
+ {transaction.toCurrency ? ( +
+ {transaction.fromCurrency} + + {transaction.toCurrency} +
+ ) : ( {transaction.fromCurrency} - - {transaction.toCurrency} -
- ) : ( - {transaction.fromCurrency} - )} - -
- - {/* Date */} - - {transaction.date} - - - {/* Status */} - - - - - {/* Amount */} - -
- {transaction.amount} -
-
- {transaction.usdAmount} -
-
-
- - {/* Mobile Accordion Row */} - -
- ))} -
-
-
- )} + )} +
+ + + {/* Date */} + + {transaction.date} + + + {/* Status */} + + + + + {/* Amount */} + +
+ {transaction.amount} +
+
+ {transaction.usdAmount} +
+
+ + + {/* Mobile Accordion Row */} + + + ))} + + + + {/* Pagination */} + {filteredTransactions.length > itemsPerPage && ( + + )} +
+ )} +
); } diff --git a/components/header/LandingNavbar.tsx b/components/header/LandingNavbar.tsx index 050a2c5..527ecff 100644 --- a/components/header/LandingNavbar.tsx +++ b/components/header/LandingNavbar.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { Button } from "../ui/button"; +import { Button } from "../ui/but"; import Link from "next/link"; import Image from "next/image"; @@ -21,26 +21,22 @@ const LandingNavbar = () => { diff --git a/components/header/Navbar.tsx b/components/header/Navbar.tsx index faf7657..535824b 100644 --- a/components/header/Navbar.tsx +++ b/components/header/Navbar.tsx @@ -6,10 +6,23 @@ import { useSidebarStore } from "@/store/sidebarStore"; import Image from "next/image"; import clsx from "clsx"; import { useState } from "react"; +import { usePathname } from "next/navigation"; +import { Button } from "../ui/but"; const navItems = ["Dashboard", "Convert"]; +const pageNames: Record = { + "/dashboard": "Dashboard", + "/dashboard/convert": "Convert", + "/dashboard/transactions": "Transactions", + "/dashboard/settings": "Settings", + "/dashboard/notifications": "Notifications", +}; + export default function Navbar() { + const pathname = usePathname(); + + const currentPageName = pageNames[pathname] || "Dashboard"; const [active, setActive] = useState("Dashboard"); const { isCollapsed, toggleCollapse, toggleMobile } = useSidebarStore(); @@ -73,32 +86,20 @@ export default function Navbar() {