Skip to content

Commit b72ead2

Browse files
committed
add swap widget
1 parent 6e572b2 commit b72ead2

22 files changed

+1447
-215
lines changed

.env

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID="be70ce90517c29ac277e795db970fbf0"

app/api/price/route.ts

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { type NextRequest } from "next/server";
2+
3+
export async function GET(request: NextRequest) {
4+
const searchParams = request.nextUrl.searchParams;
5+
6+
try {
7+
const res = await fetch(
8+
`https://api.0x.org/swap/permit2/price?${searchParams}`,
9+
{
10+
headers: {
11+
"0x-api-key": process.env.NEXT_PUBLIC_ZEROEX_API_KEY as string,
12+
"0x-version": "v2",
13+
},
14+
}
15+
);
16+
const data = await res.json();
17+
18+
console.log(
19+
"price api",
20+
`https://api.0x.org/swap/permit2/price?${searchParams}`
21+
);
22+
23+
console.log("price data", data);
24+
25+
return Response.json(data);
26+
} catch (error) {
27+
console.log(error);
28+
}
29+
}

app/layout.tsx

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { Metadata } from "next";
22
import localFont from "next/font/local";
33
import "./globals.css";
4+
import { Navbar } from "@/components/Navbar/Navbar";
45

56
const geistSans = localFont({
67
src: "./fonts/GeistVF.woff",
@@ -26,9 +27,12 @@ export default function RootLayout({
2627
return (
2728
<html lang="en">
2829
<body
29-
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
30+
className={`${geistSans.variable} ${geistMono.variable} max-w-[1440px] w-full relative h-full mx-auto antialiased`}
3031
>
32+
<div className="absolute top-0 bottom-0 left-0 bg-[#0dbbac] rounded-full blur-[300px] w-[22rem] h-[32rem] -z-10"></div>
33+
<Navbar />
3134
{children}
35+
<div className="absolute right-0 top-0 bg-[#0dbbac] rounded-full blur-[300px] w-[22rem] h-[32rem] -z-10"></div>
3236
</body>
3337
</html>
3438
);

app/page.tsx

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
import { Navbar } from "@/components/Navbar/Navbar";
2+
import { PriceChart } from "@/components/PriceChart/PriceChart";
13
import { SwapWidget } from "@/components/SwapWidgets/SwapWidget";
24
import Image from "next/image";
35

46
export default function Home() {
57
return (
6-
<div className="w-full h-full flex flex-col items-center justify-center">
8+
<div className="w-full h-full mx-auto py-10 gap-4 flex flex-col md:flex-row items-start justify-center">
9+
<PriceChart />
710
<SwapWidget />
811
</div>
912
);

components/Navbar/Navbar.tsx

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import React from "react";
2+
3+
export const Navbar = () => {
4+
return (
5+
<div className="h-14 border-b flex items-center border-b-secondary w-full font-semibold px-10">
6+
0xDex
7+
</div>
8+
);
9+
};

components/PriceChart/PriceChart.tsx

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import React from "react";
2+
3+
type Props = {};
4+
5+
export const PriceChart = (props: Props) => {
6+
return (
7+
<div className="col-span-3 hidden w-full h-full bg-red-600">PriceChart</div>
8+
);
9+
};
+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import React, { useState } from "react";
2+
import TokenSelector from "./TokenSelector"; // Import the TokenSelector component
3+
import walletBalance from "@/public/walletBalance.svg";
4+
import dropdown from "@/public/dropdown.svg";
5+
import Image from "next/image";
6+
import { useSwapActions, useSwapState } from "@/state/swapStore";
7+
import { TokenDetail } from "@/lib/types";
8+
interface AmountInputProps {
9+
title: string;
10+
token: string;
11+
Amount: string | number;
12+
walletBalanceAsset: number | string;
13+
currentTokenAsset: TokenDetail;
14+
setAmount: (amount: string) => void;
15+
setToken: (token: string) => void;
16+
setCurrentTokenDetal: (token: TokenDetail) => void;
17+
}
18+
19+
const AmountInput: React.FC<AmountInputProps> = ({
20+
title,
21+
token,
22+
Amount,
23+
setAmount,
24+
setToken,
25+
walletBalanceAsset,
26+
currentTokenAsset,
27+
setCurrentTokenDetal,
28+
}) => {
29+
const [selectorOpen, setSelectorOpen] = useState<boolean>(false);
30+
// const { setSelectorOpen } = useSwapActions();
31+
// const { selectorOpen } = useSwapState();
32+
const handleAmountChange = (e: React.ChangeEvent<HTMLInputElement>) => {
33+
setAmount(e.target.value);
34+
};
35+
36+
const handleTokenSelect = (selectedToken: any) => {
37+
setToken(selectedToken.symbol);
38+
setSelectorOpen(false);
39+
setCurrentTokenDetal(selectedToken);
40+
};
41+
42+
return (
43+
<div className="p-4 bg-[#0F1D1A] border-secondary border-[1px] rounded-xl shadow-md w-full max-w-md relative">
44+
<div className="mb-4">
45+
<div className="flex justify-between items-center">
46+
<label className="block text-sm font-medium text-textpriamry">
47+
{title}
48+
</label>
49+
<div className="flex gap-1 items-center">
50+
<Image src={walletBalance} width={20} height={20} alt={"image"} />{" "}
51+
{walletBalanceAsset || 0}
52+
</div>
53+
</div>
54+
<div className="relative w-full justify-between flex items-center gap-3">
55+
<input
56+
type="text"
57+
className="w-full placeholder:text-textprimary px-4 py-2 bg-transparent focus:none border-none text-2xl rounded-md"
58+
placeholder="0.00"
59+
value={Amount}
60+
onChange={handleAmountChange}
61+
/>
62+
<div className="w-full flex justify-end">
63+
<button
64+
className="px-3 justify-between gap-1 w-fit relative flex py-2 bg-[#202C2A] text-white items-center rounded"
65+
onClick={() => setSelectorOpen(true)}
66+
>
67+
<Image
68+
src={currentTokenAsset?.logoURI}
69+
width={20}
70+
height={20}
71+
alt={"image"}
72+
/>{" "}
73+
{currentTokenAsset?.symbol || "Select Token"}
74+
<Image
75+
src={dropdown}
76+
className="invert object-contain"
77+
width={10}
78+
height={20}
79+
alt={"image"}
80+
/>{" "}
81+
</button>
82+
</div>
83+
</div>
84+
</div>
85+
86+
{selectorOpen && (
87+
<TokenSelector
88+
onSelect={handleTokenSelect}
89+
closeModal={() => setSelectorOpen(false)}
90+
/>
91+
)}
92+
</div>
93+
);
94+
};
95+
96+
export default AmountInput;

components/SwapWidgets/SwapWidget.tsx

+45-39
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,60 @@
11
"use client";
22
import { useSwapActions, useSwapState } from "@/state/swapStore";
3-
import React from "react";
3+
import React, { useEffect } from "react";
44
import { Button } from "../ui/Button";
5+
import AmountInput from "./AmountInput";
6+
import { useTokenInitializer } from "@/hooks/useTokenInitializer";
57

68
type Props = {};
79

810
export const SwapWidget = (props: Props) => {
9-
const { sellToken, buyToken, sellAmount, buyAmount } = useSwapState();
10-
const { setBuyToken, setSellToken, setSellAmount, setBuyAmount } =
11-
useSwapActions();
11+
const {
12+
sellToken,
13+
buyToken,
14+
tokens,
15+
sellAmount,
16+
currentBuyAsset,
17+
buyAmount,
18+
currentSellAsset,
19+
} = useSwapState();
20+
const {
21+
setBuyToken,
22+
setSellToken,
23+
setSellAmount,
24+
setBuyAmount,
25+
setCurrentSellAsset,
26+
setCurrentBuyAsset,
27+
} = useSwapActions();
28+
console.log({ currentBuyAsset });
1229

1330
return (
14-
<div className="bg-primary/20 border-secondary border-[2px] rounded-xl">
15-
<h2 className="text-xl font-bold text-white mb-4">Swap</h2>
16-
<div className="mb-4">
17-
<label className="text-sm text-gray-400">you are buying</label>
18-
<select
19-
className="w-full mt-2 p-3 bg-gray-700 rounded text-white"
20-
value={buyToken}
21-
onChange={(e) => setBuyToken(e.target.value)}
22-
>
23-
<option value="DAI">DAI</option>
24-
<option value="USDC">USDC</option>
25-
</select>
26-
<input
27-
type="number"
28-
placeholder="Enter amount"
29-
className="w-full mt-2 p-3 bg-gray-700 rounded text-white"
30-
value={buyAmount}
31-
onChange={(e) => setBuyAmount(e.target.value)}
31+
<div className="bg-[#030D0A] p-4 col-span-2 max-w-[448px] w-full border-secondary border-[1px] rounded-xl">
32+
<h2 className="text-lg font-bold text-white bg-primary w-fit px-2 py-1 rounded-3xl mb-4">
33+
Swap
34+
</h2>
35+
<div className="flex flex-col gap-3">
36+
<AmountInput
37+
title="You're Buying"
38+
token={buyToken}
39+
Amount={buyAmount}
40+
currentTokenAsset={currentBuyAsset}
41+
setCurrentTokenDetal={setCurrentBuyAsset}
42+
setAmount={setBuyAmount}
43+
setToken={setBuyToken}
44+
walletBalanceAsset={500} // Replace with actual balance
3245
/>
33-
</div>
34-
<div className="mb-4">
35-
<label className="text-sm text-gray-400">you are Selling</label>
36-
<select
37-
className="w-full mt-2 p-3 bg-gray-700 rounded text-white"
38-
value={sellToken}
39-
onChange={(e) => setSellToken(e.target.value)}
40-
>
41-
<option value="DAI">DAI</option>
42-
<option value="USDC">USDC</option>
43-
</select>
44-
<input
45-
type="number"
46-
placeholder="Enter amount"
47-
className="w-full mt-2 p-3 bg-gray-700 rounded text-white"
48-
value={sellAmount}
49-
onChange={(e) => setSellAmount(e.target.value)}
46+
<AmountInput
47+
title="You're Selling"
48+
setCurrentTokenDetal={setCurrentSellAsset}
49+
token={sellToken}
50+
currentTokenAsset={currentSellAsset}
51+
Amount={sellAmount}
52+
setAmount={setSellAmount}
53+
setToken={setSellToken}
54+
walletBalanceAsset={1000} // Replace with actual balance
5055
/>
5156
</div>
57+
5258
<Button
5359
variant={"primary"}
5460
className="w-full mt-4 py-3 text-white font-bold rounded"

0 commit comments

Comments
 (0)