Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 12 additions & 20 deletions components/dashboard/convert/conversion-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useConversion } from "@/hooks/useConversion";
import { ConfirmationModal } from "../modals/confirmation-modal";
import { CurrencySelector } from "./currency-selector";
import { ExchangeRateDisplay } from "./exhange-rate-display";
import Image from "next/image";
import { ArrowDown } from "lucide-react";
// import { TokenSelectorModal } from "./modals/token-selector-modal";

// import { useState } from "react";
Expand All @@ -26,7 +26,6 @@ export function ConversionForm() {
// showTokenSelector,
currencies,
selectToken,

handleAmountChange,
openTokenSelector,
// closeTokenSelector,
Expand All @@ -35,15 +34,13 @@ export function ConversionForm() {
// const [showConfirmation, setShowConfirmation] = useState(false);

return (
<div className="p-8 max-w-2xl mx-auto">
<div className="p-4 md:p-8 max-w-2xl mx-auto">
<div className="bg-gradient-to-r from-[#FFE79C]/30 to-[#A0C3FD]/30 w-full max-w-[900px] rounded-2xl p-5 relative">
<div className="flex flex-col gap-4 relative ">
{/* From Section */}
<div className="">
<div className="bg-bg-conversion-form rounded-xl p-4 border border-gray-200">
<label className="text-md text-gray-600 font-medium mb-2 block">
From
</label>
<div className="bg-[#FDFDFD] rounded-xl p-4">
<label className="text-md font-medium mb-2 block">From</label>
<div className="flex h-[80px] relative items-center justify-between">
<input
value={conversionData.fromAmount}
Expand All @@ -58,7 +55,7 @@ export function ConversionForm() {
(parts.length > 1 ? "." + parts[1] : "");
handleAmountChange("from", formattedValue);
}}
className="text-5xl focus:outline-none placeholder:text-gray-400 font-semibold w-full border-none p-0 bg-transparent"
className="text-xl md:text-5xl focus:outline-none placeholder:text-gray-400 font-semibold w-full border-none p-0 bg-transparent"
placeholder="0"
type="text"
inputMode="decimal"
Expand All @@ -76,23 +73,18 @@ export function ConversionForm() {

{/* Swap Icon */}
<div className="flex justify-center absolute left-0 right-0 top-[8.5rem] ">
<div className="w-10 h-10 bg-gray-200 rounded-full border flex items-center justify-center">
<Image
src={"/convert-arrow.png"}
alt="arrow"
width={100}
height={100}
/>
<div className="w-10 h-10 bg-blue-600 rounded-full border flex items-center justify-center">
<ArrowDown className="text-white" />
</div>
</div>

{/* To Section */}
<div className="mb-6 ">
<div className="bg-[#EFEDED] rounded-xl p-4 border border-gray-200">
<label className="text-md font-medium text-gray-600 mb-2 block">
<div className="bg-[#E5E5E5] rounded-xl p-4 border border-gray-200">
<label className="text-md font-medium mb-2 block">
You will receive
</label>
<div className="flex relative h-[80px] items-center justify-between">
<div className="flex relative h-[80px] items-center justify-between">
<input
value={conversionData.toAmount}
onChange={(e) => {
Expand All @@ -106,8 +98,8 @@ export function ConversionForm() {
(parts.length > 1 ? "." + parts[1] : "");
handleAmountChange("to", formattedValue);
}}
className="text-5xl focus:outline-none placeholder:text-gray-400 font-semibold border-none w-full p-0 bg-transparent"
placeholder="0"
className="text-xl md:text-5xl focus:outline-none placeholder:text-gray-400 font-semibold border-none w-full p-0 bg-transparent"
placeholder="-"
type="text"
inputMode="decimal"
/>
Expand Down
221 changes: 149 additions & 72 deletions components/dashboard/convert/currency-selector.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
"use client";

import { ChevronDown, Search, X } from "lucide-react";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";

import { Currency } from "@/types";

import { useState } from "react";
import { useEffect, useRef, useState } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import Image from "next/image";
import { currencyImages } from "@/hooks/useConversion";
import { Currency } from "@/types";

interface CurrencySelectorProps {
currency: string;
variant?: "outline" | "default";
Expand All @@ -28,78 +23,160 @@ export function CurrencySelector({
className,
currencies,
onSelect,
onClick,
}: CurrencySelectorProps) {
const [open, setOpen] = useState<boolean>(false);
const handleOpenChange = () => {
setOpen(open ? open : !open);
const [open, setOpen] = useState(false);
const [showMore, setShowMore] = useState(false);
const dropdownRef = useRef<HTMLDivElement>(null);

useEffect(() => {
function handleClickOutside(event: MouseEvent) {
if (
dropdownRef.current &&
!dropdownRef.current.contains(event.target as Node)
) {
setOpen(false);
}
}

document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, []);

const handleToggle = () => {
onClick();
setOpen((prev) => !prev);
if (!open) setShowMore(false); // reset on reopen
};
console.log("isOpened", open);

return (
<DropdownMenu open={open} onOpenChange={handleOpenChange}>
<DropdownMenuTrigger
className={`ml-4 flex gap-2 w-[100px] h-[42px] items-center justify-center shadow-[0px_1px_3px_0px_rgba(0,0,0,0.02),0px_0px_0px_1px_rgba(27,31,35,0.15)] font-semibold text-lg ${
variant === "default"
? "bg-blue-500 text-lg hover:bg-blue-600 text-white rounded-full"
: ""
<div className="relative self-start" ref={dropdownRef}>
<button
onClick={handleToggle}
className={`ml-4 flex gap-2 w-30 py-3 items-center justify-center font-semibold text-lg rounded-full ${
variant === "default" ? "bg-[#F9FAF9]" : "bg-[#E5E5E5]"
} ${className}`}
>
{currency}
{currencyImages[currency] && (
<Image
src={currencyImages[currency]}
alt={currency}
width={24}
height={24}
/>
)}
<span>{currency}</span>
<ChevronDown className="w-4 h-4" />
</DropdownMenuTrigger>
<DropdownMenuContent
onFocusOutside={() => {
setOpen(false);
}}
className="sm:max-w-[611px] h-[223px] px-6 py-3 overflow-hidden mt-1 -ml-64"
>
<div className="w-full flex items-center justify-between">
<div className="text-black font-semibold">Select Token</div>
<Button
variant={"ghost"}
onClick={() => {
setOpen(false);
}}
>
<X />
</Button>
</div>
<div className="flex flex-col gap-2 py-2">
<div className="relative py-1">
<Search className="absolute mt-1 left-3 top-3 h-4 w-4 text-gray-500" />
<Input
placeholder="Search by name or paste address"
className="pl-10 h-10 bg-bg-input rounded-full"
/>
</button>

{/* Dropdown Content */}
{open && (
<div className="max-sm:fixed max-sm:inset-x-0 max-sm:mx-auto w-[95vw] md:absolute md:right-0 md:-top-20 z-50 mt-2 md:max-w-md md:w-[90vw] bg-white rounded-xl shadow-lg border border-gray-200 px-2 md:px-6 py-3">
{/* Header */}
<div className="w-full flex items-center justify-between">
<div className="text-black font-semibold">Select Token</div>
<Button variant="ghost" onClick={() => setOpen(false)}>
<X />
</Button>
</div>
<div className="flex items-center justify-center gap-2">
{currencies.map((currency: Currency) => (
<DropdownMenuItem
key={currency.code}
onClick={() => {
onSelect(currency);
setOpen(false);
}}
className="flex bg-bg-selector cursor-pointer flex-col items-center px-3 py-1 rounded-lg border border-gray-200 hover:border-gray-300 transition-colors"
>
<div className="w-6 h-6 bg-bg-selector-icon rounded-md flex items-center justify-center">
{/* <span className="text-sm font-semibold">{currency.icon}</span> */}

{/* Search */}
<div className="flex flex-col gap-2 py-2">
<div className="relative py-1">
<Search className="absolute left-3 top-4 h-4 w-4 text-gray-500" />
<Input
placeholder="Search by name or paste address"
className="pl-10 h-10 bg-bg-input rounded-full"
/>
</div>

{/* Currency Grid */}
<div className="flex flex-wrap items-center justify-center gap-2">
{currencies.map((currency: Currency) => (
<div
key={currency.code}
onClick={() => {
onSelect(currency);
setOpen(false);
}}
className="flex bg-bg-selector cursor-pointer flex-col items-center px-3 md:px-5 py-3 rounded-lg border border-gray-200 hover:border-gray-300 transition-colors space-y-2"
>
<div className="w-6 h-6 bg-bg-selector-icon rounded-md flex items-center justify-center">
{currencyImages[currency.code] && (
<Image
src={currencyImages[currency.code]}
alt={currency.code}
width={24}
height={24}
/>
)}
</div>
<span className="text-sm font-medium">{currency.code}</span>
</div>
<span className="text-sm font-medium">{currency.code}</span>
</DropdownMenuItem>
))}
))}
</div>
</div>
</div>
<div className=" flex gap-2 items-center w-full justify-center ">
<div className="h-[0.5px] bg-gray-500/30 w-1/2"></div>
<Button
className="hover:bg-transparent font-light text-xs p-0"
variant={"ghost"}

{/* Divider + Show More */}
<div className="flex gap-2 items-center w-full justify-center">
<div className="h-[0.5px] bg-gray-500/30 w-1/2"></div>
<Button
className="hover:bg-transparent font-light text-xs p-0"
variant="ghost"
onClick={() => setShowMore((prev) => !prev)}
>
{showMore ? "Show less" : "Show more"}
</Button>
<div className="h-[0.5px] bg-gray-500/30 w-1/2"></div>
</div>

{/* Extra Content with Transition */}
<div
className={`transition-all duration-500 ease-in-out overflow-hidden ${
showMore ? "max-h-44 mt-3" : "max-h-0"
}`}
>
Show more
</Button>
<div className="h-[0.5px] bg-gray-500/30 w-1/2"></div>
<div className="space-y-2 divide-y divide-gray-400">
{currencies
.filter((el) => el.code !== "USDC" && el.code !== "NGN")
.map((currency: Currency) => (
<div
className="flex justify-between items-center py-2"
key={currency.code}
>
<div className="flex items-center space-x-2">
{currencyImages[currency.code] && (
<Image
src={currencyImages[currency.code]}
alt={currency.code}
width={26}
height={26}
/>
)}
<div className="flex flex-col leading-tight">
<p className="text-sm font-semibold">{currency.code}</p>
<p className="text-xs text-gray-500">{currency.name}</p>
</div>
</div>
<div className="font-semibold">
<span>0.0000</span>
</div>
</div>
))}
</div>
</div>
</div>
</DropdownMenuContent>
</DropdownMenu>
)}

{/* Overlay (mobile only, optional) */}
{open && (
<div
className="fixed inset-0 bg-black/40 z-40 md:hidden"
onClick={() => setOpen(false)}
/>
)}
</div>
);
}
Loading