@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.
- package/dist/comradecircle/ComradeCircleRoutes.d.ts.map +1 -1
- package/dist/comradecircle/ComradeCircleRoutes.js +11 -7
- package/dist/comradecircle/ComradeCircleRoutes.js.map +1 -1
- package/dist/comradecircle/hooks/useComSubscription.d.ts +18 -0
- package/dist/comradecircle/hooks/useComSubscription.d.ts.map +1 -0
- package/dist/comradecircle/hooks/useComSubscription.js +110 -0
- package/dist/comradecircle/hooks/useComSubscription.js.map +1 -0
- package/dist/comradecircle/hooks/useComradeCircleApi.d.ts +51 -1
- package/dist/comradecircle/hooks/useComradeCircleApi.d.ts.map +1 -1
- package/dist/comradecircle/hooks/useComradeCircleApi.js +435 -223
- package/dist/comradecircle/hooks/useComradeCircleApi.js.map +1 -1
- package/dist/comradecircle/pages/circles/CircleDetailPage.d.ts.map +1 -1
- package/dist/comradecircle/pages/circles/CircleDetailPage.js +268 -266
- package/dist/comradecircle/pages/circles/CircleDetailPage.js.map +1 -1
- package/dist/comradecircle/pages/events/EventDetailPage.d.ts.map +1 -1
- package/dist/comradecircle/pages/events/EventDetailPage.js +84 -82
- package/dist/comradecircle/pages/events/EventDetailPage.js.map +1 -1
- package/dist/comradecircle/pages/members/MemberProfilePage.d.ts.map +1 -1
- package/dist/comradecircle/pages/members/MemberProfilePage.js +251 -129
- package/dist/comradecircle/pages/members/MemberProfilePage.js.map +1 -1
- package/dist/comradecircle/pages/monetization/MonetizationPage.d.ts +13 -0
- package/dist/comradecircle/pages/monetization/MonetizationPage.d.ts.map +1 -0
- package/dist/comradecircle/pages/monetization/MonetizationPage.js +596 -0
- package/dist/comradecircle/pages/monetization/MonetizationPage.js.map +1 -0
- package/dist/comradecircle/pages/posts/PostThreadPage.d.ts.map +1 -1
- package/dist/comradecircle/pages/posts/PostThreadPage.js +26 -24
- package/dist/comradecircle/pages/posts/PostThreadPage.js.map +1 -1
- package/dist/comradecircle/pages/profile/MyProfilePage.d.ts.map +1 -1
- package/dist/comradecircle/pages/profile/MyProfilePage.js +101 -96
- package/dist/comradecircle/pages/profile/MyProfilePage.js.map +1 -1
- package/dist/comradecircle/types/index.d.ts +126 -0
- package/dist/comradecircle/types/index.d.ts.map +1 -1
- package/dist/comradecircle/utils/shellBridge.d.ts +45 -0
- package/dist/comradecircle/utils/shellBridge.d.ts.map +1 -0
- package/dist/comradecircle/utils/shellBridge.js +19 -0
- package/dist/comradecircle/utils/shellBridge.js.map +1 -0
- 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 “{tip.message}”\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,
|
|
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 {
|
|
4
|
+
import { useComCommentAddedLive as n, useComPost as r } from "../../hooks/useComradeCircleApi.js";
|
|
5
5
|
import "../../hooks/index.js";
|
|
6
|
-
import { PostCard as
|
|
7
|
-
import { ErrorView as
|
|
8
|
-
import { ArrowLeft as
|
|
9
|
-
import { useParams as
|
|
10
|
-
import { jsx as
|
|
11
|
-
import { Button as
|
|
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
|
|
14
|
-
let { postId:
|
|
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: () =>
|
|
18
|
-
children: [/* @__PURE__ */
|
|
19
|
+
onClick: () => p(""),
|
|
20
|
+
children: [/* @__PURE__ */ l(s, { className: "mr-1.5 h-4 w-4" }), " Back"]
|
|
19
21
|
});
|
|
20
|
-
return
|
|
22
|
+
return h ? /* @__PURE__ */ l(t, {
|
|
21
23
|
title: "Thread",
|
|
22
|
-
actions:
|
|
23
|
-
children: /* @__PURE__ */
|
|
24
|
-
}) :
|
|
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__ */
|
|
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: () =>
|
|
32
|
+
onRetry: () => _()
|
|
31
33
|
})
|
|
32
|
-
}) : /* @__PURE__ */
|
|
34
|
+
}) : /* @__PURE__ */ l(t, {
|
|
33
35
|
title: "Thread",
|
|
34
|
-
actions:
|
|
35
|
-
children: /* @__PURE__ */
|
|
36
|
+
actions: v,
|
|
37
|
+
children: /* @__PURE__ */ l("div", {
|
|
36
38
|
className: "mx-auto max-w-2xl",
|
|
37
|
-
children: /* @__PURE__ */
|
|
38
|
-
post:
|
|
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 {
|
|
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,
|
|
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,
|
|
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 {
|
|
16
|
-
import { jsx as
|
|
17
|
-
import { Button as
|
|
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
|
|
19
|
+
var A = [
|
|
20
20
|
"ONLINE",
|
|
21
21
|
"AWAY",
|
|
22
22
|
"BUSY",
|
|
23
23
|
"OFFLINE"
|
|
24
24
|
];
|
|
25
|
-
function
|
|
26
|
-
let { currentUser: r } = e(),
|
|
27
|
-
return
|
|
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__ */
|
|
30
|
-
}) :
|
|
29
|
+
children: /* @__PURE__ */ _(l, { label: "Loading your profile…" })
|
|
30
|
+
}) : u ? /* @__PURE__ */ _(t, {
|
|
31
31
|
title: "My Profile",
|
|
32
|
-
children: /* @__PURE__ */
|
|
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: () =>
|
|
35
|
+
onRetry: () => d()
|
|
36
36
|
})
|
|
37
|
-
}) : /* @__PURE__ */
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
|
47
|
-
return /* @__PURE__ */
|
|
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
|
|
57
|
+
function N(e, t) {
|
|
53
58
|
return e.length === t.length && e.every((e, n) => e === t[n]);
|
|
54
59
|
}
|
|
55
|
-
function
|
|
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,
|
|
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:
|
|
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 ||
|
|
91
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
98
|
+
children: [/* @__PURE__ */ _(b, {
|
|
94
99
|
treatment: "plain",
|
|
95
100
|
className: "order-2 p-5 sm:p-6 lg:order-1",
|
|
96
|
-
children: /* @__PURE__ */
|
|
101
|
+
children: /* @__PURE__ */ v("div", {
|
|
97
102
|
className: "flex flex-col gap-6",
|
|
98
103
|
children: [
|
|
99
|
-
/* @__PURE__ */
|
|
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__ */
|
|
107
|
+
/* @__PURE__ */ v("div", {
|
|
103
108
|
className: "flex items-baseline justify-between gap-3",
|
|
104
|
-
children: [/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
119
|
+
/* @__PURE__ */ _("p", {
|
|
115
120
|
className: "text-xs text-text-secondary",
|
|
116
121
|
children: Z
|
|
117
122
|
})
|
|
118
123
|
]
|
|
119
124
|
}),
|
|
120
|
-
/* @__PURE__ */
|
|
125
|
+
/* @__PURE__ */ v("section", {
|
|
121
126
|
className: "grid gap-4",
|
|
122
127
|
children: [
|
|
123
|
-
/* @__PURE__ */
|
|
124
|
-
/* @__PURE__ */
|
|
128
|
+
/* @__PURE__ */ _(M, { children: "Identity" }),
|
|
129
|
+
/* @__PURE__ */ v("div", {
|
|
125
130
|
className: "grid gap-1.5",
|
|
126
|
-
children: [/* @__PURE__ */
|
|
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__ */
|
|
137
|
+
/* @__PURE__ */ v("div", {
|
|
133
138
|
className: "grid gap-1.5",
|
|
134
|
-
children: [/* @__PURE__ */
|
|
139
|
+
children: [/* @__PURE__ */ _(S, {
|
|
135
140
|
htmlFor: "profile-name",
|
|
136
141
|
children: "Display name"
|
|
137
|
-
}), /* @__PURE__ */
|
|
142
|
+
}), /* @__PURE__ */ _(x, {
|
|
138
143
|
id: "profile-name",
|
|
139
144
|
value: l,
|
|
140
|
-
onChange: (e) =>
|
|
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__ */
|
|
151
|
+
/* @__PURE__ */ v("div", {
|
|
147
152
|
className: "grid gap-1.5",
|
|
148
|
-
children: [/* @__PURE__ */
|
|
153
|
+
children: [/* @__PURE__ */ _(S, {
|
|
149
154
|
htmlFor: "profile-headline",
|
|
150
155
|
children: "Headline"
|
|
151
|
-
}), /* @__PURE__ */
|
|
156
|
+
}), /* @__PURE__ */ _(x, {
|
|
152
157
|
id: "profile-headline",
|
|
153
|
-
value:
|
|
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__ */
|
|
165
|
+
/* @__PURE__ */ v("section", {
|
|
161
166
|
className: "grid gap-4 border-t border-border-seam pt-6",
|
|
162
167
|
children: [
|
|
163
|
-
/* @__PURE__ */
|
|
164
|
-
/* @__PURE__ */
|
|
168
|
+
/* @__PURE__ */ _(M, { children: "About you" }),
|
|
169
|
+
/* @__PURE__ */ v("div", {
|
|
165
170
|
className: "grid gap-1.5",
|
|
166
|
-
children: [/* @__PURE__ */
|
|
171
|
+
children: [/* @__PURE__ */ _(S, {
|
|
167
172
|
htmlFor: "profile-bio",
|
|
168
173
|
children: "Bio"
|
|
169
|
-
}), /* @__PURE__ */
|
|
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__ */
|
|
182
|
+
/* @__PURE__ */ v("div", {
|
|
178
183
|
className: "grid gap-1.5",
|
|
179
|
-
children: [/* @__PURE__ */
|
|
184
|
+
children: [/* @__PURE__ */ _(S, {
|
|
180
185
|
htmlFor: "profile-interests",
|
|
181
186
|
children: "Interests"
|
|
182
|
-
}), /* @__PURE__ */
|
|
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__ */
|
|
194
|
+
/* @__PURE__ */ v("div", {
|
|
190
195
|
className: "grid gap-1.5",
|
|
191
|
-
children: [/* @__PURE__ */
|
|
196
|
+
children: [/* @__PURE__ */ _(S, {
|
|
192
197
|
htmlFor: "profile-skills",
|
|
193
198
|
children: "Skills"
|
|
194
|
-
}), /* @__PURE__ */
|
|
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__ */
|
|
208
|
+
/* @__PURE__ */ v("section", {
|
|
204
209
|
className: "grid gap-4 border-t border-border-seam pt-6",
|
|
205
210
|
children: [
|
|
206
|
-
/* @__PURE__ */
|
|
207
|
-
/* @__PURE__ */
|
|
211
|
+
/* @__PURE__ */ _(M, { children: "Visibility" }),
|
|
212
|
+
/* @__PURE__ */ v("div", {
|
|
208
213
|
className: "grid gap-1.5",
|
|
209
|
-
children: [/* @__PURE__ */
|
|
214
|
+
children: [/* @__PURE__ */ _(S, {
|
|
210
215
|
htmlFor: "profile-presence",
|
|
211
216
|
children: "Presence"
|
|
212
|
-
}), /* @__PURE__ */
|
|
217
|
+
}), /* @__PURE__ */ v(C, {
|
|
213
218
|
value: V,
|
|
214
219
|
onValueChange: (e) => H(e),
|
|
215
|
-
children: [/* @__PURE__ */
|
|
220
|
+
children: [/* @__PURE__ */ _(E, {
|
|
216
221
|
id: "profile-presence",
|
|
217
|
-
children: /* @__PURE__ */
|
|
218
|
-
}), /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
231
|
+
children: [/* @__PURE__ */ v("div", {
|
|
227
232
|
className: "min-w-0",
|
|
228
|
-
children: [/* @__PURE__ */
|
|
233
|
+
children: [/* @__PURE__ */ _(S, {
|
|
229
234
|
htmlFor: "profile-discoverable",
|
|
230
235
|
children: "List me in the member directory"
|
|
231
|
-
}), /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
252
|
+
children: [!Q && !n.isPending && /* @__PURE__ */ _("span", {
|
|
248
253
|
className: "text-xs text-text-tertiary",
|
|
249
254
|
children: "No changes to save"
|
|
250
|
-
}), /* @__PURE__ */
|
|
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:
|
|
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
|
|
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__ */
|
|
283
|
+
}), /* @__PURE__ */ _("div", {
|
|
279
284
|
className: "order-1 lg:order-2",
|
|
280
|
-
children: /* @__PURE__ */
|
|
285
|
+
children: /* @__PURE__ */ v(b, {
|
|
281
286
|
treatment: "plain",
|
|
282
287
|
className: "overflow-hidden p-0 lg:sticky lg:top-6",
|
|
283
|
-
children: [/* @__PURE__ */
|
|
288
|
+
children: [/* @__PURE__ */ v("div", {
|
|
284
289
|
className: "relative h-24 bg-gloss-card",
|
|
285
|
-
children: [/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
297
|
+
}), /* @__PURE__ */ v("div", {
|
|
293
298
|
className: "px-5 pb-5",
|
|
294
299
|
children: [
|
|
295
|
-
/* @__PURE__ */
|
|
300
|
+
/* @__PURE__ */ v("div", {
|
|
296
301
|
className: "-mt-12 flex flex-col items-center text-center",
|
|
297
302
|
children: [
|
|
298
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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
|
-
|
|
314
|
+
j.trim() && /* @__PURE__ */ _("p", {
|
|
310
315
|
className: "mt-0.5 max-w-full truncate text-sm text-text-secondary",
|
|
311
|
-
children:
|
|
316
|
+
children: j.trim()
|
|
312
317
|
}),
|
|
313
|
-
/* @__PURE__ */
|
|
318
|
+
/* @__PURE__ */ _("div", {
|
|
314
319
|
className: "mt-2.5",
|
|
315
|
-
children: /* @__PURE__ */
|
|
320
|
+
children: /* @__PURE__ */ _(u, { status: V })
|
|
316
321
|
})
|
|
317
322
|
]
|
|
318
323
|
}),
|
|
319
|
-
F.trim() && /* @__PURE__ */
|
|
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__ */
|
|
328
|
+
L.length > 0 && /* @__PURE__ */ v("div", {
|
|
324
329
|
className: "mt-5",
|
|
325
|
-
children: [/* @__PURE__ */
|
|
330
|
+
children: [/* @__PURE__ */ _("p", {
|
|
326
331
|
className: "mb-1.5 text-xs font-medium text-text-tertiary",
|
|
327
332
|
children: "Interests"
|
|
328
|
-
}), /* @__PURE__ */
|
|
333
|
+
}), /* @__PURE__ */ _("div", {
|
|
329
334
|
className: "flex flex-wrap gap-1.5",
|
|
330
|
-
children: L.map((e) => /* @__PURE__ */
|
|
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__ */
|
|
341
|
+
z.length > 0 && /* @__PURE__ */ v("div", {
|
|
337
342
|
className: "mt-4",
|
|
338
|
-
children: [/* @__PURE__ */
|
|
343
|
+
children: [/* @__PURE__ */ _("p", {
|
|
339
344
|
className: "mb-1.5 text-xs font-medium text-text-tertiary",
|
|
340
345
|
children: "Skills"
|
|
341
|
-
}), /* @__PURE__ */
|
|
346
|
+
}), /* @__PURE__ */ _("div", {
|
|
342
347
|
className: "flex flex-wrap gap-1.5",
|
|
343
|
-
children: z.map((e) => /* @__PURE__ */
|
|
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__ */
|
|
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 {
|
|
365
|
+
export { j as MyProfilePage };
|
|
361
366
|
|
|
362
367
|
//# sourceMappingURL=MyProfilePage.js.map
|