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

@@ -21,6 +21,8 @@ export type User = {
filesystem_node_count: number,
is_admin: boolean,
balance_micro_eur: number,
subscription_months: number,
subscription_period_end: string,
monthly_transfer_cap: number,
monthly_transfer_used: number,
file_viewer_branding: Map<string, string>,
@@ -29,12 +31,15 @@ export type User = {
checkout_country: string,
checkout_name: string,
checkout_provider: string,
usage_based_billing: boolean,
}
export type Subscription = {
id: string,
name: string,
type: string,
monthly_fee: number,
min_months: number,
file_size_limit: number,
storage_limit: number,
price_per_tb_storage: number,
@@ -156,13 +161,10 @@ export const put_user = async (data: Object) => {
{ method: "PUT", body: dict_to_form(data) },
))
// Update the user store
user.update((user: User) => {
for (let key of Object.keys(data)) {
user[key] = data[key]
}
return user
})
// Fetch the user again to update the store. The submitted fields don't
// always match the fields on the user object, and the server can change or
// ignore them, so we can't apply the submitted values locally
await request_user()
}
export const logout_user = async (redirect_path: string) => {
@@ -183,3 +185,49 @@ export type VATRate = {
export const get_misc_vat_rate = async (country_code: string) => {
return await check_response(await fetch(get_endpoint() + "/misc/vat_rate/" + country_code)) as VATRate
}
// The available subscription plans. The discount for a longer subscription
// period is applied by the server too, see SubscriptionDiscount in Go
export type SubscriptionPeriod = {
months: number,
discount: number,
name: string,
label: string,
}
export const subscription_periods: SubscriptionPeriod[] = [
{ months: 1, discount: 1, name: "Monthly", label: "Monthly" },
{ months: 6, discount: 0.9, name: "Bi-yearly", label: "Bi-yearly (save 10%)" },
{ months: 12, discount: 0.8, name: "Yearly", label: "Yearly (save 20%)" },
]
// Subscriptions are charged per day. This is the average length of a month, the
// same value the server divides the monthly fee by
export const days_per_month = 365.25 / 12
export const get_misc_subscriptions = async () => {
return await check_response(
await fetch(get_endpoint() + "/misc/subscriptions")
) as Subscription[]
}
export type Invoice = {
id: string,
time: Date,
amount: number,
vat: number,
country: string,
payment_gateway: string,
payment_method: string,
status: "open" | "processing" | "paid" | "expired" | "canceled",
}
export const get_user_invoices = async (): Promise<Invoice[]> => {
const invoices = await check_response(
await fetch(get_endpoint() + "/user/invoice"),
) as Invoice[]
invoices.forEach(row => row.time = new Date(row.time))
invoices.sort((a, b) => b.time.getTime() - a.time.getTime())
return invoices
}