diff --git a/src/components/CommunityDetailPage.tsx b/src/components/CommunityDetailPage.tsx index 8d76a224..ff76e319 100644 --- a/src/components/CommunityDetailPage.tsx +++ b/src/components/CommunityDetailPage.tsx @@ -2,15 +2,18 @@ import { useMemo, useCallback, useState } from 'react'; import { Link, useNavigate } from 'react-router-dom'; import { nip19 } from 'nostr-tools'; import { + CalendarClock, CalendarDays, ChevronLeft, Crown, HandHeart, Info, + MapPin, Megaphone, MoreVertical, Pencil, Shield, + Target, Share2, UserCheck, UserMinus, @@ -25,8 +28,10 @@ import { PostActionBar } from '@/components/PostActionBar'; import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; +import { Card } from '@/components/ui/card'; import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'; +import { Progress } from '@/components/ui/progress'; import { Skeleton } from '@/components/ui/skeleton'; import { DonateDialog } from '@/components/DonateDialog'; import { NoteContent } from '@/components/NoteContent'; @@ -51,13 +56,17 @@ import { } from '@/hooks/useOrganizationActivity'; import { useProfileUrl } from '@/hooks/useProfileUrl'; import { useToast } from '@/hooks/useToast'; +import { useSubmissionZapTotals } from '@/hooks/useSubmissionZapTotals'; import { CommunityModerationContext } from '@/contexts/CommunityModerationContext'; import { useLayoutOptions } from '@/contexts/LayoutContext'; import { applyCommunityModerationToEvents, parseCommunityEvent } from '@/lib/communityUtils'; import type { ParsedCampaign } from '@/lib/campaign'; import type { Action } from '@/hooks/useActions'; +import { formatSats, satsToUSDWhole } from '@/lib/bitcoin'; +import { getGeoDisplayName } from '@/lib/countries'; +import { DEFAULT_COVER_IMAGE } from '@/lib/defaultActionCovers'; import { formatNumber } from '@/lib/formatNumber'; -import { genUserName } from '@/lib/genUserName'; +import { genUserName, getDisplayName } from '@/lib/genUserName'; import { sanitizeUrl } from '@/lib/sanitizeUrl'; import { cn } from '@/lib/utils'; @@ -185,8 +194,57 @@ function formatShelfEventDate(event: NostrEvent): string { return shelfDateFormatter.format(new Date(ts * 1000)); } +function formatPledgeAmount(sats: number, btcPrice: number | undefined): string { + if (btcPrice) return satsToUSDWhole(sats, btcPrice); + return `${formatSats(sats)} sats`; +} + +function formatPledgeDeadline(unixSeconds: number): { label: string; isPast: boolean } { + const now = Math.floor(Date.now() / 1000); + const diff = unixSeconds - now; + if (diff <= 0) return { label: 'Ended', isPast: true }; + const days = Math.ceil(diff / 86_400); + if (days <= 1) return { label: 'Ends today', isPast: false }; + if (days < 30) return { label: `${days} days left`, isPast: false }; + const months = Math.round(days / 30); + return { label: `${months} mo left`, isPast: false }; +} + +function PledgeShelfProgress({ pledgedSats, fundedSats, btcPrice }: { pledgedSats: number; fundedSats: number; btcPrice: number | undefined }) { + const pct = pledgedSats > 0 ? Math.min(100, Math.round((fundedSats / pledgedSats) * 100)) : 0; + return ( +
+ {pledge.description} +
+ )}{pledge.description}
- )} -