Skip to content

Commit

Permalink
redesign
Browse files Browse the repository at this point in the history
  • Loading branch information
manideep1428 committed Sep 24, 2024
1 parent 57a86f3 commit 638d611
Show file tree
Hide file tree
Showing 44 changed files with 2,353 additions and 1,492 deletions.
16 changes: 16 additions & 0 deletions app/(pages)/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Appbar } from '@/components/Appbar'
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {

return (
<html lang="en">
<body>
<Appbar/>
{children}
</body>
</html>
)
}
147 changes: 147 additions & 0 deletions app/(pages)/markets/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
"use client"

import { useState, useEffect } from "react"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { Table, TableBody, TableCell, TableRow } from "@/components/ui/table"
import { ArrowDown, ArrowUp } from "lucide-react"
import { getCrypto } from "@/app/utils/ServerProps"
import Image from "next/image"
import { useRouter } from "next/navigation"

interface CryptoData {
symbol: string
current_price: string
priceChangePercent: string
volume: string
marketCap: string
image: string
name: string
}

export default function CryptoList() {
const [cryptoData, setCryptoData] = useState<CryptoData[]>([])
const [sortColumn, setSortColumn] = useState<keyof CryptoData>("marketCap")
const [sortDirection, setSortDirection] = useState<"asc" | "desc">("desc")
const [activeTab, setActiveTab] = useState("all")
const router = useRouter()

const fetchData = async () => {
try {
const data = await getCrypto()
const formattedData: CryptoData[] = data.map((item: any) => ({
image: item.image,
symbol: item.symbol,
current_price: item.current_price,
name: item.name,
priceChangePercent: parseFloat(item.price_change_percentage_24h).toFixed(2),
volume: formatVolume(parseFloat(item.total_volume)),
marketCap: formatMarketCap(parseFloat(item.market_cap)),
}))
setCryptoData(formattedData)
} catch (error) {
console.error("Error fetching data:", error)
}
}

const formatVolume = (volume: number): string => {
if (volume >= 1e12) return `${(volume / 1e12).toFixed(2)}T`
if (volume >= 1e9) return `${(volume / 1e9).toFixed(2)}B`
if (volume >= 1e6) return `${(volume / 1e6).toFixed(2)}M`
return volume.toFixed(2)
}

const formatMarketCap = (marketCap: number): string => {
if (marketCap >= 1e12) return `$${(marketCap / 1e12).toFixed(2)}T`
if (marketCap >= 1e9) return `$${(marketCap / 1e9).toFixed(2)}B`
if (marketCap >= 1e6) return `$${(marketCap / 1e6).toFixed(2)}M`
return `$${marketCap.toFixed(2)}`
}

useEffect(() => {
fetchData()
const interval = setInterval(fetchData, 2000)
return () => clearInterval(interval)
}, [])

const sortData = (column: keyof CryptoData) => {
if (column === sortColumn) {
setSortDirection(sortDirection === "asc" ? "desc" : "asc")
} else {
setSortColumn(column)
setSortDirection("desc")
}
}

const handleTabClick = (tab: string) => {
setActiveTab(tab)
if (tab === "24h") {
setSortColumn("priceChangePercent")
} else if (tab === "volume") {
setSortColumn("volume")
} else if (tab === "marketCap") {
setSortColumn("marketCap")
}
setSortDirection("desc")
}

const sortedData = [...cryptoData].sort((a, b) => {
const aValue = parseFloat(a[sortColumn].replace(/[^\d.-]/g, ""))
const bValue = parseFloat(b[sortColumn].replace(/[^\d.-]/g, ""))
return sortDirection === "asc" ? aValue - bValue : bValue - aValue
})

const renderTable = (data: CryptoData[]) => (
<div className="overflow-x-auto">
<Table>
<TableBody>
{data.map((crypto) => (
<TableRow
key={crypto.symbol}
className="hover:cursor-pointer"
onClick={() => router.push(`/trade/${crypto.symbol}usdt`)}
>
<TableCell className="font-medium flex items-center space-x-2">
<Image src={crypto.image} alt={crypto.name} width={20} height={20} />
<span className="hidden sm:inline">{crypto.name}</span>
<span className="sm:hidden">{crypto.symbol.toUpperCase()}</span>
</TableCell>
<TableCell className="text-right">${crypto.current_price}</TableCell>
<TableCell
className={`text-right ${
crypto.priceChangePercent[0] === "-" ? "text-red-500" : "text-green-500"
}`}
>
{crypto.priceChangePercent}%
</TableCell>
<TableCell className="text-right hidden sm:table-cell">{crypto.volume}</TableCell>
<TableCell className="text-right hidden md:table-cell">{crypto.marketCap}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
)

return (
<div className="container mx-auto py-4 px-2 sm:px-4 md:px-6">
<Tabs value={activeTab} onValueChange={handleTabClick} className="w-full">
<TabsList className="grid grid-cols-2 sm:grid-cols-4 w-1/2 rounded-lg">
<TabsTrigger value="all">All</TabsTrigger>
<TabsTrigger value="24h">24h Change</TabsTrigger>
<TabsTrigger value="volume">Volume</TabsTrigger>
<TabsTrigger value="marketCap">Market Cap</TabsTrigger>
</TabsList>
<div className="mt-4">
<div className="flex justify-between items-center mb-2">
<h2 className="text-lg font-semibold">{activeTab === "all" ? "All Cryptocurrencies" : `Sorted by ${activeTab}`}</h2>
<button onClick={() => sortData(sortColumn)} className="flex items-center text-sm">
{sortDirection === "asc" ? <ArrowUp className="h-4 w-4 mr-1" /> : <ArrowDown className="h-4 w-4 mr-1" />}
{sortColumn === "priceChangePercent" ? "24h" : sortColumn}
</button>
</div>
{renderTable(sortedData)}
</div>
</Tabs>
</div>
)
}
110 changes: 110 additions & 0 deletions app/(pages)/trade/[market]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
"use client";

import { useState, useEffect } from "react";
import useWebSocket from "react-use-websocket";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Ask } from "@/components/depth/AskTable";
import { Bid } from "@/components/depth/BidTable";
import { OrderUI } from "@/components/OrderUI";
import { useParams } from "next/navigation";
import { MarketBar } from "@/components/MarketBar";
import TradeViewChart from "@/components/TradeView";
import { Skeleton } from "@/components/ui/skeleton";
import { TradeViewChartSkeleton } from "@/components/Skeletons/TradingViewSkeleton";
import { MarketBarSkeleton } from "@/components/Skeletons/MarketBarSkeleton";
import { AskSkeleton } from "@/components/Skeletons/AskBidSkeleton";

type Order = [string, string];
type OrderBookUpdate = {
e: string;
E: number;
s: string;
U: number;
u: number;
b: Order[];
a: Order[];
};

type OrderBookState = {
bids: Map<string, string>;
asks: Map<string, string>;
};

export default function Markets() {
const { market } = useParams();
const [orderBook, setOrderBook] = useState<OrderBookState>({
bids: new Map(),
asks: new Map(),
});
const [isLoading, setIsLoading] = useState(true);
const { lastJsonMessage, readyState } = useWebSocket(
`wss://stream.binance.com:9443/ws/${market}@depth`
);

useEffect(() => {
if (lastJsonMessage) {
const update = lastJsonMessage as OrderBookUpdate;
setIsLoading(false);
setOrderBook((prevOrderBook) => {
const newBids = new Map(prevOrderBook.bids);
const newAsks = new Map(prevOrderBook.asks);

update.b.forEach(([price, quantity]) => {
if (parseFloat(quantity) === 0) {
newBids.delete(price);
} else {
newBids.set(price, quantity);
}
});

update.a.forEach(([price, quantity]) => {
if (parseFloat(quantity) === 0) {
newAsks.delete(price);
} else {
newAsks.set(price, quantity);
}
});

return { bids: newBids, asks: newAsks };
});
setIsLoading(false);
}
}, [lastJsonMessage]);

const LoadingSkeleton = () => (
<div className="space-y-2">
<Skeleton className="h-4 w-[250px]" />
<Skeleton className="h-4 w-[200px]" />
</div>
);

return (
<div className="container mx-auto p-4">
<MarketBar market={market as string} />
<div className="flex gap-4">
<Card className="mb-4 flex-1 w-[4/7] border-none">
<div className="h-[400px]">
{isLoading ? (
<TradeViewChartSkeleton />
) : (
<TradeViewChart market={market.toString()} />
)}
</div>
</Card>

<div className="hidden sm:flex flex-col md:grid-cols-2 gap-4">
{isLoading ? <AskSkeleton /> : <Ask asks={orderBook.asks} />}
{isLoading ? <AskSkeleton /> : <Bid bids={orderBook.bids} />}
</div>

<div className="flex h-full justify-items-end">
{isLoading ? (
<Skeleton className="h-[400px] w-[300px]" />
) : (
<OrderUI market={market as string} />
)}
</div>
</div>
</div>
);
}
76 changes: 3 additions & 73 deletions app/api/auth/[...nextauth]/route.ts
Original file line number Diff line number Diff line change
@@ -1,76 +1,6 @@
import NextAuth, { NextAuthOptions } from "next-auth"
import GoogleProvider from "next-auth/providers/google"
import CredentialsProvider from "next-auth/providers/credentials"
import { PrismaAdapter } from "@next-auth/prisma-adapter"
import { PrismaClient } from "@prisma/client"
import bcrypt from "bcryptjs"
import { authOptions } from "@/lib/auth"
import NextAuth from "next-auth"

const prisma = new PrismaClient()

export const authOptions: NextAuthOptions = {
adapter: PrismaAdapter(prisma),
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
}),
CredentialsProvider({
name: 'Credentials',
credentials: {
email: { label: "Email", type: "text" },
password: { label: "Password", type: "password" }
},
async authorize(credentials) {
if (!credentials?.email || !credentials?.password) {
return null
}

const user = await prisma.user.findUnique({
where: { email: credentials.email }
})
//@ts-ignore
if (!user || !user.password) {
return null
}
//@ts-ignore
const isPasswordValid = await bcrypt.compare(credentials.password, user.password)

if (!isPasswordValid) {
return null
}

return {
id: user.id,
email: user.email,
name: user.name,
}
}
})
],
session: {
strategy: 'jwt'
},
pages: {
signIn: '/auth/signin',
// signUp :"/api/signup"
},
callbacks: {
async jwt({ token, user }) {
if (user) {
token.id = user.id
}
return token
},
async session({ session, token }) {
if (session.user) {
//@ts-ignore
session.user.id = token.id as string
}
return session
},
},
}

const handler = NextAuth(authOptions)
const handler = NextAuth(authOptions)

export { handler as GET, handler as POST }
7 changes: 0 additions & 7 deletions app/auth/error/page.tsx

This file was deleted.

9 changes: 0 additions & 9 deletions app/auth/signIn/page.tsx

This file was deleted.

Loading

0 comments on commit 638d611

Please sign in to comment.