From 26d36adbebb1c17a924d668a8f73c7dff92e4ef7 Mon Sep 17 00:00:00 2001 From: kieran Date: Tue, 11 Mar 2025 15:59:32 +0000 Subject: [PATCH] feat: taxes ref: https://git.v0l.io/LNVPS/api/issues/18 --- .env.development | 3 +- package.json | 1 + src/api.ts | 2 + src/components/revolut.tsx | 107 +++++++++++++-------------- src/components/vps-payment.tsx | 7 +- src/pages/account-settings.tsx | 127 ++++++++++++++++++--------------- src/pages/home.tsx | 4 +- src/pages/vm-billing.tsx | 6 +- yarn.lock | 8 +++ 9 files changed, 149 insertions(+), 116 deletions(-) diff --git a/.env.development b/.env.development index 0a8dc40..e713aa9 100644 --- a/.env.development +++ b/.env.development @@ -1 +1,2 @@ -#VITE_API_URL="http://localhost:8000" \ No newline at end of file +VITE_API_URL="http://localhost:8000" +VITE_REVOLUT_MODE="sandbox" \ No newline at end of file diff --git a/package.json b/package.json index 7e6320e..ff74a28 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "@xterm/addon-webgl": "^0.18.0", "@xterm/xterm": "^5.5.0", "classnames": "^2.5.1", + "iso-3166-1": "^2.1.1", "marked": "^15.0.7", "qr-code-styling": "^1.8.4", "react": "^18.3.1", diff --git a/src/api.ts b/src/api.ts index 95195d8..7f8b6e4 100644 --- a/src/api.ts +++ b/src/api.ts @@ -24,6 +24,7 @@ export interface AccountDetail { email?: string; contact_nip17: boolean; contact_email: boolean; + country_code: string; } export interface VmCostPlan { @@ -141,6 +142,7 @@ export interface VmPayment { created: string; expires: string; amount: number; + tax: number; is_paid: boolean; data: { lightning?: string; diff --git a/src/components/revolut.tsx b/src/components/revolut.tsx index c700e38..01e69d1 100644 --- a/src/components/revolut.tsx +++ b/src/components/revolut.tsx @@ -1,64 +1,65 @@ import RevolutCheckout, { Mode } from "@revolut/checkout"; import { useEffect, useRef } from "react"; +import { VmCostPlan } from "../api"; interface RevolutProps { - amount: { - currency: string; - amount: number; - }; - pubkey: string; - loadOrder: () => Promise; - onPaid: () => void; - onCancel?: () => void; - mode?: string; + amount: VmCostPlan | { + amount: number; + currency: string; + tax?: number; + }; + pubkey: string; + loadOrder: () => Promise; + onPaid: () => void; + onCancel?: () => void; + mode?: string; } export function RevolutPayWidget({ - pubkey, - loadOrder, - amount, - onPaid, - onCancel, - mode, + pubkey, + loadOrder, + amount, + onPaid, + onCancel, + mode, }: RevolutProps) { - const ref = useRef(null); - async function load(pubkey: string, ref: HTMLDivElement) { - const { revolutPay } = await RevolutCheckout.payments({ - locale: "auto", - mode: (mode ?? "sandbox") as Mode, - publicToken: pubkey, - }); - ref.innerHTML = ""; - revolutPay.mount(ref, { - sessionToken: "", - currency: amount.currency, - totalAmount: amount.amount, - createOrder: async () => { - const id = await loadOrder(); - return { - publicId: id, - }; - }, - buttonStyle: { - cashback: false, - }, - }); - revolutPay.on("payment", (payload) => { - console.debug(payload); - if (payload.type === "success") { - onPaid(); - } - if (payload.type === "cancel") { - onCancel?.(); - } - }); - } - - useEffect(() => { - if (ref.current) { - load(pubkey, ref.current); + const ref = useRef(null); + async function load(pubkey: string, ref: HTMLDivElement) { + const { revolutPay } = await RevolutCheckout.payments({ + locale: "auto", + mode: (mode ?? "prod") as Mode, + publicToken: pubkey, + }); + ref.innerHTML = ""; + revolutPay.mount(ref, { + currency: amount.currency, + totalAmount: amount.amount, + createOrder: async () => { + const id = await loadOrder(); + return { + publicId: id, + }; + }, + buttonStyle: { + cashback: false, + }, + }); + revolutPay.on("payment", (payload) => { + console.debug(payload); + if (payload.type === "success") { + onPaid(); + } + if (payload.type === "cancel") { + onCancel?.(); + } + }); } - }, [pubkey, ref]); - return
; + useEffect(() => { + if (ref.current) { + load(pubkey, ref.current); + } + }, [pubkey, ref]); + + return
; } diff --git a/src/components/vps-payment.tsx b/src/components/vps-payment.tsx index e17bb36..f90c1d0 100644 --- a/src/components/vps-payment.tsx +++ b/src/components/vps-payment.tsx @@ -48,7 +48,12 @@ export default function VpsPayment({ avatar="/logo.jpg" className="cursor-pointer rounded-xl overflow-hidden" /> - {(payment.amount / 1000).toLocaleString()} sats +
+
{((payment.amount + payment.tax) / 1000).toLocaleString()} sats
+ {payment.tax > 0 &&
+ including {(payment.tax / 1000).toLocaleString()} sats tax +
} +
{invoice}
diff --git a/src/pages/account-settings.tsx b/src/pages/account-settings.tsx index 5c84563..8b82cfd 100644 --- a/src/pages/account-settings.tsx +++ b/src/pages/account-settings.tsx @@ -3,6 +3,7 @@ import { useEffect, useState } from "react"; import { AccountDetail } from "../api"; import { AsyncButton } from "../components/button"; import { Icon } from "../components/icon"; +import { default as iso } from "iso-3166-1"; export function AccountSettings() { const login = useLogin(); @@ -13,63 +14,73 @@ export function AccountSettings() { login?.api.getAccount().then(setAcc); }, [login]); - function notifications() { - return ( - <> -

Notification Settings

-
- { - setAcc((s) => - s ? { ...s, contact_email: e.target.checked } : undefined, - ); - }} - /> - Email - { - setAcc((s) => - s ? { ...s, contact_nip17: e.target.checked } : undefined, - ); - }} - /> - Nostr DM -
-
-

Email

- - setAcc((s) => (s ? { ...s, email: e.target.value } : undefined)) - } - /> - {!editEmail && ( - setEditEmail(true)} /> - )} -
-
- { - if (login?.api && acc) { - await login.api.updateAccount(acc); - const newAcc = await login.api.getAccount(); - setAcc(newAcc); - setEditEmail(false); - } - }} - > - Save - -
- - ); - } + if (!acc) return; + return
+

+ Account Settings +

- return <>{notifications()}; +
+

Country

+ +
+ +

Notification Settings

+
+ { + setAcc((s) => + s ? { ...s, contact_email: e.target.checked } : undefined, + ); + }} + /> + Email + { + setAcc((s) => + s ? { ...s, contact_nip17: e.target.checked } : undefined, + ); + }} + /> + Nostr DM +
+
+

Email

+ + setAcc((s) => (s ? { ...s, email: e.target.value } : undefined)) + } + /> + {!editEmail && ( + setEditEmail(true)} /> + )} +
+
+ { + if (login?.api && acc) { + await login.api.updateAccount(acc); + const newAcc = await login.api.getAccount(); + setAcc(newAcc); + setEditEmail(false); + } + }} + > + Save + +
+
} diff --git a/src/pages/home.tsx b/src/pages/home.tsx index 86824a8..3a0bba1 100644 --- a/src/pages/home.tsx +++ b/src/pages/home.tsx @@ -34,8 +34,8 @@ export default function HomePage() { {offers?.custom_template && ( )} - - All VPS come with 1x IPv4 and 1x IPv6 address and unmetered traffic + + All VPS come with 1x IPv4 and 1x IPv6 address and unmetered traffic, all prices are excluding taxes.
diff --git a/src/pages/vm-billing.tsx b/src/pages/vm-billing.tsx index 6606d43..0cab88f 100644 --- a/src/pages/vm-billing.tsx +++ b/src/pages/vm-billing.tsx @@ -67,6 +67,7 @@ export function VmBillingPage() {
{state && ( { @@ -122,7 +123,10 @@ export function VmBillingPage() {
Renewal for #{state.id}
- +
+ + ex. tax +
{days > 0 && (
diff --git a/yarn.lock b/yarn.lock index eb9c521..c552a13 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2451,6 +2451,13 @@ __metadata: languageName: node linkType: hard +"iso-3166-1@npm:^2.1.1": + version: 2.1.1 + resolution: "iso-3166-1@npm:2.1.1" + checksum: 10c0/65daf0283d22b2848d733a50ba6116a01df3e4d77970bb31d0df0696b4b386bdad0946dea53c9bb1e748e5e5e74608c07b6f4fe044908a5cffbf46f315385400 + languageName: node + linkType: hard + "isomorphic-ws@npm:^5.0.0": version: 5.0.0 resolution: "isomorphic-ws@npm:5.0.0" @@ -2618,6 +2625,7 @@ __metadata: eslint-plugin-react-hooks: "npm:^5.1.0-rc.0" eslint-plugin-react-refresh: "npm:^0.4.9" globals: "npm:^15.9.0" + iso-3166-1: "npm:^2.1.1" marked: "npm:^15.0.7" postcss: "npm:^8.4.41" prettier: "npm:^3.3.3"