Remove IDE configuration files and add new selling feature
Removed unnecessary IntelliJ IDEA (`.idea`) configuration files to clean up the repository. Added new sell-related functionality including the SellCryptoPage, SellModal, SellForm, and updated relevant types and UI components.
This commit is contained in:
parent
ea7ab60e5c
commit
e3aa219389
8
.idea/.gitignore
generated
vendored
8
.idea/.gitignore
generated
vendored
@ -1,8 +0,0 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
7
.idea/discord.xml
generated
7
.idea/discord.xml
generated
@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DiscordProjectSettings">
|
||||
<option name="show" value="PROJECT_FILES" />
|
||||
<option name="description" value="" />
|
||||
</component>
|
||||
</project>
|
10
.idea/inspectionProfiles/Project_Default.xml
generated
10
.idea/inspectionProfiles/Project_Default.xml
generated
@ -1,10 +0,0 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="DuplicatedCode" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<Languages>
|
||||
<language minSize="86" name="TypeScript" />
|
||||
</Languages>
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
8
.idea/modules.xml
generated
8
.idea/modules.xml
generated
@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/brief-07-front.iml" filepath="$PROJECT_DIR$/.idea/brief-07-front.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
12
.idea/neptune-frontend.iml
generated
12
.idea/neptune-frontend.iml
generated
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
15
README.md
15
README.md
@ -1,3 +1,16 @@
|
||||
# neptune-front
|
||||
|
||||
The project to validate my DWWM diploma on the front end.
|
||||
The project to validate my DWWM diploma on the front end.
|
||||
|
||||
## Déploiement
|
||||
- Configurer les variables d'environnements
|
||||
### En développement
|
||||
```shell
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
### En production
|
||||
```shell
|
||||
pnpm build
|
||||
pnpm start
|
||||
```
|
@ -5,7 +5,7 @@
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"dev": "next dev --turbo",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
|
@ -10,7 +10,6 @@ import { useEffect, useState } from "react";
|
||||
export default function DashboardPage() {
|
||||
const [isLoading, setIsLoading] = useState<boolean>(true);
|
||||
const [cryptosList, setCryptosList] = useState<ICryptoInWalletInfo[]>([]);
|
||||
//FIX the loop
|
||||
|
||||
useEffect(() => {
|
||||
ApiRequest.authenticated.get
|
||||
|
@ -14,7 +14,7 @@ import type React from "react";
|
||||
export const metadata: Metadata = {
|
||||
title: "Neptune Crypto",
|
||||
description: "A fictive app",
|
||||
icons: "neptune.svg",
|
||||
icons: "/neptune.svg",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
|
@ -1,18 +1,18 @@
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Bitcoin, DollarSign, LineChart, Lock, Zap } from "lucide-react"
|
||||
import Link from "next/link"
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Bitcoin, DollarSign, LineChart, Lock, Zap } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function HomePage() {
|
||||
return (
|
||||
<div className="flex flex-col min-h-screen">
|
||||
<main className="flex-1">
|
||||
<section className="w-full py-12 md:py-16 lg:py-24xl:py-32">
|
||||
<section className="w-full py-12 md:py-16 lg:py-24 xl:py-32">
|
||||
<div className="container px-4 md:px-6">
|
||||
<div className="flex flex-col items-center space-y-4 text-center">
|
||||
<div className="space-y-2">
|
||||
<h1 className="text-3xl font-bold tracking-tighter sm:text-4xl md:text-5xl lg:text-6xl/none">
|
||||
<h1 className="text-3xl font-bold tracking-tighter sm:text-4xl md:text-5xl lg:text-6xl">
|
||||
Welcome to Neptune Crypto
|
||||
</h1>
|
||||
<p className="mx-auto max-w-[700px] text-gray-500 md:text-xl dark:text-gray-400">
|
||||
@ -26,27 +26,28 @@ export default function HomePage() {
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="w-full py-12 md:py-16 lg:py-20 bg-card rounded">
|
||||
<div className="container px-4 md:px-6 rounded">
|
||||
<h2 className="text-3xl font-bold tracking-tighter sm:text-5xl text-center mb-12">Our Features</h2>
|
||||
<div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<Bitcoin className="h-10 w-10 mb-2" />
|
||||
<Bitcoin className="h-10 w-10 mb-2"/>
|
||||
<CardTitle>Multiple Cryptocurrencies</CardTitle>
|
||||
<CardDescription>Trade a wide variety of popular cryptocurrencies.</CardDescription>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<Lock className="h-10 w-10 mb-2" />
|
||||
<Lock className="h-10 w-10 mb-2"/>
|
||||
<CardTitle>Secure Storage</CardTitle>
|
||||
<CardDescription>Your assets are protected with state-of-the-art security measures.</CardDescription>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<LineChart className="h-10 w-10 mb-2" />
|
||||
<LineChart className="h-10 w-10 mb-2"/>
|
||||
<CardTitle>Advanced Trading Tools</CardTitle>
|
||||
<CardDescription>Access powerful analytics and trading features.</CardDescription>
|
||||
</CardHeader>
|
||||
@ -54,24 +55,25 @@ export default function HomePage() {
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="w-full py-12 md:py-24 lg:py-32">
|
||||
<div className="container px-4 md:px-6">
|
||||
<div className="flex flex-col items-center justify-center space-y-4 text-center">
|
||||
<div className="space-y-2">
|
||||
<h2 className="text-3xl font-bold tracking-tighter sm:text-5xl">Start Trading Today</h2>
|
||||
<p className="mx-auto max-w-[600px] text-gray-500 md:text-xl/relaxed lg:text-base/relaxed xl:text-xl/relaxed dark:text-gray-400">
|
||||
<p className="mx-auto max-w-[600px] text-gray-500 md:text-xl lg:text-base xl:text-xl dark:text-gray-400">
|
||||
Join thousands of traders and investors on our platform. Get started with as little as $10.
|
||||
</p>
|
||||
</div>
|
||||
<div className="w-full max-w-sm space-y-2">
|
||||
<Button>
|
||||
Sign Up
|
||||
<DollarSign className="ml-2 h-4 w-4" />
|
||||
</Button>
|
||||
<Button>
|
||||
Sign Up
|
||||
<DollarSign className="ml-2 h-4 w-4"/>
|
||||
</Button>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400">
|
||||
By signing up, you agree to our{" "}
|
||||
<Link className="underline underline-offset-2" href="#">
|
||||
Terms & Conditions
|
||||
<Link title="Go to legal notice" className="underline underline-offset-2" href="/legal">
|
||||
Legal Notice
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
@ -80,5 +82,5 @@ export default function HomePage() {
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
39
src/app/sell/[cryptoId]/page.tsx
Normal file
39
src/app/sell/[cryptoId]/page.tsx
Normal file
@ -0,0 +1,39 @@
|
||||
"use client"
|
||||
|
||||
import {OfferList} from "@/components/sub/OfferList";
|
||||
import {SellForm} from "@/components/sell-form";
|
||||
|
||||
|
||||
interface SellCryptoPageProps {
|
||||
params: IParams;
|
||||
}
|
||||
|
||||
interface IParams {
|
||||
cryptoId: string;
|
||||
}
|
||||
|
||||
export default function SellCryptoPage({ params }: SellCryptoPageProps) {
|
||||
return (
|
||||
<main className="flex flex-col sm:flex-row items-center justify-center w-full h-full gap-4 sm:p-4">
|
||||
<section className={"w-full sm:w-1/3 h-full p-0.5 sm:p-2 flex flex-col items-center justify-center gap-4"}>
|
||||
{/* Graph demande achat/you/other */}
|
||||
<div className={"w-full h-1/3 rounded bg-card text-card-foreground"}>
|
||||
Graph
|
||||
</div>
|
||||
{/* stats */}
|
||||
<div className={"w-full h-2/3 rounded bg-card text-card-foreground"}>
|
||||
Stats
|
||||
</div>
|
||||
</section>
|
||||
<section className={"w-full sm:w-2/3 h-full p-0.5 sm:p-2 flex flex-col items-center justify-center gap-4"}>
|
||||
{/* Formulaire */}
|
||||
<div className={"w-full h-2/3 rounded bg-card text-card-foreground p-2"}>
|
||||
Formulaire
|
||||
<SellForm defaultCryptoId={params.cryptoId}/>
|
||||
</div>
|
||||
{/* Tab Liste offfres vente existante */}
|
||||
<OfferList className={"w-full h-1/3"} trades={[]}/>
|
||||
</section>
|
||||
</main>
|
||||
);
|
||||
}
|
@ -14,7 +14,6 @@ export default function WalletPage() {
|
||||
const [isLoading, setIsLoading] = useState<boolean>(true);
|
||||
const [cryptosList, setCryptosList] = useState<ICryptoInWalletInfo[]>([]);
|
||||
const userContext = useContext(UserDataContext);
|
||||
//FIX the loop
|
||||
|
||||
useEffect(() => {
|
||||
console.log(userContext?.userData);
|
||||
|
@ -64,6 +64,9 @@ const registerSchema = z.object({
|
||||
.regex(/[0-9]/, "Password must contain at least one number.")
|
||||
.regex(/[^a-zA-Z0-9]/, "Password must contain at least one special character.")
|
||||
.describe("Your account password."),
|
||||
|
||||
promoCode: z
|
||||
.string().max(255, "Your promotional code is too long.").optional(),
|
||||
});
|
||||
|
||||
export function AuthForms() {
|
||||
|
@ -3,7 +3,6 @@ import type { DefaultValues } from "react-hook-form";
|
||||
import type { z } from "zod";
|
||||
import type { FieldConfig } from "./types";
|
||||
|
||||
// TODO: This should support recursive ZodEffects but TypeScript doesn't allow circular type definitions.
|
||||
export type ZodObjectOrWrapped =
|
||||
| z.ZodObject<any, any>
|
||||
| z.ZodEffects<z.ZodObject<any, any>>;
|
||||
|
10
src/components/cryptos/sell-modal.tsx
Normal file
10
src/components/cryptos/sell-modal.tsx
Normal file
@ -0,0 +1,10 @@
|
||||
import type {Row} from "@tanstack/react-table";
|
||||
import type {ICryptoInUserWalletInfo} from "@/interfaces/crypto.interface";
|
||||
|
||||
|
||||
interface SellModalProps {
|
||||
row: Row<ICryptoInUserWalletInfo>
|
||||
}
|
||||
export function SellModal({ row }: SellModalProps) {
|
||||
|
||||
}
|
@ -10,15 +10,11 @@ import { ViewModal } from "@/components/cryptos/view-modal";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { DataTable } from "@/components/ui/data-table";
|
||||
import type { IUserWallet } from "@/interfaces/userdata.interface";
|
||||
import {
|
||||
type ColumnDef,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
useReactTable,
|
||||
import type {
|
||||
ColumnDef,
|
||||
} from "@tanstack/react-table";
|
||||
import { ArrowUpDown, MoreHorizontal } from "lucide-react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
|
||||
interface DataTableProps<TData, TValue> {
|
||||
columns: ColumnDef<TData, TValue>[];
|
||||
|
@ -14,8 +14,8 @@ export function Header({
|
||||
"flex flex-col md:flex-row justify-between items-center w-full p-1 md:px-3 md:py-2 pb-2 border-b-2"
|
||||
}
|
||||
>
|
||||
<Link href={"/"} className={"flex flex-row justify-center md:justify-start items-center w-fit gap-2"}>
|
||||
<Image src={"neptune.svg"} alt={"Logo of Neptune"} width={42} height={42} />
|
||||
<Link title={"Return to home page"} href={"/"} className={"flex flex-row justify-center md:justify-start items-center w-fit gap-2"}>
|
||||
<Image src={"/neptune.svg"} alt={"Logo of Neptune"} width={42} height={42} />
|
||||
<h1 className={"font-bold text-xl align-middle text-center text-wrap"}>
|
||||
{title || "Neptune"}
|
||||
</h1>
|
||||
|
187
src/components/sell-form.tsx
Normal file
187
src/components/sell-form.tsx
Normal file
@ -0,0 +1,187 @@
|
||||
"use client";
|
||||
import * as z from "zod";
|
||||
import ApiRequest from "@/services/apiRequest";
|
||||
import { toast } from "@/components/ui/use-toast";
|
||||
import * as React from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useEffect, useState } from "react";
|
||||
import type { IUserWalletCryptos } from "@/interfaces/crypto.interface";
|
||||
import type { IApiUserAssetsRes } from "@/interfaces/api.interface";
|
||||
import { Slider } from "@/components/ui/slider";
|
||||
import { DollarSign, Equal, X } from "lucide-react";
|
||||
import { Card } from "@/components/ui/card";
|
||||
|
||||
export function SellForm() {
|
||||
const [currentWallet, setCurrentWallet] = useState<IUserWalletCryptos[]>();
|
||||
const [sliderValue, setSliderValue] = useState(0);
|
||||
const [quantity, setQuantity] = useState(0);
|
||||
const [selectedCrypto, setSelectedCrypto] = useState<string>();
|
||||
|
||||
useEffect(() => {
|
||||
async function fetchAssets() {
|
||||
const res = await ApiRequest.authenticated.get.json<IApiUserAssetsRes>("user/my-assets");
|
||||
setCurrentWallet(res.data.UserHasCrypto);
|
||||
}
|
||||
fetchAssets();
|
||||
}, []);
|
||||
|
||||
function getMaxSharesForCrypto(cryptoId: string) {
|
||||
return currentWallet?.find((crypto) => crypto.Crypto.id === cryptoId)?.amount || 0;
|
||||
}
|
||||
|
||||
function getCryptoValue(cryptoId: string) {
|
||||
return currentWallet?.find((crypto) => crypto.Crypto.id === cryptoId)?.Crypto.value || 0;
|
||||
}
|
||||
|
||||
function getCryptoName(cryptoId: string) {
|
||||
return currentWallet?.find((crypto) => crypto.Crypto.id === cryptoId)?.Crypto.name || "";
|
||||
}
|
||||
|
||||
const sellToUserSchema = z.object({
|
||||
cryptoId: z.string({ required_error: "You should select a crypto from your wallet." }).uuid(),
|
||||
amount: z.number({
|
||||
required_error: "You should select an amount of the assets that you want to sell.",
|
||||
}).max(sliderValue),
|
||||
});
|
||||
|
||||
async function onSellToUserSubmit(data: z.infer<typeof sellToUserSchema>) {
|
||||
const res = await ApiRequest.authenticated.post.json("offer/create", {
|
||||
id_crypto: data.cryptoId,
|
||||
amount: data.amount,
|
||||
});
|
||||
|
||||
if (res.status !== 201) {
|
||||
toast({
|
||||
title: "An error occurred!",
|
||||
description: (
|
||||
<pre className="mt-2 w-[340px] rounded-md bg-slate-950 p-4">
|
||||
<code className="text-white text-wrap">{JSON.stringify(res.statusText, null, 2)}</code>
|
||||
</pre>
|
||||
),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(res);
|
||||
toast({
|
||||
title: "Transaction accepted.",
|
||||
description: <p>The page is going to reload.</p>,
|
||||
});
|
||||
setTimeout(() => location.reload(), 1_500);
|
||||
|
||||
toast({
|
||||
title: "You submitted the following values:",
|
||||
description: (
|
||||
<pre className="mt-2 w-[340px] rounded-md bg-slate-950 p-4">
|
||||
<code className="text-white">{JSON.stringify(data, null, 2)}</code>
|
||||
</pre>
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
const sellToUserForm = useForm<z.infer<typeof sellToUserSchema>>({
|
||||
resolver: zodResolver(sellToUserSchema),
|
||||
});
|
||||
|
||||
if (!currentWallet) {
|
||||
return (
|
||||
<Card>
|
||||
<div className="flex items-center justify-center p-2">
|
||||
<p>Loading...</p>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Form {...sellToUserForm}>
|
||||
<form onSubmit={sellToUserForm.handleSubmit(onSellToUserSubmit)} className="w-full space-y-6">
|
||||
<FormField
|
||||
control={sellToUserForm.control}
|
||||
name="cryptoId"
|
||||
render={({ field }) => (
|
||||
<FormItem
|
||||
onChange={(event) => {
|
||||
// @ts-ignore
|
||||
const maxShares = getMaxSharesForCrypto(event.target.value as string);
|
||||
setSliderValue(maxShares);
|
||||
setQuantity(maxShares);
|
||||
// @ts-ignore
|
||||
setSelectedCrypto(event.target.value as string);
|
||||
}}
|
||||
>
|
||||
<FormLabel>Sell shares of your wallet</FormLabel>
|
||||
<Select
|
||||
onValueChange={(val) => {
|
||||
const maxShares = getMaxSharesForCrypto(val);
|
||||
setSliderValue(maxShares);
|
||||
setQuantity(1);
|
||||
setSelectedCrypto(val);
|
||||
field.onChange(val);
|
||||
}}
|
||||
>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select a crypto from your wallet." />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
{currentWallet?.map((crypto) => (
|
||||
<SelectItem value={crypto.Crypto.id} key={crypto.Crypto.id}>
|
||||
{`${crypto.amount}x ${crypto.Crypto.name} - ${crypto.Crypto.value}$/u`}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={sellToUserForm.control}
|
||||
name="amount"
|
||||
render={({ field }) => (
|
||||
<FormItem hidden={!selectedCrypto}>
|
||||
<FormLabel>Quantity</FormLabel>
|
||||
<div className="flex items-center justify-between gap-2 p-2">
|
||||
<p className="bg-accent text-accent-foreground p-1 rounded">{field.value}</p>
|
||||
<Slider
|
||||
form="amount"
|
||||
onValueChange={(val) => {
|
||||
const singleValue = val[0];
|
||||
setQuantity(singleValue as number);
|
||||
field.onChange(singleValue);
|
||||
}}
|
||||
value={[quantity]}
|
||||
min={1}
|
||||
max={sliderValue}
|
||||
step={1}
|
||||
/>
|
||||
</div>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
{selectedCrypto && (
|
||||
<div className="flex items-center justify-center p-2 gap-2">
|
||||
<p>{getCryptoName(selectedCrypto)}</p>
|
||||
<X />
|
||||
<p>{quantity}</p>
|
||||
<Equal />
|
||||
<em className="bg-secondary/35 p-1 rounded">
|
||||
{(quantity * getCryptoValue(selectedCrypto)).toLocaleString("en-US")}
|
||||
</em>
|
||||
<DollarSign />
|
||||
</div>
|
||||
)}
|
||||
<Button type="submit" disabled={!quantity}>
|
||||
Place sell order
|
||||
</Button>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
}
|
0
src/components/sub/GraphSellOffer.tsx
Normal file
0
src/components/sub/GraphSellOffer.tsx
Normal file
50
src/components/sub/OfferList.tsx
Normal file
50
src/components/sub/OfferList.tsx
Normal file
@ -0,0 +1,50 @@
|
||||
import {Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table";
|
||||
import {ScrollArea} from "@/components/ui/scroll-area";
|
||||
import type {IAllTrades} from "@/interfaces/crypto.interface";
|
||||
import {cn} from "@/lib/utils";
|
||||
|
||||
interface OfferListProps {
|
||||
className?: string;
|
||||
trades: IAllTrades;
|
||||
}
|
||||
|
||||
interface RenderRowsProps {
|
||||
data?: IAllTrades;
|
||||
}
|
||||
|
||||
function RenderRows({ data }: RenderRowsProps) {
|
||||
if (!data || data?.length === 0) return (<TableRow>
|
||||
<TableCell className="font-medium">{" "}</TableCell>
|
||||
<TableCell>{" "}</TableCell>
|
||||
<TableCell>{"No history..."}</TableCell>
|
||||
<TableCell className="text-right">{" "}</TableCell>
|
||||
</TableRow>);
|
||||
|
||||
return data.map((item, index) => (
|
||||
<TableRow key={item.Crypto.created_at.toString()}>
|
||||
<TableCell className="font-medium">{item.Giver.pseudo}</TableCell>
|
||||
<TableCell>{item.Receiver.pseudo}</TableCell>
|
||||
<TableCell>{item.Crypto.quantity}</TableCell>
|
||||
<TableCell className="text-right">${item.Crypto.value}</TableCell>
|
||||
</TableRow>
|
||||
));
|
||||
}
|
||||
|
||||
export function OfferList({ className, trades}: OfferListProps) {
|
||||
return (<div className={cn("bg-card text-card-foreground rounded p-2", className)}>
|
||||
<Table>
|
||||
<TableCaption>A list of recent sell offers.</TableCaption>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="w-[100px]">Seller</TableHead>
|
||||
<TableHead>Buyer</TableHead>
|
||||
<TableHead>Crypto share amount</TableHead>
|
||||
<TableHead className="text-right">$</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<RenderRows data={trades}/>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>)
|
||||
}
|
@ -15,7 +15,6 @@ export interface IUserData {
|
||||
dollarAvailables: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
//TODO get on register
|
||||
wallet: IUserWallet;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user