Add sponsors system with time slider, LNbits invoices, and UX improvements
- Sponsors table, LNbits createInvoice, webhook handler - Sponsor routes: create, homepage, list, my-ads, click, extend, check-payment - Admin routes for sponsor management - Frontend: SponsorForm, SponsorTimeSlider, SponsorCard, SponsorsSection - Sponsors page, My Ads page, homepage sponsor block - Header login dropdown with My Ads, Create Sponsor - Transactions integration for sponsor payments - View/click tracking - OG meta fetch for sponsor images - Sponsor modal spacing, invoice polling fallback - Remove Lightning address and Category fields from sponsor form Made-with: Cursor
This commit is contained in:
+55
-30
@@ -7,6 +7,9 @@ import { ClaimWizard } from "./components/ClaimWizard";
|
||||
import { StatsSection } from "./components/StatsSection";
|
||||
import { DepositSection } from "./components/DepositSection";
|
||||
import { TransactionsPage } from "./pages/TransactionsPage";
|
||||
import { SponsorsPage } from "./pages/SponsorsPage";
|
||||
import { MyAdsPage } from "./pages/MyAdsPage";
|
||||
import { SponsorsSection } from "./components/SponsorsSection";
|
||||
|
||||
const FaucetSvg = () => (
|
||||
<svg className="faucet-svg" viewBox="0 0 100 140" xmlns="http://www.w3.org/2000/svg">
|
||||
@@ -29,9 +32,13 @@ export default function App() {
|
||||
const [loginMethod, setLoginMethod] = useState<LoginMethod | null>(null);
|
||||
const [statsRefetchTrigger, setStatsRefetchTrigger] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const refreshAuth = useCallback(() => {
|
||||
const token = getToken();
|
||||
if (!token) return;
|
||||
if (!token) {
|
||||
setPubkey(null);
|
||||
setLoginMethod(null);
|
||||
return;
|
||||
}
|
||||
getAuthMe()
|
||||
.then((r) => {
|
||||
setPubkey(r.pubkey);
|
||||
@@ -44,6 +51,13 @@ export default function App() {
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
refreshAuth();
|
||||
const onAuthChanged = () => refreshAuth();
|
||||
window.addEventListener("auth-changed", onAuthChanged);
|
||||
return () => window.removeEventListener("auth-changed", onAuthChanged);
|
||||
}, [refreshAuth]);
|
||||
|
||||
const handlePubkeyChange = useCallback((pk: string | null, method?: LoginMethod) => {
|
||||
setPubkey(pk);
|
||||
setLoginMethod(pk ? (method ?? "nip98") : null);
|
||||
@@ -62,40 +76,33 @@ export default function App() {
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<div className="app">
|
||||
<Header pubkey={pubkey} onLogout={handleLogout} />
|
||||
<Header pubkey={pubkey} onLogout={handleLogout} onLoginSuccess={handlePubkeyChange} />
|
||||
<div className="topbar" />
|
||||
<div className="app-body">
|
||||
<Routes>
|
||||
<Route
|
||||
path="/"
|
||||
element={
|
||||
<div className="container">
|
||||
<aside className="sidebar sidebar-left">
|
||||
<div className="funding-panel">
|
||||
<DepositSection />
|
||||
</div>
|
||||
<div className="sidebar-links">
|
||||
<p className="sidebar-links-title">Sats available</p>
|
||||
<p className="label">Other Sites:</p>
|
||||
<a href="https://bitcoin.org/en/" target="_blank" rel="noopener noreferrer">
|
||||
Bitcoin.org
|
||||
</a>
|
||||
<a href="https://bitcoin.org/en/buy" target="_blank" rel="noopener noreferrer">
|
||||
Bitcoin Market
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
<main className="main">
|
||||
<div className="header">
|
||||
<FaucetSvg />
|
||||
<h1>Sats Faucet</h1>
|
||||
</div>
|
||||
<ClaimWizard pubkey={pubkey} loginMethod={loginMethod} onPubkeyChange={handlePubkeyChange} onClaimSuccess={handleClaimSuccess} />
|
||||
</main>
|
||||
<aside className="sidebar sidebar-right">
|
||||
<StatsSection refetchTrigger={statsRefetchTrigger} />
|
||||
</aside>
|
||||
</div>
|
||||
<>
|
||||
<div className="container">
|
||||
<aside className="sidebar sidebar-left">
|
||||
<div className="funding-panel">
|
||||
<DepositSection />
|
||||
</div>
|
||||
</aside>
|
||||
<main className="main">
|
||||
<div className="header">
|
||||
<FaucetSvg />
|
||||
<h1>Sats Faucet</h1>
|
||||
</div>
|
||||
<ClaimWizard pubkey={pubkey} loginMethod={loginMethod} onPubkeyChange={handlePubkeyChange} onClaimSuccess={handleClaimSuccess} />
|
||||
</main>
|
||||
<aside className="sidebar sidebar-right">
|
||||
<StatsSection refetchTrigger={statsRefetchTrigger} />
|
||||
</aside>
|
||||
</div>
|
||||
<SponsorsSection />
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
@@ -108,6 +115,24 @@ export default function App() {
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/sponsors"
|
||||
element={
|
||||
<div className="sponsors-route">
|
||||
<SponsorsPage />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/my-ads"
|
||||
element={
|
||||
<div className="container container--single">
|
||||
<main className="main main--full">
|
||||
<MyAdsPage />
|
||||
</main>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</Routes>
|
||||
</div>
|
||||
<Footer />
|
||||
|
||||
Reference in New Issue
Block a user