diff --git a/backend/src/routes/sponsor.ts b/backend/src/routes/sponsor.ts index 7936b0d..bd38d61 100644 --- a/backend/src/routes/sponsor.ts +++ b/backend/src/routes/sponsor.ts @@ -9,6 +9,11 @@ const router = Router(); const SNAP_DAYS = [1, 3, 7, 14, 30, 60, 90, 180, 365]; +/** Public endpoint: returns base sponsor price per day for display. */ +router.get("/price", (_req: Request, res: Response) => { + res.json({ baseSponsorPricePerDay: config.baseSponsorPricePerDay }); +}); + function snapDays(days: number): number { let best = SNAP_DAYS[0]; for (const d of SNAP_DAYS) { diff --git a/frontend/src/api.ts b/frontend/src/api.ts index 93749be..18781de 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -375,6 +375,14 @@ export interface SponsorCreateResult { status: string; } +export interface SponsorPrice { + baseSponsorPricePerDay: number; +} + +export async function getSponsorPrice(): Promise { + return request("/sponsor/price"); +} + export async function getSponsorHomepage(): Promise { return request("/sponsor/homepage"); } diff --git a/frontend/src/components/SponsorForm.tsx b/frontend/src/components/SponsorForm.tsx index 8f1052d..bd701f2 100644 --- a/frontend/src/components/SponsorForm.tsx +++ b/frontend/src/components/SponsorForm.tsx @@ -2,10 +2,8 @@ import { useState, useCallback, useMemo } from "react"; import { postSponsorCreate, type SponsorCreateResult } from "../api"; import { SponsorTimeSlider } from "./SponsorTimeSlider"; -const BASE_PRICE = 200; - -function calculatePrice(days: number): number { - let price = BASE_PRICE * days; +function calculatePrice(basePricePerDay: number, days: number): number { + let price = basePricePerDay * days; if (days >= 180) price *= 0.7; else if (days >= 90) price *= 0.8; else if (days >= 30) price *= 0.9; @@ -13,11 +11,12 @@ function calculatePrice(days: number): number { } interface SponsorFormProps { + basePricePerDay: number; onSuccess?: (result: SponsorCreateResult) => void; onCancel?: () => void; } -export function SponsorForm({ onSuccess, onCancel }: SponsorFormProps) { +export function SponsorForm({ basePricePerDay, onSuccess, onCancel }: SponsorFormProps) { const [title, setTitle] = useState(""); const [description, setDescription] = useState(""); const [linkUrl, setLinkUrl] = useState(""); @@ -26,7 +25,7 @@ export function SponsorForm({ onSuccess, onCancel }: SponsorFormProps) { const [loading, setLoading] = useState(false); const [error, setError] = useState(null); - const priceSats = useMemo(() => calculatePrice(durationDays), [durationDays]); + const priceSats = useMemo(() => calculatePrice(basePricePerDay, durationDays), [basePricePerDay, durationDays]); const handleSubmit = useCallback( async (e: React.FormEvent) => { diff --git a/frontend/src/pages/SponsorsPage.tsx b/frontend/src/pages/SponsorsPage.tsx index c81d576..78205a0 100644 --- a/frontend/src/pages/SponsorsPage.tsx +++ b/frontend/src/pages/SponsorsPage.tsx @@ -1,6 +1,6 @@ import { useState, useEffect } from "react"; import { useSearchParams } from "react-router-dom"; -import { getSponsorList, getToken, postSponsorExtend } from "../api"; +import { getSponsorList, getSponsorPrice, getToken, postSponsorExtend } from "../api"; import { SponsorCard } from "../components/SponsorCard"; import { SponsorForm } from "../components/SponsorForm"; import { SponsorInvoiceModal } from "../components/SponsorInvoiceModal"; @@ -27,6 +27,7 @@ export function SponsorsPage() { const [extendDuration, setExtendDuration] = useState(30); const [extendLoading, setExtendLoading] = useState(false); const [extendError, setExtendError] = useState(null); + const [basePricePerDay, setBasePricePerDay] = useState(null); useEffect(() => { document.title = "Sponsors — Sats Faucet"; @@ -41,6 +42,12 @@ export function SponsorsPage() { .finally(() => setLoading(false)); }; + useEffect(() => { + getSponsorPrice() + .then((p) => setBasePricePerDay(p.baseSponsorPricePerDay)) + .catch(() => setBasePricePerDay(200)); // fallback if fetch fails + }, []); + useEffect(() => { let cancelled = false; setLoading(true); @@ -127,7 +134,9 @@ export function SponsorsPage() {

Pricing

-

Base: 200 sats/day. Discounts: 30+ days 10% off, 90+ days 20% off, 180+ days 30% off.

+

+ Base: {basePricePerDay != null ? basePricePerDay.toLocaleString() : "…"} sats/day. Discounts: 30+ days 10% off, 90+ days 20% off, 180+ days 30% off. +

@@ -158,10 +167,15 @@ export function SponsorsPage() { setFormOpen(false)} title="Create Sponsor" variant="sponsor"> - setFormOpen(false)} - /> + {basePricePerDay != null ? ( + setFormOpen(false)} + /> + ) : ( +
Loading pricing…
+ )}
Total: - {Math.round(200 * extendDuration * (extendDuration >= 180 ? 0.7 : extendDuration >= 90 ? 0.8 : extendDuration >= 30 ? 0.9 : 1)).toLocaleString()} sats + {basePricePerDay != null + ? Math.round( + basePricePerDay * extendDuration * (extendDuration >= 180 ? 0.7 : extendDuration >= 90 ? 0.8 : extendDuration >= 30 ? 0.9 : 1) + ).toLocaleString() + : "…"}{" "} + sats
{extendError &&

{extendError}

}