(null);
- const [copied, setCopied] = useState(false);
-
- useEffect(() => {
- let active = true;
- QRCode.toDataURL(SILENT_URI, { width: 200, margin: 1 })
- .then((url) => { if (active) setQr(url); })
- .catch(() => { if (active) setQr(null); });
- return () => { active = false; };
- }, []);
-
- const copy = async () => {
- try {
- await navigator.clipboard.writeText(SILENT_NAME);
- setCopied(true);
- setTimeout(() => setCopied(false), 1500);
- } catch { /* clipboard blocked */ }
- };
-
- return (
-
-
-
π΅οΈ
-
-
- {t('walletUi.supporters.silentTitle')}
-
-
{t('walletUi.supporters.silentDesc')}
-
-
-
-
- {qr && (
-

- )}
-
-
{SILENT_NAME}
-
-
- {t('walletUi.supporters.silentWallets')}
-
-
-
-
- );
-}
// βββ Section header βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
@@ -322,6 +263,7 @@ interface SupporterEntry {
receiptId?: string;
note?: string;
anonymous?: boolean;
+ at?: number;
}
const TIER_META = {
@@ -406,6 +348,7 @@ function SupporterRow({ rank, entry }: { rank: number; entry: SupporterEntry })
|| (entry.npub ? `${entry.npub.slice(0, 12)}β¦${entry.npub.slice(-6)}` : t('walletUi.supporters.anonymousBacker'));
const avatar = entry.anonymous ? undefined : (entry.logo || meta?.picture);
const tier = TIER_META[tierOf(entry.sats)];
+ const when = entry.at ? formatDistanceToNow(new Date(entry.at * 1000), { addSuffix: true }) : undefined;
const profileHref = !entry.anonymous && entry.npub ? `/${entry.npub}` : undefined;
const linkHref = profileHref || entry.url;
const proofUrl = entry.txid
@@ -456,6 +399,7 @@ function SupporterRow({ rank, entry }: { rank: number; entry: SupporterEntry })
{tier.emoji} {t(tier.key)}
{entry.note && !entry.anonymous && {entry.note}}
+ {when && Β· {when}}
@@ -524,6 +468,7 @@ export default function SupportersPage() {
txid: b.txid,
note: b.note,
anonymous: b.anonymous,
+ at: b.at,
});
});
for (const z of zappers) {
@@ -533,6 +478,7 @@ export default function SupportersPage() {
existing.sats += z.sats;
existing.zap = true;
existing.receiptId = z.receiptId;
+ if (z.createdAt && (!existing.at || z.createdAt > existing.at)) existing.at = z.createdAt;
} else {
map.set(npub, {
key: npub,
@@ -543,12 +489,15 @@ export default function SupportersPage() {
angor: false,
zap: true,
receiptId: z.receiptId,
+ at: z.createdAt,
});
}
}
return [...map.values()].sort((a, b) => b.sats - a.sats);
}, [zappers]);
+ const latestAt = supporters.reduce((m, s) => Math.max(m, s.at ?? 0), 0);
+
// `growth-stats` is persisted, so an older cache may lack newer fields β guard every read.
const num = (v: number | undefined) => v ?? 0;
const labTotal = stats
@@ -601,6 +550,12 @@ export default function SupportersPage() {
{t('walletUi.supporters.backAngor')}
+
+ {t('walletUi.supporters.donatePageLink')} β
+
{/* ββ 1. Support ββ */}
@@ -612,24 +567,7 @@ export default function SupportersPage() {
color="#f7931a"
/>
- {/* Ways to support β purpose-first trio (each scrolls to its rail). */}
-
- {[
- { id: 'support-lightning', emoji: 'β‘', title: t('walletUi.supporters.wayLightningTitle'), desc: t('walletUi.supporters.wayLightningDesc') },
- { id: 'support-silent', emoji: 'π΅οΈ', title: t('walletUi.supporters.waySilentTitle'), desc: t('walletUi.supporters.waySilentDesc') },
- { id: 'support-angor', emoji: 'β', title: t('walletUi.supporters.wayAngorTitle'), desc: t('walletUi.supporters.wayAngorDesc') },
- ].map((w) => (
-
- ))}
-
+
{/* Lightning rail β the in-app way to chip in (zap publicly or pay quietly). */}
@@ -640,32 +578,8 @@ export default function SupportersPage() {
-
-
π§‘β‘
-
{t('walletUi.supporters.backTitle')}
-
- {t('walletUi.supporters.backDesc')}
-
-
-
- {t('walletUi.supporters.donateNote')}
-
-
- {t('walletUi.supporters.joinSupporters', { count: supporters.length })}
-
+
@@ -762,6 +676,13 @@ export default function SupportersPage() {
{t('walletUi.supporters.quietNote')}
+ {latestAt > 0 && (
+
+ {t('walletUi.supporters.updatedAt', {
+ when: formatDistanceToNow(new Date(latestAt * 1000), { addSuffix: true }),
+ })}
+
+ )}
>
) : (