import { useCallback, useEffect, useState } from "react"; import { Link, useLocation, useNavigate, useParams } from "react-router-dom"; import { PaymentMethod, VmInstance, VmPayment } from "../api"; import VpsPayment from "../components/vps-payment"; import useLogin from "../hooks/login"; import { AsyncButton } from "../components/button"; import CostLabel, { CostAmount } from "../components/cost"; import { RevolutPayWidget } from "../components/revolut"; import { timeValue } from "../utils"; export function VmBillingPage() { const location = useLocation() as { state?: VmInstance }; const params = useParams(); const login = useLogin(); const navigate = useNavigate(); const [methods, setMethods] = useState>(); const [method, setMethod] = useState(); const [payment, setPayment] = useState(); const [payments, setPayments] = useState>([]); const [state, setState] = useState(location?.state); async function listPayments() { if (!state) return; const history = await login?.api.listPayments(state.id); setPayments(history ?? []); } async function reloadVmState() { if (!state) return; const newState = await login?.api.getVm(state.id); setState(newState); setMethod(undefined); setMethods(undefined); return newState; } async function onPaid() { setMethod(undefined); setMethods(undefined); const s = reloadVmState(); if (params["action"] === "renew") { navigate("/vm", { state: s }); } } function paymentMethod(v: PaymentMethod) { const className = "flex items-center justify-between px-3 py-2 bg-neutral-900 rounded-xl cursor-pointer"; switch (v.name) { case "lightning": { return (
{ setMethod(v); renew(v.name); }} >
{v.name.toUpperCase()} ({v.currencies.join(",")})
Pay Now
); } case "revolut": { const pkey = v.metadata?.["pubkey"]; if (!pkey) return Missing Revolut pubkey; return (
{v.name.toUpperCase()} ({v.currencies.join(",")})
{state && ( { onPaid(); }} loadOrder={async () => { if (!login?.api || !state) { throw new Error("Not logged in"); } const p = await login.api.renewVm(state.id, v.name); return p.data.revolut!.token; }} /> )}
); } } } const loadPaymentMethods = useCallback( async function () { if (!login?.api || !state) return; const p = await login?.api.getPaymentMethods(); setMethods(p); }, [login?.api, state], ); const renew = useCallback( async function (m: string) { if (!login?.api || !state) return; const p = await login?.api.renewVm(state.id, m); setPayment(p); }, [login?.api, state], ); useEffect(() => { if (params["action"] === "renew" && login && state) { loadPaymentMethods(); } if (login && state) { listPayments(); } }, [login, state, params, renew]); if (!state) return; const expireDate = new Date(state.expires); const days = (expireDate.getTime() - new Date().getTime()) / 1000 / 24 / 60 / 60; return (
< Back
Renewal for #{state.id}
ex. tax
{days > 0 && (
Expires: {expireDate.toDateString()} ({Math.floor(days)} days)
)} {days < 0 && !methods && (
Expired
)} {!methods && (
Extend Now
)} {methods && !method && ( <>
Payment Method:
{methods.map((v) => paymentMethod(v))} )} {payment && ( <>

Renew VPS

{ setPayment(undefined); onPaid(); }} /> )}
Payment History
{payments.sort((a, b) => new Date(b.created).getTime() - new Date(a.created).getTime()) .map(a => )}
Date Amount Time Status
{new Date(a.created).toLocaleString()} {timeValue(a.time)} {a.is_paid ? "Paid" : (new Date(a.expires) <= new Date() ? "Expired" : "Unpaid")}
); }