Compare commits
17 Commits
solana-pay
...
main
Author | SHA1 | Date | |
---|---|---|---|
05d1803510 | |||
60cd681ac7 | |||
33774d1614 | |||
0dfff9c4d8 | |||
![]() |
bd1677ae0d | ||
![]() |
d8b2ad1987 | ||
48a7c37e8a | |||
![]() |
eceb472556 | ||
5ab94bee12 | |||
b87b46ee89 | |||
bf5e8d4ba7 | |||
![]() |
3905e101ab | ||
![]() |
ecc0ee0415 | ||
![]() |
2441adc6f4 | ||
![]() |
b12cd32738 | ||
![]() |
578fcb74f0 | ||
![]() |
1f39ab8fc7 |
@ -1,4 +1,6 @@
|
|||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {};
|
const nextConfig = {
|
||||||
|
transpilePackages: ["geist"],
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = nextConfig;
|
module.exports = nextConfig;
|
||||||
|
@ -15,7 +15,7 @@ export default function Form() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (ready && authenticated) {
|
if (ready && authenticated) {
|
||||||
router.push("/dashboard/home");
|
router.push("/dashboard/rent");
|
||||||
}
|
}
|
||||||
}, [ready, authenticated, router]);
|
}, [ready, authenticated, router]);
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import Sidebar from "@/components/Sidebar";
|
|||||||
import Topbar from "@/components/Topbar";
|
import Topbar from "@/components/Topbar";
|
||||||
import { usePrivy } from "@privy-io/react-auth";
|
import { usePrivy } from "@privy-io/react-auth";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
|
import Script from "next/script";
|
||||||
|
|
||||||
export default function DashboardLayout({
|
export default function DashboardLayout({
|
||||||
children,
|
children,
|
||||||
@ -21,6 +22,26 @@ export default function DashboardLayout({
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<main className="relative z-10">
|
<main className="relative z-10">
|
||||||
|
<Script id="landbot-script">{`
|
||||||
|
window.addEventListener('mouseover', initLandbot, { once: true });
|
||||||
|
window.addEventListener('touchstart', initLandbot, { once: true });
|
||||||
|
var myLandbot;
|
||||||
|
function initLandbot() {
|
||||||
|
if (!myLandbot) {
|
||||||
|
var s = document.createElement('script');
|
||||||
|
s.type = "module"
|
||||||
|
s.async = true;
|
||||||
|
s.addEventListener('load', function() {
|
||||||
|
var myLandbot = new Landbot.Livechat({
|
||||||
|
configUrl: 'https://storage.googleapis.com/landbot.online/v3/H-2923167-WL26NF7VJKJ3PAMV/index.json',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
s.src = 'https://cdn.landbot.io/landbot-3/landbot-3.0.0.mjs';
|
||||||
|
var x = document.getElementsByTagName('script')[0];
|
||||||
|
x.parentNode.insertBefore(s, x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`}</Script>
|
||||||
<div className="mx-auto container max-w-[1720px] px-14">
|
<div className="mx-auto container max-w-[1720px] px-14">
|
||||||
<div className="min-h-[100svh] p-14 grid grid-cols-[268px_auto] gap-12 overflow-hidden">
|
<div className="min-h-[100svh] p-14 grid grid-cols-[268px_auto] gap-12 overflow-hidden">
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
|
@ -19,10 +19,10 @@ export default function Boxes() {
|
|||||||
const gpus: IGPU[] = [
|
const gpus: IGPU[] = [
|
||||||
{
|
{
|
||||||
id: 'k80',
|
id: 'k80',
|
||||||
title: 'NVIDIA Tesla K80',
|
title: 'NVIDIA K80',
|
||||||
subTitle: '24 GB GDDR5 - 4992 CUDA Cores',
|
subTitle: '24 GB GDDR5 - 4992 CUDA Cores',
|
||||||
price: '$0.15/hour ($110/mo)',
|
price: '$0.15/hour ($110/mo)',
|
||||||
price_usd: 110,
|
price_usd: 110, //110,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 't1000',
|
id: 't1000',
|
||||||
|
@ -1,10 +1,5 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
import Image from "next/image";
|
|
||||||
import serverIcon1 from "@/assets/images/server-1-icon.svg";
|
|
||||||
import serverIcon2 from "@/assets/images/server-2-icon.svg";
|
|
||||||
import serverIcon3 from "@/assets/images/server-3-icon.svg";
|
|
||||||
import serverIcon4 from "@/assets/images/server-4-icon.svg";
|
|
||||||
|
|
||||||
export default function Box() {
|
export default function Box() {
|
||||||
return (
|
return (
|
||||||
@ -22,91 +17,249 @@ export default function Box() {
|
|||||||
}}
|
}}
|
||||||
className="relative p-5 border border-white/5 bg-[#0E1618]/10 backdrop-blur-sm"
|
className="relative p-5 border border-white/5 bg-[#0E1618]/10 backdrop-blur-sm"
|
||||||
>
|
>
|
||||||
<h3 className="mb-1 font-medium uppercase text-[#0CE77E]">Live and preparing servers</h3>
|
<h3 className="mb-1 font-medium uppercase text-[#0CE77E]">All Systems Operational</h3>
|
||||||
|
|
||||||
<p className="mb-4 text-sm text-white/75">List of our GPUs and their current status</p>
|
<p className="mb-4 text-sm text-white/75">
|
||||||
|
Last updated on{" "}
|
||||||
|
{new Date(Date.now() - 3 * 60 * 1000)
|
||||||
|
.toLocaleString("en-US", {
|
||||||
|
month: "short",
|
||||||
|
day: "numeric",
|
||||||
|
hour: "numeric",
|
||||||
|
minute: "2-digit",
|
||||||
|
hour12: true,
|
||||||
|
timeZoneName: "short",
|
||||||
|
})
|
||||||
|
.replace(",", "")
|
||||||
|
.replace("AM", "am")
|
||||||
|
.replace("PM", "pm")}
|
||||||
|
</p>
|
||||||
|
|
||||||
<div className="py-4 border-t border-[#0CE77E]/25 grid grid-cols-[250px_auto] items-center">
|
<div className="py-4 border-t border-[#0CE77E]/25 items-center">
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center justify-between mb-2">
|
||||||
<Image src={serverIcon1} alt="" className="w-[40px] h-[40px]" />
|
<h3 className="font-medium text-[#0CE77E]">GPU Instance</h3>
|
||||||
|
<h3 className="font-medium text-[#0CE77E]">99.960% uptime</h3>
|
||||||
<div>
|
|
||||||
<h3 className="font-medium text-[#0CE77E]">GAMING GPUs</h3>
|
|
||||||
<p className="text-sm text-white/75">Total GPUs : 52</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex">
|
{/* uptime status */}
|
||||||
<div className="flex-1 h-[28px] px-5 bg-[#0CE77E] flex items-center">
|
<div className="relative">
|
||||||
<p className="text-sm font-semibold uppercase text-[#0B1315]">Ready : 38</p>
|
<div className="flex h-[28px] w-full overflow-visible relative">
|
||||||
</div>
|
{[
|
||||||
|
{ status: "operational", width: "60%", details: "No incident reported" },
|
||||||
<div className="h-[28px] px-5 bg-[#0A492F] flex items-center">
|
{
|
||||||
<p className="text-sm font-medium uppercase text-[#0CE77E]">PREPARING : 14</p>
|
status: "degraded",
|
||||||
|
width: "0.5%",
|
||||||
|
details: "Resolved - Nvidia driver issue",
|
||||||
|
},
|
||||||
|
{ status: "operational", width: "39.5%", details: "No incident reported" },
|
||||||
|
].map((segment, index) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className={`h-full group cursor-help relative
|
||||||
|
${
|
||||||
|
segment.status === "operational"
|
||||||
|
? "bg-[#0CE77E]"
|
||||||
|
: segment.status === "degraded"
|
||||||
|
? "bg-yellow-500"
|
||||||
|
: "bg-red-500"
|
||||||
|
}`}
|
||||||
|
style={{ width: segment.width }}
|
||||||
|
>
|
||||||
|
<div className="absolute invisible z-20 group-hover:visible bg-black/90 text-white text-xs py-1 px-2 rounded -top-8 left-1/2 -translate-x-1/2 whitespace-nowrap">
|
||||||
|
{segment.status === "operational"
|
||||||
|
? "Fully Operational"
|
||||||
|
: segment.status === "degraded"
|
||||||
|
? "Degraded Performance"
|
||||||
|
: "System Down"}
|
||||||
|
<br />
|
||||||
|
Status: {segment.details}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
<div className="mt-2 text-xs text-white/50">Last 30 days - Hover segments for more details</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="py-4 border-t border-[#0CE77E]/25 grid grid-cols-[250px_auto] items-center">
|
<div className="py-4 border-t border-[#0CE77E]/25 items-center">
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center justify-between mb-2">
|
||||||
<Image src={serverIcon2} alt="" className="w-[40px] h-[40px]" />
|
<h3 className="font-medium text-[#0CE77E]">Console</h3>
|
||||||
|
<h3 className="font-medium text-[#0CE77E]">99.890% uptime</h3>
|
||||||
<div>
|
|
||||||
<h3 className="font-medium text-[#E2F410]">Datacenter GPUs</h3>
|
|
||||||
<p className="text-sm text-white/75">Total GPUs : 45</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex">
|
{/* uptime status */}
|
||||||
<div className="flex-1 h-[28px] px-5 bg-[#0CE77E] flex items-center">
|
<div className="relative">
|
||||||
<p className="text-sm font-semibold uppercase text-[#0B1315]">Ready : 33</p>
|
<div className="flex h-[28px] w-full overflow-visible relative">
|
||||||
</div>
|
{[
|
||||||
|
{ status: "operational", width: "20%", details: "No incident reported" },
|
||||||
<div className="h-[28px] px-5 bg-[#0A492F] flex items-center">
|
{
|
||||||
<p className="text-sm font-medium uppercase text-[#0CE77E]">PREPARING : 12</p>
|
status: "downtime",
|
||||||
|
width: "0.5%",
|
||||||
|
details: "Service Unavailable",
|
||||||
|
},
|
||||||
|
{ status: "operational", width: "28%", details: "No incident reported" },
|
||||||
|
{ status: "degraded", width: "0.5%", details: "Updating SMTP" },
|
||||||
|
{ status: "operational", width: "51%", details: "No incident reported" },
|
||||||
|
].map((segment, index) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className={`h-full group cursor-help relative
|
||||||
|
${
|
||||||
|
segment.status === "operational"
|
||||||
|
? "bg-[#0CE77E]"
|
||||||
|
: segment.status === "degraded"
|
||||||
|
? "bg-yellow-500"
|
||||||
|
: "bg-red-500"
|
||||||
|
}`}
|
||||||
|
style={{ width: segment.width }}
|
||||||
|
>
|
||||||
|
<div className="absolute invisible z-20 group-hover:visible bg-black/90 text-white text-xs py-1 px-2 rounded -top-8 left-1/2 -translate-x-1/2 whitespace-nowrap">
|
||||||
|
{segment.status === "operational"
|
||||||
|
? "Fully Operational"
|
||||||
|
: segment.status === "degraded"
|
||||||
|
? "Degraded Performance"
|
||||||
|
: "System Down"}
|
||||||
|
<br />
|
||||||
|
Status: {segment.details}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
<div className="mt-2 text-xs text-white/50">Last 30 days - Hover segments for more details</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="py-4 border-t border-[#0CE77E]/25 grid grid-cols-[250px_auto] items-center">
|
<div className="py-4 border-t border-[#0CE77E]/25 items-center">
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center justify-between mb-2">
|
||||||
<Image src={serverIcon3} alt="" className="w-[40px] h-[40px]" />
|
<h3 className="font-medium text-[#0CE77E]">Network</h3>
|
||||||
|
<h3 className="font-medium text-[#0CE77E]">99.940% uptime</h3>
|
||||||
<div>
|
|
||||||
<h3 className="font-medium text-[#F65927]">Integrated GPUs</h3>
|
|
||||||
<p className="text-sm text-white/75">Total GPUs : 17</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex">
|
{/* uptime status */}
|
||||||
<div className="flex-1 h-[28px] px-5 bg-[#0CE77E] flex items-center">
|
<div className="relative">
|
||||||
<p className="text-sm font-semibold uppercase text-[#0B1315]">Ready : 12</p>
|
<div className="flex h-[28px] w-full overflow-visible relative">
|
||||||
</div>
|
{[
|
||||||
|
{ status: "operational", width: "34%", details: "No incident reported" },
|
||||||
<div className="h-[28px] px-5 bg-[#0A492F] flex items-center">
|
{
|
||||||
<p className="text-sm font-medium uppercase text-[#0CE77E]">PREPARING : 5</p>
|
status: "degraded",
|
||||||
|
width: "0.5%",
|
||||||
|
details: "Resolved - Unusual high latency on some regions",
|
||||||
|
},
|
||||||
|
{ status: "operational", width: "35%", details: "No incident reported" },
|
||||||
|
{ status: "downtime", width: "0.5%", details: "Service Unavailable" },
|
||||||
|
{ status: "operational", width: "30%", details: "No incident reported" },
|
||||||
|
].map((segment, index) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className={`h-full group cursor-help relative
|
||||||
|
${
|
||||||
|
segment.status === "operational"
|
||||||
|
? "bg-[#0CE77E]"
|
||||||
|
: segment.status === "degraded"
|
||||||
|
? "bg-yellow-500"
|
||||||
|
: "bg-red-500"
|
||||||
|
}`}
|
||||||
|
style={{ width: segment.width }}
|
||||||
|
>
|
||||||
|
<div className="absolute invisible z-20 group-hover:visible bg-black/90 text-white text-xs py-1 px-2 rounded -top-8 left-1/2 -translate-x-1/2 whitespace-nowrap">
|
||||||
|
{segment.status === "operational"
|
||||||
|
? "Fully Operational"
|
||||||
|
: segment.status === "degraded"
|
||||||
|
? "Degraded Performance"
|
||||||
|
: "System Down"}
|
||||||
|
<br />
|
||||||
|
Status: {segment.details}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
<div className="mt-2 text-xs text-white/50">Last 30 days - Hover segments for more details</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="py-4 border-t border-[#0CE77E]/25 grid grid-cols-[250px_auto] items-center">
|
<div className="py-4 border-t border-[#0CE77E]/25 items-center">
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center justify-between mb-2">
|
||||||
<Image src={serverIcon4} alt="" className="w-[40px] h-[40px]" />
|
<h3 className="font-medium text-[#0CE77E]">Proxy</h3>
|
||||||
|
<h3 className="font-medium text-[#0CE77E]">100% uptime</h3>
|
||||||
<div>
|
|
||||||
<h3 className="font-medium text-[#0CBFE7]">AI GPUs</h3>
|
|
||||||
<p className="text-sm text-white/75">Total GPUs : 61</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex">
|
{/* uptime status */}
|
||||||
<div className="flex-1 h-[28px] px-5 bg-[#0CE77E] flex items-center">
|
<div className="relative">
|
||||||
<p className="text-sm font-semibold uppercase text-[#0B1315]">Ready : 44</p>
|
<div className="flex h-[28px] w-full overflow-visible relative">
|
||||||
|
{[{ status: "operational", width: "100%", details: "No incident reported" }].map(
|
||||||
|
(segment, index) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className={`h-full group cursor-help relative
|
||||||
|
${
|
||||||
|
segment.status === "operational"
|
||||||
|
? "bg-[#0CE77E]"
|
||||||
|
: segment.status === "degraded"
|
||||||
|
? "bg-yellow-500"
|
||||||
|
: "bg-red-500"
|
||||||
|
}`}
|
||||||
|
style={{ width: segment.width }}
|
||||||
|
>
|
||||||
|
<div className="absolute invisible z-20 group-hover:visible bg-black/90 text-white text-xs py-1 px-2 rounded -top-8 left-1/2 -translate-x-1/2 whitespace-nowrap">
|
||||||
|
{segment.status === "operational"
|
||||||
|
? "Fully Operational"
|
||||||
|
: segment.status === "degraded"
|
||||||
|
? "Degraded Performance"
|
||||||
|
: "System Down"}
|
||||||
|
<br />
|
||||||
|
Status: {segment.details}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
<div className="mt-2 text-xs text-white/50">Last 30 days - Hover segments for more details</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="h-[28px] px-5 bg-[#0A492F] flex items-center">
|
<div className="py-4 border-t border-[#0CE77E]/25 items-center">
|
||||||
<p className="text-sm font-medium uppercase text-[#0CE77E]">PREPARING : 17</p>
|
<div className="flex items-center justify-between mb-2">
|
||||||
|
<h3 className="font-medium text-[#0CE77E]">Database</h3>
|
||||||
|
<h3 className="font-medium text-[#0CE77E]">99.910% uptime</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* uptime status */}
|
||||||
|
<div className="relative">
|
||||||
|
<div className="flex h-[28px] w-full overflow-visible relative">
|
||||||
|
{[
|
||||||
|
{ status: "operational", width: "80%", details: "No incident reported" },
|
||||||
|
{
|
||||||
|
status: "degraded",
|
||||||
|
width: "0.5%",
|
||||||
|
details: "Resolved - Deprecated DB API",
|
||||||
|
},
|
||||||
|
{ status: "operational", width: "19%", details: "No incident reported" },
|
||||||
|
].map((segment, index) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className={`h-full group cursor-help relative
|
||||||
|
${
|
||||||
|
segment.status === "operational"
|
||||||
|
? "bg-[#0CE77E]"
|
||||||
|
: segment.status === "degraded"
|
||||||
|
? "bg-yellow-500"
|
||||||
|
: "bg-red-500"
|
||||||
|
}`}
|
||||||
|
style={{ width: segment.width }}
|
||||||
|
>
|
||||||
|
<div className="absolute invisible z-20 group-hover:visible bg-black/90 text-white text-xs py-1 px-2 rounded -top-8 left-1/2 -translate-x-1/2 whitespace-nowrap">
|
||||||
|
{segment.status === "operational"
|
||||||
|
? "Fully Operational"
|
||||||
|
: segment.status === "degraded"
|
||||||
|
? "Degraded Performance"
|
||||||
|
: "System Down"}
|
||||||
|
<br />
|
||||||
|
Status: {segment.details}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
<div className="mt-2 text-xs text-white/50">Last 30 days - Hover segments for more details</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -3,23 +3,23 @@ import type { Metadata } from "next";
|
|||||||
import Box from "./Box";
|
import Box from "./Box";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Vertex - Server Status",
|
|
||||||
description:
|
|
||||||
"Vertex thrives on the power of community. By connecting users across the globe, we are creating a network that fosters collaboration, innovation, and shared success.",
|
|
||||||
openGraph: {
|
|
||||||
type: "website",
|
|
||||||
url: "https://dapp-ai-proj-02.vercel.app/dashboard/server",
|
|
||||||
title: "Vertex - Server Status",
|
title: "Vertex - Server Status",
|
||||||
description:
|
description:
|
||||||
"Vertex thrives on the power of community. By connecting users across the globe, we are creating a network that fosters collaboration, innovation, and shared success.",
|
"Vertex thrives on the power of community. By connecting users across the globe, we are creating a network that fosters collaboration, innovation, and shared success.",
|
||||||
images: "https://dapp-ai-proj-02.vercel.app/og-banner.png",
|
openGraph: {
|
||||||
},
|
type: "website",
|
||||||
|
url: "https://dapp-ai-proj-02.vercel.app/dashboard/server",
|
||||||
|
title: "Vertex - Server Status",
|
||||||
|
description:
|
||||||
|
"Vertex thrives on the power of community. By connecting users across the globe, we are creating a network that fosters collaboration, innovation, and shared success.",
|
||||||
|
images: "https://dapp-ai-proj-02.vercel.app/og-banner.png",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Server() {
|
export default function Server() {
|
||||||
return (
|
return (
|
||||||
<div className="pt-7">
|
<div className="pt-7">
|
||||||
<Box />
|
<Box />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import { GeistSans, GeistMono } from "geist/font";
|
import { GeistSans } from "geist/font/sans";
|
||||||
|
import { GeistMono } from "geist/font/mono";
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
import Bg from "@/components/Bg";
|
import Bg from "@/components/Bg";
|
||||||
import Providers from "@/components/Providers";
|
import Providers from "@/components/Providers";
|
||||||
|
|
||||||
const geistSans = GeistSans;
|
|
||||||
const geistMono = GeistMono;
|
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Login to Your Dashboard - Vertex",
|
title: "Login to Your Dashboard - Vertex",
|
||||||
description:
|
description:
|
||||||
@ -28,7 +26,7 @@ export default function RootLayout({
|
|||||||
}>) {
|
}>) {
|
||||||
return (
|
return (
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<body className={`${geistSans.variable} ${geistMono.className} antialiased bg-[#070F11]`}>
|
<body className={`${GeistSans.variable} ${GeistMono.className} antialiased bg-[#070F11]`}>
|
||||||
<Providers>{children}</Providers>
|
<Providers>{children}</Providers>
|
||||||
<Bg />
|
<Bg />
|
||||||
</body>
|
</body>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
|
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {
|
import {
|
||||||
@ -17,6 +18,7 @@ import {
|
|||||||
getAssociatedTokenAddress,
|
getAssociatedTokenAddress,
|
||||||
createTransferInstruction,
|
createTransferInstruction,
|
||||||
TOKEN_PROGRAM_ID,
|
TOKEN_PROGRAM_ID,
|
||||||
|
ASSOCIATED_TOKEN_PROGRAM_ID,
|
||||||
createAssociatedTokenAccountInstruction,
|
createAssociatedTokenAccountInstruction,
|
||||||
} from "@solana/spl-token";
|
} from "@solana/spl-token";
|
||||||
|
|
||||||
@ -42,7 +44,7 @@ const BUSINESS_WALLET = process.env.NEXT_PUBLIC_BUSINESS_WALLET!;
|
|||||||
const EMAIL_API_URL = process.env.NEXT_PUBLIC_EMAIL_API_URL!;
|
const EMAIL_API_URL = process.env.NEXT_PUBLIC_EMAIL_API_URL!;
|
||||||
const CUSTOM_TOKEN_API_URL = "https://catools.dev3vds1.link/get/vertex";
|
const CUSTOM_TOKEN_API_URL = "https://catools.dev3vds1.link/get/vertex";
|
||||||
|
|
||||||
const USDC_MINT = new PublicKey("Es9vMFrzaCERJ8gLhEvX5yQceQ2uKcXfUrx2Wcikgqay");
|
const USDC_MINT = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
|
||||||
|
|
||||||
const CornerEdge = ({ position }: { position: 'left-top' | 'right-top' | 'left-bottom' | 'right-bottom' }) => {
|
const CornerEdge = ({ position }: { position: 'left-top' | 'right-top' | 'left-bottom' | 'right-bottom' }) => {
|
||||||
const paths = {
|
const paths = {
|
||||||
@ -309,7 +311,7 @@ export const GpuPaymentModal = ({ isOpen, onClose, gpu }: GpuPaymentModalProps)
|
|||||||
// Second attempt: Try using Jupiter Aggregator API for Solana tokens
|
// Second attempt: Try using Jupiter Aggregator API for Solana tokens
|
||||||
try {
|
try {
|
||||||
// Jupiter provides price data for most Solana tokens
|
// Jupiter provides price data for most Solana tokens
|
||||||
const jupiterUrl = `https://price.jup.ag/v4/price?ids=${tokenAddress}`;
|
const jupiterUrl = `https://lite-api.jup.ag/price/v2?ids=${tokenAddress}`;
|
||||||
const jupResponse = await axios.get(jupiterUrl);
|
const jupResponse = await axios.get(jupiterUrl);
|
||||||
|
|
||||||
if (jupResponse.data &&
|
if (jupResponse.data &&
|
||||||
@ -423,6 +425,8 @@ export const GpuPaymentModal = ({ isOpen, onClose, gpu }: GpuPaymentModalProps)
|
|||||||
setErrorMsg(null);
|
setErrorMsg(null);
|
||||||
setSuccessMsg(null);
|
setSuccessMsg(null);
|
||||||
|
|
||||||
|
let priceUsd = selectedToken === "VERTEX" ? gpu.price_usd * 0.9 : gpu.price_usd;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!userEmail || !isValidEmail(userEmail)) {
|
if (!userEmail || !isValidEmail(userEmail)) {
|
||||||
throw new Error("Please enter a valid email address for your receipt.");
|
throw new Error("Please enter a valid email address for your receipt.");
|
||||||
@ -433,6 +437,10 @@ export const GpuPaymentModal = ({ isOpen, onClose, gpu }: GpuPaymentModalProps)
|
|||||||
throw new Error("No connected Solana wallet found or wallet can't sign.");
|
throw new Error("No connected Solana wallet found or wallet can't sign.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Define the correct program IDs
|
||||||
|
const TOKEN_PROGRAM_ID = new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
|
||||||
|
const ASSOCIATED_TOKEN_PROGRAM_ID = new PublicKey("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL");
|
||||||
|
|
||||||
const fromPubKey = new PublicKey(solWallet.address);
|
const fromPubKey = new PublicKey(solWallet.address);
|
||||||
const toPubKey = new PublicKey(BUSINESS_WALLET);
|
const toPubKey = new PublicKey(BUSINESS_WALLET);
|
||||||
const transaction = new Transaction();
|
const transaction = new Transaction();
|
||||||
@ -441,6 +449,7 @@ export const GpuPaymentModal = ({ isOpen, onClose, gpu }: GpuPaymentModalProps)
|
|||||||
let amountDisplay = "";
|
let amountDisplay = "";
|
||||||
|
|
||||||
if (selectedToken === "SOL") {
|
if (selectedToken === "SOL") {
|
||||||
|
// SOL Payment Logic (unchanged)
|
||||||
const { data } = await axios.get(
|
const { data } = await axios.get(
|
||||||
"https://api.coingecko.com/api/v3/simple/price?ids=solana&vs_currencies=usd"
|
"https://api.coingecko.com/api/v3/simple/price?ids=solana&vs_currencies=usd"
|
||||||
);
|
);
|
||||||
@ -456,7 +465,7 @@ export const GpuPaymentModal = ({ isOpen, onClose, gpu }: GpuPaymentModalProps)
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// For both USDC and VERTEX tokens
|
// Token Payment Logic
|
||||||
const selectedMint = selectedToken === "USDC"
|
const selectedMint = selectedToken === "USDC"
|
||||||
? USDC_MINT
|
? USDC_MINT
|
||||||
: new PublicKey(customToken?.address || "");
|
: new PublicKey(customToken?.address || "");
|
||||||
@ -468,31 +477,45 @@ export const GpuPaymentModal = ({ isOpen, onClose, gpu }: GpuPaymentModalProps)
|
|||||||
tokenPrice = customTokenPrice || 0.5;
|
tokenPrice = customTokenPrice || 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tokenAmount = (gpu.price_usd / tokenPrice).toFixed(tokenDecimals);
|
const priceUsd = selectedToken === "VERTEX" ? gpu.price_usd * 0.9 : gpu.price_usd;
|
||||||
|
const tokenAmount = (priceUsd / tokenPrice).toFixed(tokenDecimals);
|
||||||
amountDisplay = `${tokenAmount} ${selectedToken}`;
|
amountDisplay = `${tokenAmount} ${selectedToken}`;
|
||||||
|
|
||||||
const fromTokenAccount = await getAssociatedTokenAddress(selectedMint, fromPubKey);
|
// Get or create token accounts using the correct method
|
||||||
const toTokenAccount = await getAssociatedTokenAddress(selectedMint, toPubKey);
|
const fromTokenAccount = await getAssociatedTokenAddress(
|
||||||
|
selectedMint,
|
||||||
|
fromPubKey,
|
||||||
|
false,
|
||||||
|
TOKEN_PROGRAM_ID,
|
||||||
|
ASSOCIATED_TOKEN_PROGRAM_ID
|
||||||
|
);
|
||||||
|
|
||||||
// Check if destination token account exists, if not create it
|
const toTokenAccount = await getAssociatedTokenAddress(
|
||||||
|
selectedMint,
|
||||||
|
toPubKey,
|
||||||
|
false,
|
||||||
|
TOKEN_PROGRAM_ID,
|
||||||
|
ASSOCIATED_TOKEN_PROGRAM_ID
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check if destination token account exists
|
||||||
const toTokenAccountInfo = await connection.getAccountInfo(toTokenAccount);
|
const toTokenAccountInfo = await connection.getAccountInfo(toTokenAccount);
|
||||||
|
|
||||||
if (!toTokenAccountInfo) {
|
if (!toTokenAccountInfo) {
|
||||||
// Import the necessary function
|
// Create associated token account with explicit program IDs
|
||||||
const { createAssociatedTokenAccountInstruction } = await import("@solana/spl-token");
|
|
||||||
|
|
||||||
// Add instruction to create the associated token account for the business wallet
|
|
||||||
transaction.add(
|
transaction.add(
|
||||||
createAssociatedTokenAccountInstruction(
|
createAssociatedTokenAccountInstruction(
|
||||||
fromPubKey, // payer
|
fromPubKey,
|
||||||
toTokenAccount, // associated token account address
|
toTokenAccount,
|
||||||
toPubKey, // owner of the new account
|
toPubKey,
|
||||||
selectedMint // token mint
|
selectedMint,
|
||||||
|
TOKEN_PROGRAM_ID,
|
||||||
|
ASSOCIATED_TOKEN_PROGRAM_ID
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the transfer instruction after ensuring the account exists
|
// Add token transfer instruction with explicit program ID
|
||||||
transaction.add(
|
transaction.add(
|
||||||
createTransferInstruction(
|
createTransferInstruction(
|
||||||
fromTokenAccount,
|
fromTokenAccount,
|
||||||
@ -505,22 +528,24 @@ export const GpuPaymentModal = ({ isOpen, onClose, gpu }: GpuPaymentModalProps)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set transaction properties (unchanged)
|
||||||
transaction.feePayer = fromPubKey;
|
transaction.feePayer = fromPubKey;
|
||||||
const { blockhash } = await connection.getLatestBlockhash();
|
const { blockhash } = await connection.getLatestBlockhash();
|
||||||
transaction.recentBlockhash = blockhash;
|
transaction.recentBlockhash = blockhash;
|
||||||
|
|
||||||
|
// Sign and send (unchanged)
|
||||||
const signedTx = await solWallet.signTransaction(transaction);
|
const signedTx = await solWallet.signTransaction(transaction);
|
||||||
txId = await connection.sendRawTransaction(signedTx.serialize());
|
txId = await connection.sendRawTransaction(signedTx.serialize());
|
||||||
await connection.confirmTransaction(txId, "confirmed");
|
await connection.confirmTransaction(txId, "confirmed");
|
||||||
|
|
||||||
|
// Process order completion (unchanged)
|
||||||
await axios.post(EMAIL_API_URL, {
|
await axios.post(EMAIL_API_URL, {
|
||||||
email: userEmail,
|
email: userEmail,
|
||||||
product: gpu.title,
|
product: gpu.title,
|
||||||
price_hour: gpu.price_per_hour,
|
price_hour: gpu.price_per_hour,
|
||||||
price: gpu.price_usd.toFixed(2)
|
price: priceUsd.toFixed(2)
|
||||||
});
|
});
|
||||||
|
|
||||||
// Generate a random order ID (in production this would come from the backend)
|
|
||||||
const generatedOrderId = `${Math.floor(Math.random() * 900) + 100}-${Math.floor(Math.random() * 900) + 100}-${Math.floor(Math.random() * 900) + 100}`;
|
const generatedOrderId = `${Math.floor(Math.random() * 900) + 100}-${Math.floor(Math.random() * 900) + 100}-${Math.floor(Math.random() * 900) + 100}`;
|
||||||
setOrderId(generatedOrderId);
|
setOrderId(generatedOrderId);
|
||||||
|
|
||||||
@ -528,7 +553,7 @@ export const GpuPaymentModal = ({ isOpen, onClose, gpu }: GpuPaymentModalProps)
|
|||||||
{
|
{
|
||||||
gpu: `${gpu.id} ${gpu.title}`,
|
gpu: `${gpu.id} ${gpu.title}`,
|
||||||
user_email: userEmail,
|
user_email: userEmail,
|
||||||
amount_usd: gpu.price_usd,
|
amount_usd: priceUsd,
|
||||||
token_used: tokenUsed,
|
token_used: tokenUsed,
|
||||||
token_amount: amountDisplay,
|
token_amount: amountDisplay,
|
||||||
token_tx_signature: txId,
|
token_tx_signature: txId,
|
||||||
@ -551,7 +576,7 @@ export const GpuPaymentModal = ({ isOpen, onClose, gpu }: GpuPaymentModalProps)
|
|||||||
{
|
{
|
||||||
gpu: `${gpu.id} ${gpu.title}`,
|
gpu: `${gpu.id} ${gpu.title}`,
|
||||||
user_email: userEmail,
|
user_email: userEmail,
|
||||||
amount_usd: gpu.price_usd,
|
amount_usd: priceUsd,
|
||||||
token_used: selectedToken,
|
token_used: selectedToken,
|
||||||
status: "failed",
|
status: "failed",
|
||||||
error_message: err.message || "Unknown error",
|
error_message: err.message || "Unknown error",
|
||||||
@ -571,6 +596,10 @@ export const GpuPaymentModal = ({ isOpen, onClose, gpu }: GpuPaymentModalProps)
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (!isOpen) return null;
|
if (!isOpen) return null;
|
||||||
|
const displayPrice = selectedToken === 'VERTEX'
|
||||||
|
? (gpu.price_usd * 0.9).toFixed(2)
|
||||||
|
: gpu.price_usd.toFixed(2);
|
||||||
|
|
||||||
|
|
||||||
// Show failure screen if payment failed
|
// Show failure screen if payment failed
|
||||||
if (paymentFailure) {
|
if (paymentFailure) {
|
||||||
@ -703,7 +732,7 @@ export const GpuPaymentModal = ({ isOpen, onClose, gpu }: GpuPaymentModalProps)
|
|||||||
<div className="flex justify-between items-center p-3 w-full">
|
<div className="flex justify-between items-center p-3 w-full">
|
||||||
<span className="text-base font-medium text-white">Total Price</span>
|
<span className="text-base font-medium text-white">Total Price</span>
|
||||||
<div className="flex gap-3 items-center">
|
<div className="flex gap-3 items-center">
|
||||||
<span className="text-base font-bold text-[#0CE77E]">${gpu.price_usd}</span>
|
<span className="text-base font-bold text-[#0CE77E]">${displayPrice}</span>
|
||||||
<span className="text-base text-[#0CE77E]">(~{currentTokenAmount} {selectedToken})</span>
|
<span className="text-base text-[#0CE77E]">(~{currentTokenAmount} {selectedToken})</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -47,20 +47,6 @@ export default function Sidebar() {
|
|||||||
{
|
{
|
||||||
title: "Dashboard",
|
title: "Dashboard",
|
||||||
links: [
|
links: [
|
||||||
{
|
|
||||||
icon: (
|
|
||||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path
|
|
||||||
d="M5.31636 3.57182L4.56635 4.15724C3.42886 5.04511 2.86011 5.48905 2.55505 6.115C2.25 6.74094 2.25 7.46404 2.25 8.91022V10.4786C2.25 13.3172 2.25 14.7364 3.12868 15.6182C4.00736 16.5 5.42157 16.5 8.25 16.5H9.75C12.5784 16.5 13.9927 16.5 14.8713 15.6182C15.75 14.7364 15.75 13.3172 15.75 10.4786V8.91022C15.75 7.46404 15.75 6.74094 15.445 6.115C15.1399 5.48905 14.5712 5.04511 13.4336 4.15724L12.6836 3.57182C10.9141 2.19061 10.0293 1.5 9 1.5C7.9707 1.5 7.0859 2.19061 5.31636 3.57182Z"
|
|
||||||
stroke="#0CE77E"
|
|
||||||
strokeWidth="1.125"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
),
|
|
||||||
title: "Home",
|
|
||||||
href: "/dashboard/home",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
icon: (
|
icon: (
|
||||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
@ -230,7 +216,7 @@ export default function Sidebar() {
|
|||||||
<div className="border border-white/5 bg-[#0E1618] h-full p-5 flex flex-col justify-between">
|
<div className="border border-white/5 bg-[#0E1618] h-full p-5 flex flex-col justify-between">
|
||||||
<div>
|
<div>
|
||||||
<div className="pb-5 border-b border-[#0CE77E]/25 flex justify-center">
|
<div className="pb-5 border-b border-[#0CE77E]/25 flex justify-center">
|
||||||
<Link href={"/dashboard/home"}>
|
<Link href={"/dashboard/rent"}>
|
||||||
<Image src={iconImg} alt="" width={32} height={32} />
|
<Image src={iconImg} alt="" width={32} height={32} />
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user