87 lines
3.5 KiB
TypeScript
87 lines
3.5 KiB
TypeScript
import * as m from '$lib/paraglide/messages';
|
|
|
|
/**
|
|
* Supporter configuration.
|
|
*
|
|
* The frontend stays fully static and open source; the only server piece is the
|
|
* tiny `drizzli-paywall` verify API (a separate, self-hosted repo). Point the
|
|
* build at your deployment with the `VITE_SUPPORTER_*` env vars (e.g. in a
|
|
* `.env` file), otherwise the sensible drizz.li defaults are used. The
|
|
* pre-rename `VITE_PAYWALL_*` names still work.
|
|
*/
|
|
|
|
const env = import.meta.env as Record<string, string | undefined>;
|
|
|
|
const stripTrailingSlash = (url: string): string => url.replace(/\/+$/, '');
|
|
|
|
/**
|
|
* Master switch for the supporter features. While this is `false` everything
|
|
* supporter-related is parked: the nav entry points are hidden, no key is
|
|
* verified, and every gated page renders as if the visitor were a supporter.
|
|
* The logic stays in place — set `VITE_SUPPORTER_ENABLED=true` (or default this
|
|
* to `true`) to bring it back.
|
|
*/
|
|
export const SUPPORTER_ENABLED = env.VITE_SUPPORTER_ENABLED === 'true';
|
|
|
|
/** Base URL of the self-hosted verify API (drizzli-paywall). */
|
|
export const SUPPORTER_API_BASE = stripTrailingSlash(
|
|
env.VITE_SUPPORTER_API_BASE ?? env.VITE_PAYWALL_API_BASE ?? 'https://support.drizz.li'
|
|
);
|
|
|
|
/** Where prospective supporters go to sign up (the verify API's signup form). */
|
|
export const SIGNUP_URL =
|
|
env.VITE_SUPPORTER_SIGNUP_URL ?? env.VITE_PAYWALL_SIGNUP_URL ?? `${SUPPORTER_API_BASE}/`;
|
|
|
|
// ─── Location-based pricing ──────────────────────────────────────────────────
|
|
// The signup form charges 3 in the visitor's currency (EUR / USD / CHF), picked
|
|
// from their location. Mirror that here so the supporter copy matches. Detection
|
|
// is timezone/locale based (no network geo lookup) and guarded for SSR.
|
|
|
|
const CURRENCY_SYMBOL: Record<string, string> = { EUR: '€', USD: '$', CHF: 'CHF' };
|
|
const US_ZONES =
|
|
/^America\/(New_York|Detroit|Chicago|Denver|Boise|Phoenix|Los_Angeles|Anchorage|Adak|Juneau|Sitka|Nome|Yakutat|Menominee|Indiana|Kentucky|North_Dakota)/;
|
|
|
|
export type SupporterCurrency = 'EUR' | 'USD' | 'CHF';
|
|
|
|
export function detectCurrency(): SupporterCurrency {
|
|
if (typeof Intl === 'undefined') return 'EUR';
|
|
let tz = '';
|
|
try {
|
|
tz = Intl.DateTimeFormat().resolvedOptions().timeZone || '';
|
|
} catch {
|
|
/* ignore */
|
|
}
|
|
if (/Zurich|Vaduz/.test(tz)) return 'CHF';
|
|
let region = '';
|
|
try {
|
|
if (typeof navigator !== 'undefined') {
|
|
region = new Intl.Locale(navigator.language).maximize().region || '';
|
|
}
|
|
} catch {
|
|
/* ignore */
|
|
}
|
|
if (region === 'CH') return 'CHF';
|
|
if (region === 'US' || US_ZONES.test(tz)) return 'USD';
|
|
return 'EUR';
|
|
}
|
|
|
|
/** Display price for the locked panel, e.g. "€3 / month" or "CHF 3 / Monat". */
|
|
export function getSupporterPrice(): string {
|
|
// VITE_PREMIUM_PRICE is the pre-rename name, still honoured so an existing
|
|
// deployment's .env keeps working.
|
|
const configured = env.VITE_SUPPORTER_PRICE ?? env.VITE_PREMIUM_PRICE;
|
|
if (configured) return configured;
|
|
const currency = detectCurrency();
|
|
const symbol = CURRENCY_SYMBOL[currency];
|
|
const amount = currency === 'CHF' ? `${symbol} 3` : `${symbol}3`;
|
|
return m.supporter_price_per_month({ amount });
|
|
}
|
|
|
|
/** Short, human list of what supporting unlocks (shown on the locked panel).
|
|
* A function, not a constant: the copy has to follow the active locale. */
|
|
export const SUPPORTER_PERKS = (): string[] => [
|
|
m.supporter_perk_historical(),
|
|
m.supporter_perk_seasonal(),
|
|
m.supporter_perk_future()
|
|
];
|