mirror of
https://github.com/luxfi/bridge.git
synced 2026-09-24 00:26:46 +00:00
370 lines
13 KiB
TypeScript
370 lines
13 KiB
TypeScript
"use client";
|
|
import { ApiResponse } from "@/models/ApiResponse";
|
|
import useSWR from "swr";
|
|
import { ChevronRight } from "lucide-react";
|
|
import { useSettings } from "@/context/settings";
|
|
import Image from "next/image";
|
|
import Link from "next/link";
|
|
import LoadingBlocks from "@/components/LoadingBlocks";
|
|
import { SwapStatus } from "@/models/SwapStatus";
|
|
import { useRouter } from "next/navigation";
|
|
import AppSettings from "@/lib/AppSettings";
|
|
import Error500 from "@/components/Error500";
|
|
import { TransactionType } from "@/models/TransactionTypes";
|
|
|
|
type Swap = {
|
|
created_date: string;
|
|
status: string;
|
|
destination_address: string;
|
|
source_asset: string;
|
|
source_network: string;
|
|
source_exchange: string;
|
|
destination_asset: string;
|
|
destination_network: string;
|
|
destination_exchange: string;
|
|
refuel: boolean;
|
|
transactions: Transaction[];
|
|
};
|
|
|
|
type Transaction = {
|
|
from: string;
|
|
to: string;
|
|
created_date: string;
|
|
transaction_id: string;
|
|
explorer_url: string;
|
|
confirmations: number;
|
|
max_confirmations: number;
|
|
amount: number;
|
|
usd_price: number;
|
|
usd_value: number;
|
|
type: string;
|
|
transaction_hash: string;
|
|
};
|
|
|
|
const DataTable: React.FC = () => {
|
|
const fetcher = async (url: string) => {
|
|
const res = await fetch(url);
|
|
return res.json();
|
|
};
|
|
// const version = process.env.NEXT_PUBLIC_API_VERSION
|
|
const version = "sandbox";
|
|
const settings = useSettings();
|
|
|
|
const { data, error, isLoading } = useSWR<ApiResponse<Swap[]>>(
|
|
`${AppSettings.BridgeApiUri}/api/explorer?statuses=1&statuses=3&statuses=4&version=${version}`,
|
|
fetcher,
|
|
{ dedupingInterval: 60000 }
|
|
);
|
|
|
|
const swapsData = data?.data;
|
|
console.log("🚀 ~ swapsData:", swapsData);
|
|
const router = useRouter();
|
|
|
|
if (error) return <Error500 />;
|
|
if (isLoading) return <LoadingBlocks />;
|
|
// console.log('settings?.layers======',settings?.layers);
|
|
|
|
const Row: React.FC<{
|
|
swap: Swap;
|
|
index: number;
|
|
}> = ({ swap, index }) => {
|
|
console.log("🚀 ~ swap:", swap)
|
|
// console.log(' swap.source_network?', swap.source_network);
|
|
|
|
const sourceLayer = settings?.layers?.find(
|
|
(l) =>
|
|
l.internal_name?.toLowerCase() === swap.source_network?.toLowerCase()
|
|
);
|
|
// console.log("🚀 ~ settings?.layers:", sourceLayer, index);
|
|
const sourceToken = sourceLayer?.assets?.find(
|
|
(a) => a?.asset == swap?.source_asset
|
|
);
|
|
// console.log("sourceToken----->", sourceToken, index);
|
|
|
|
const sourceExchange = settings?.exchanges?.find(
|
|
(l) =>
|
|
l.internal_name?.toLowerCase() === swap.source_exchange?.toLowerCase()
|
|
);
|
|
// console.log("sourceExchange----->", sourceExchange, index);
|
|
|
|
const destination_exchange = settings?.exchanges?.find(
|
|
(l) =>
|
|
l.internal_name?.toLowerCase() ===
|
|
swap.destination_exchange?.toLowerCase()
|
|
);
|
|
|
|
// console.log("destination_exchange----->", destination_exchange, index);
|
|
|
|
const destinationLayer = settings?.layers?.find(
|
|
(l) =>
|
|
l.internal_name?.toLowerCase() ===
|
|
swap.destination_network?.toLowerCase()
|
|
);
|
|
const destinationToken = destinationLayer?.assets?.find(
|
|
(a) => a?.asset == swap?.destination_asset
|
|
);
|
|
|
|
const input_transaction = swap?.transactions?.find(
|
|
(t) => t?.type == TransactionType.Input
|
|
);
|
|
const output_transaction = swap?.transactions?.find(
|
|
(t) => t?.type == TransactionType.Output
|
|
);
|
|
// console.log("🚀 ~ input_transaction:", input_transaction);
|
|
console.log("🚀 ~ output_transaction:", output_transaction);
|
|
|
|
return (
|
|
<tr
|
|
key={index}
|
|
onClick={() => {
|
|
router.push(`/${input_transaction?.transaction_hash}`);
|
|
}}
|
|
className="cursor-pointer hover:bg-level-1"
|
|
>
|
|
<td className="whitespace-nowrap border-l border-r border-b border-[#404040] py-2 px-3 text-sm font-medium flex flex-col">
|
|
<div className="flex flex-row items-center py-1 rounded">
|
|
<StatusPill swap={swap} />
|
|
</div>
|
|
<span className="text-muted">
|
|
{new Date(swap.created_date).toLocaleString()}
|
|
</span>
|
|
</td>
|
|
<td className="whitespace-nowrap border-r border-b border-[#404040] px-3 py-2 text-sm text-muted ">
|
|
<div className="flex flex-row">
|
|
<div className="flex flex-col items-start mr-4">
|
|
<span className="text-sm md:text-base font-normal place-items-end mb-1">
|
|
Token:
|
|
</span>
|
|
<span className="text-sm md:text-base font-normal place-items-end min-w-[70px]">
|
|
Source:
|
|
</span>
|
|
</div>
|
|
<div className="flex flex-col">
|
|
<div className="text-sm md:text-base flex flex-row mb-1">
|
|
<div className="flex flex-row items-center">
|
|
<div className="relative h-4 w-4 md:h-5 md:w-5">
|
|
<span>
|
|
<Image
|
|
alt={`Source token icon ${index}`}
|
|
src={settings?.resolveImgSrc(sourceToken) || ""}
|
|
width={20}
|
|
height={20}
|
|
decoding="async"
|
|
data-nimg="responsive"
|
|
className="rounded-md"
|
|
/>
|
|
</span>
|
|
</div>
|
|
<div className="mx-2.5">
|
|
<span>{input_transaction?.amount}</span>
|
|
<span className="mx-1 ">{swap?.source_asset}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="text-sm md:text-base flex flex-row items-center">
|
|
<div className="relative h-4 w-4 md:h-5 md:w-5">
|
|
<span>
|
|
<Image
|
|
alt={`Source chain icon ${index}`}
|
|
src={
|
|
settings?.resolveImgSrc(
|
|
sourceExchange ? sourceExchange : sourceLayer
|
|
) || ""
|
|
}
|
|
width={20}
|
|
height={20}
|
|
decoding="async"
|
|
data-nimg="responsive"
|
|
className="rounded-md"
|
|
/>
|
|
</span>
|
|
</div>
|
|
<div className="mx-2 ">
|
|
<Link
|
|
href={`/${input_transaction?.transaction_hash}`}
|
|
onClick={(e) => e.stopPropagation()}
|
|
target="_blank"
|
|
className="hover:text-gray-300 inline-flex items-center w-fit"
|
|
>
|
|
<span className="mx-0.5 hover:text-gray-300 underline hover:no-underline">
|
|
{sourceExchange
|
|
? sourceExchange?.display_name
|
|
: sourceLayer?.display_name}
|
|
</span>
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td className="whitespace-nowrap border-b border-[#404040] px-3 py-2 text-sm text-muted">
|
|
<div className="flex flex-row">
|
|
<div className="flex flex-col items-start">
|
|
<span className="text-sm md:text-base font-normal place-items-end mb-1">
|
|
Token:
|
|
</span>
|
|
<span className="text-sm md:text-base font-normal place-items-end min-w-[70px]">
|
|
Destination:
|
|
</span>
|
|
</div>
|
|
<div className="flex flex-col">
|
|
<div className="text-sm md:text-base flex flex-row">
|
|
<div className="flex flex-row items-center ml-4 mb-1">
|
|
<div className="relative h-4 w-4 md:h-5 md:w-5">
|
|
<span>
|
|
<Image
|
|
alt={`Destination token icon ${index}`}
|
|
src={settings?.resolveImgSrc(destinationToken) || ""}
|
|
width={20}
|
|
height={20}
|
|
decoding="async"
|
|
data-nimg="responsive"
|
|
className="rounded-md"
|
|
/>
|
|
</span>
|
|
</div>
|
|
{output_transaction?.amount ? (
|
|
<div className="mx-2.5">
|
|
<span className="">{output_transaction?.amount}</span>
|
|
<span className="mx-1 ">{swap?.destination_asset}</span>
|
|
</div>
|
|
) : (
|
|
<span className="ml-2.5">-</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
<div className="text-sm md:text-base flex flex-row items-center ml-4">
|
|
<div className="relative h-4 w-4 md:h-5 md:w-5">
|
|
<span>
|
|
<Image
|
|
alt={`Destination chain icon ${index}`}
|
|
src={
|
|
settings?.resolveImgSrc(
|
|
destination_exchange
|
|
? destination_exchange
|
|
: destinationLayer
|
|
) || ""
|
|
}
|
|
width={20}
|
|
height={20}
|
|
decoding="async"
|
|
data-nimg="responsive"
|
|
className="rounded-md"
|
|
/>
|
|
</span>
|
|
</div>
|
|
<div className="mx-2 ">
|
|
{output_transaction?.transaction_hash ? (
|
|
<Link
|
|
href={`/${output_transaction?.transaction_hash}`}
|
|
onClick={(e) => e.stopPropagation()}
|
|
target="_blank"
|
|
className={`${
|
|
!output_transaction ? "disabled" : ""
|
|
} hover:text-gray-300 inline-flex items-center w-fit`}
|
|
>
|
|
<span
|
|
className={`underline mx-0.5 hover:text-gray-300 hover:no-underline`}
|
|
>
|
|
{destination_exchange
|
|
? destination_exchange?.displayName
|
|
: destinationLayer?.displayName}
|
|
</span>
|
|
</Link>
|
|
) : (
|
|
<span className={`mx-0.5`}>
|
|
{destination_exchange
|
|
? destination_exchange?.displayName
|
|
: destinationLayer?.displayName}
|
|
</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td className="whitespace-nowrap border-b border-[#404040] text-sm mr-4 text-foreground">
|
|
<ChevronRight />
|
|
</td>
|
|
</tr>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<div className="w-full my-4 h-full">
|
|
<div className="max-h-[65vh] w-full align-middle border-b border-[#404040] overflow-y-auto dataTable">
|
|
<table className="border-separate border-spacing-0 w-full relative gap-0">
|
|
<thead className="sticky top-0 z-10 bg-background">
|
|
<tr>
|
|
<th
|
|
scope="col"
|
|
className="cursor-default rounded-tl-lg border-[#404040] border-l border-b border-t px-3 py-3.5 text-left text-sm font-semibold text-muted"
|
|
>
|
|
Status
|
|
</th>
|
|
<th
|
|
scope="col"
|
|
className="cursor-default border-[#404040] border-b border-t px-3 py-3.5 text-left text-sm font-semibold text-muted"
|
|
>
|
|
Source
|
|
</th>
|
|
<th
|
|
scope="col"
|
|
className="cursor-default border-[#404040] border-b border-t px-3 py-3.5 text-left text-sm font-semibold text-muted "
|
|
>
|
|
Destination
|
|
</th>
|
|
<th
|
|
scope="col"
|
|
className="border-[#404040] border-b border-t px-4 py-3.5 text-left text-sm font-semibold text-muted "
|
|
/>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{swapsData?.map((swap, index) => (
|
|
<Row swap={swap} index={index} />
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const StatusPill: React.FC<{
|
|
swap: Swap | undefined;
|
|
}> = ({ swap }) => {
|
|
const swapStatus = swap?.status;
|
|
const input_transaction = swap?.transactions?.find(
|
|
(t) => t?.type == TransactionType.Input
|
|
);
|
|
if (swapStatus == SwapStatus.UserTransferPending) {
|
|
return (
|
|
<span className="font-medium md:text-sm text-xs border p-1 rounded-md text-yellow-200 !border-yellow-200/50">
|
|
Pending
|
|
</span>
|
|
);
|
|
} else if (swapStatus == SwapStatus.BridgeTransferPending) {
|
|
return (
|
|
<span className="font-medium md:text-sm text-xs border p-1 rounded-md text-yellow-200 !border-yellow-200/50">
|
|
Pending
|
|
</span>
|
|
);
|
|
} else if (swapStatus == SwapStatus.Failed && input_transaction) {
|
|
return (
|
|
<span className="font-medium md:text-sm text-xs border p-1 rounded-md text-red-200 !border-red-200/50">
|
|
Failed
|
|
</span>
|
|
);
|
|
} else if (swapStatus == SwapStatus.Completed) {
|
|
return (
|
|
<span className="font-medium md:text-sm text-xs border p-1 rounded-md text-green-200 !border-green-200/50">
|
|
Completed
|
|
</span>
|
|
);
|
|
}
|
|
return <></>;
|
|
};
|
|
|
|
export default DataTable;
|