Files
web/src/pages/order.tsx
2024-12-29 19:15:04 +00:00

95 lines
2.9 KiB
TypeScript

import { useLocation, useNavigate } from "react-router-dom";
import { LNVpsApi, VmOsImage, VmTemplate } from "../api";
import { useEffect, useState } from "react";
import CostLabel from "../components/cost";
import { ApiUrl } from "../const";
import useLogin from "../hooks/login";
import { AsyncButton } from "../components/button";
import classNames from "classnames";
import VpsResources from "../components/vps-resources";
import OsImageName from "../components/os-image-name";
import SSHKeySelector from "../components/ssh-keys";
export default function OrderPage() {
const { state } = useLocation();
const login = useLogin();
const navigate = useNavigate();
const template = state as VmTemplate | undefined;
const [useImage, setUseImage] = useState(-1);
const [useSshKey, setUseSshKey] = useState(-1);
const [images, setImages] = useState<Array<VmOsImage>>([]);
const [orderError, setOrderError] = useState("");
useEffect(() => {
if (!login?.builder) return;
const api = new LNVpsApi(ApiUrl, login.builder);
api.listOsImages().then((a) => setImages(a));
}, [login]);
async function createOrder() {
if (!login?.builder || !template) return;
const api = new LNVpsApi(ApiUrl, login.builder);
setOrderError("");
try {
const newVm = await api.orderVm(template.id, useImage, useSshKey);
navigate("/vm/renew", {
state: newVm,
});
} catch (e) {
if (e instanceof Error) {
setOrderError(e.message);
}
}
}
const sortedImages = images.sort(
(a, b) =>
new Date(b.release_date).getTime() - new Date(a.release_date).getTime(),
);
if (!template || !login) {
return <h3>No order found</h3>;
}
return (
<div className="flex flex-col gap-4">
<div className="text-xl">New Order</div>
<div className="flex justify-between items-center rounded-xl bg-neutral-900 px-4 py-3">
<div className="flex flex-col gap-1">
<div>{template.name}</div>
<VpsResources vm={template} />
</div>
{template.cost_plan && <CostLabel cost={template.cost_plan} />}
</div>
<hr />
<div className="flex flex-col gap-2">
<b>Select OS:</b>
{sortedImages.map((a) => (
<div
className={classNames(
"flex justify-between items-center rounded-xl px-4 py-3 cursor-pointer",
{
"bg-neutral-900": useImage !== a.id,
"bg-neutral-700": useImage === a.id,
},
)}
onClick={() => setUseImage(a.id)}
>
<OsImageName image={a} />
</div>
))}
</div>
<hr />
<SSHKeySelector selectedKey={useSshKey} setSelectedKey={setUseSshKey} />
<AsyncButton
disabled={useSshKey === -1 || useImage === -1}
onClick={createOrder}
>
Create Order
</AsyncButton>
{orderError && <b className="text-red-500">{orderError}</b>}
</div>
);
}