@burdenoff/microfe-comradecircle 2026.723.1 → 2026.730.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/comradecircle/ComradeCircleRoutes.d.ts.map +1 -1
  2. package/dist/comradecircle/ComradeCircleRoutes.js +11 -7
  3. package/dist/comradecircle/ComradeCircleRoutes.js.map +1 -1
  4. package/dist/comradecircle/hooks/useComSubscription.d.ts +18 -0
  5. package/dist/comradecircle/hooks/useComSubscription.d.ts.map +1 -0
  6. package/dist/comradecircle/hooks/useComSubscription.js +110 -0
  7. package/dist/comradecircle/hooks/useComSubscription.js.map +1 -0
  8. package/dist/comradecircle/hooks/useComradeCircleApi.d.ts +51 -1
  9. package/dist/comradecircle/hooks/useComradeCircleApi.d.ts.map +1 -1
  10. package/dist/comradecircle/hooks/useComradeCircleApi.js +435 -223
  11. package/dist/comradecircle/hooks/useComradeCircleApi.js.map +1 -1
  12. package/dist/comradecircle/pages/circles/CircleDetailPage.d.ts.map +1 -1
  13. package/dist/comradecircle/pages/circles/CircleDetailPage.js +268 -266
  14. package/dist/comradecircle/pages/circles/CircleDetailPage.js.map +1 -1
  15. package/dist/comradecircle/pages/events/EventDetailPage.d.ts.map +1 -1
  16. package/dist/comradecircle/pages/events/EventDetailPage.js +84 -82
  17. package/dist/comradecircle/pages/events/EventDetailPage.js.map +1 -1
  18. package/dist/comradecircle/pages/members/MemberProfilePage.d.ts.map +1 -1
  19. package/dist/comradecircle/pages/members/MemberProfilePage.js +251 -129
  20. package/dist/comradecircle/pages/members/MemberProfilePage.js.map +1 -1
  21. package/dist/comradecircle/pages/monetization/MonetizationPage.d.ts +13 -0
  22. package/dist/comradecircle/pages/monetization/MonetizationPage.d.ts.map +1 -0
  23. package/dist/comradecircle/pages/monetization/MonetizationPage.js +596 -0
  24. package/dist/comradecircle/pages/monetization/MonetizationPage.js.map +1 -0
  25. package/dist/comradecircle/pages/posts/PostThreadPage.d.ts.map +1 -1
  26. package/dist/comradecircle/pages/posts/PostThreadPage.js +26 -24
  27. package/dist/comradecircle/pages/posts/PostThreadPage.js.map +1 -1
  28. package/dist/comradecircle/pages/profile/MyProfilePage.d.ts.map +1 -1
  29. package/dist/comradecircle/pages/profile/MyProfilePage.js +101 -96
  30. package/dist/comradecircle/pages/profile/MyProfilePage.js.map +1 -1
  31. package/dist/comradecircle/types/index.d.ts +126 -0
  32. package/dist/comradecircle/types/index.d.ts.map +1 -1
  33. package/dist/comradecircle/utils/shellBridge.d.ts +45 -0
  34. package/dist/comradecircle/utils/shellBridge.d.ts.map +1 -0
  35. package/dist/comradecircle/utils/shellBridge.js +19 -0
  36. package/dist/comradecircle/utils/shellBridge.js.map +1 -0
  37. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MonetizationPage.js","names":[],"sources":["../../../../src/comradecircle/pages/monetization/MonetizationPage.tsx"],"sourcesContent":["/**\n * MonetizationPage — creator-facing monetization management console (BOFF-4454).\n * @module comradecircle/pages/monetization\n *\n * Bounded pricing/catalog CATALOG core: a creator manages their own membership\n * tiers, paid events, and digital products (create + archive), and reviews the\n * tip intents they've received. Nothing here talks to a payment processor —\n * `comCreatorHasPaymentsEnabled` always resolves false today, so this page\n * never claims a real checkout exists. Live payment processing and payout/\n * revenue-split accounting are a separate, larger follow-up ticket.\n */\n\nimport { useState, type FormEvent, type ReactNode } from 'react';\nimport { Coins, Gift, Package, Plus, Ticket, Trash2, Users } from 'lucide-react';\nimport { Button, GlassCard, Input, Label, Textarea, Badge } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { EmptyState } from '../../components/EmptyState';\nimport { ErrorView, LoadingView } from '../../components/StateViews';\nimport {\n useComMyMembershipTiers,\n useComCreateMembershipTier,\n useComArchiveMembershipTier,\n useComMyPaidEvents,\n useComCreatePaidEvent,\n useComUpdatePaidEvent,\n useComArchivePaidEvent,\n useComMyDigitalProducts,\n useComCreateDigitalProduct,\n useComArchiveDigitalProduct,\n useComMyReceivedTips,\n} from '../../hooks';\nimport { notify, describeError } from '../../lib/toast';\nimport { cn } from '../../utils/cn';\nimport type {\n ComCreatorMembershipTier,\n ComPaidEvent,\n ComDigitalProduct,\n ComTipIntent,\n} from '../../types';\n\ntype Tab = 'tiers' | 'events' | 'products' | 'tips';\n\nconst TABS: { id: Tab; label: string; icon: typeof Users }[] = [\n { id: 'tiers', label: 'Membership tiers', icon: Users },\n { id: 'events', label: 'Paid events', icon: Ticket },\n { id: 'products', label: 'Digital products', icon: Package },\n { id: 'tips', label: 'Tips received', icon: Gift },\n];\n\nfunction formatMoney(amount: number, currency: string): string {\n try {\n return new Intl.NumberFormat(undefined, { style: 'currency', currency }).format(amount);\n } catch {\n return `${currency} ${amount.toFixed(2)}`;\n }\n}\n\n/** A quiet uppercase section header. */\nfunction SectionLabel({ children }: { children: ReactNode }) {\n return (\n <p className=\"text-xs font-semibold uppercase tracking-[0.08em] text-text-tertiary\">\n {children}\n </p>\n );\n}\n\n/** Every listing row shares this shell: name/title, price, status badge, archive. */\nfunction CatalogRow({\n title,\n subtitle,\n price,\n statusLabel,\n statusTone,\n onArchive,\n archiving,\n archiveLabel = 'Archive',\n}: {\n title: string;\n subtitle?: string | null;\n price: string;\n statusLabel: string;\n statusTone: 'positive' | 'neutral' | 'negative';\n onArchive?: () => void;\n archiving?: boolean;\n archiveLabel?: string;\n}) {\n return (\n <div className=\"flex flex-col gap-3 rounded-xl border border-border-seam bg-bg-surface p-4 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"min-w-0\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <h4 className=\"truncate text-sm font-semibold text-text-primary\">{title}</h4>\n <Badge\n variant={\n statusTone === 'positive'\n ? 'default'\n : statusTone === 'negative'\n ? 'destructive'\n : 'secondary'\n }\n >\n {statusLabel}\n </Badge>\n </div>\n {subtitle && <p className=\"mt-1 truncate text-xs text-text-secondary\">{subtitle}</p>}\n </div>\n <div className=\"flex shrink-0 items-center gap-3\">\n <span className=\"text-sm font-semibold tabular-nums text-text-primary\">{price}</span>\n {onArchive && (\n <Button variant=\"ghost\" size=\"sm\" onClick={onArchive} disabled={archiving}>\n <Trash2 className=\"mr-1.5 h-3.5 w-3.5\" /> {archiveLabel}\n </Button>\n )}\n </div>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Membership tiers\n// ---------------------------------------------------------------------------\n\nfunction CreateTierForm({ onDone }: { onDone: () => void }) {\n const create = useComCreateMembershipTier();\n const [name, setName] = useState('');\n const [description, setDescription] = useState('');\n const [price, setPrice] = useState('');\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault();\n const priceAmount = Number(price);\n if (!name.trim()) {\n notify.error('Name required', 'Give your tier a name.');\n return;\n }\n if (!Number.isFinite(priceAmount) || priceAmount < 0) {\n notify.error('Invalid price', 'Enter a price of 0 or more.');\n return;\n }\n try {\n await create.mutateAsync({\n name: name.trim(),\n description: description.trim() || null,\n priceAmount,\n billingInterval: 'MONTHLY',\n });\n notify.success('Membership tier created');\n setName('');\n setDescription('');\n setPrice('');\n onDone();\n } catch (err) {\n notify.error('Could not create tier', describeError(err));\n }\n };\n\n return (\n <form\n onSubmit={handleSubmit}\n className=\"grid gap-3 rounded-xl border border-border-seam bg-bg-surface p-4\"\n >\n <div className=\"grid gap-3 sm:grid-cols-[2fr_1fr]\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"tier-name\">Tier name</Label>\n <Input\n id=\"tier-name\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"e.g. Supporter\"\n required\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"tier-price\">Price / month (USD)</Label>\n <Input\n id=\"tier-price\"\n type=\"number\"\n min=\"0\"\n step=\"0.01\"\n value={price}\n onChange={(e) => setPrice(e.target.value)}\n placeholder=\"4.99\"\n required\n />\n </div>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"tier-description\">Perks description</Label>\n <Textarea\n id=\"tier-description\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n rows={2}\n placeholder=\"What supporters get at this tier\"\n />\n </div>\n <div className=\"flex justify-end\">\n <Button type=\"submit\" disabled={create.isPending}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> {create.isPending ? 'Creating…' : 'Create tier'}\n </Button>\n </div>\n </form>\n );\n}\n\nfunction TiersPanel() {\n const { data, isLoading, isError, refetch } = useComMyMembershipTiers();\n const archive = useComArchiveMembershipTier();\n const [showForm, setShowForm] = useState(false);\n const tiers = data?.items ?? [];\n\n const handleArchive = async (tier: ComCreatorMembershipTier) => {\n try {\n await archive.mutateAsync(tier.id);\n notify.success('Tier archived', tier.name);\n } catch (err) {\n notify.error('Could not archive tier', describeError(err));\n }\n };\n\n if (isLoading) return <LoadingView label=\"Loading your membership tiers…\" />;\n if (isError)\n return (\n <ErrorView message=\"We couldn't load your membership tiers.\" onRetry={() => refetch()} />\n );\n\n return (\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex items-center justify-between\">\n <SectionLabel>Your membership tiers</SectionLabel>\n <Button variant=\"outline\" size=\"sm\" onClick={() => setShowForm((v) => !v)}>\n <Plus className=\"mr-1.5 h-3.5 w-3.5\" /> New tier\n </Button>\n </div>\n {showForm && <CreateTierForm onDone={() => setShowForm(false)} />}\n {tiers.length === 0 ? (\n <EmptyState\n icon={<Users className=\"h-10 w-10\" />}\n title=\"No membership tiers yet\"\n description=\"Create a tier so fans can support you on a recurring basis.\"\n />\n ) : (\n <div className=\"flex flex-col gap-3\">\n {tiers.map((tier) => (\n <CatalogRow\n key={tier.id}\n title={tier.name}\n subtitle={tier.description}\n price={`${formatMoney(tier.priceAmount, tier.currency)}/${tier.billingInterval === 'YEARLY' ? 'yr' : 'mo'}`}\n statusLabel={tier.status}\n statusTone={tier.status === 'ACTIVE' ? 'positive' : 'neutral'}\n onArchive={tier.status === 'ACTIVE' ? () => handleArchive(tier) : undefined}\n archiving={archive.isPending}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Paid events\n// ---------------------------------------------------------------------------\n\nfunction CreateEventForm({ onDone }: { onDone: () => void }) {\n const create = useComCreatePaidEvent();\n const [title, setTitle] = useState('');\n const [price, setPrice] = useState('');\n const [capacity, setCapacity] = useState('');\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault();\n const priceAmount = Number(price);\n if (!title.trim()) {\n notify.error('Title required', 'Give your event a title.');\n return;\n }\n if (!Number.isFinite(priceAmount) || priceAmount < 0) {\n notify.error('Invalid price', 'Enter a ticket price of 0 or more.');\n return;\n }\n try {\n await create.mutateAsync({\n title: title.trim(),\n priceAmount,\n capacity: capacity.trim() ? Number(capacity) : null,\n });\n notify.success('Paid event created as a draft', 'Publish it once you’re ready.');\n setTitle('');\n setPrice('');\n setCapacity('');\n onDone();\n } catch (err) {\n notify.error('Could not create event', describeError(err));\n }\n };\n\n return (\n <form\n onSubmit={handleSubmit}\n className=\"grid gap-3 rounded-xl border border-border-seam bg-bg-surface p-4\"\n >\n <div className=\"grid gap-3 sm:grid-cols-[2fr_1fr_1fr]\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"event-title\">Event title</Label>\n <Input\n id=\"event-title\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n required\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"event-price\">Ticket price (USD)</Label>\n <Input\n id=\"event-price\"\n type=\"number\"\n min=\"0\"\n step=\"0.01\"\n value={price}\n onChange={(e) => setPrice(e.target.value)}\n required\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"event-capacity\">Capacity (optional)</Label>\n <Input\n id=\"event-capacity\"\n type=\"number\"\n min=\"1\"\n value={capacity}\n onChange={(e) => setCapacity(e.target.value)}\n />\n </div>\n </div>\n <div className=\"flex justify-end\">\n <Button type=\"submit\" disabled={create.isPending}>\n <Plus className=\"mr-1.5 h-4 w-4\" />{' '}\n {create.isPending ? 'Creating…' : 'Create event (draft)'}\n </Button>\n </div>\n </form>\n );\n}\n\nfunction EventsPanel() {\n const { data, isLoading, isError, refetch } = useComMyPaidEvents();\n const update = useComUpdatePaidEvent();\n const archive = useComArchivePaidEvent();\n const [showForm, setShowForm] = useState(false);\n const events = data?.items ?? [];\n\n const publish = async (event: ComPaidEvent) => {\n try {\n await update.mutateAsync({ id: event.id, input: { status: 'PUBLISHED' } });\n notify.success('Event published', event.title);\n } catch (err) {\n notify.error('Could not publish event', describeError(err));\n }\n };\n\n const handleArchive = async (event: ComPaidEvent) => {\n try {\n await archive.mutateAsync(event.id);\n notify.success('Event cancelled', event.title);\n } catch (err) {\n notify.error('Could not cancel event', describeError(err));\n }\n };\n\n if (isLoading) return <LoadingView label=\"Loading your paid events…\" />;\n if (isError)\n return <ErrorView message=\"We couldn't load your paid events.\" onRetry={() => refetch()} />;\n\n return (\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex items-center justify-between\">\n <SectionLabel>Your paid events</SectionLabel>\n <Button variant=\"outline\" size=\"sm\" onClick={() => setShowForm((v) => !v)}>\n <Plus className=\"mr-1.5 h-3.5 w-3.5\" /> New event\n </Button>\n </div>\n {showForm && <CreateEventForm onDone={() => setShowForm(false)} />}\n {events.length === 0 ? (\n <EmptyState\n icon={<Ticket className=\"h-10 w-10\" />}\n title=\"No paid events yet\"\n description=\"Create a ticketed event — it starts as a draft until you publish it.\"\n />\n ) : (\n <div className=\"flex flex-col gap-3\">\n {events.map((event) => (\n <div\n key={event.id}\n className=\"flex flex-col gap-3 rounded-xl border border-border-seam bg-bg-surface p-4 sm:flex-row sm:items-center sm:justify-between\"\n >\n <div className=\"min-w-0\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <h4 className=\"truncate text-sm font-semibold text-text-primary\">\n {event.title}\n </h4>\n <Badge\n variant={\n event.status === 'PUBLISHED'\n ? 'default'\n : event.status === 'CANCELLED'\n ? 'destructive'\n : 'secondary'\n }\n >\n {event.status}\n </Badge>\n </div>\n {event.capacity != null && (\n <p className=\"mt-1 text-xs text-text-secondary\">Capacity: {event.capacity}</p>\n )}\n </div>\n <div className=\"flex shrink-0 items-center gap-2\">\n <span className=\"text-sm font-semibold tabular-nums text-text-primary\">\n {formatMoney(event.priceAmount, event.currency)}\n </span>\n {event.status === 'DRAFT' && (\n <Button size=\"sm\" onClick={() => publish(event)} disabled={update.isPending}>\n Publish\n </Button>\n )}\n {event.status !== 'CANCELLED' && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => handleArchive(event)}\n disabled={archive.isPending}\n >\n <Trash2 className=\"mr-1.5 h-3.5 w-3.5\" /> Cancel\n </Button>\n )}\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Digital products\n// ---------------------------------------------------------------------------\n\nfunction CreateProductForm({ onDone }: { onDone: () => void }) {\n const create = useComCreateDigitalProduct();\n const [title, setTitle] = useState('');\n const [price, setPrice] = useState('');\n const [description, setDescription] = useState('');\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault();\n const priceAmount = Number(price);\n if (!title.trim()) {\n notify.error('Title required', 'Give your product a title.');\n return;\n }\n if (!Number.isFinite(priceAmount) || priceAmount < 0) {\n notify.error('Invalid price', 'Enter a price of 0 or more.');\n return;\n }\n try {\n await create.mutateAsync({\n title: title.trim(),\n description: description.trim() || null,\n priceAmount,\n productType: 'DOWNLOAD',\n });\n notify.success('Digital product created');\n setTitle('');\n setPrice('');\n setDescription('');\n onDone();\n } catch (err) {\n notify.error('Could not create product', describeError(err));\n }\n };\n\n return (\n <form\n onSubmit={handleSubmit}\n className=\"grid gap-3 rounded-xl border border-border-seam bg-bg-surface p-4\"\n >\n <div className=\"grid gap-3 sm:grid-cols-[2fr_1fr]\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"product-title\">Product title</Label>\n <Input\n id=\"product-title\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n required\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"product-price\">Price (USD)</Label>\n <Input\n id=\"product-price\"\n type=\"number\"\n min=\"0\"\n step=\"0.01\"\n value={price}\n onChange={(e) => setPrice(e.target.value)}\n required\n />\n </div>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"product-description\">Description</Label>\n <Textarea\n id=\"product-description\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n rows={2}\n placeholder=\"What's included in this download\"\n />\n </div>\n <div className=\"flex justify-end\">\n <Button type=\"submit\" disabled={create.isPending}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> {create.isPending ? 'Creating…' : 'Create product'}\n </Button>\n </div>\n </form>\n );\n}\n\nfunction ProductsPanel() {\n const { data, isLoading, isError, refetch } = useComMyDigitalProducts();\n const archive = useComArchiveDigitalProduct();\n const [showForm, setShowForm] = useState(false);\n const products = data?.items ?? [];\n\n const handleArchive = async (product: ComDigitalProduct) => {\n try {\n await archive.mutateAsync(product.id);\n notify.success('Product archived', product.title);\n } catch (err) {\n notify.error('Could not archive product', describeError(err));\n }\n };\n\n if (isLoading) return <LoadingView label=\"Loading your digital products…\" />;\n if (isError)\n return (\n <ErrorView message=\"We couldn't load your digital products.\" onRetry={() => refetch()} />\n );\n\n return (\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex items-center justify-between\">\n <SectionLabel>Your digital products</SectionLabel>\n <Button variant=\"outline\" size=\"sm\" onClick={() => setShowForm((v) => !v)}>\n <Plus className=\"mr-1.5 h-3.5 w-3.5\" /> New product\n </Button>\n </div>\n {showForm && <CreateProductForm onDone={() => setShowForm(false)} />}\n {products.length === 0 ? (\n <EmptyState\n icon={<Package className=\"h-10 w-10\" />}\n title=\"No digital products yet\"\n description=\"List a downloadable or access-gated product with a price.\"\n />\n ) : (\n <div className=\"flex flex-col gap-3\">\n {products.map((product) => (\n <CatalogRow\n key={product.id}\n title={product.title}\n subtitle={product.description}\n price={formatMoney(product.priceAmount, product.currency)}\n statusLabel={product.status}\n statusTone={product.status === 'ACTIVE' ? 'positive' : 'neutral'}\n onArchive={product.status === 'ACTIVE' ? () => handleArchive(product) : undefined}\n archiving={archive.isPending}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Tips received\n// ---------------------------------------------------------------------------\n\nfunction TipsPanel() {\n const { data, isLoading, isError, refetch } = useComMyReceivedTips();\n const tips = data?.items ?? [];\n const total = tips.filter((t) => t.status === 'RECORDED').reduce((sum, t) => sum + t.amount, 0);\n\n if (isLoading) return <LoadingView label=\"Loading tips received…\" />;\n if (isError) return <ErrorView message=\"We couldn't load your tips.\" onRetry={() => refetch()} />;\n\n return (\n <div className=\"flex flex-col gap-4\">\n <div className=\"rounded-xl border border-border-seam bg-bg-surface p-4\">\n <SectionLabel>Total recorded (not yet payable)</SectionLabel>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {formatMoney(total, tips[0]?.currency ?? 'USD')}\n </p>\n <p className=\"mt-1 text-xs text-text-tertiary\">\n These are recorded tip intents only — payment integration is pending, so no funds have\n actually moved yet.\n </p>\n </div>\n {tips.length === 0 ? (\n <EmptyState\n icon={<Gift className=\"h-10 w-10\" />}\n title=\"No tips recorded yet\"\n description=\"When fans tip you, the recorded intents will show up here.\"\n />\n ) : (\n <div className=\"flex flex-col gap-3\">\n {tips.map((tip: ComTipIntent) => (\n <div\n key={tip.id}\n className=\"flex items-center justify-between gap-3 rounded-xl border border-border-seam bg-bg-surface p-4\"\n >\n <div className=\"min-w-0\">\n <p className=\"text-sm font-medium text-text-primary\">\n {formatMoney(tip.amount, tip.currency)}\n <span className=\"ml-2 text-xs font-normal text-text-tertiary\">\n {new Date(tip.createdAt).toLocaleDateString()}\n </span>\n </p>\n {tip.message && (\n <p className=\"mt-1 truncate text-xs text-text-secondary\">\n &ldquo;{tip.message}&rdquo;\n </p>\n )}\n </div>\n <Badge variant={tip.status === 'RECORDED' ? 'secondary' : 'destructive'}>\n {tip.status}\n </Badge>\n </div>\n ))}\n </div>\n )}\n </div>\n );\n}\n\nexport function MonetizationPage() {\n const [tab, setTab] = useState<Tab>('tiers');\n\n return (\n <PageLayout\n title=\"Monetization\"\n description=\"Manage the membership tiers, paid events, and digital products you offer — and see the tips you've received. This is a pricing/catalog core: payment integration is pending, so no checkout is live yet.\"\n >\n <GlassCard treatment=\"plain\" className=\"mb-5 flex flex-wrap gap-1 p-1.5\">\n {TABS.map(({ id, label, icon: Icon }) => (\n <button\n key={id}\n type=\"button\"\n onClick={() => setTab(id)}\n className={cn(\n 'flex items-center gap-1.5 rounded-lg px-3 py-2 text-xs font-medium transition-colors',\n tab === id\n ? 'bg-[var(--color-accent-soft)] text-accent'\n : 'text-text-secondary hover:bg-bg-sunken hover:text-text-primary'\n )}\n >\n <Icon className=\"h-4 w-4\" /> {label}\n </button>\n ))}\n </GlassCard>\n\n <div className=\"mb-5 flex items-center gap-2 rounded-xl border border-status-warning-border bg-status-warning-bg-subtle px-4 py-3 text-xs text-status-warning-text\">\n <Coins className=\"h-4 w-4 shrink-0\" />\n Payment integration pending — prices are informational until checkout goes live.\n </div>\n\n {tab === 'tiers' && <TiersPanel />}\n {tab === 'events' && <EventsPanel />}\n {tab === 'products' && <ProductsPanel />}\n {tab === 'tips' && <TipsPanel />}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"PostThreadPage.d.ts","sourceRoot":"","sources":["../../../../src/comradecircle/pages/posts/PostThreadPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAWH,wBAAgB,cAAc,4CA2C7B"}
1
+ {"version":3,"file":"PostThreadPage.d.ts","sourceRoot":"","sources":["../../../../src/comradecircle/pages/posts/PostThreadPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAWH,wBAAgB,cAAc,4CA6C7B"}
@@ -1,41 +1,43 @@
1
1
  import { useComradeCircle as e } from "../../context/ComradeCircleContext.js";
2
2
  import "../../context/index.js";
3
3
  import { PageLayout as t } from "../../components/PageLayout.js";
4
- import { useComPost as n } from "../../hooks/useComradeCircleApi.js";
4
+ import { useComCommentAddedLive as n, useComPost as r } from "../../hooks/useComradeCircleApi.js";
5
5
  import "../../hooks/index.js";
6
- import { PostCard as r } from "../../components/PostCard.js";
7
- import { ErrorView as i, LoadingView as a } from "../../components/StateViews.js";
8
- import { ArrowLeft as o } from "lucide-react";
9
- import { useParams as s } from "react-router-dom";
10
- import { jsx as c, jsxs as l } from "react/jsx-runtime";
11
- import { Button as u } from "@burdenoff/fe-libs/ui";
6
+ import { PostCard as i } from "../../components/PostCard.js";
7
+ import { ErrorView as a, LoadingView as o } from "../../components/StateViews.js";
8
+ import { ArrowLeft as s } from "lucide-react";
9
+ import { useParams as c } from "react-router-dom";
10
+ import { jsx as l, jsxs as u } from "react/jsx-runtime";
11
+ import { Button as d } from "@burdenoff/fe-libs/ui";
12
12
  //#region src/comradecircle/pages/posts/PostThreadPage.tsx
13
- function d() {
14
- let { postId: d } = s(), { navigateTo: f } = e(), { data: p, isLoading: m, isError: h, refetch: g } = n(d), _ = /* @__PURE__ */ l(u, {
13
+ function f() {
14
+ let { postId: f } = c(), { navigateTo: p } = e(), { data: m, isLoading: h, isError: g, refetch: _ } = r(f);
15
+ n(f);
16
+ let v = /* @__PURE__ */ u(d, {
15
17
  variant: "ghost",
16
18
  size: "sm",
17
- onClick: () => f(""),
18
- children: [/* @__PURE__ */ c(o, { className: "mr-1.5 h-4 w-4" }), " Back"]
19
+ onClick: () => p(""),
20
+ children: [/* @__PURE__ */ l(s, { className: "mr-1.5 h-4 w-4" }), " Back"]
19
21
  });
20
- return m ? /* @__PURE__ */ c(t, {
22
+ return h ? /* @__PURE__ */ l(t, {
21
23
  title: "Thread",
22
- actions: _,
23
- children: /* @__PURE__ */ c(a, { label: "Loading post…" })
24
- }) : h || !p ? /* @__PURE__ */ c(t, {
24
+ actions: v,
25
+ children: /* @__PURE__ */ l(o, { label: "Loading post…" })
26
+ }) : g || !m ? /* @__PURE__ */ l(t, {
25
27
  title: "Thread",
26
- actions: _,
27
- children: /* @__PURE__ */ c(i, {
28
+ actions: v,
29
+ children: /* @__PURE__ */ l(a, {
28
30
  title: "Post not found",
29
31
  message: "This post may have been removed, or you may not have access to it.",
30
- onRetry: () => g()
32
+ onRetry: () => _()
31
33
  })
32
- }) : /* @__PURE__ */ c(t, {
34
+ }) : /* @__PURE__ */ l(t, {
33
35
  title: "Thread",
34
- actions: _,
35
- children: /* @__PURE__ */ c("div", {
36
+ actions: v,
37
+ children: /* @__PURE__ */ l("div", {
36
38
  className: "mx-auto max-w-2xl",
37
- children: /* @__PURE__ */ c(r, {
38
- post: p,
39
+ children: /* @__PURE__ */ l(i, {
40
+ post: m,
39
41
  defaultExpanded: !0,
40
42
  hideThreadLink: !0
41
43
  })
@@ -43,6 +45,6 @@ function d() {
43
45
  });
44
46
  }
45
47
  //#endregion
46
- export { d as PostThreadPage };
48
+ export { f as PostThreadPage };
47
49
 
48
50
  //# sourceMappingURL=PostThreadPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PostThreadPage.js","names":[],"sources":["../../../../src/comradecircle/pages/posts/PostThreadPage.tsx"],"sourcesContent":["/**\n * PostThreadPage — a dedicated, focused view of a single post and its thread.\n * @module comradecircle/pages/posts\n *\n * BOFF-3955: the mocks (`comradecircle-14-channel-post-thread.png`) show a post\n * opened into its own surface — author, body, reactions, and comments — rather\n * than only the inline collapsible thread inside the channel feed. Reads\n * `comPost(id)` (post + its comments in one round trip) and renders the\n * existing {@link PostCard} (which already composes {@link ReactionBar} +\n * {@link CommentThread} when expanded) so the thread view stays in lock-step\n * with the inline one instead of duplicating rendering logic.\n */\n\nimport { ArrowLeft } from 'lucide-react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { useParams } from 'react-router-dom';\nimport { PageLayout } from '../../components/PageLayout';\nimport { PostCard } from '../../components/PostCard';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { useComPost } from '../../hooks';\nimport { useComradeCircle } from '../../context';\n\nexport function PostThreadPage() {\n const { postId } = useParams<{ postId: string }>();\n const { navigateTo } = useComradeCircle();\n const { data: post, isLoading, isError, refetch } = useComPost(postId);\n\n // Home feed is the one destination every thread is always reachable from\n // (channel feeds link here too), matching the fixed-destination back-button\n // convention already used by EventDetailPage / MemberProfilePage rather\n // than relying on browser history depth, which isn't reliable once this\n // MFE is mounted inside the host shell's own router.\n const backButton = (\n <Button variant=\"ghost\" size=\"sm\" onClick={() => navigateTo('')}>\n <ArrowLeft className=\"mr-1.5 h-4 w-4\" /> Back\n </Button>\n );\n\n if (isLoading) {\n return (\n <PageLayout title=\"Thread\" actions={backButton}>\n <LoadingView label=\"Loading post…\" />\n </PageLayout>\n );\n }\n\n if (isError || !post) {\n return (\n <PageLayout title=\"Thread\" actions={backButton}>\n <ErrorView\n title=\"Post not found\"\n message=\"This post may have been removed, or you may not have access to it.\"\n onRetry={() => refetch()}\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout title=\"Thread\" actions={backButton}>\n <div className=\"mx-auto max-w-2xl\">\n <PostCard post={post} defaultExpanded hideThreadLink />\n </div>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;AAsBA,SAAgB,IAAiB;CAC/B,IAAM,EAAE,cAAW,EAA8B,GAC3C,EAAE,kBAAe,EAAiB,GAClC,EAAE,MAAM,GAAM,cAAW,YAAS,eAAY,EAAW,CAAM,GAO/D,IACJ,kBAAC,GAAD;EAAQ,SAAQ;EAAQ,MAAK;EAAK,eAAe,EAAW,EAAE;YAA9D,CACE,kBAAC,GAAD,EAAW,WAAU,iBAAkB,CAAA,GAAC,OAClC;;CAuBV,OApBI,IAEA,kBAAC,GAAD;EAAY,OAAM;EAAS,SAAS;YAClC,kBAAC,GAAD,EAAa,OAAM,gBAAiB,CAAA;CAC1B,CAAA,IAIZ,KAAW,CAAC,IAEZ,kBAAC,GAAD;EAAY,OAAM;EAAS,SAAS;YAClC,kBAAC,GAAD;GACE,OAAM;GACN,SAAQ;GACR,eAAe,EAAQ;EACxB,CAAA;CACS,CAAA,IAKd,kBAAC,GAAD;EAAY,OAAM;EAAS,SAAS;YAClC,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,GAAD;IAAgB;IAAM,iBAAA;IAAgB,gBAAA;GAAgB,CAAA;EACnD,CAAA;CACK,CAAA;AAEhB"}
1
+ {"version":3,"file":"PostThreadPage.js","names":[],"sources":["../../../../src/comradecircle/pages/posts/PostThreadPage.tsx"],"sourcesContent":["/**\n * PostThreadPage — a dedicated, focused view of a single post and its thread.\n * @module comradecircle/pages/posts\n *\n * BOFF-3955: the mocks (`comradecircle-14-channel-post-thread.png`) show a post\n * opened into its own surface — author, body, reactions, and comments — rather\n * than only the inline collapsible thread inside the channel feed. Reads\n * `comPost(id)` (post + its comments in one round trip) and renders the\n * existing {@link PostCard} (which already composes {@link ReactionBar} +\n * {@link CommentThread} when expanded) so the thread view stays in lock-step\n * with the inline one instead of duplicating rendering logic.\n */\n\nimport { ArrowLeft } from 'lucide-react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { useParams } from 'react-router-dom';\nimport { PageLayout } from '../../components/PageLayout';\nimport { PostCard } from '../../components/PostCard';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { useComPost, useComCommentAddedLive } from '../../hooks';\nimport { useComradeCircle } from '../../context';\n\nexport function PostThreadPage() {\n const { postId } = useParams<{ postId: string }>();\n const { navigateTo } = useComradeCircle();\n const { data: post, isLoading, isError, refetch } = useComPost(postId);\n // BOFF-4455: live-update this thread's comments without a manual refresh.\n useComCommentAddedLive(postId);\n\n // Home feed is the one destination every thread is always reachable from\n // (channel feeds link here too), matching the fixed-destination back-button\n // convention already used by EventDetailPage / MemberProfilePage rather\n // than relying on browser history depth, which isn't reliable once this\n // MFE is mounted inside the host shell's own router.\n const backButton = (\n <Button variant=\"ghost\" size=\"sm\" onClick={() => navigateTo('')}>\n <ArrowLeft className=\"mr-1.5 h-4 w-4\" /> Back\n </Button>\n );\n\n if (isLoading) {\n return (\n <PageLayout title=\"Thread\" actions={backButton}>\n <LoadingView label=\"Loading post…\" />\n </PageLayout>\n );\n }\n\n if (isError || !post) {\n return (\n <PageLayout title=\"Thread\" actions={backButton}>\n <ErrorView\n title=\"Post not found\"\n message=\"This post may have been removed, or you may not have access to it.\"\n onRetry={() => refetch()}\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout title=\"Thread\" actions={backButton}>\n <div className=\"mx-auto max-w-2xl\">\n <PostCard post={post} defaultExpanded hideThreadLink />\n </div>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;AAsBA,SAAgB,IAAiB;CAC/B,IAAM,EAAE,cAAW,EAA8B,GAC3C,EAAE,kBAAe,EAAiB,GAClC,EAAE,MAAM,GAAM,cAAW,YAAS,eAAY,EAAW,CAAM;CAErE,EAAuB,CAAM;CAO7B,IAAM,IACJ,kBAAC,GAAD;EAAQ,SAAQ;EAAQ,MAAK;EAAK,eAAe,EAAW,EAAE;YAA9D,CACE,kBAAC,GAAD,EAAW,WAAU,iBAAkB,CAAA,GAAC,OAClC;;CAuBV,OApBI,IAEA,kBAAC,GAAD;EAAY,OAAM;EAAS,SAAS;YAClC,kBAAC,GAAD,EAAa,OAAM,gBAAiB,CAAA;CAC1B,CAAA,IAIZ,KAAW,CAAC,IAEZ,kBAAC,GAAD;EAAY,OAAM;EAAS,SAAS;YAClC,kBAAC,GAAD;GACE,OAAM;GACN,SAAQ;GACR,eAAe,EAAQ;EACxB,CAAA;CACS,CAAA,IAKd,kBAAC,GAAD;EAAY,OAAM;EAAS,SAAS;YAClC,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,GAAD;IAAgB;IAAM,iBAAA;IAAgB,gBAAA;GAAgB,CAAA;EACnD,CAAA;CACK,CAAA;AAEhB"}
@@ -1 +1 @@
1
- {"version":3,"file":"MyProfilePage.d.ts","sourceRoot":"","sources":["../../../../src/comradecircle/pages/profile/MyProfilePage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAgCH,wBAAgB,aAAa,4CA4C5B"}
1
+ {"version":3,"file":"MyProfilePage.d.ts","sourceRoot":"","sources":["../../../../src/comradecircle/pages/profile/MyProfilePage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAgCH,wBAAgB,aAAa,4CAiD5B"}
@@ -12,47 +12,52 @@ import { TagInput as d } from "../../components/TagInput.js";
12
12
  import { MiniBar as f } from "../../components/MiniBar.js";
13
13
  import { AvatarUploadField as p } from "../../components/AvatarUploadField.js";
14
14
  import { useState as m } from "react";
15
- import { Save as h } from "lucide-react";
16
- import { jsx as g, jsxs as _ } from "react/jsx-runtime";
17
- import { Button as v, GlassCard as y, Input as b, Label as x, Select as S, SelectContent as C, SelectItem as w, SelectTrigger as T, SelectValue as E, Switch as D, Textarea as O } from "@burdenoff/fe-libs/ui";
15
+ import { Coins as h, Save as g } from "lucide-react";
16
+ import { jsx as _, jsxs as v } from "react/jsx-runtime";
17
+ import { Button as y, GlassCard as b, Input as x, Label as S, Select as C, SelectContent as w, SelectItem as T, SelectTrigger as E, SelectValue as D, Switch as O, Textarea as k } from "@burdenoff/fe-libs/ui";
18
18
  //#region src/comradecircle/pages/profile/MyProfilePage.tsx
19
- var k = [
19
+ var A = [
20
20
  "ONLINE",
21
21
  "AWAY",
22
22
  "BUSY",
23
23
  "OFFLINE"
24
24
  ];
25
- function A() {
26
- let { currentUser: r } = e(), i = r?.id, { data: a, isLoading: o, isError: s, refetch: u } = n(i), d = r?.name ?? r?.email ?? "";
27
- return o ? /* @__PURE__ */ g(t, {
25
+ function j() {
26
+ let { currentUser: r, navigateTo: i } = e(), a = r?.id, { data: o, isLoading: s, isError: u, refetch: d } = n(a), f = r?.name ?? r?.email ?? "";
27
+ return s ? /* @__PURE__ */ _(t, {
28
28
  title: "My Profile",
29
- children: /* @__PURE__ */ g(l, { label: "Loading your profile…" })
30
- }) : s ? /* @__PURE__ */ g(t, {
29
+ children: /* @__PURE__ */ _(l, { label: "Loading your profile…" })
30
+ }) : u ? /* @__PURE__ */ _(t, {
31
31
  title: "My Profile",
32
- children: /* @__PURE__ */ g(c, {
32
+ children: /* @__PURE__ */ _(c, {
33
33
  title: "We couldn't load your profile",
34
34
  message: "Something went wrong while fetching your profile. Retry before editing so you don't overwrite saved details.",
35
- onRetry: () => u()
35
+ onRetry: () => d()
36
36
  })
37
- }) : /* @__PURE__ */ g(t, {
37
+ }) : /* @__PURE__ */ _(t, {
38
38
  title: "My Profile",
39
39
  description: "Your profile is your identity across every circle — it's how members recognise, find and follow you.",
40
- children: /* @__PURE__ */ g(N, {
41
- initialProfile: a ?? null,
42
- identityName: d
43
- }, a?.id ?? "new")
40
+ actions: /* @__PURE__ */ v(y, {
41
+ variant: "outline",
42
+ onClick: () => i("monetization"),
43
+ children: [/* @__PURE__ */ _(h, { className: "mr-1.5 h-4 w-4" }), " Monetization"]
44
+ }),
45
+ children: /* @__PURE__ */ _(P, {
46
+ initialProfile: o ?? null,
47
+ identityName: f
48
+ }, o?.id ?? "new")
44
49
  });
45
50
  }
46
- function j({ children: e }) {
47
- return /* @__PURE__ */ g("p", {
51
+ function M({ children: e }) {
52
+ return /* @__PURE__ */ _("p", {
48
53
  className: "text-xs font-semibold uppercase tracking-[0.08em] text-text-tertiary",
49
54
  children: e
50
55
  });
51
56
  }
52
- function M(e, t) {
57
+ function N(e, t) {
53
58
  return e.length === t.length && e.every((e, n) => e === t[n]);
54
59
  }
55
- function N({ initialProfile: e, identityName: t }) {
60
+ function P({ initialProfile: e, identityName: t }) {
56
61
  let n = r(), c = {
57
62
  displayName: e?.displayName ?? t,
58
63
  headline: e?.headline ?? "",
@@ -62,7 +67,7 @@ function N({ initialProfile: e, identityName: t }) {
62
67
  presence: e?.presence ?? "ONLINE",
63
68
  discoverable: e?.discoverable ?? !0,
64
69
  avatarFileId: e?.avatar?.id ?? null
65
- }, [l, A] = m(c.displayName), [N, P] = m(c.headline), [F, I] = m(c.bio), [L, R] = m(c.interests), [z, B] = m(c.skills), [V, H] = m(c.presence), [U, W] = m(c.discoverable), [G, K] = m(c.avatarFileId), q = l.trim(), J = [
70
+ }, [l, h] = m(c.displayName), [j, P] = m(c.headline), [F, I] = m(c.bio), [L, R] = m(c.interests), [z, B] = m(c.skills), [V, H] = m(c.presence), [U, W] = m(c.discoverable), [G, K] = m(c.avatarFileId), q = l.trim(), J = [
66
71
  {
67
72
  done: !!G,
68
73
  nudge: "Add a profile photo so members recognise you at a glance."
@@ -72,7 +77,7 @@ function N({ initialProfile: e, identityName: t }) {
72
77
  nudge: "Add a display name so members know who you are."
73
78
  },
74
79
  {
75
- done: N.trim().length > 0,
80
+ done: j.trim().length > 0,
76
81
  nudge: "Add a headline to sum yourself up in one line."
77
82
  },
78
83
  {
@@ -87,86 +92,86 @@ function N({ initialProfile: e, identityName: t }) {
87
92
  done: z.length > 0,
88
93
  nudge: "List some skills so circles know what you bring."
89
94
  }
90
- ], Y = J.filter((e) => e.done).length, X = Math.round(Y / J.length * 100), Z = J.find((e) => !e.done)?.nudge ?? "Your profile is complete — it looks great.", Q = l !== c.displayName || N !== c.headline || F !== c.bio || V !== c.presence || U !== c.discoverable || G !== c.avatarFileId || !M(L, c.interests) || !M(z, c.skills);
91
- return /* @__PURE__ */ _("div", {
95
+ ], Y = J.filter((e) => e.done).length, X = Math.round(Y / J.length * 100), Z = J.find((e) => !e.done)?.nudge ?? "Your profile is complete — it looks great.", Q = l !== c.displayName || j !== c.headline || F !== c.bio || V !== c.presence || U !== c.discoverable || G !== c.avatarFileId || !N(L, c.interests) || !N(z, c.skills);
96
+ return /* @__PURE__ */ v("div", {
92
97
  className: "grid gap-6 lg:grid-cols-[1fr_320px]",
93
- children: [/* @__PURE__ */ g(y, {
98
+ children: [/* @__PURE__ */ _(b, {
94
99
  treatment: "plain",
95
100
  className: "order-2 p-5 sm:p-6 lg:order-1",
96
- children: /* @__PURE__ */ _("div", {
101
+ children: /* @__PURE__ */ v("div", {
97
102
  className: "flex flex-col gap-6",
98
103
  children: [
99
- /* @__PURE__ */ _("div", {
104
+ /* @__PURE__ */ v("div", {
100
105
  className: "grid gap-2 rounded-xl border border-border-seam bg-bg-surface p-4",
101
106
  children: [
102
- /* @__PURE__ */ _("div", {
107
+ /* @__PURE__ */ v("div", {
103
108
  className: "flex items-baseline justify-between gap-3",
104
- children: [/* @__PURE__ */ g(j, { children: "Profile completeness" }), /* @__PURE__ */ _("span", {
109
+ children: [/* @__PURE__ */ _(M, { children: "Profile completeness" }), /* @__PURE__ */ v("span", {
105
110
  className: "text-sm font-semibold tabular-nums text-text-primary",
106
111
  children: [X, "%"]
107
112
  })]
108
113
  }),
109
- /* @__PURE__ */ g(f, {
114
+ /* @__PURE__ */ _(f, {
110
115
  value: X,
111
116
  height: 8,
112
117
  barClassName: "bg-gradient-to-r from-accent to-[var(--color-accent-soft)]"
113
118
  }),
114
- /* @__PURE__ */ g("p", {
119
+ /* @__PURE__ */ _("p", {
115
120
  className: "text-xs text-text-secondary",
116
121
  children: Z
117
122
  })
118
123
  ]
119
124
  }),
120
- /* @__PURE__ */ _("section", {
125
+ /* @__PURE__ */ v("section", {
121
126
  className: "grid gap-4",
122
127
  children: [
123
- /* @__PURE__ */ g(j, { children: "Identity" }),
124
- /* @__PURE__ */ _("div", {
128
+ /* @__PURE__ */ _(M, { children: "Identity" }),
129
+ /* @__PURE__ */ v("div", {
125
130
  className: "grid gap-1.5",
126
- children: [/* @__PURE__ */ g(x, { children: "Avatar" }), /* @__PURE__ */ g(p, {
131
+ children: [/* @__PURE__ */ _(S, { children: "Avatar" }), /* @__PURE__ */ _(p, {
127
132
  fileId: G,
128
133
  name: q || t,
129
134
  onUploaded: K
130
135
  })]
131
136
  }),
132
- /* @__PURE__ */ _("div", {
137
+ /* @__PURE__ */ v("div", {
133
138
  className: "grid gap-1.5",
134
- children: [/* @__PURE__ */ g(x, {
139
+ children: [/* @__PURE__ */ _(S, {
135
140
  htmlFor: "profile-name",
136
141
  children: "Display name"
137
- }), /* @__PURE__ */ g(b, {
142
+ }), /* @__PURE__ */ _(x, {
138
143
  id: "profile-name",
139
144
  value: l,
140
- onChange: (e) => A(e.target.value),
145
+ onChange: (e) => h(e.target.value),
141
146
  placeholder: "How members see you",
142
147
  required: !0,
143
148
  "aria-required": "true"
144
149
  })]
145
150
  }),
146
- /* @__PURE__ */ _("div", {
151
+ /* @__PURE__ */ v("div", {
147
152
  className: "grid gap-1.5",
148
- children: [/* @__PURE__ */ g(x, {
153
+ children: [/* @__PURE__ */ _(S, {
149
154
  htmlFor: "profile-headline",
150
155
  children: "Headline"
151
- }), /* @__PURE__ */ g(b, {
156
+ }), /* @__PURE__ */ _(x, {
152
157
  id: "profile-headline",
153
- value: N,
158
+ value: j,
154
159
  onChange: (e) => P(e.target.value),
155
160
  placeholder: "e.g. Community organiser · Photographer"
156
161
  })]
157
162
  })
158
163
  ]
159
164
  }),
160
- /* @__PURE__ */ _("section", {
165
+ /* @__PURE__ */ v("section", {
161
166
  className: "grid gap-4 border-t border-border-seam pt-6",
162
167
  children: [
163
- /* @__PURE__ */ g(j, { children: "About you" }),
164
- /* @__PURE__ */ _("div", {
168
+ /* @__PURE__ */ _(M, { children: "About you" }),
169
+ /* @__PURE__ */ v("div", {
165
170
  className: "grid gap-1.5",
166
- children: [/* @__PURE__ */ g(x, {
171
+ children: [/* @__PURE__ */ _(S, {
167
172
  htmlFor: "profile-bio",
168
173
  children: "Bio"
169
- }), /* @__PURE__ */ g(O, {
174
+ }), /* @__PURE__ */ _(k, {
170
175
  id: "profile-bio",
171
176
  value: F,
172
177
  onChange: (e) => I(e.target.value),
@@ -174,24 +179,24 @@ function N({ initialProfile: e, identityName: t }) {
174
179
  placeholder: "Tell circles a little about yourself."
175
180
  })]
176
181
  }),
177
- /* @__PURE__ */ _("div", {
182
+ /* @__PURE__ */ v("div", {
178
183
  className: "grid gap-1.5",
179
- children: [/* @__PURE__ */ g(x, {
184
+ children: [/* @__PURE__ */ _(S, {
180
185
  htmlFor: "profile-interests",
181
186
  children: "Interests"
182
- }), /* @__PURE__ */ g(d, {
187
+ }), /* @__PURE__ */ _(d, {
183
188
  id: "profile-interests",
184
189
  value: L,
185
190
  onChange: R,
186
191
  placeholder: "Add an interest…"
187
192
  })]
188
193
  }),
189
- /* @__PURE__ */ _("div", {
194
+ /* @__PURE__ */ v("div", {
190
195
  className: "grid gap-1.5",
191
- children: [/* @__PURE__ */ g(x, {
196
+ children: [/* @__PURE__ */ _(S, {
192
197
  htmlFor: "profile-skills",
193
198
  children: "Skills"
194
- }), /* @__PURE__ */ g(d, {
199
+ }), /* @__PURE__ */ _(d, {
195
200
  id: "profile-skills",
196
201
  value: z,
197
202
  onChange: B,
@@ -200,39 +205,39 @@ function N({ initialProfile: e, identityName: t }) {
200
205
  })
201
206
  ]
202
207
  }),
203
- /* @__PURE__ */ _("section", {
208
+ /* @__PURE__ */ v("section", {
204
209
  className: "grid gap-4 border-t border-border-seam pt-6",
205
210
  children: [
206
- /* @__PURE__ */ g(j, { children: "Visibility" }),
207
- /* @__PURE__ */ _("div", {
211
+ /* @__PURE__ */ _(M, { children: "Visibility" }),
212
+ /* @__PURE__ */ v("div", {
208
213
  className: "grid gap-1.5",
209
- children: [/* @__PURE__ */ g(x, {
214
+ children: [/* @__PURE__ */ _(S, {
210
215
  htmlFor: "profile-presence",
211
216
  children: "Presence"
212
- }), /* @__PURE__ */ _(S, {
217
+ }), /* @__PURE__ */ v(C, {
213
218
  value: V,
214
219
  onValueChange: (e) => H(e),
215
- children: [/* @__PURE__ */ g(T, {
220
+ children: [/* @__PURE__ */ _(E, {
216
221
  id: "profile-presence",
217
- children: /* @__PURE__ */ g(E, {})
218
- }), /* @__PURE__ */ g(C, { children: k.map((e) => /* @__PURE__ */ g(w, {
222
+ children: /* @__PURE__ */ _(D, {})
223
+ }), /* @__PURE__ */ _(w, { children: A.map((e) => /* @__PURE__ */ _(T, {
219
224
  value: e,
220
225
  children: s(e)
221
226
  }, e)) })]
222
227
  })]
223
228
  }),
224
- /* @__PURE__ */ _("div", {
229
+ /* @__PURE__ */ v("div", {
225
230
  className: "flex items-start justify-between gap-4 rounded-xl border border-border-seam bg-bg-surface p-3.5",
226
- children: [/* @__PURE__ */ _("div", {
231
+ children: [/* @__PURE__ */ v("div", {
227
232
  className: "min-w-0",
228
- children: [/* @__PURE__ */ g(x, {
233
+ children: [/* @__PURE__ */ _(S, {
229
234
  htmlFor: "profile-discoverable",
230
235
  children: "List me in the member directory"
231
- }), /* @__PURE__ */ g("p", {
236
+ }), /* @__PURE__ */ _("p", {
232
237
  className: "mt-1 text-xs text-text-tertiary",
233
238
  children: "When on, your profile appears in the discoverable member directory so others can find and follow you. Turn it off to stay unlisted."
234
239
  })]
235
- }), /* @__PURE__ */ g(D, {
240
+ }), /* @__PURE__ */ _(O, {
236
241
  id: "profile-discoverable",
237
242
  checked: U,
238
243
  onCheckedChange: W,
@@ -242,12 +247,12 @@ function N({ initialProfile: e, identityName: t }) {
242
247
  })
243
248
  ]
244
249
  }),
245
- /* @__PURE__ */ _("div", {
250
+ /* @__PURE__ */ v("div", {
246
251
  className: "flex flex-wrap items-center justify-end gap-3 border-t border-border-seam pt-5",
247
- children: [!Q && !n.isPending && /* @__PURE__ */ g("span", {
252
+ children: [!Q && !n.isPending && /* @__PURE__ */ _("span", {
248
253
  className: "text-xs text-text-tertiary",
249
254
  children: "No changes to save"
250
- }), /* @__PURE__ */ _(v, {
255
+ }), /* @__PURE__ */ v(y, {
251
256
  onClick: async () => {
252
257
  let e = l.trim();
253
258
  if (!e) {
@@ -257,7 +262,7 @@ function N({ initialProfile: e, identityName: t }) {
257
262
  try {
258
263
  await n.mutateAsync({
259
264
  displayName: e,
260
- headline: N.trim() || null,
265
+ headline: j.trim() || null,
261
266
  bio: F.trim() || null,
262
267
  avatarFileId: G,
263
268
  interests: L,
@@ -270,83 +275,83 @@ function N({ initialProfile: e, identityName: t }) {
270
275
  }
271
276
  },
272
277
  disabled: n.isPending || !Q,
273
- children: [/* @__PURE__ */ g(h, { className: "mr-1.5 h-4 w-4" }), n.isPending ? "Saving…" : "Save profile"]
278
+ children: [/* @__PURE__ */ _(g, { className: "mr-1.5 h-4 w-4" }), n.isPending ? "Saving…" : "Save profile"]
274
279
  })]
275
280
  })
276
281
  ]
277
282
  })
278
- }), /* @__PURE__ */ g("div", {
283
+ }), /* @__PURE__ */ _("div", {
279
284
  className: "order-1 lg:order-2",
280
- children: /* @__PURE__ */ _(y, {
285
+ children: /* @__PURE__ */ v(b, {
281
286
  treatment: "plain",
282
287
  className: "overflow-hidden p-0 lg:sticky lg:top-6",
283
- children: [/* @__PURE__ */ _("div", {
288
+ children: [/* @__PURE__ */ v("div", {
284
289
  className: "relative h-24 bg-gloss-card",
285
- children: [/* @__PURE__ */ g("div", {
290
+ children: [/* @__PURE__ */ _("div", {
286
291
  className: "absolute inset-0 bg-gradient-to-br from-[var(--color-accent-soft)] via-[var(--color-accent-soft)]/30 to-transparent",
287
292
  "aria-hidden": "true"
288
- }), /* @__PURE__ */ g("span", {
293
+ }), /* @__PURE__ */ _("span", {
289
294
  className: "absolute right-3 top-3 rounded-full bg-bg-surface/80 px-2 py-0.5 text-[0.62rem] font-medium uppercase tracking-[0.08em] text-text-tertiary backdrop-blur",
290
295
  children: "How members see you"
291
296
  })]
292
- }), /* @__PURE__ */ _("div", {
297
+ }), /* @__PURE__ */ v("div", {
293
298
  className: "px-5 pb-5",
294
299
  children: [
295
- /* @__PURE__ */ _("div", {
300
+ /* @__PURE__ */ v("div", {
296
301
  className: "-mt-12 flex flex-col items-center text-center",
297
302
  children: [
298
- /* @__PURE__ */ g(i, {
303
+ /* @__PURE__ */ _(i, {
299
304
  name: q || t,
300
305
  size: "xl",
301
306
  presence: V,
302
307
  fileId: G,
303
308
  ring: !0
304
309
  }),
305
- /* @__PURE__ */ g("h3", {
310
+ /* @__PURE__ */ _("h3", {
306
311
  className: "mt-3 max-w-full truncate text-lg font-semibold text-text-primary",
307
312
  children: q || "Your name"
308
313
  }),
309
- N.trim() && /* @__PURE__ */ g("p", {
314
+ j.trim() && /* @__PURE__ */ _("p", {
310
315
  className: "mt-0.5 max-w-full truncate text-sm text-text-secondary",
311
- children: N.trim()
316
+ children: j.trim()
312
317
  }),
313
- /* @__PURE__ */ g("div", {
318
+ /* @__PURE__ */ _("div", {
314
319
  className: "mt-2.5",
315
- children: /* @__PURE__ */ g(u, { status: V })
320
+ children: /* @__PURE__ */ _(u, { status: V })
316
321
  })
317
322
  ]
318
323
  }),
319
- F.trim() && /* @__PURE__ */ g("p", {
324
+ F.trim() && /* @__PURE__ */ _("p", {
320
325
  className: "mt-4 whitespace-pre-wrap break-words text-center text-sm text-text-secondary",
321
326
  children: F.trim()
322
327
  }),
323
- L.length > 0 && /* @__PURE__ */ _("div", {
328
+ L.length > 0 && /* @__PURE__ */ v("div", {
324
329
  className: "mt-5",
325
- children: [/* @__PURE__ */ g("p", {
330
+ children: [/* @__PURE__ */ _("p", {
326
331
  className: "mb-1.5 text-xs font-medium text-text-tertiary",
327
332
  children: "Interests"
328
- }), /* @__PURE__ */ g("div", {
333
+ }), /* @__PURE__ */ _("div", {
329
334
  className: "flex flex-wrap gap-1.5",
330
- children: L.map((e) => /* @__PURE__ */ g("span", {
335
+ children: L.map((e) => /* @__PURE__ */ _("span", {
331
336
  className: "rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs font-medium text-text-secondary",
332
337
  children: e
333
338
  }, e))
334
339
  })]
335
340
  }),
336
- z.length > 0 && /* @__PURE__ */ _("div", {
341
+ z.length > 0 && /* @__PURE__ */ v("div", {
337
342
  className: "mt-4",
338
- children: [/* @__PURE__ */ g("p", {
343
+ children: [/* @__PURE__ */ _("p", {
339
344
  className: "mb-1.5 text-xs font-medium text-text-tertiary",
340
345
  children: "Skills"
341
- }), /* @__PURE__ */ g("div", {
346
+ }), /* @__PURE__ */ _("div", {
342
347
  className: "flex flex-wrap gap-1.5",
343
- children: z.map((e) => /* @__PURE__ */ g("span", {
348
+ children: z.map((e) => /* @__PURE__ */ _("span", {
344
349
  className: "rounded-full bg-[var(--color-accent-soft)] px-2.5 py-0.5 text-xs font-medium text-text-primary",
345
350
  children: e
346
351
  }, e))
347
352
  })]
348
353
  }),
349
- !U && /* @__PURE__ */ g("p", {
354
+ !U && /* @__PURE__ */ _("p", {
350
355
  className: "mt-5 text-center text-xs text-text-tertiary",
351
356
  children: "Hidden from the member directory."
352
357
  })
@@ -357,6 +362,6 @@ function N({ initialProfile: e, identityName: t }) {
357
362
  });
358
363
  }
359
364
  //#endregion
360
- export { A as MyProfilePage };
365
+ export { j as MyProfilePage };
361
366
 
362
367
  //# sourceMappingURL=MyProfilePage.js.map