From a50ac7310f6f374228e3991a246095037c03a884 Mon Sep 17 00:00:00 2001 From: Wim Brand Date: Tue, 6 Oct 2026 00:46:54 +0200 Subject: [PATCH] Tweak subscriptions some more --- svelte/src/home_page/FeatureTable.svelte | 353 ------------------ svelte/src/lib/NovaAPI.ts | 14 + .../src/user_home/HotlinkProgressBar.svelte | 16 +- svelte/src/user_home/SharingSettings.svelte | 17 +- .../src/user_home/StorageProgressBar.svelte | 19 +- svelte/src/user_home/Transactions.svelte | 12 +- .../dashboard/CardPrepaidTransactions.svelte | 4 +- .../dashboard/CardSubscription.svelte | 40 +- .../src/user_home/dashboard/CardUsage.svelte | 4 +- 9 files changed, 107 insertions(+), 372 deletions(-) delete mode 100644 svelte/src/home_page/FeatureTable.svelte diff --git a/svelte/src/home_page/FeatureTable.svelte b/svelte/src/home_page/FeatureTable.svelte deleted file mode 100644 index c23ff43..0000000 --- a/svelte/src/home_page/FeatureTable.svelte +++ /dev/null @@ -1,353 +0,0 @@ - - -
-

- Nova features two different payment modes. We offer a monthly - subscription which is managed by Patreon, and a Prepaid subscription - which supports a dozen different payment providers. With Prepaid you pay - in advance to charge your credit, then usage will be subtracted from - your account credit. For low usage Prepaid is usually better as the - monthly fee is much lower. -

-
- -
-
-
-
- Free -
-
- Pro -
-
- Prepaid -
- -
- Recurring price -
-
- None -
-
- - {#snippet label()} - - €4 / month or - €40 / year - - {/snippet} - The Pro subscription is managed by Patreon. Patreon's own fees - and sales tax will be added to this price. After paying you need - to link your Nova account to Patreon to activate the plan. - -
-
- - {#snippet label()} - €1 / month minimum - {/snippet} -

- The minimum fee is only charged when usage is less than €1. - This calculation is per day, the €1 amount is divided by the - number of days in the month and if your usage is lower than - that, you will be charged the minimum fee. -

-
-
- - -
- - {#snippet label()} - 6 GB per day - {/snippet} -

- Free users are limited to downloading 6 GB per day, this - limit is linked to your IP address, even if you are logged - in to an account. -

-

- When the download limit is exceeded the download speed is - reduced to 1 MiB/s. You can have at most three concurrent - downloads running. -

-
-
-
- - {#snippet label()} - 4 TB per 30 days - {/snippet} -

- The transfer limit is used for downloading, sharing and - hotlinking files. -

-

- Paid plans do not have a concurrent connection limit. -

-
-
-
- - {#snippet label()} - €1 per TB transferred - {/snippet} -

- Prepaid does not have a transfer limit, instead you are - charged for what you use at a rate of €1 per terabyte - downloaded. This applies to downloading your own files, - other people's files and others downloading your files (if - you have hotlinking enabled in your account settings). -

-

- Paid plans do not have a concurrent connection limit. -

-
-
- - -
- Hotlinking not supported
- Hotlinked files get blocked -
-
- Hotlinking supported
- Hotlinking uses your transfer limit -
- -
- Storage -
-
- No limit
- Files expire when they are not downloaded -
-
- €4 / TB / month
- No limit, you pay for what you use -
- - -
- - {#snippet label()} - 120 days (4 months) - {/snippet} -

- Files expire when they have not been downloaded in the last - 120 days. A download is counted when more than 10% of the - whole file was downloaded in a single request. -

-
-
-
- - {#snippet label()} - 240 days (8 months) - {/snippet} -

- The Pro plan has 240 day file expiry. The same rules apply - as the free plan. Higher Patreon subscription plans are - available where files do not expire at all. -

-
-
-
- - {#snippet label()} - Files do not expire - {/snippet} -

- Files don't expire while your Prepaid plan is active. If - your credit runs out you have one week to top up your - balance. If you fail to do so your files will revert to the - regular file expiry rules. -

-
-
- -
- Download page customization -
-
- None -
-
- None -
-
- Theme, background, header and footer image can be customized -
- -
- Max file size -
-
- 20 GB per file -
-
- 100 GB per file -
- -
- Payment processors -
-
- None -
-
- PayPal, Credit/debit -
-
- PayPal, - Bitcoin, - Litecoin, - Monero -
- -
-
- Free -
-
- {#if $user !== null && $user.subscription.id === "patreon_1"} - You have this plan
- Thank you for supporting Nova! - {:else} - - € 4 per month - - or - - € 40 per year! - -
- (Excluding tax) -
- Subscription managed by Patreon - {/if} -
-
- {#if $user === null} - - Account required
- - login - Log in - - or - - how_to_reg - Register - -
- Payments processed by Mollie
- No recurring payments - {:else} - - {#if $user.subscription.type === ""} - - Deposit credit - - to activate Prepaid - {:else if $user.subscription.type === "patreon"} - Patreon subscription active. Prepaid cannot be activated - {:else if $user.subscription.type === "prepaid"} - Prepaid subscription is active
- Current balance -
- - Top up my credit - - {/if} - {/if} -
-
-
- -
-

Other plans available on Patreon

- -
- - diff --git a/svelte/src/lib/NovaAPI.ts b/svelte/src/lib/NovaAPI.ts index 2db0d88..9930ac1 100644 --- a/svelte/src/lib/NovaAPI.ts +++ b/svelte/src/lib/NovaAPI.ts @@ -208,6 +208,20 @@ export const subscription_periods: SubscriptionPeriod[] = [ // same value the server divides the monthly fee by export const days_per_month = 365.25 / 12 +// The price of the subscription period the user is in. This is also how far +// the balance can go below zero before usage above the plan is refused +export const period_price = (u: User) => { + const period = subscription_periods.find(p => p.months === u.subscription_months) + return period === undefined ? 0 : + u.subscription.monthly_fee * period.months * period.discount +} + +// Whether usage above a limit of the plan is billed instead of refused. price +// is what the plan charges for that usage. The server does the same check in +// billsExtra +export const bills_extra = (u: User, price: number) => + u.usage_based_billing && price > 0 && u.balance_micro_eur >= -period_price(u) + export const get_misc_subscriptions = async () => { return await check_response( await fetch(get_endpoint() + "/misc/subscriptions") diff --git a/svelte/src/user_home/HotlinkProgressBar.svelte b/svelte/src/user_home/HotlinkProgressBar.svelte index ebef4e0..291de41 100644 --- a/svelte/src/user_home/HotlinkProgressBar.svelte +++ b/svelte/src/user_home/HotlinkProgressBar.svelte @@ -2,6 +2,7 @@ import ProgressBar from "util/ProgressBar.svelte"; import { formatDataVolume, formatEuros } from "util/Formatting" import { user } from "lib/UserStore"; +import { bills_extra } from "lib/NovaAPI"; let { total = 0, used = 0 }: { total?: number; @@ -10,8 +11,11 @@ let { total = 0, used = 0 }: { let frac = $derived(used / total) let bill_shock = $derived($user !== null && $user.monthly_transfer_cap === total) -let billable = $derived($user !== null && $user.subscription.price_per_tb_bandwidth > 0) -let billed = $derived(billable && $user.usage_based_billing) +let price = $derived($user === null ? 0 : $user.subscription.price_per_tb_bandwidth) +let billed = $derived($user !== null && bills_extra($user, price)) + +// Usage based billing is on, but the balance is too far below zero for it +let overdrawn = $derived($user !== null && $user.usage_based_billing && price > 0 && !billed) let included = $derived($user === null ? 0 : $user.subscription.monthly_transfer_cap) @@ -50,6 +54,14 @@ let included = $derived($user === null ? 0 : $user.subscription.monthly_transfer This is your bill shock limit. Increase or disable the limit to continue sharing files.

+ {:else if overdrawn} +

+ Your balance is too far below zero to bill more data transfer. + Top up your credit to continue sharing files. +

+ + paid Top up credit + {:else}

Upgrade your plan or enable diff --git a/svelte/src/user_home/SharingSettings.svelte b/svelte/src/user_home/SharingSettings.svelte index 2f3f548..81304a3 100644 --- a/svelte/src/user_home/SharingSettings.svelte +++ b/svelte/src/user_home/SharingSettings.svelte @@ -3,11 +3,12 @@ import { onMount } from "svelte"; import { formatDataVolume, formatEuros } from "util/Formatting"; import ProgressBar from "util/ProgressBar.svelte"; import { loading_run } from "lib/Loading"; -import { get_endpoint, put_user } from 'lib/NovaAPI'; +import { get_endpoint, period_price, put_user } from 'lib/NovaAPI'; import SuccessMessage from 'util/SuccessMessage.svelte'; import { user } from "lib/UserStore"; let success_message: SuccessMessage = $state() + let transfer_cap = $state($user === null ? 0 : $user.monthly_transfer_cap / 1e12) const update_user = async (e: SubmitEvent) => { @@ -99,6 +100,12 @@ onMount(async () => { {formatEuros($user.subscription.price_per_tb_bandwidth, 2)} per TB for data transfer.

+

+ This usage is charged from your account credit afterwards. When + your balance is more than {formatEuros(period_price($user), 2)} below zero + (the price of your subscription period) the limits of your plan + apply again, until you top up your credit. +