Modify the checkout widget to support subscriptions. Add usage-based billing toggle to sharing settings.

This commit is contained in:
2026-09-30 19:26:21 +02:00
parent 4b9434ce0a
commit 7b2e4b4240
25 changed files with 1060 additions and 684 deletions

View File

@@ -1,7 +1,11 @@
import type { countries } from "country-data-list";
import { get_endpoint } from "lib/NovaAPI";
import { get_endpoint, subscription_periods, type Subscription } from "lib/NovaAPI";
export type CheckoutState = {
// undefined means the user has not picked yet, null means they chose to
// only deposit credit without starting a subscription
subscription: Subscription | null | undefined
months: number
country: typeof countries.all[0]
provider: PaymentProvider
amount: number
@@ -9,6 +13,16 @@ export type CheckoutState = {
name: string
}
// The price of the chosen subscription period in euro. The deposit can't be
// lower than this
export const plan_price = (state: CheckoutState): number => {
if (!state.subscription) {
return 0
}
return state.subscription.monthly_fee * state.months *
subscription_periods.find(p => p.months === state.months).discount / 1e6
}
export type PaymentProvider = {
icon: string
name: string
@@ -77,6 +91,8 @@ export const payment_providers: PaymentProvider[] = [
]
export const checkout = async (state: CheckoutState) => {
// Whether the deposit covers the subscription is checked by the server,
// which knows how much credit is already on the account
if (state.amount < 10) {
alert("Amount needs to be at least €10")
return
@@ -94,6 +110,12 @@ export const checkout = async (state: CheckoutState) => {
form.set("name", state.name)
}
// The server activates the subscription when the invoice is paid
if (state.subscription) {
form.set("subscription", state.subscription.id)
form.set("subscription_months", String(state.months))
}
try {
const resp = await fetch(
get_endpoint() + "/user/invoice",