@burdenoff/microfe-comradecircle 2026.827.1 → 2026.830.1
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/components/AvatarUploadField.js +8 -8
- package/dist/comradecircle/components/CircleCard.js +4 -4
- package/dist/comradecircle/components/CommentThread.d.ts.map +1 -1
- package/dist/comradecircle/components/CommentThread.js +66 -61
- package/dist/comradecircle/components/CommentThread.js.map +1 -1
- package/dist/comradecircle/components/CreateCircleDialog.d.ts.map +1 -1
- package/dist/comradecircle/components/CreateCircleDialog.js +89 -88
- package/dist/comradecircle/components/CreateCircleDialog.js.map +1 -1
- package/dist/comradecircle/components/CreateEventDialog.d.ts.map +1 -1
- package/dist/comradecircle/components/CreateEventDialog.js +28 -27
- package/dist/comradecircle/components/CreateEventDialog.js.map +1 -1
- package/dist/comradecircle/components/DraftsPanel.js +13 -13
- package/dist/comradecircle/components/EventCard.js +5 -5
- package/dist/comradecircle/components/FileImage.js +5 -5
- package/dist/comradecircle/components/ImageAttachments.js +21 -21
- package/dist/comradecircle/components/MemberIdentity.js +4 -4
- package/dist/comradecircle/components/MobileBottomNav.d.ts.map +1 -1
- package/dist/comradecircle/components/MobileBottomNav.js +37 -30
- package/dist/comradecircle/components/MobileBottomNav.js.map +1 -1
- package/dist/comradecircle/components/Pagination.d.ts.map +1 -1
- package/dist/comradecircle/components/Pagination.js +37 -28
- package/dist/comradecircle/components/Pagination.js.map +1 -1
- package/dist/comradecircle/components/PollCard.js +13 -13
- package/dist/comradecircle/components/PostCard.d.ts.map +1 -1
- package/dist/comradecircle/components/PostCard.js +102 -89
- package/dist/comradecircle/components/PostCard.js.map +1 -1
- package/dist/comradecircle/components/PostComposer.js +4 -4
- package/dist/comradecircle/components/ReactionBar.d.ts.map +1 -1
- package/dist/comradecircle/components/ReactionBar.js +65 -55
- package/dist/comradecircle/components/ReactionBar.js.map +1 -1
- package/dist/comradecircle/components/StateViews.d.ts.map +1 -1
- package/dist/comradecircle/components/StateViews.js +38 -30
- package/dist/comradecircle/components/StateViews.js.map +1 -1
- package/dist/comradecircle/components/UpcomingEvents.js +17 -17
- package/dist/comradecircle/hooks/index.d.ts +1 -0
- package/dist/comradecircle/hooks/index.d.ts.map +1 -1
- package/dist/comradecircle/hooks/index.js +1 -0
- package/dist/comradecircle/hooks/useTr.d.ts +18 -0
- package/dist/comradecircle/hooks/useTr.d.ts.map +1 -0
- package/dist/comradecircle/hooks/useTr.js +12 -0
- package/dist/comradecircle/hooks/useTr.js.map +1 -0
- package/dist/comradecircle/pages/FeedPage.d.ts.map +1 -1
- package/dist/comradecircle/pages/FeedPage.js +75 -62
- package/dist/comradecircle/pages/FeedPage.js.map +1 -1
- package/dist/comradecircle/pages/circles/CircleDetailPage.d.ts.map +1 -1
- package/dist/comradecircle/pages/circles/CircleDetailPage.js +439 -401
- package/dist/comradecircle/pages/circles/CircleDetailPage.js.map +1 -1
- package/dist/comradecircle/pages/circles/CirclesPage.d.ts.map +1 -1
- package/dist/comradecircle/pages/circles/CirclesPage.js +124 -117
- package/dist/comradecircle/pages/circles/CirclesPage.js.map +1 -1
- package/dist/comradecircle/pages/events/EventDetailPage.d.ts.map +1 -1
- package/dist/comradecircle/pages/events/EventDetailPage.js +182 -153
- package/dist/comradecircle/pages/events/EventDetailPage.js.map +1 -1
- package/dist/comradecircle/pages/events/EventsPage.d.ts.map +1 -1
- package/dist/comradecircle/pages/events/EventsPage.js +100 -91
- package/dist/comradecircle/pages/events/EventsPage.js.map +1 -1
- package/dist/comradecircle/pages/members/MemberProfilePage.d.ts.map +1 -1
- package/dist/comradecircle/pages/members/MemberProfilePage.js +172 -159
- package/dist/comradecircle/pages/members/MemberProfilePage.js.map +1 -1
- package/dist/comradecircle/pages/members/MembersPage.d.ts.map +1 -1
- package/dist/comradecircle/pages/members/MembersPage.js +103 -104
- package/dist/comradecircle/pages/members/MembersPage.js.map +1 -1
- package/dist/comradecircle/pages/monetization/MonetizationPage.d.ts.map +1 -1
- package/dist/comradecircle/pages/monetization/MonetizationPage.js +319 -297
- package/dist/comradecircle/pages/monetization/MonetizationPage.js.map +1 -1
- package/dist/comradecircle/pages/posts/PostThreadPage.d.ts.map +1 -1
- package/dist/comradecircle/pages/posts/PostThreadPage.js +37 -32
- 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 +182 -177
- package/dist/comradecircle/pages/profile/MyProfilePage.js.map +1 -1
- package/dist/comradecircle/utils/i18n.js +15 -0
- package/dist/comradecircle/utils/i18n.js.map +1 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PostCard.js","names":[],"sources":["../../../src/comradecircle/components/PostCard.tsx"],"sourcesContent":["/**\n * PostCard — a single post with reactions and a collapsible comment thread.\n * @module comradecircle/components\n *\n * Reads its data from a `ComPost`; writes via `comUpdatePost` (edit / pin) and\n * `comRemovePost` (delete). Reactions + comments are delegated to\n * {@link ReactionBar} and {@link CommentThread}. Author-only actions (edit, pin,\n * delete) are gated on `authorId === currentUser.id`.\n */\n\nimport { useState } from 'react';\nimport { MessageSquare, MoreHorizontal, Pin, Pencil, Trash2, ArrowUpRight } from 'lucide-react';\nimport {\n GlassCard,\n Button,\n Textarea,\n DropdownMenu,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n} from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/cn';\nimport { MemberIdentity } from './MemberIdentity';\nimport { ReactionBar } from './ReactionBar';\nimport { CommentThread } from './CommentThread';\nimport { AttachmentGrid } from './ImageAttachments';\nimport { useComUpdatePost, useComRemovePost } from '../hooks';\nimport { useComradeCircle } from '../context';\nimport { formatRelativeTime } from '../utils/formatters';\nimport { notify, describeError } from '../lib/toast';\nimport type { ComPost } from '../types';\n\ninterface PostCardProps {\n post: ComPost;\n /** Start with the comment thread open. */\n defaultExpanded?: boolean;\n /** Hide the \"open thread\" link — set when already rendered on the thread page itself. */\n hideThreadLink?: boolean;\n}\n\nexport function PostCard({ post, defaultExpanded = false, hideThreadLink = false }: PostCardProps) {\n const { currentUser, navigateTo } = useComradeCircle();\n const updatePost = useComUpdatePost();\n const removePost = useComRemovePost();\n const [expanded, setExpanded] = useState(defaultExpanded);\n const [editing, setEditing] = useState(false);\n const [draft, setDraft] = useState(post.body);\n\n const isAuthor = Boolean(currentUser?.id && currentUser.id === post.authorId);\n\n const saveEdit = async () => {\n const text = draft.trim();\n if (!text || text === post.body) {\n setEditing(false);\n return;\n }\n try {\n await updatePost.mutateAsync({ id: post.id, input: { body: text } });\n setEditing(false);\n notify.success('Post updated');\n } catch (err) {\n notify.error('Could not update post', describeError(err));\n }\n };\n\n const togglePin = async () => {\n try {\n await updatePost.mutateAsync({ id: post.id, input: { isPinned: !post.isPinned } });\n notify.success(post.isPinned ? 'Post unpinned' : 'Post pinned');\n } catch (err) {\n notify.error('Could not update post', describeError(err));\n }\n };\n\n const remove = async () => {\n try {\n await removePost.mutateAsync({ id: post.id, channelId: post.channelId });\n notify.success('Post removed');\n } catch (err) {\n notify.error('Could not remove post', describeError(err));\n }\n };\n\n return (\n <GlassCard\n treatment=\"plain\"\n className={cn(\n 'p-4 transition-all duration-200 motion-safe:hover:-translate-y-0.5 hover:border-[var(--color-accent-soft)]',\n post.isPinned && 'ring-1 ring-accent/40'\n )}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <MemberIdentity\n memberId={post.authorId}\n variant=\"row\"\n size=\"md\"\n suffix={formatRelativeTime(post.createdAt)}\n showPresence\n />\n <div className=\"flex items-center gap-1\">\n {post.isPinned && (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-[var(--color-accent-soft)] px-2 py-0.5 text-xs font-medium text-text-primary\">\n <Pin className=\"h-3 w-3\" /> Pinned\n </span>\n )}\n {isAuthor && (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n aria-label=\"Post actions\"\n className=\"rounded-lg p-1.5 text-text-tertiary transition-colors hover:bg-bg-sunken hover:text-text-primary\"\n >\n <MoreHorizontal className=\"h-4 w-4\" />\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem onClick={() => setEditing(true)}>\n <Pencil className=\"mr-2 h-4 w-4\" /> Edit\n </DropdownMenuItem>\n <DropdownMenuItem onClick={togglePin}>\n <Pin className=\"mr-2 h-4 w-4\" /> {post.isPinned ? 'Unpin' : 'Pin'}\n </DropdownMenuItem>\n <DropdownMenuSeparator />\n <DropdownMenuItem\n onClick={remove}\n className=\"text-status-error-text focus:text-status-error-text\"\n >\n <Trash2 className=\"mr-2 h-4 w-4\" /> Delete\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n </div>\n </div>\n\n {editing ? (\n <div className=\"mt-3\">\n <Textarea\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n rows={3}\n className=\"resize-none\"\n />\n <div className=\"mt-2 flex justify-end gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => {\n setDraft(post.body);\n setEditing(false);\n }}\n >\n Cancel\n </Button>\n <Button size=\"sm\" onClick={saveEdit} disabled={updatePost.isPending}>\n Save\n </Button>\n </div>\n </div>\n ) : (\n <p className=\"mt-3 whitespace-pre-wrap break-words text-sm text-text-primary\">\n {post.body}\n </p>\n )}\n\n {post.tags.length > 0 && (\n <div className=\"mt-2 flex flex-wrap gap-1.5\">\n {post.tags.map((tag) => (\n <span\n key={tag}\n className=\"rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary\"\n >\n #{tag}\n </span>\n ))}\n </div>\n )}\n\n {post.attachmentFileIds.length > 0 && <AttachmentGrid fileIds={post.attachmentFileIds} />}\n\n <div className=\"mt-3 flex items-center justify-between gap-3 border-t border-border-seam pt-3\">\n <ReactionBar post={post} />\n <div className=\"flex items-center gap-1\">\n <button\n type=\"button\"\n onClick={() => setExpanded((s) => !s)}\n aria-expanded={expanded}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-xs font-medium transition-colors',\n expanded\n ? 'bg-[var(--color-accent-soft)] text-text-primary'\n : 'text-text-secondary hover:bg-bg-sunken hover:text-text-primary'\n )}\n >\n <MessageSquare className=\"h-3.5 w-3.5\" />\n <span className=\"tabular-nums\">{post.commentCount}</span>\n <span className=\"hidden sm:inline\">\n {post.commentCount === 1 ? 'comment' : 'comments'}\n </span>\n </button>\n\n {!hideThreadLink && (\n <button\n type=\"button\"\n onClick={() => navigateTo(`posts/${post.id}`)}\n aria-label=\"Open thread\"\n title=\"Open thread\"\n className=\"inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium text-text-tertiary transition-colors hover:bg-bg-sunken hover:text-text-primary\"\n >\n <ArrowUpRight className=\"h-3.5 w-3.5\" />\n <span className=\"hidden sm:inline\">Open thread</span>\n </button>\n )}\n </div>\n </div>\n\n {expanded && <CommentThread postId={post.id} />}\n </GlassCard>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PostCard.js","names":[],"sources":["../../../src/comradecircle/components/PostCard.tsx"],"sourcesContent":["/**\n * PostCard — a single post with reactions and a collapsible comment thread.\n * @module comradecircle/components\n *\n * Reads its data from a `ComPost`; writes via `comUpdatePost` (edit / pin) and\n * `comRemovePost` (delete). Reactions + comments are delegated to\n * {@link ReactionBar} and {@link CommentThread}. Author-only actions (edit, pin,\n * delete) are gated on `authorId === currentUser.id`.\n */\n\nimport { useState } from 'react';\nimport { MessageSquare, MoreHorizontal, Pin, Pencil, Trash2, ArrowUpRight } from 'lucide-react';\nimport {\n GlassCard,\n Button,\n Textarea,\n DropdownMenu,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n} from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/cn';\nimport { MemberIdentity } from './MemberIdentity';\nimport { ReactionBar } from './ReactionBar';\nimport { CommentThread } from './CommentThread';\nimport { AttachmentGrid } from './ImageAttachments';\nimport { useComUpdatePost, useComRemovePost, useTr } from '../hooks';\nimport { useComradeCircle } from '../context';\nimport { formatRelativeTime } from '../utils/formatters';\nimport { notify, describeError } from '../lib/toast';\nimport type { ComPost } from '../types';\n\ninterface PostCardProps {\n post: ComPost;\n /** Start with the comment thread open. */\n defaultExpanded?: boolean;\n /** Hide the \"open thread\" link — set when already rendered on the thread page itself. */\n hideThreadLink?: boolean;\n}\n\nexport function PostCard({ post, defaultExpanded = false, hideThreadLink = false }: PostCardProps) {\n const { currentUser, navigateTo } = useComradeCircle();\n const updatePost = useComUpdatePost();\n const removePost = useComRemovePost();\n const tr = useTr();\n const [expanded, setExpanded] = useState(defaultExpanded);\n const [editing, setEditing] = useState(false);\n const [draft, setDraft] = useState(post.body);\n\n const isAuthor = Boolean(currentUser?.id && currentUser.id === post.authorId);\n\n const saveEdit = async () => {\n const text = draft.trim();\n if (!text || text === post.body) {\n setEditing(false);\n return;\n }\n try {\n await updatePost.mutateAsync({ id: post.id, input: { body: text } });\n setEditing(false);\n notify.success(tr('comradecircle.components.postCard.updatedSuccess', 'Post updated'));\n } catch (err) {\n notify.error(\n tr('comradecircle.components.postCard.updateError', 'Could not update post'),\n describeError(err)\n );\n }\n };\n\n const togglePin = async () => {\n try {\n await updatePost.mutateAsync({ id: post.id, input: { isPinned: !post.isPinned } });\n notify.success(\n post.isPinned\n ? tr('comradecircle.components.postCard.unpinnedSuccess', 'Post unpinned')\n : tr('comradecircle.components.postCard.pinnedSuccess', 'Post pinned')\n );\n } catch (err) {\n notify.error(\n tr('comradecircle.components.postCard.pinError', 'Could not update post'),\n describeError(err)\n );\n }\n };\n\n const remove = async () => {\n try {\n await removePost.mutateAsync({ id: post.id, channelId: post.channelId });\n notify.success(tr('comradecircle.components.postCard.removedSuccess', 'Post removed'));\n } catch (err) {\n notify.error(\n tr('comradecircle.components.postCard.removeError', 'Could not remove post'),\n describeError(err)\n );\n }\n };\n\n return (\n <GlassCard\n treatment=\"plain\"\n className={cn(\n 'p-4 transition-all duration-200 motion-safe:hover:-translate-y-0.5 hover:border-[var(--color-accent-soft)]',\n post.isPinned && 'ring-1 ring-accent/40'\n )}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <MemberIdentity\n memberId={post.authorId}\n variant=\"row\"\n size=\"md\"\n suffix={formatRelativeTime(post.createdAt)}\n showPresence\n />\n <div className=\"flex items-center gap-1\">\n {post.isPinned && (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-[var(--color-accent-soft)] px-2 py-0.5 text-xs font-medium text-text-primary\">\n <Pin className=\"h-3 w-3\" /> {tr('comradecircle.components.postCard.pinned', 'Pinned')}\n </span>\n )}\n {isAuthor && (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n aria-label={tr(\n 'comradecircle.components.postCard.postActionsAriaLabel',\n 'Post actions'\n )}\n className=\"rounded-lg p-1.5 text-text-tertiary transition-colors hover:bg-bg-sunken hover:text-text-primary\"\n >\n <MoreHorizontal className=\"h-4 w-4\" />\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem onClick={() => setEditing(true)}>\n <Pencil className=\"mr-2 h-4 w-4\" />{' '}\n {tr('comradecircle.components.postCard.edit', 'Edit')}\n </DropdownMenuItem>\n <DropdownMenuItem onClick={togglePin}>\n <Pin className=\"mr-2 h-4 w-4\" />{' '}\n {post.isPinned\n ? tr('comradecircle.components.postCard.unpin', 'Unpin')\n : tr('comradecircle.components.postCard.pin', 'Pin')}\n </DropdownMenuItem>\n <DropdownMenuSeparator />\n <DropdownMenuItem\n onClick={remove}\n className=\"text-status-error-text focus:text-status-error-text\"\n >\n <Trash2 className=\"mr-2 h-4 w-4\" />{' '}\n {tr('comradecircle.components.postCard.delete', 'Delete')}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n </div>\n </div>\n\n {editing ? (\n <div className=\"mt-3\">\n <Textarea\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n rows={3}\n className=\"resize-none\"\n />\n <div className=\"mt-2 flex justify-end gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => {\n setDraft(post.body);\n setEditing(false);\n }}\n >\n {tr('comradecircle.components.postCard.cancel', 'Cancel')}\n </Button>\n <Button size=\"sm\" onClick={saveEdit} disabled={updatePost.isPending}>\n {tr('comradecircle.components.postCard.save', 'Save')}\n </Button>\n </div>\n </div>\n ) : (\n <p className=\"mt-3 whitespace-pre-wrap break-words text-sm text-text-primary\">\n {post.body}\n </p>\n )}\n\n {post.tags.length > 0 && (\n <div className=\"mt-2 flex flex-wrap gap-1.5\">\n {post.tags.map((tag) => (\n <span\n key={tag}\n className=\"rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary\"\n >\n #{tag}\n </span>\n ))}\n </div>\n )}\n\n {post.attachmentFileIds.length > 0 && <AttachmentGrid fileIds={post.attachmentFileIds} />}\n\n <div className=\"mt-3 flex items-center justify-between gap-3 border-t border-border-seam pt-3\">\n <ReactionBar post={post} />\n <div className=\"flex items-center gap-1\">\n <button\n type=\"button\"\n onClick={() => setExpanded((s) => !s)}\n aria-expanded={expanded}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-xs font-medium transition-colors',\n expanded\n ? 'bg-[var(--color-accent-soft)] text-text-primary'\n : 'text-text-secondary hover:bg-bg-sunken hover:text-text-primary'\n )}\n >\n <MessageSquare className=\"h-3.5 w-3.5\" />\n <span className=\"tabular-nums\">{post.commentCount}</span>\n <span className=\"hidden sm:inline\">\n {post.commentCount === 1\n ? tr('comradecircle.components.postCard.comment', 'comment')\n : tr('comradecircle.components.postCard.comments', 'comments')}\n </span>\n </button>\n\n {!hideThreadLink && (\n <button\n type=\"button\"\n onClick={() => navigateTo(`posts/${post.id}`)}\n aria-label={tr(\n 'comradecircle.components.postCard.openThreadAriaLabel',\n 'Open thread'\n )}\n title={tr('comradecircle.components.postCard.openThreadTitle', 'Open thread')}\n className=\"inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium text-text-tertiary transition-colors hover:bg-bg-sunken hover:text-text-primary\"\n >\n <ArrowUpRight className=\"h-3.5 w-3.5\" />\n <span className=\"hidden sm:inline\">\n {tr('comradecircle.components.postCard.openThread', 'Open thread')}\n </span>\n </button>\n )}\n </div>\n </div>\n\n {expanded && <CommentThread postId={post.id} />}\n </GlassCard>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useComradeCircle as e } from "../context/ComradeCircleContext.js";
|
|
2
2
|
import "../context/index.js";
|
|
3
|
-
import {
|
|
4
|
-
import { useComCreatePost as n } from "../hooks/useComradeCircleApi.js";
|
|
3
|
+
import { useComCreatePost as t } from "../hooks/useComradeCircleApi.js";
|
|
5
4
|
import "../hooks/index.js";
|
|
5
|
+
import { cn as n } from "../utils/cn.js";
|
|
6
6
|
import { Avatar as r } from "./Avatar.js";
|
|
7
7
|
import { describeError as i, notify as a } from "../lib/toast.js";
|
|
8
8
|
import { AttachmentPicker as o } from "./ImageAttachments.js";
|
|
@@ -13,7 +13,7 @@ import { Fragment as f, jsx as p, jsxs as m } from "react/jsx-runtime";
|
|
|
13
13
|
import { Button as h, GlassCard as g, Textarea as _ } from "@burdenoff/fe-libs/ui";
|
|
14
14
|
//#region src/comradecircle/components/PostComposer.tsx
|
|
15
15
|
function v({ channelId: v, channelName: y, onPosted: b, onDraftSaved: x, variant: S = "default" }) {
|
|
16
|
-
let C = S === "announcement", { currentUser: w } = e(), T =
|
|
16
|
+
let C = S === "announcement", { currentUser: w } = e(), T = t(), [E, D] = c(""), [O, k] = c([]), [A, j] = c(!1), [M, N] = c([]), P = !E.trim() && M.length === 0, F = async (e) => {
|
|
17
17
|
let t = E.trim();
|
|
18
18
|
if (!t && M.length === 0) return;
|
|
19
19
|
let n = e === "DRAFT";
|
|
@@ -31,7 +31,7 @@ function v({ channelId: v, channelName: y, onPosted: b, onDraftSaved: x, variant
|
|
|
31
31
|
};
|
|
32
32
|
return /* @__PURE__ */ m(g, {
|
|
33
33
|
treatment: "plain",
|
|
34
|
-
className:
|
|
34
|
+
className: n("p-4", C && "border-2 border-[color:var(--color-accent)]"),
|
|
35
35
|
children: [C && /* @__PURE__ */ m("div", {
|
|
36
36
|
className: "mb-3 flex items-center gap-1.5 text-xs font-semibold uppercase tracking-wide text-accent",
|
|
37
37
|
children: [/* @__PURE__ */ p(u, { className: "h-3.5 w-3.5" }), " New announcement"]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReactionBar.d.ts","sourceRoot":"","sources":["../../../src/comradecircle/components/ReactionBar.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AASH,OAAO,KAAK,EAAE,OAAO,EAAmB,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"ReactionBar.d.ts","sourceRoot":"","sources":["../../../src/comradecircle/components/ReactionBar.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AASH,OAAO,KAAK,EAAE,OAAO,EAAmB,MAAM,UAAU,CAAC;AA+BzD,UAAU,gBAAgB;IACxB,IAAI,EAAE,OAAO,CAAC;CACf;AAED,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE,gBAAgB,2CAqGrD"}
|
|
@@ -1,111 +1,121 @@
|
|
|
1
1
|
import { useComradeCircle as e } from "../context/ComradeCircleContext.js";
|
|
2
2
|
import "../context/index.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { useComReactToPost as t } from "../hooks/useComradeCircleApi.js";
|
|
4
|
+
import { useTr as n } from "../hooks/useTr.js";
|
|
5
5
|
import "../hooks/index.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
6
|
+
import { cn as r } from "../utils/cn.js";
|
|
7
|
+
import { describeError as i, notify as a } from "../lib/toast.js";
|
|
8
|
+
import { useState as o } from "react";
|
|
9
|
+
import { SmilePlus as s } from "lucide-react";
|
|
10
|
+
import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
11
|
+
import { Popover as u, PopoverContent as d, PopoverTrigger as f } from "@burdenoff/fe-libs/ui";
|
|
11
12
|
//#region src/comradecircle/components/ReactionBar.tsx
|
|
12
|
-
var
|
|
13
|
+
var p = [
|
|
13
14
|
{
|
|
14
15
|
type: "LIKE",
|
|
15
16
|
emoji: "👍",
|
|
16
|
-
|
|
17
|
+
key: "comradecircle.components.reactionBar.like",
|
|
18
|
+
fallback: "Like"
|
|
17
19
|
},
|
|
18
20
|
{
|
|
19
21
|
type: "LOVE",
|
|
20
22
|
emoji: "❤️",
|
|
21
|
-
|
|
23
|
+
key: "comradecircle.components.reactionBar.love",
|
|
24
|
+
fallback: "Love"
|
|
22
25
|
},
|
|
23
26
|
{
|
|
24
27
|
type: "CELEBRATE",
|
|
25
28
|
emoji: "🎉",
|
|
26
|
-
|
|
29
|
+
key: "comradecircle.components.reactionBar.celebrate",
|
|
30
|
+
fallback: "Celebrate"
|
|
27
31
|
},
|
|
28
32
|
{
|
|
29
33
|
type: "INSIGHTFUL",
|
|
30
34
|
emoji: "💡",
|
|
31
|
-
|
|
35
|
+
key: "comradecircle.components.reactionBar.insightful",
|
|
36
|
+
fallback: "Insightful"
|
|
32
37
|
},
|
|
33
38
|
{
|
|
34
39
|
type: "LAUGH",
|
|
35
40
|
emoji: "😄",
|
|
36
|
-
|
|
41
|
+
key: "comradecircle.components.reactionBar.funny",
|
|
42
|
+
fallback: "Funny"
|
|
37
43
|
},
|
|
38
44
|
{
|
|
39
45
|
type: "SUPPORT",
|
|
40
46
|
emoji: "🤝",
|
|
41
|
-
|
|
47
|
+
key: "comradecircle.components.reactionBar.support",
|
|
48
|
+
fallback: "Support"
|
|
42
49
|
}
|
|
43
50
|
];
|
|
44
|
-
function
|
|
45
|
-
let { currentUser:
|
|
46
|
-
for (let e of
|
|
47
|
-
let t =
|
|
51
|
+
function m({ post: m }) {
|
|
52
|
+
let { currentUser: h } = e(), g = t(), _ = n(), [v, y] = o(!1), b = h?.id, x = /* @__PURE__ */ new Map();
|
|
53
|
+
for (let e of m.reactions ?? []) {
|
|
54
|
+
let t = x.get(e.type) ?? {
|
|
48
55
|
count: 0,
|
|
49
56
|
mine: !1
|
|
50
57
|
};
|
|
51
|
-
t.count += 1,
|
|
58
|
+
t.count += 1, b && e.memberId === b && (t.mine = !0), x.set(e.type, t);
|
|
52
59
|
}
|
|
53
|
-
let
|
|
54
|
-
|
|
60
|
+
let S = async (e) => {
|
|
61
|
+
y(!1);
|
|
55
62
|
try {
|
|
56
|
-
await
|
|
57
|
-
postId:
|
|
63
|
+
await g.mutateAsync({
|
|
64
|
+
postId: m.id,
|
|
58
65
|
type: e
|
|
59
66
|
});
|
|
60
67
|
} catch (e) {
|
|
61
|
-
|
|
68
|
+
a.error(_("comradecircle.components.reactionBar.reactError", "Could not react"), i(e));
|
|
62
69
|
}
|
|
63
70
|
};
|
|
64
|
-
return /* @__PURE__ */
|
|
71
|
+
return /* @__PURE__ */ l("div", {
|
|
65
72
|
className: "flex flex-wrap items-center gap-1.5",
|
|
66
|
-
children: [
|
|
67
|
-
let
|
|
68
|
-
return /* @__PURE__ */
|
|
73
|
+
children: [p.filter((e) => (x.get(e.type)?.count ?? 0) > 0).map((e) => {
|
|
74
|
+
let t = x.get(e.type);
|
|
75
|
+
return /* @__PURE__ */ l("button", {
|
|
69
76
|
type: "button",
|
|
70
|
-
onClick: () =>
|
|
71
|
-
disabled:
|
|
72
|
-
"aria-pressed":
|
|
73
|
-
"aria-label":
|
|
74
|
-
|
|
75
|
-
|
|
77
|
+
onClick: () => S(e.type),
|
|
78
|
+
disabled: g.isPending,
|
|
79
|
+
"aria-pressed": t.mine,
|
|
80
|
+
"aria-label": _("comradecircle.components.reactionBar.reactionAriaLabel", "{{label}} ({{count}})", {
|
|
81
|
+
label: _(e.key, e.fallback),
|
|
82
|
+
count: t.count
|
|
83
|
+
}),
|
|
84
|
+
className: r("inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-xs font-medium transition-transform duration-150 active:scale-90", t.mine ? "border-accent bg-[var(--color-accent-soft)] text-text-primary shadow-[0_0_0_2px_var(--color-accent-soft)]" : "border-border-seam bg-bg-surface text-text-secondary hover:-translate-y-px hover:bg-bg-sunken"),
|
|
85
|
+
children: [/* @__PURE__ */ c("span", {
|
|
76
86
|
"aria-hidden": "true",
|
|
77
87
|
children: e.emoji
|
|
78
|
-
}), /* @__PURE__ */
|
|
88
|
+
}), /* @__PURE__ */ c("span", {
|
|
79
89
|
className: "tabular-nums",
|
|
80
|
-
children:
|
|
90
|
+
children: t.count
|
|
81
91
|
})]
|
|
82
92
|
}, e.type);
|
|
83
|
-
}), /* @__PURE__ */
|
|
84
|
-
open:
|
|
85
|
-
onOpenChange:
|
|
86
|
-
children: [/* @__PURE__ */
|
|
93
|
+
}), /* @__PURE__ */ l(u, {
|
|
94
|
+
open: v,
|
|
95
|
+
onOpenChange: y,
|
|
96
|
+
children: [/* @__PURE__ */ c(f, {
|
|
87
97
|
asChild: !0,
|
|
88
|
-
children: /* @__PURE__ */
|
|
98
|
+
children: /* @__PURE__ */ c("button", {
|
|
89
99
|
type: "button",
|
|
90
|
-
"aria-label": "Add reaction",
|
|
100
|
+
"aria-label": _("comradecircle.components.reactionBar.addReactionAriaLabel", "Add reaction"),
|
|
91
101
|
className: "inline-flex items-center gap-1 rounded-full border border-border-seam bg-bg-surface px-2 py-0.5 text-xs text-text-secondary transition-colors hover:bg-bg-sunken hover:text-text-primary",
|
|
92
|
-
children: /* @__PURE__ */ s
|
|
102
|
+
children: /* @__PURE__ */ c(s, { className: "h-3.5 w-3.5" })
|
|
93
103
|
})
|
|
94
|
-
}), /* @__PURE__ */
|
|
104
|
+
}), /* @__PURE__ */ c(d, {
|
|
95
105
|
className: "w-auto p-1.5",
|
|
96
106
|
align: "start",
|
|
97
|
-
children: /* @__PURE__ */
|
|
107
|
+
children: /* @__PURE__ */ c("div", {
|
|
98
108
|
className: "flex items-center gap-0.5",
|
|
99
|
-
children:
|
|
100
|
-
let
|
|
101
|
-
return /* @__PURE__ */
|
|
109
|
+
children: p.map((e) => {
|
|
110
|
+
let t = x.get(e.type)?.mine ?? !1, n = _(e.key, e.fallback);
|
|
111
|
+
return /* @__PURE__ */ c("button", {
|
|
102
112
|
type: "button",
|
|
103
|
-
onClick: () =>
|
|
104
|
-
disabled:
|
|
105
|
-
title:
|
|
106
|
-
"aria-label":
|
|
107
|
-
className:
|
|
108
|
-
children: /* @__PURE__ */
|
|
113
|
+
onClick: () => S(e.type),
|
|
114
|
+
disabled: g.isPending,
|
|
115
|
+
title: n,
|
|
116
|
+
"aria-label": n,
|
|
117
|
+
className: r("flex h-9 w-9 items-center justify-center rounded-lg text-lg transition-transform hover:scale-110 hover:bg-bg-sunken", t && "bg-[var(--color-accent-soft)]"),
|
|
118
|
+
children: /* @__PURE__ */ c("span", {
|
|
109
119
|
"aria-hidden": "true",
|
|
110
120
|
children: e.emoji
|
|
111
121
|
})
|
|
@@ -117,6 +127,6 @@ function p({ post: p }) {
|
|
|
117
127
|
});
|
|
118
128
|
}
|
|
119
129
|
//#endregion
|
|
120
|
-
export {
|
|
130
|
+
export { m as ReactionBar };
|
|
121
131
|
|
|
122
132
|
//# sourceMappingURL=ReactionBar.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReactionBar.js","names":[],"sources":["../../../src/comradecircle/components/ReactionBar.tsx"],"sourcesContent":["/**\n * ReactionBar — Slack-style multi-reaction control for a post.\n * @module comradecircle/components\n *\n * `comReactToPost(postId, type)` is an idempotent toggle for one typed reaction,\n * so a member may hold several distinct reactions on a post. We render a chip\n * per reaction type that has a count (highlighted when the caller reacted) plus\n * a popover to add any of the six types.\n */\n\nimport { useState } from 'react';\nimport { SmilePlus } from 'lucide-react';\nimport { Popover, PopoverContent, PopoverTrigger } from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/cn';\nimport { useComReactToPost } from '../hooks';\nimport { useComradeCircle } from '../context';\nimport { notify, describeError } from '../lib/toast';\nimport type { ComPost, ComReactionType } from '../types';\n\nconst REACTIONS: { type: ComReactionType; emoji: string;
|
|
1
|
+
{"version":3,"file":"ReactionBar.js","names":[],"sources":["../../../src/comradecircle/components/ReactionBar.tsx"],"sourcesContent":["/**\n * ReactionBar — Slack-style multi-reaction control for a post.\n * @module comradecircle/components\n *\n * `comReactToPost(postId, type)` is an idempotent toggle for one typed reaction,\n * so a member may hold several distinct reactions on a post. We render a chip\n * per reaction type that has a count (highlighted when the caller reacted) plus\n * a popover to add any of the six types.\n */\n\nimport { useState } from 'react';\nimport { SmilePlus } from 'lucide-react';\nimport { Popover, PopoverContent, PopoverTrigger } from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/cn';\nimport { useComReactToPost, useTr } from '../hooks';\nimport { useComradeCircle } from '../context';\nimport { notify, describeError } from '../lib/toast';\nimport type { ComPost, ComReactionType } from '../types';\n\nconst REACTIONS: { type: ComReactionType; emoji: string; key: string; fallback: string }[] = [\n { type: 'LIKE', emoji: '👍', key: 'comradecircle.components.reactionBar.like', fallback: 'Like' },\n { type: 'LOVE', emoji: '❤️', key: 'comradecircle.components.reactionBar.love', fallback: 'Love' },\n {\n type: 'CELEBRATE',\n emoji: '🎉',\n key: 'comradecircle.components.reactionBar.celebrate',\n fallback: 'Celebrate',\n },\n {\n type: 'INSIGHTFUL',\n emoji: '💡',\n key: 'comradecircle.components.reactionBar.insightful',\n fallback: 'Insightful',\n },\n {\n type: 'LAUGH',\n emoji: '😄',\n key: 'comradecircle.components.reactionBar.funny',\n fallback: 'Funny',\n },\n {\n type: 'SUPPORT',\n emoji: '🤝',\n key: 'comradecircle.components.reactionBar.support',\n fallback: 'Support',\n },\n];\n\ninterface ReactionBarProps {\n post: ComPost;\n}\n\nexport function ReactionBar({ post }: ReactionBarProps) {\n const { currentUser } = useComradeCircle();\n const react = useComReactToPost();\n const tr = useTr();\n const [open, setOpen] = useState(false);\n\n const meId = currentUser?.id;\n const counts = new Map<ComReactionType, { count: number; mine: boolean }>();\n for (const r of post.reactions ?? []) {\n const cur = counts.get(r.type) ?? { count: 0, mine: false };\n cur.count += 1;\n if (meId && r.memberId === meId) cur.mine = true;\n counts.set(r.type, cur);\n }\n\n const toggle = async (type: ComReactionType) => {\n setOpen(false);\n try {\n await react.mutateAsync({ postId: post.id, type });\n } catch (err) {\n notify.error(\n tr('comradecircle.components.reactionBar.reactError', 'Could not react'),\n describeError(err)\n );\n }\n };\n\n const active = REACTIONS.filter((r) => (counts.get(r.type)?.count ?? 0) > 0);\n\n return (\n <div className=\"flex flex-wrap items-center gap-1.5\">\n {active.map((r) => {\n const info = counts.get(r.type)!;\n return (\n <button\n key={r.type}\n type=\"button\"\n onClick={() => toggle(r.type)}\n disabled={react.isPending}\n aria-pressed={info.mine}\n aria-label={tr(\n 'comradecircle.components.reactionBar.reactionAriaLabel',\n '{{label}} ({{count}})',\n {\n label: tr(r.key, r.fallback),\n count: info.count,\n }\n )}\n className={cn(\n 'inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-xs font-medium transition-transform duration-150 active:scale-90',\n info.mine\n ? 'border-accent bg-[var(--color-accent-soft)] text-text-primary shadow-[0_0_0_2px_var(--color-accent-soft)]'\n : 'border-border-seam bg-bg-surface text-text-secondary hover:-translate-y-px hover:bg-bg-sunken'\n )}\n >\n <span aria-hidden=\"true\">{r.emoji}</span>\n <span className=\"tabular-nums\">{info.count}</span>\n </button>\n );\n })}\n\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n aria-label={tr(\n 'comradecircle.components.reactionBar.addReactionAriaLabel',\n 'Add reaction'\n )}\n className=\"inline-flex items-center gap-1 rounded-full border border-border-seam bg-bg-surface px-2 py-0.5 text-xs text-text-secondary transition-colors hover:bg-bg-sunken hover:text-text-primary\"\n >\n <SmilePlus className=\"h-3.5 w-3.5\" />\n </button>\n </PopoverTrigger>\n <PopoverContent className=\"w-auto p-1.5\" align=\"start\">\n <div className=\"flex items-center gap-0.5\">\n {REACTIONS.map((r) => {\n const mine = counts.get(r.type)?.mine ?? false;\n const label = tr(r.key, r.fallback);\n return (\n <button\n key={r.type}\n type=\"button\"\n onClick={() => toggle(r.type)}\n disabled={react.isPending}\n title={label}\n aria-label={label}\n className={cn(\n 'flex h-9 w-9 items-center justify-center rounded-lg text-lg transition-transform hover:scale-110 hover:bg-bg-sunken',\n mine && 'bg-[var(--color-accent-soft)]'\n )}\n >\n <span aria-hidden=\"true\">{r.emoji}</span>\n </button>\n );\n })}\n </div>\n </PopoverContent>\n </Popover>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;AAmBA,IAAM,IAAuF;CAC3F;EAAE,MAAM;EAAQ,OAAO;EAAM,KAAK;EAA6C,UAAU;CAAO;CAChG;EAAE,MAAM;EAAQ,OAAO;EAAM,KAAK;EAA6C,UAAU;CAAO;CAChG;EACE,MAAM;EACN,OAAO;EACP,KAAK;EACL,UAAU;CACZ;CACA;EACE,MAAM;EACN,OAAO;EACP,KAAK;EACL,UAAU;CACZ;CACA;EACE,MAAM;EACN,OAAO;EACP,KAAK;EACL,UAAU;CACZ;CACA;EACE,MAAM;EACN,OAAO;EACP,KAAK;EACL,UAAU;CACZ;AACF;AAMA,SAAgB,EAAY,EAAE,WAA0B;CACtD,IAAM,EAAE,mBAAgB,EAAiB,GACnC,IAAQ,EAAkB,GAC1B,IAAK,EAAM,GACX,CAAC,GAAM,KAAW,EAAS,EAAK,GAEhC,IAAO,GAAa,IACpB,oBAAS,IAAI,IAAuD;CAC1E,KAAK,IAAM,KAAK,EAAK,aAAa,CAAC,GAAG;EACpC,IAAM,IAAM,EAAO,IAAI,EAAE,IAAI,KAAK;GAAE,OAAO;GAAG,MAAM;EAAM;EAG1D,AAFA,EAAI,SAAS,GACT,KAAQ,EAAE,aAAa,MAAM,EAAI,OAAO,KAC5C,EAAO,IAAI,EAAE,MAAM,CAAG;CACxB;CAEA,IAAM,IAAS,OAAO,MAA0B;EAC9C,EAAQ,EAAK;EACb,IAAI;GACF,MAAM,EAAM,YAAY;IAAE,QAAQ,EAAK;IAAI;GAAK,CAAC;EACnD,SAAS,GAAK;GACZ,EAAO,MACL,EAAG,mDAAmD,iBAAiB,GACvE,EAAc,CAAG,CACnB;EACF;CACF;CAIA,OACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CAHa,EAAU,QAAQ,OAAO,EAAO,IAAI,EAAE,IAAI,GAAG,SAAS,KAAK,CAIrE,EAAO,KAAK,MAAM;GACjB,IAAM,IAAO,EAAO,IAAI,EAAE,IAAI;GAC9B,OACE,kBAAC,UAAD;IAEE,MAAK;IACL,eAAe,EAAO,EAAE,IAAI;IAC5B,UAAU,EAAM;IAChB,gBAAc,EAAK;IACnB,cAAY,EACV,0DACA,yBACA;KACE,OAAO,EAAG,EAAE,KAAK,EAAE,QAAQ;KAC3B,OAAO,EAAK;IACd,CACF;IACA,WAAW,EACT,wIACA,EAAK,OACD,8GACA,+FACN;cAnBF,CAqBE,kBAAC,QAAD;KAAM,eAAY;eAAQ,EAAE;IAAY,CAAA,GACxC,kBAAC,QAAD;KAAM,WAAU;eAAgB,EAAK;IAAY,CAAA,CAC3C;MAtBD,EAAE,IAsBD;EAEZ,CAAC,GAED,kBAAC,GAAD;GAAe;GAAM,cAAc;aAAnC,CACE,kBAAC,GAAD;IAAgB,SAAA;cACd,kBAAC,UAAD;KACE,MAAK;KACL,cAAY,EACV,6DACA,cACF;KACA,WAAU;eAEV,kBAAC,GAAD,EAAW,WAAU,cAAe,CAAA;IAC9B,CAAA;GACM,CAAA,GAChB,kBAAC,GAAD;IAAgB,WAAU;IAAe,OAAM;cAC7C,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAU,KAAK,MAAM;MACpB,IAAM,IAAO,EAAO,IAAI,EAAE,IAAI,GAAG,QAAQ,IACnC,IAAQ,EAAG,EAAE,KAAK,EAAE,QAAQ;MAClC,OACE,kBAAC,UAAD;OAEE,MAAK;OACL,eAAe,EAAO,EAAE,IAAI;OAC5B,UAAU,EAAM;OAChB,OAAO;OACP,cAAY;OACZ,WAAW,EACT,uHACA,KAAQ,+BACV;iBAEA,kBAAC,QAAD;QAAM,eAAY;kBAAQ,EAAE;OAAY,CAAA;MAClC,GAZD,EAAE,IAYD;KAEZ,CAAC;IACE,CAAA;GACS,CAAA,CACT;IACN;;AAET"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StateViews.d.ts","sourceRoot":"","sources":["../../../src/comradecircle/components/StateViews.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"StateViews.d.ts","sourceRoot":"","sources":["../../../src/comradecircle/components/StateViews.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAM3C,UAAU,gBAAgB;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,WAAW,EAAE,EAAE,CAAC,gBAAgB,CAU5C,CAAC;AAEF,UAAU,cAAc;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,SAAS,EAAE,EAAE,CAAC,cAAc,CA2BxC,CAAC;AAEF,UAAU,YAAY;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,OAAO,EAAE,EAAE,CAAC,YAAY,CAWpC,CAAC"}
|
|
@@ -1,34 +1,42 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { useTr as e } from "../hooks/useTr.js";
|
|
2
|
+
import "../hooks/index.js";
|
|
3
|
+
import { cn as t } from "../utils/cn.js";
|
|
4
|
+
import { AlertCircle as n } from "lucide-react";
|
|
5
|
+
import { jsx as r, jsxs as i } from "react/jsx-runtime";
|
|
6
|
+
import { Spinner as a } from "@burdenoff/fe-libs/ui";
|
|
5
7
|
//#region src/comradecircle/components/StateViews.tsx
|
|
6
|
-
var
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
className: "
|
|
10
|
-
children:
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
className: "
|
|
21
|
-
children:
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
8
|
+
var o = ({ label: n, className: o }) => {
|
|
9
|
+
let s = e();
|
|
10
|
+
return /* @__PURE__ */ i("div", {
|
|
11
|
+
className: t("flex min-h-[40vh] flex-col items-center justify-center gap-3", o),
|
|
12
|
+
children: [/* @__PURE__ */ r(a, { size: "lg" }), /* @__PURE__ */ r("p", {
|
|
13
|
+
className: "text-sm text-text-secondary",
|
|
14
|
+
children: n ?? s("comradecircle.components.stateViews.loading", "Loading…")
|
|
15
|
+
})]
|
|
16
|
+
});
|
|
17
|
+
}, s = ({ title: a, message: o, onRetry: s, className: c }) => {
|
|
18
|
+
let l = e();
|
|
19
|
+
return /* @__PURE__ */ i("div", {
|
|
20
|
+
className: t("flex min-h-[40vh] flex-col items-center justify-center gap-4 text-center", c),
|
|
21
|
+
children: [
|
|
22
|
+
/* @__PURE__ */ r(n, { className: "h-10 w-10 text-status-error-text" }),
|
|
23
|
+
/* @__PURE__ */ i("div", { children: [/* @__PURE__ */ r("h2", {
|
|
24
|
+
className: "text-lg font-semibold text-text-primary",
|
|
25
|
+
children: a ?? l("comradecircle.components.stateViews.errorTitle", "Something went wrong")
|
|
26
|
+
}), o && /* @__PURE__ */ r("p", {
|
|
27
|
+
className: "mt-1 max-w-md text-sm text-text-secondary",
|
|
28
|
+
children: o
|
|
29
|
+
})] }),
|
|
30
|
+
s && /* @__PURE__ */ r("button", {
|
|
31
|
+
type: "button",
|
|
32
|
+
onClick: s,
|
|
33
|
+
className: "rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90",
|
|
34
|
+
children: l("comradecircle.components.stateViews.retry", "Retry")
|
|
35
|
+
})
|
|
36
|
+
]
|
|
37
|
+
});
|
|
38
|
+
};
|
|
31
39
|
//#endregion
|
|
32
|
-
export {
|
|
40
|
+
export { s as ErrorView, o as LoadingView };
|
|
33
41
|
|
|
34
42
|
//# sourceMappingURL=StateViews.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StateViews.js","names":[],"sources":["../../../src/comradecircle/components/StateViews.tsx"],"sourcesContent":["/**\n * Shared loading / error / section state views\n * @module comradecircle/components\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { AlertCircle } from 'lucide-react';\nimport { Spinner } from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/cn';\n\ninterface LoadingViewProps {\n label?: string;\n className?: string;\n}\n\nexport const LoadingView: FC<LoadingViewProps> = ({ label
|
|
1
|
+
{"version":3,"file":"StateViews.js","names":[],"sources":["../../../src/comradecircle/components/StateViews.tsx"],"sourcesContent":["/**\n * Shared loading / error / section state views\n * @module comradecircle/components\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { AlertCircle } from 'lucide-react';\nimport { Spinner } from '@burdenoff/fe-libs/ui';\nimport { useTr } from '../hooks';\nimport { cn } from '../utils/cn';\n\ninterface LoadingViewProps {\n label?: string;\n className?: string;\n}\n\nexport const LoadingView: FC<LoadingViewProps> = ({ label, className }) => {\n const tr = useTr();\n return (\n <div className={cn('flex min-h-[40vh] flex-col items-center justify-center gap-3', className)}>\n <Spinner size=\"lg\" />\n <p className=\"text-sm text-text-secondary\">\n {label ?? tr('comradecircle.components.stateViews.loading', 'Loading…')}\n </p>\n </div>\n );\n};\n\ninterface ErrorViewProps {\n title?: string;\n message?: string;\n onRetry?: () => void;\n className?: string;\n}\n\nexport const ErrorView: FC<ErrorViewProps> = ({ title, message, onRetry, className }) => {\n const tr = useTr();\n return (\n <div\n className={cn(\n 'flex min-h-[40vh] flex-col items-center justify-center gap-4 text-center',\n className\n )}\n >\n <AlertCircle className=\"h-10 w-10 text-status-error-text\" />\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {title ?? tr('comradecircle.components.stateViews.errorTitle', 'Something went wrong')}\n </h2>\n {message && <p className=\"mt-1 max-w-md text-sm text-text-secondary\">{message}</p>}\n </div>\n {onRetry && (\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90\"\n >\n {tr('comradecircle.components.stateViews.retry', 'Retry')}\n </button>\n )}\n </div>\n );\n};\n\ninterface SectionProps {\n title: string;\n description?: string;\n action?: ReactNode;\n children: ReactNode;\n className?: string;\n}\n\nexport const Section: FC<SectionProps> = ({ title, description, action, children, className }) => (\n <section className={cn('mt-8 first:mt-0', className)}>\n <div className=\"mb-3 flex items-end justify-between gap-3\">\n <div>\n <h2 className=\"text-base font-semibold text-text-primary\">{title}</h2>\n {description && <p className=\"mt-0.5 text-sm text-text-secondary\">{description}</p>}\n </div>\n {action && <div className=\"shrink-0\">{action}</div>}\n </div>\n {children}\n </section>\n);\n"],"mappings":";;;;;;;AAgBA,IAAa,KAAqC,EAAE,UAAO,mBAAgB;CACzE,IAAM,IAAK,EAAM;CACjB,OACE,kBAAC,OAAD;EAAK,WAAW,EAAG,gEAAgE,CAAS;YAA5F,CACE,kBAAC,GAAD,EAAS,MAAK,KAAM,CAAA,GACpB,kBAAC,KAAD;GAAG,WAAU;aACV,KAAS,EAAG,+CAA+C,UAAU;EACrE,CAAA,CACA;;AAET,GASa,KAAiC,EAAE,UAAO,YAAS,YAAS,mBAAgB;CACvF,IAAM,IAAK,EAAM;CACjB,OACE,kBAAC,OAAD;EACE,WAAW,EACT,4EACA,CACF;YAJF;GAME,kBAAC,GAAD,EAAa,WAAU,mCAAoC,CAAA;GAC3D,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;IAAI,WAAU;cACX,KAAS,EAAG,kDAAkD,sBAAsB;GACnF,CAAA,GACH,KAAW,kBAAC,KAAD;IAAG,WAAU;cAA6C;GAAW,CAAA,CAC9E,EAAA,CAAA;GACJ,KACC,kBAAC,UAAD;IACE,MAAK;IACL,SAAS;IACT,WAAU;cAET,EAAG,6CAA6C,OAAO;GAClD,CAAA;EAEP;;AAET"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useComradeCircle as e } from "../context/ComradeCircleContext.js";
|
|
2
2
|
import "../context/index.js";
|
|
3
|
-
import {
|
|
4
|
-
import { useComEvents as n, useComRsvpEvent as r } from "../hooks/useComradeCircleApi.js";
|
|
3
|
+
import { useComEvents as t, useComRsvpEvent as n } from "../hooks/useComradeCircleApi.js";
|
|
5
4
|
import "../hooks/index.js";
|
|
5
|
+
import { cn as r } from "../utils/cn.js";
|
|
6
6
|
import { describeError as i, notify as a } from "../lib/toast.js";
|
|
7
7
|
import { formatDateTime as o, formatNumber as s } from "../utils/formatters.js";
|
|
8
8
|
import { useEffect as c, useMemo as l, useState as u } from "react";
|
|
@@ -18,17 +18,17 @@ function C(e = S) {
|
|
|
18
18
|
return () => clearInterval(t);
|
|
19
19
|
}, [e]), t;
|
|
20
20
|
}
|
|
21
|
-
function w({ limit:
|
|
22
|
-
let { navigateTo: a } = e(), o = C(), { data: s, isLoading: c, isError: u } =
|
|
21
|
+
function w({ limit: n = 3, className: i }) {
|
|
22
|
+
let { navigateTo: a } = e(), o = C(), { data: s, isLoading: c, isError: u } = t({
|
|
23
23
|
status: "SCHEDULED",
|
|
24
24
|
pagination: { limit: x }
|
|
25
|
-
}), p = l(() => (s?.items ?? []).filter((e) => new Date(e.startsAt).getTime() >= o).slice(0,
|
|
25
|
+
}), p = l(() => (s?.items ?? []).filter((e) => new Date(e.startsAt).getTime() >= o).slice(0, n), [
|
|
26
26
|
s,
|
|
27
27
|
o,
|
|
28
|
-
|
|
28
|
+
n
|
|
29
29
|
]);
|
|
30
30
|
return c || u || p.length === 0 ? null : /* @__PURE__ */ y("section", {
|
|
31
|
-
className:
|
|
31
|
+
className: r("mx-auto w-full max-w-2xl", i),
|
|
32
32
|
"aria-labelledby": "cc-upcoming",
|
|
33
33
|
children: [/* @__PURE__ */ y("div", {
|
|
34
34
|
className: "mb-2 flex items-center justify-between gap-3",
|
|
@@ -51,13 +51,13 @@ function w({ limit: r = 3, className: i }) {
|
|
|
51
51
|
})]
|
|
52
52
|
});
|
|
53
53
|
}
|
|
54
|
-
function T({ event:
|
|
55
|
-
let { navigateTo: c } = e(), l =
|
|
54
|
+
function T({ event: t }) {
|
|
55
|
+
let { navigateTo: c } = e(), l = n(), [d, x] = u(null), S = d === "GOING", C = t.mode === "IN_PERSON" ? m : g, w = t.mode === "IN_PERSON" ? t.location || "In person" : t.mode === "HYBRID" ? `Hybrid${t.location ? ` · ${t.location}` : ""}` : "Online", T = async () => {
|
|
56
56
|
try {
|
|
57
57
|
await l.mutateAsync({
|
|
58
|
-
eventId:
|
|
58
|
+
eventId: t.id,
|
|
59
59
|
status: "GOING"
|
|
60
|
-
}), x("GOING"), a.success("RSVP: Going",
|
|
60
|
+
}), x("GOING"), a.success("RSVP: Going", t.title);
|
|
61
61
|
} catch (e) {
|
|
62
62
|
a.error("Could not RSVP", i(e));
|
|
63
63
|
}
|
|
@@ -74,13 +74,13 @@ function T({ event: n }) {
|
|
|
74
74
|
className: "min-w-0 flex-1",
|
|
75
75
|
children: [/* @__PURE__ */ v("button", {
|
|
76
76
|
type: "button",
|
|
77
|
-
onClick: () => c(`events/${
|
|
77
|
+
onClick: () => c(`events/${t.id}`),
|
|
78
78
|
className: "block max-w-full truncate text-left text-sm font-semibold text-text-primary transition-colors hover:text-accent",
|
|
79
|
-
children:
|
|
79
|
+
children: t.title
|
|
80
80
|
}), /* @__PURE__ */ y("div", {
|
|
81
81
|
className: "mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-0.5 text-xs text-text-tertiary",
|
|
82
82
|
children: [
|
|
83
|
-
/* @__PURE__ */ v("span", { children: o(
|
|
83
|
+
/* @__PURE__ */ v("span", { children: o(t.startsAt) }),
|
|
84
84
|
/* @__PURE__ */ v("span", {
|
|
85
85
|
"aria-hidden": "true",
|
|
86
86
|
children: "·"
|
|
@@ -101,8 +101,8 @@ function T({ event: n }) {
|
|
|
101
101
|
className: "inline-flex items-center gap-1",
|
|
102
102
|
children: [
|
|
103
103
|
/* @__PURE__ */ v(h, { className: "h-3 w-3" }),
|
|
104
|
-
s(
|
|
105
|
-
|
|
104
|
+
s(t.rsvpCount),
|
|
105
|
+
t.capacity ? ` / ${s(t.capacity)}` : ""
|
|
106
106
|
]
|
|
107
107
|
})
|
|
108
108
|
]
|
|
@@ -114,7 +114,7 @@ function T({ event: n }) {
|
|
|
114
114
|
onClick: () => void T(),
|
|
115
115
|
disabled: l.isPending,
|
|
116
116
|
"aria-pressed": S,
|
|
117
|
-
className:
|
|
117
|
+
className: r("shrink-0", S && "text-accent"),
|
|
118
118
|
children: S ? /* @__PURE__ */ y(_, { children: [/* @__PURE__ */ v(p, { className: "mr-1 h-3.5 w-3.5" }), " Going"] }) : "RSVP"
|
|
119
119
|
})
|
|
120
120
|
]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/comradecircle/hooks/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/comradecircle/hooks/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useTr — translation hook with fallback semantics.
|
|
3
|
+
*
|
|
4
|
+
* Wraps `useI18n().t()` so that when a key has no translation (i.e. the
|
|
5
|
+
* provider returns the key itself), the caller's English fallback is used
|
|
6
|
+
* instead. This keeps consumer call sites consistent and avoids leaking
|
|
7
|
+
* untranslated keys into the UI.
|
|
8
|
+
*
|
|
9
|
+
* Supports optional interpolation params using `{{key}}` placeholders.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* const tr = useTr();
|
|
13
|
+
* return <h1>{tr('comradecircle.pages.feed.title', 'Home')}</h1>;
|
|
14
|
+
* return <p>{tr('comradecircle.components.pagination.showing', 'Showing {{from}}–{{to}}', { from: 1, to: 10 })}</p>;
|
|
15
|
+
*/
|
|
16
|
+
export type TranslationParams = Record<string, string | number>;
|
|
17
|
+
export declare function useTr(): (key: string, fallback: string, params?: TranslationParams) => string;
|
|
18
|
+
//# sourceMappingURL=useTr.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTr.d.ts","sourceRoot":"","sources":["../../../src/comradecircle/hooks/useTr.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;AAEhE,wBAAgB,KAAK,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,iBAAiB,KAAK,MAAM,CAQ7F"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { tWithFallback as e } from "../utils/i18n.js";
|
|
2
|
+
import { useCallback as t } from "react";
|
|
3
|
+
import { useI18n as n } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
4
|
+
//#region src/comradecircle/hooks/useTr.ts
|
|
5
|
+
function r() {
|
|
6
|
+
let { t: r } = n();
|
|
7
|
+
return t((t, n, i) => e(r, t, n, i), [r]);
|
|
8
|
+
}
|
|
9
|
+
//#endregion
|
|
10
|
+
export { r as useTr };
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=useTr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTr.js","names":[],"sources":["../../../src/comradecircle/hooks/useTr.ts"],"sourcesContent":["/**\n * useTr — translation hook with fallback semantics.\n *\n * Wraps `useI18n().t()` so that when a key has no translation (i.e. the\n * provider returns the key itself), the caller's English fallback is used\n * instead. This keeps consumer call sites consistent and avoids leaking\n * untranslated keys into the UI.\n *\n * Supports optional interpolation params using `{{key}}` placeholders.\n *\n * @example\n * const tr = useTr();\n * return <h1>{tr('comradecircle.pages.feed.title', 'Home')}</h1>;\n * return <p>{tr('comradecircle.components.pagination.showing', 'Showing {{from}}–{{to}}', { from: 1, to: 10 })}</p>;\n */\n\nimport { useCallback } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { tWithFallback } from '../utils/i18n';\n\nexport type TranslationParams = Record<string, string | number>;\n\nexport function useTr(): (key: string, fallback: string, params?: TranslationParams) => string {\n const { t } = useI18n();\n\n return useCallback(\n (key: string, fallback: string, params?: TranslationParams): string =>\n tWithFallback(t, key, fallback, params),\n [t]\n );\n}\n"],"mappings":";;;;AAsBA,SAAgB,IAA+E;CAC7F,IAAM,EAAE,SAAM,EAAQ;CAEtB,OAAO,GACJ,GAAa,GAAkB,MAC9B,EAAc,GAAG,GAAK,GAAU,CAAM,GACxC,CAAC,CAAC,CACJ;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FeedPage.d.ts","sourceRoot":"","sources":["../../../src/comradecircle/pages/FeedPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAkEH,wBAAgB,QAAQ,
|
|
1
|
+
{"version":3,"file":"FeedPage.d.ts","sourceRoot":"","sources":["../../../src/comradecircle/pages/FeedPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAkEH,wBAAgB,QAAQ,4CAgFvB"}
|