@burdenoff/microfe-comradecircle 2026.704.2 → 2026.713.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/ComradeCircleRoot.d.ts +5 -0
- package/dist/comradecircle/ComradeCircleRoot.d.ts.map +1 -0
- package/dist/comradecircle/ComradeCircleRoutes.d.ts +4 -0
- package/dist/comradecircle/ComradeCircleRoutes.d.ts.map +1 -0
- package/dist/comradecircle/components/Avatar.d.ts +20 -0
- package/dist/comradecircle/components/Avatar.d.ts.map +1 -0
- package/dist/comradecircle/components/Avatar.js +40 -17
- package/dist/comradecircle/components/Avatar.js.map +1 -1
- package/dist/comradecircle/components/AvatarUploadField.d.ts +21 -0
- package/dist/comradecircle/components/AvatarUploadField.d.ts.map +1 -0
- package/dist/comradecircle/components/AvatarUploadField.js +25 -14
- package/dist/comradecircle/components/AvatarUploadField.js.map +1 -1
- package/dist/comradecircle/components/CircleCard.d.ts +10 -0
- package/dist/comradecircle/components/CircleCard.d.ts.map +1 -0
- package/dist/comradecircle/components/CircleCard.js +54 -52
- package/dist/comradecircle/components/CircleCard.js.map +1 -1
- package/dist/comradecircle/components/CommentThread.d.ts +14 -0
- package/dist/comradecircle/components/CommentThread.d.ts.map +1 -0
- package/dist/comradecircle/components/CommentThread.js +80 -64
- package/dist/comradecircle/components/CommentThread.js.map +1 -1
- package/dist/comradecircle/components/CreateCircleDialog.d.ts +10 -0
- package/dist/comradecircle/components/CreateCircleDialog.d.ts.map +1 -0
- package/dist/comradecircle/components/CreateEventDialog.d.ts +12 -0
- package/dist/comradecircle/components/CreateEventDialog.d.ts.map +1 -0
- package/dist/comradecircle/components/DataTable.d.ts +28 -0
- package/dist/comradecircle/components/DataTable.d.ts.map +1 -0
- package/dist/comradecircle/components/EmptyState.d.ts +18 -0
- package/dist/comradecircle/components/EmptyState.d.ts.map +1 -0
- package/dist/comradecircle/components/EventCard.d.ts +9 -0
- package/dist/comradecircle/components/EventCard.d.ts.map +1 -0
- package/dist/comradecircle/components/EventCard.js +84 -58
- package/dist/comradecircle/components/EventCard.js.map +1 -1
- package/dist/comradecircle/components/FileImage.d.ts +18 -0
- package/dist/comradecircle/components/FileImage.d.ts.map +1 -0
- package/dist/comradecircle/components/FilterTabs.d.ts +18 -0
- package/dist/comradecircle/components/FilterTabs.d.ts.map +1 -0
- package/dist/comradecircle/components/ImageAttachments.d.ts +20 -0
- package/dist/comradecircle/components/ImageAttachments.d.ts.map +1 -0
- package/dist/comradecircle/components/MemberIdentity.d.ts +16 -0
- package/dist/comradecircle/components/MemberIdentity.d.ts.map +1 -0
- package/dist/comradecircle/components/MemberIdentity.js +2 -1
- package/dist/comradecircle/components/MemberIdentity.js.map +1 -1
- package/dist/comradecircle/components/MetricsCard.d.ts +23 -0
- package/dist/comradecircle/components/MetricsCard.d.ts.map +1 -0
- package/dist/comradecircle/components/MiniBar.d.ts +16 -0
- package/dist/comradecircle/components/MiniBar.d.ts.map +1 -0
- package/dist/comradecircle/components/PageLayout.d.ts +16 -0
- package/dist/comradecircle/components/PageLayout.d.ts.map +1 -0
- package/dist/comradecircle/components/Pagination.d.ts +22 -0
- package/dist/comradecircle/components/Pagination.d.ts.map +1 -0
- package/dist/comradecircle/components/PollCard.d.ts +10 -0
- package/dist/comradecircle/components/PollCard.d.ts.map +1 -0
- package/dist/comradecircle/components/PollCard.js +65 -44
- package/dist/comradecircle/components/PollCard.js.map +1 -1
- package/dist/comradecircle/components/PostCard.d.ts +10 -0
- package/dist/comradecircle/components/PostCard.d.ts.map +1 -0
- package/dist/comradecircle/components/PostCard.js +1 -1
- package/dist/comradecircle/components/PostCard.js.map +1 -1
- package/dist/comradecircle/components/PostComposer.d.ts +16 -0
- package/dist/comradecircle/components/PostComposer.d.ts.map +1 -0
- package/dist/comradecircle/components/ReactionBar.d.ts +8 -0
- package/dist/comradecircle/components/ReactionBar.d.ts.map +1 -0
- package/dist/comradecircle/components/ReactionBar.js +1 -1
- package/dist/comradecircle/components/ReactionBar.js.map +1 -1
- package/dist/comradecircle/components/StateViews.d.ts +24 -0
- package/dist/comradecircle/components/StateViews.d.ts.map +1 -0
- package/dist/comradecircle/components/StateViews.js +1 -16
- package/dist/comradecircle/components/StateViews.js.map +1 -1
- package/dist/comradecircle/components/StatusBadge.d.ts +9 -0
- package/dist/comradecircle/components/StatusBadge.d.ts.map +1 -0
- package/dist/comradecircle/components/StatusBadge.js +1 -1
- package/dist/comradecircle/components/StatusBadge.js.map +1 -1
- package/dist/comradecircle/components/Tabs.d.ts +17 -0
- package/dist/comradecircle/components/Tabs.d.ts.map +1 -0
- package/dist/comradecircle/components/TagInput.d.ts +18 -0
- package/dist/comradecircle/components/TagInput.d.ts.map +1 -0
- package/dist/comradecircle/components/index.d.ts +30 -0
- package/dist/comradecircle/components/index.d.ts.map +1 -0
- package/dist/comradecircle/context/ComradeCircleContext.d.ts +16 -0
- package/dist/comradecircle/context/ComradeCircleContext.d.ts.map +1 -0
- package/dist/comradecircle/context/index.d.ts +6 -0
- package/dist/comradecircle/context/index.d.ts.map +1 -0
- package/dist/comradecircle/hooks/index.d.ts +8 -0
- package/dist/comradecircle/hooks/index.d.ts.map +1 -0
- package/dist/comradecircle/hooks/useComradeCircleApi.d.ts +103 -0
- package/dist/comradecircle/hooks/useComradeCircleApi.d.ts.map +1 -0
- package/dist/comradecircle/hooks/useComradeCircleApi.js +1 -1
- package/dist/comradecircle/hooks/useComradeCircleApi.js.map +1 -1
- package/dist/comradecircle/hooks/useCursorPager.d.ts +33 -0
- package/dist/comradecircle/hooks/useCursorPager.d.ts.map +1 -0
- package/dist/comradecircle/hooks/useFiles.d.ts +28 -0
- package/dist/comradecircle/hooks/useFiles.d.ts.map +1 -0
- package/dist/comradecircle/index.d.ts +10 -0
- package/dist/comradecircle/index.d.ts.map +1 -0
- package/dist/comradecircle/index.js +1 -0
- package/dist/comradecircle/lib/graphql-cache.d.ts +26 -0
- package/dist/comradecircle/lib/graphql-cache.d.ts.map +1 -0
- package/dist/comradecircle/lib/toast.d.ts +23 -0
- package/dist/comradecircle/lib/toast.d.ts.map +1 -0
- package/dist/comradecircle/pages/FeedPage.d.ts +10 -0
- package/dist/comradecircle/pages/FeedPage.d.ts.map +1 -0
- package/dist/comradecircle/pages/FeedPage.js +79 -33
- package/dist/comradecircle/pages/FeedPage.js.map +1 -1
- package/dist/comradecircle/pages/circles/CircleDetailPage.d.ts +11 -0
- package/dist/comradecircle/pages/circles/CircleDetailPage.d.ts.map +1 -0
- package/dist/comradecircle/pages/circles/CircleDetailPage.js +354 -243
- package/dist/comradecircle/pages/circles/CircleDetailPage.js.map +1 -1
- package/dist/comradecircle/pages/circles/CirclesPage.d.ts +11 -0
- package/dist/comradecircle/pages/circles/CirclesPage.d.ts.map +1 -0
- package/dist/comradecircle/pages/circles/CirclesPage.js +97 -47
- package/dist/comradecircle/pages/circles/CirclesPage.js.map +1 -1
- package/dist/comradecircle/pages/events/EventDetailPage.d.ts +11 -0
- package/dist/comradecircle/pages/events/EventDetailPage.d.ts.map +1 -0
- package/dist/comradecircle/pages/events/EventDetailPage.js +193 -126
- package/dist/comradecircle/pages/events/EventDetailPage.js.map +1 -1
- package/dist/comradecircle/pages/events/EventsPage.d.ts +11 -0
- package/dist/comradecircle/pages/events/EventsPage.d.ts.map +1 -0
- package/dist/comradecircle/pages/events/EventsPage.js +74 -34
- package/dist/comradecircle/pages/events/EventsPage.js.map +1 -1
- package/dist/comradecircle/pages/members/MemberProfilePage.d.ts +13 -0
- package/dist/comradecircle/pages/members/MemberProfilePage.d.ts.map +1 -0
- package/dist/comradecircle/pages/members/MemberProfilePage.js +154 -82
- package/dist/comradecircle/pages/members/MemberProfilePage.js.map +1 -1
- package/dist/comradecircle/pages/members/MembersPage.d.ts +13 -0
- package/dist/comradecircle/pages/members/MembersPage.d.ts.map +1 -0
- package/dist/comradecircle/pages/members/MembersPage.js +140 -71
- package/dist/comradecircle/pages/members/MembersPage.js.map +1 -1
- package/dist/comradecircle/pages/profile/MyProfilePage.d.ts +17 -0
- package/dist/comradecircle/pages/profile/MyProfilePage.d.ts.map +1 -0
- package/dist/comradecircle/pages/profile/MyProfilePage.js +298 -202
- package/dist/comradecircle/pages/profile/MyProfilePage.js.map +1 -1
- package/dist/comradecircle/types/index.d.ts +362 -0
- package/dist/comradecircle/types/index.d.ts.map +1 -0
- package/dist/comradecircle/utils/cn.d.ts +4 -0
- package/dist/comradecircle/utils/cn.d.ts.map +1 -0
- package/dist/comradecircle/utils/formatters.d.ts +26 -0
- package/dist/comradecircle/utils/formatters.d.ts.map +1 -0
- package/dist/comradecircle/utils/i18n.d.ts +6 -0
- package/dist/comradecircle/utils/i18n.d.ts.map +1 -0
- package/dist/comradecircle/utils/index.d.ts +10 -0
- package/dist/comradecircle/utils/index.d.ts.map +1 -0
- package/dist/comradecircle/utils/navigation.d.ts +14 -0
- package/dist/comradecircle/utils/navigation.d.ts.map +1 -0
- package/dist/comradecircle/utils/slug.d.ts +6 -0
- package/dist/comradecircle/utils/slug.d.ts.map +1 -0
- package/dist/dev/main.d.ts +2 -0
- package/dist/dev/main.d.ts.map +1 -0
- package/dist/generated/global-operations.d.ts +2 -0
- package/dist/generated/global-operations.d.ts.map +1 -0
- package/dist/generated/global-types.d.ts +18199 -0
- package/dist/generated/global-types.d.ts.map +1 -0
- package/dist/generated/wspace-operations.d.ts +2 -0
- package/dist/generated/wspace-operations.d.ts.map +1 -0
- package/dist/generated/wspace-types.d.ts +43046 -0
- package/dist/generated/wspace-types.d.ts.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -1
- package/dist/services/createSandboxAssistantTransport.d.ts +24 -0
- package/dist/services/createSandboxAssistantTransport.d.ts.map +1 -0
- package/dist/services/createSandboxAssistantTransport.js +12 -0
- package/dist/services/createSandboxAssistantTransport.js.map +1 -0
- package/package.json +6 -2
|
@@ -1,17 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { useComradeCircle as e } from "../context/ComradeCircleContext.js";
|
|
2
|
+
import { cn as t } from "../utils/cn.js";
|
|
3
|
+
import "../context/index.js";
|
|
4
|
+
import { useComAddComment as n, useComComments as r } from "../hooks/useComradeCircleApi.js";
|
|
3
5
|
import "../hooks/index.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
6
|
+
import { Avatar as i } from "./Avatar.js";
|
|
7
|
+
import { MemberIdentity as a } from "./MemberIdentity.js";
|
|
8
|
+
import { describeError as o, notify as s } from "../lib/toast.js";
|
|
9
|
+
import { formatRelativeTime as c } from "../utils/formatters.js";
|
|
10
|
+
import { useMemo as l, useState as u } from "react";
|
|
11
|
+
import { CornerDownRight as d, MessageCircle as f, Send as p } from "lucide-react";
|
|
12
|
+
import { jsx as m, jsxs as h } from "react/jsx-runtime";
|
|
13
|
+
import { Button as g, Spinner as _, Textarea as v } from "@burdenoff/fe-libs/ui";
|
|
11
14
|
//#region src/comradecircle/components/CommentThread.tsx
|
|
12
|
-
function
|
|
13
|
-
let { data:
|
|
14
|
-
let e =
|
|
15
|
+
function y({ postId: y }) {
|
|
16
|
+
let { currentUser: b } = e(), { data: x, isLoading: S } = r(y), C = n(), [w, T] = u(""), [E, D] = u(null), { roots: O, repliesByParent: k } = l(() => {
|
|
17
|
+
let e = x ?? [], t = /* @__PURE__ */ new Map(), n = [];
|
|
15
18
|
for (let r of e) if (r.parentId) {
|
|
16
19
|
let e = t.get(r.parentId) ?? [];
|
|
17
20
|
e.push(r), t.set(r.parentId, e);
|
|
@@ -20,86 +23,99 @@ function g({ postId: g }) {
|
|
|
20
23
|
roots: n,
|
|
21
24
|
repliesByParent: t
|
|
22
25
|
};
|
|
23
|
-
}, [
|
|
24
|
-
let e =
|
|
26
|
+
}, [x]), A = async () => {
|
|
27
|
+
let e = w.trim();
|
|
25
28
|
if (e) try {
|
|
26
|
-
await
|
|
27
|
-
postId:
|
|
29
|
+
await C.mutateAsync({
|
|
30
|
+
postId: y,
|
|
28
31
|
body: e,
|
|
29
|
-
parentId:
|
|
30
|
-
}),
|
|
32
|
+
parentId: E?.id ?? null
|
|
33
|
+
}), T(""), D(null);
|
|
31
34
|
} catch (e) {
|
|
32
|
-
|
|
35
|
+
s.error("Could not add comment", o(e));
|
|
33
36
|
}
|
|
34
|
-
},
|
|
35
|
-
className:
|
|
36
|
-
children: [/* @__PURE__ */
|
|
37
|
+
}, j = (e, n = !1) => /* @__PURE__ */ h("div", {
|
|
38
|
+
className: t("flex flex-col gap-1", n && "ml-8"),
|
|
39
|
+
children: [/* @__PURE__ */ h("div", {
|
|
37
40
|
className: "rounded-xl bg-bg-sunken/60 px-3 py-2",
|
|
38
|
-
children: [/* @__PURE__ */
|
|
41
|
+
children: [/* @__PURE__ */ h("div", {
|
|
39
42
|
className: "flex items-center justify-between gap-2",
|
|
40
|
-
children: [/* @__PURE__ */
|
|
41
|
-
memberId:
|
|
43
|
+
children: [/* @__PURE__ */ m(a, {
|
|
44
|
+
memberId: e.authorId,
|
|
42
45
|
size: "xs",
|
|
43
|
-
suffix:
|
|
44
|
-
}), !n && /* @__PURE__ */
|
|
46
|
+
suffix: c(e.createdAt)
|
|
47
|
+
}), !n && /* @__PURE__ */ h("button", {
|
|
45
48
|
type: "button",
|
|
46
|
-
onClick: () =>
|
|
49
|
+
onClick: () => D(e),
|
|
47
50
|
className: "inline-flex items-center gap-1 text-xs text-text-tertiary transition-colors hover:text-text-primary",
|
|
48
|
-
children: [/* @__PURE__ */ d
|
|
51
|
+
children: [/* @__PURE__ */ m(d, { className: "h-3 w-3" }), " Reply"]
|
|
49
52
|
})]
|
|
50
|
-
}), /* @__PURE__ */
|
|
53
|
+
}), /* @__PURE__ */ m("p", {
|
|
51
54
|
className: "mt-1 whitespace-pre-wrap break-words text-sm text-text-primary",
|
|
52
|
-
children:
|
|
55
|
+
children: e.body
|
|
53
56
|
})]
|
|
54
|
-
}), (
|
|
55
|
-
},
|
|
56
|
-
return /* @__PURE__ */
|
|
57
|
+
}), (k.get(e.id) ?? []).map((e) => j(e, !0))]
|
|
58
|
+
}, e.id);
|
|
59
|
+
return /* @__PURE__ */ h("div", {
|
|
57
60
|
className: "mt-3 border-t border-border-seam pt-3",
|
|
58
|
-
children: [
|
|
61
|
+
children: [S ? /* @__PURE__ */ m("div", {
|
|
59
62
|
className: "flex justify-center py-4",
|
|
60
|
-
children: /* @__PURE__ */
|
|
61
|
-
}) :
|
|
62
|
-
className: "
|
|
63
|
-
children: "
|
|
64
|
-
|
|
63
|
+
children: /* @__PURE__ */ m(_, { size: "sm" })
|
|
64
|
+
}) : O.length === 0 ? /* @__PURE__ */ h("div", {
|
|
65
|
+
className: "flex flex-col items-center gap-1.5 py-4 text-center",
|
|
66
|
+
children: [/* @__PURE__ */ m(f, { className: "h-6 w-6 text-text-tertiary opacity-60" }), /* @__PURE__ */ m("p", {
|
|
67
|
+
className: "text-sm text-text-tertiary",
|
|
68
|
+
children: "No comments yet — start the conversation."
|
|
69
|
+
})]
|
|
70
|
+
}) : /* @__PURE__ */ m("div", {
|
|
65
71
|
className: "flex flex-col gap-3",
|
|
66
|
-
children:
|
|
67
|
-
}), /* @__PURE__ */
|
|
72
|
+
children: O.map((e) => j(e))
|
|
73
|
+
}), /* @__PURE__ */ h("div", {
|
|
68
74
|
className: "mt-3 flex flex-col gap-2",
|
|
69
|
-
children: [
|
|
75
|
+
children: [E && /* @__PURE__ */ h("div", {
|
|
70
76
|
className: "flex items-center justify-between rounded-lg bg-bg-sunken px-3 py-1.5 text-xs text-text-secondary",
|
|
71
|
-
children: [/* @__PURE__ */
|
|
77
|
+
children: [/* @__PURE__ */ m("span", {
|
|
72
78
|
className: "truncate",
|
|
73
79
|
children: "Replying to a comment"
|
|
74
|
-
}), /* @__PURE__ */
|
|
80
|
+
}), /* @__PURE__ */ m("button", {
|
|
75
81
|
type: "button",
|
|
76
|
-
onClick: () =>
|
|
82
|
+
onClick: () => D(null),
|
|
77
83
|
className: "text-text-tertiary hover:text-text-primary",
|
|
78
84
|
children: "Cancel"
|
|
79
85
|
})]
|
|
80
|
-
}), /* @__PURE__ */
|
|
86
|
+
}), /* @__PURE__ */ h("div", {
|
|
81
87
|
className: "flex items-end gap-2",
|
|
82
|
-
children: [
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
88
|
+
children: [
|
|
89
|
+
/* @__PURE__ */ m(i, {
|
|
90
|
+
name: b?.name ?? b?.email ?? "You",
|
|
91
|
+
seed: b?.id,
|
|
92
|
+
size: "sm",
|
|
93
|
+
className: "mb-1"
|
|
94
|
+
}),
|
|
95
|
+
/* @__PURE__ */ m(v, {
|
|
96
|
+
value: w,
|
|
97
|
+
onChange: (e) => T(e.target.value),
|
|
98
|
+
placeholder: "Add a comment…",
|
|
99
|
+
rows: 1,
|
|
100
|
+
className: "min-h-[40px] resize-none",
|
|
101
|
+
onKeyDown: (e) => {
|
|
102
|
+
e.key === "Enter" && (e.metaKey || e.ctrlKey) && (e.preventDefault(), A());
|
|
103
|
+
}
|
|
104
|
+
}),
|
|
105
|
+
/* @__PURE__ */ m(g, {
|
|
106
|
+
size: "icon",
|
|
107
|
+
onClick: A,
|
|
108
|
+
disabled: !w.trim() || C.isPending,
|
|
109
|
+
"aria-label": "Post comment",
|
|
110
|
+
className: "shrink-0 rounded-full",
|
|
111
|
+
children: /* @__PURE__ */ m(p, { className: "h-4 w-4" })
|
|
112
|
+
})
|
|
113
|
+
]
|
|
98
114
|
})]
|
|
99
115
|
})]
|
|
100
116
|
});
|
|
101
117
|
}
|
|
102
118
|
//#endregion
|
|
103
|
-
export {
|
|
119
|
+
export { y as CommentThread };
|
|
104
120
|
|
|
105
121
|
//# sourceMappingURL=CommentThread.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CommentThread.js","names":[],"sources":["../../../src/comradecircle/components/CommentThread.tsx"],"sourcesContent":["/**\n * CommentThread — threaded comments for a post.\n * @module comradecircle/components\n *\n * Reads `comListComments(postId)`; writes `comAddComment`. Top-level comments\n * (parentId == null) render replies one level deep. Author identity comes from\n * `ComProfile` via {@link MemberIdentity}.\n */\n\nimport { useMemo, useState } from 'react';\nimport { CornerDownRight, Send } from 'lucide-react';\nimport { Button, Textarea, Spinner } from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/cn';\nimport { useComComments, useComAddComment } from '../hooks';\nimport { MemberIdentity } from './MemberIdentity';\nimport { formatRelativeTime } from '../utils/formatters';\nimport { notify, describeError } from '../lib/toast';\nimport type { ComComment } from '../types';\n\ninterface CommentThreadProps {\n postId: string;\n}\n\nexport function CommentThread({ postId }: CommentThreadProps) {\n const { data: comments, isLoading } = useComComments(postId);\n const addComment = useComAddComment();\n const [body, setBody] = useState('');\n const [replyTo, setReplyTo] = useState<ComComment | null>(null);\n\n const { roots, repliesByParent } = useMemo(() => {\n const list = comments ?? [];\n const repliesMap = new Map<string, ComComment[]>();\n const top: ComComment[] = [];\n for (const c of list) {\n if (c.parentId) {\n const arr = repliesMap.get(c.parentId) ?? [];\n arr.push(c);\n repliesMap.set(c.parentId, arr);\n } else {\n top.push(c);\n }\n }\n return { roots: top, repliesByParent: repliesMap };\n }, [comments]);\n\n const submit = async () => {\n const text = body.trim();\n if (!text) return;\n try {\n await addComment.mutateAsync({ postId, body: text, parentId: replyTo?.id ?? null });\n setBody('');\n setReplyTo(null);\n } catch (err) {\n notify.error('Could not add comment', describeError(err));\n }\n };\n\n const renderComment = (c: ComComment, isReply = false) => (\n <div key={c.id} className={cn('flex flex-col gap-1', isReply && 'ml-8')}>\n <div className=\"rounded-xl bg-bg-sunken/60 px-3 py-2\">\n <div className=\"flex items-center justify-between gap-2\">\n <MemberIdentity\n memberId={c.authorId}\n size=\"xs\"\n suffix={formatRelativeTime(c.createdAt)}\n />\n {!isReply && (\n <button\n type=\"button\"\n onClick={() => setReplyTo(c)}\n className=\"inline-flex items-center gap-1 text-xs text-text-tertiary transition-colors hover:text-text-primary\"\n >\n <CornerDownRight className=\"h-3 w-3\" /> Reply\n </button>\n )}\n </div>\n <p className=\"mt-1 whitespace-pre-wrap break-words text-sm text-text-primary\">{c.body}</p>\n </div>\n {(repliesByParent.get(c.id) ?? []).map((r) => renderComment(r, true))}\n </div>\n );\n\n return (\n <div className=\"mt-3 border-t border-border-seam pt-3\">\n {isLoading ? (\n <div className=\"flex justify-center py-4\">\n <Spinner size=\"sm\" />\n </div>\n ) : roots.length === 0 ? (\n <
|
|
1
|
+
{"version":3,"file":"CommentThread.js","names":[],"sources":["../../../src/comradecircle/components/CommentThread.tsx"],"sourcesContent":["/**\n * CommentThread — threaded comments for a post.\n * @module comradecircle/components\n *\n * Reads `comListComments(postId)`; writes `comAddComment`. Top-level comments\n * (parentId == null) render replies one level deep. Author identity comes from\n * `ComProfile` via {@link MemberIdentity}.\n */\n\nimport { useMemo, useState } from 'react';\nimport { CornerDownRight, Send, MessageCircle } from 'lucide-react';\nimport { Button, Textarea, Spinner } from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/cn';\nimport { useComComments, useComAddComment } from '../hooks';\nimport { useComradeCircle } from '../context';\nimport { MemberIdentity } from './MemberIdentity';\nimport { Avatar } from './Avatar';\nimport { formatRelativeTime } from '../utils/formatters';\nimport { notify, describeError } from '../lib/toast';\nimport type { ComComment } from '../types';\n\ninterface CommentThreadProps {\n postId: string;\n}\n\nexport function CommentThread({ postId }: CommentThreadProps) {\n const { currentUser } = useComradeCircle();\n const { data: comments, isLoading } = useComComments(postId);\n const addComment = useComAddComment();\n const [body, setBody] = useState('');\n const [replyTo, setReplyTo] = useState<ComComment | null>(null);\n\n const { roots, repliesByParent } = useMemo(() => {\n const list = comments ?? [];\n const repliesMap = new Map<string, ComComment[]>();\n const top: ComComment[] = [];\n for (const c of list) {\n if (c.parentId) {\n const arr = repliesMap.get(c.parentId) ?? [];\n arr.push(c);\n repliesMap.set(c.parentId, arr);\n } else {\n top.push(c);\n }\n }\n return { roots: top, repliesByParent: repliesMap };\n }, [comments]);\n\n const submit = async () => {\n const text = body.trim();\n if (!text) return;\n try {\n await addComment.mutateAsync({ postId, body: text, parentId: replyTo?.id ?? null });\n setBody('');\n setReplyTo(null);\n } catch (err) {\n notify.error('Could not add comment', describeError(err));\n }\n };\n\n const renderComment = (c: ComComment, isReply = false) => (\n <div key={c.id} className={cn('flex flex-col gap-1', isReply && 'ml-8')}>\n <div className=\"rounded-xl bg-bg-sunken/60 px-3 py-2\">\n <div className=\"flex items-center justify-between gap-2\">\n <MemberIdentity\n memberId={c.authorId}\n size=\"xs\"\n suffix={formatRelativeTime(c.createdAt)}\n />\n {!isReply && (\n <button\n type=\"button\"\n onClick={() => setReplyTo(c)}\n className=\"inline-flex items-center gap-1 text-xs text-text-tertiary transition-colors hover:text-text-primary\"\n >\n <CornerDownRight className=\"h-3 w-3\" /> Reply\n </button>\n )}\n </div>\n <p className=\"mt-1 whitespace-pre-wrap break-words text-sm text-text-primary\">{c.body}</p>\n </div>\n {(repliesByParent.get(c.id) ?? []).map((r) => renderComment(r, true))}\n </div>\n );\n\n return (\n <div className=\"mt-3 border-t border-border-seam pt-3\">\n {isLoading ? (\n <div className=\"flex justify-center py-4\">\n <Spinner size=\"sm\" />\n </div>\n ) : roots.length === 0 ? (\n <div className=\"flex flex-col items-center gap-1.5 py-4 text-center\">\n <MessageCircle className=\"h-6 w-6 text-text-tertiary opacity-60\" />\n <p className=\"text-sm text-text-tertiary\">No comments yet — start the conversation.</p>\n </div>\n ) : (\n <div className=\"flex flex-col gap-3\">{roots.map((c) => renderComment(c))}</div>\n )}\n\n <div className=\"mt-3 flex flex-col gap-2\">\n {replyTo && (\n <div className=\"flex items-center justify-between rounded-lg bg-bg-sunken px-3 py-1.5 text-xs text-text-secondary\">\n <span className=\"truncate\">Replying to a comment</span>\n <button\n type=\"button\"\n onClick={() => setReplyTo(null)}\n className=\"text-text-tertiary hover:text-text-primary\"\n >\n Cancel\n </button>\n </div>\n )}\n <div className=\"flex items-end gap-2\">\n <Avatar\n name={currentUser?.name ?? currentUser?.email ?? 'You'}\n seed={currentUser?.id}\n size=\"sm\"\n className=\"mb-1\"\n />\n <Textarea\n value={body}\n onChange={(e) => setBody(e.target.value)}\n placeholder=\"Add a comment…\"\n rows={1}\n className=\"min-h-[40px] resize-none\"\n onKeyDown={(e) => {\n if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n void submit();\n }\n }}\n />\n <Button\n size=\"icon\"\n onClick={submit}\n disabled={!body.trim() || addComment.isPending}\n aria-label=\"Post comment\"\n className=\"shrink-0 rounded-full\"\n >\n <Send className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ComCircle } from '../types';
|
|
2
|
+
|
|
3
|
+
interface CreateCircleDialogProps {
|
|
4
|
+
open: boolean;
|
|
5
|
+
onOpenChange: (open: boolean) => void;
|
|
6
|
+
onCreated?: (circle: ComCircle) => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function CreateCircleDialog({ open, onOpenChange, onCreated }: CreateCircleDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=CreateCircleDialog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CreateCircleDialog.d.ts","sourceRoot":"","sources":["../../../src/comradecircle/components/CreateCircleDialog.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AA0BH,OAAO,KAAK,EAAE,SAAS,EAAuB,MAAM,UAAU,CAAC;AAI/D,UAAU,uBAAuB;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,KAAK,IAAI,CAAC;CACzC;AAED,wBAAgB,kBAAkB,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,EAAE,uBAAuB,2CAsJ5F"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ComEvent } from '../types';
|
|
2
|
+
|
|
3
|
+
interface CreateEventDialogProps {
|
|
4
|
+
open: boolean;
|
|
5
|
+
onOpenChange: (open: boolean) => void;
|
|
6
|
+
/** Fixed circle — when omitted the dialog shows an active-circle picker. */
|
|
7
|
+
circleId?: string;
|
|
8
|
+
onCreated?: (event: ComEvent) => void;
|
|
9
|
+
}
|
|
10
|
+
export declare function CreateEventDialog({ open, onOpenChange, circleId, onCreated, }: CreateEventDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=CreateEventDialog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CreateEventDialog.d.ts","sourceRoot":"","sources":["../../../src/comradecircle/components/CreateEventDialog.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAwBH,OAAO,KAAK,EAAE,QAAQ,EAAgB,MAAM,UAAU,CAAC;AAUvD,UAAU,sBAAsB;IAC9B,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;CACvC;AAED,wBAAgB,iBAAiB,CAAC,EAChC,IAAI,EACJ,YAAY,EACZ,QAAQ,EACR,SAAS,GACV,EAAE,sBAAsB,2CAyMxB"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface Column<T> {
|
|
4
|
+
key: string;
|
|
5
|
+
header: ReactNode;
|
|
6
|
+
render: (row: T) => ReactNode;
|
|
7
|
+
align?: 'left' | 'right' | 'center';
|
|
8
|
+
className?: string;
|
|
9
|
+
/** Hide below the `md` breakpoint for a mobile-friendly layout. */
|
|
10
|
+
hideOnMobile?: boolean;
|
|
11
|
+
/** Provide to make this column click-sortable (returns a comparable value). */
|
|
12
|
+
sortValue?: (row: T) => string | number;
|
|
13
|
+
}
|
|
14
|
+
interface DataTableProps<T> {
|
|
15
|
+
columns: Column<T>[];
|
|
16
|
+
rows: T[];
|
|
17
|
+
rowKey: (row: T) => string;
|
|
18
|
+
onRowClick?: (row: T) => void;
|
|
19
|
+
className?: string;
|
|
20
|
+
/** Default sort: a column key + direction. */
|
|
21
|
+
defaultSort?: {
|
|
22
|
+
key: string;
|
|
23
|
+
dir: 'asc' | 'desc';
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export declare function DataTable<T>({ columns, rows, rowKey, onRowClick, className, defaultSort, }: DataTableProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=DataTable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DataTable.d.ts","sourceRoot":"","sources":["../../../src/comradecircle/components/DataTable.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAK1D,MAAM,WAAW,MAAM,CAAC,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,SAAS,CAAC;IAClB,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,SAAS,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,+EAA+E;IAC/E,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,MAAM,GAAG,MAAM,CAAC;CACzC;AAED,UAAU,cAAc,CAAC,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IACrB,IAAI,EAAE,CAAC,EAAE,CAAC;IACV,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,IAAI,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8CAA8C;IAC9C,WAAW,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,KAAK,GAAG,MAAM,CAAA;KAAE,CAAC;CACpD;AAQD,wBAAgB,SAAS,CAAC,CAAC,EAAE,EAC3B,OAAO,EACP,IAAI,EACJ,MAAM,EACN,UAAU,EACV,SAAS,EACT,WAAW,GACZ,EAAE,cAAc,CAAC,CAAC,CAAC,2CAqGnB"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { FC, ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
interface EmptyStateProps {
|
|
4
|
+
icon?: ReactNode;
|
|
5
|
+
/**
|
|
6
|
+
* On-brand illustration name → `/illustrations/<name>.webp`. Standard names:
|
|
7
|
+
* empty-data, empty-search, empty-files, empty-people, empty-notifications,
|
|
8
|
+
* onboarding, empty-generic.
|
|
9
|
+
*/
|
|
10
|
+
illustration?: string;
|
|
11
|
+
title: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
action?: ReactNode;
|
|
14
|
+
className?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare const EmptyState: FC<EmptyStateProps>;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=EmptyState.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmptyState.d.ts","sourceRoot":"","sources":["../../../src/comradecircle/components/EmptyState.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAI3C,UAAU,eAAe;IACvB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,UAAU,EAAE,EAAE,CAAC,eAAe,CA8B1C,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ComEvent } from '../types';
|
|
2
|
+
|
|
3
|
+
interface EventCardProps {
|
|
4
|
+
event: ComEvent;
|
|
5
|
+
onOpen: () => void;
|
|
6
|
+
}
|
|
7
|
+
export declare function EventCard({ event, onOpen }: EventCardProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=EventCard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EventCard.d.ts","sourceRoot":"","sources":["../../../src/comradecircle/components/EventCard.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAWH,OAAO,KAAK,EAAE,QAAQ,EAAiB,MAAM,UAAU,CAAC;AAExD,UAAU,cAAc;IACtB,KAAK,EAAE,QAAQ,CAAC;IAChB,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAOD,wBAAgB,SAAS,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,cAAc,2CAgI1D"}
|
|
@@ -1,93 +1,119 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { cn as e } from "../utils/cn.js";
|
|
2
|
+
import { useComRsvpEvent as t } from "../hooks/useComradeCircleApi.js";
|
|
2
3
|
import "../hooks/index.js";
|
|
3
|
-
import { describeError as
|
|
4
|
-
import { formatDateTime as
|
|
5
|
-
import { StatusBadge as
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
4
|
+
import { describeError as n, notify as r } from "../lib/toast.js";
|
|
5
|
+
import { formatDateTime as i, formatNumber as a, formatRelativeTime as o } from "../utils/formatters.js";
|
|
6
|
+
import { StatusBadge as s } from "./StatusBadge.js";
|
|
7
|
+
import { MiniBar as c } from "./MiniBar.js";
|
|
8
|
+
import { useState as l } from "react";
|
|
9
|
+
import { Calendar as u, Check as d, ExternalLink as f, MapPin as p, Users as m, Video as h } from "lucide-react";
|
|
10
|
+
import { jsx as g, jsxs as _ } from "react/jsx-runtime";
|
|
11
|
+
import { Button as v, GlassCard as y } from "@burdenoff/fe-libs/ui";
|
|
9
12
|
//#region src/comradecircle/components/EventCard.tsx
|
|
10
|
-
var
|
|
13
|
+
var b = [{
|
|
11
14
|
status: "GOING",
|
|
12
15
|
label: "Going"
|
|
13
16
|
}, {
|
|
14
17
|
status: "INTERESTED",
|
|
15
18
|
label: "Interested"
|
|
16
19
|
}];
|
|
17
|
-
function
|
|
18
|
-
let
|
|
20
|
+
function x({ event: x, onOpen: S }) {
|
|
21
|
+
let C = t(), [w, T] = l(null), E = x.status === "SCHEDULED" || x.status === "LIVE", D = x.status === "LIVE", O = async (e) => {
|
|
19
22
|
try {
|
|
20
|
-
await
|
|
21
|
-
eventId:
|
|
23
|
+
await C.mutateAsync({
|
|
24
|
+
eventId: x.id,
|
|
22
25
|
status: e
|
|
23
|
-
}),
|
|
26
|
+
}), T(e), r.success(`RSVP: ${e === "GOING" ? "Going" : "Interested"}`, x.title);
|
|
24
27
|
} catch (e) {
|
|
25
|
-
|
|
28
|
+
r.error("Could not RSVP", n(e));
|
|
26
29
|
}
|
|
27
|
-
},
|
|
28
|
-
return /* @__PURE__ */
|
|
30
|
+
}, k = x.mode === "IN_PERSON" ? p : h, A = x.capacity ? Math.min(100, x.rsvpCount / x.capacity * 100) : 0, j = A >= 80;
|
|
31
|
+
return /* @__PURE__ */ _(y, {
|
|
29
32
|
treatment: "plain",
|
|
30
|
-
className: "flex flex-col p-5",
|
|
33
|
+
className: e("flex flex-col p-5 transition-all duration-200 motion-safe:hover:-translate-y-0.5 hover:border-[var(--color-accent-soft)]", D && "ring-1 ring-[var(--color-accent-soft)]"),
|
|
31
34
|
children: [
|
|
32
|
-
/* @__PURE__ */
|
|
35
|
+
/* @__PURE__ */ _("div", {
|
|
33
36
|
className: "flex items-start justify-between gap-3",
|
|
34
|
-
children: [/* @__PURE__ */
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
children: [/* @__PURE__ */ g(s, { status: x.status }), E && /* @__PURE__ */ g("span", {
|
|
38
|
+
className: "text-xs font-medium text-text-tertiary",
|
|
39
|
+
children: o(x.startsAt)
|
|
40
|
+
})]
|
|
41
|
+
}),
|
|
42
|
+
/* @__PURE__ */ g("button", {
|
|
43
|
+
type: "button",
|
|
44
|
+
onClick: S,
|
|
45
|
+
className: "mt-2 text-left text-base font-semibold text-text-primary transition-colors hover:text-accent",
|
|
46
|
+
children: x.title
|
|
40
47
|
}),
|
|
41
|
-
|
|
42
|
-
className: "mt-
|
|
43
|
-
children:
|
|
48
|
+
x.description && /* @__PURE__ */ g("p", {
|
|
49
|
+
className: "mt-1.5 line-clamp-2 text-sm text-text-secondary",
|
|
50
|
+
children: x.description
|
|
44
51
|
}),
|
|
45
|
-
/* @__PURE__ */
|
|
52
|
+
/* @__PURE__ */ _("div", {
|
|
46
53
|
className: "mt-3 flex flex-col gap-1.5 text-sm text-text-secondary",
|
|
47
|
-
children: [/* @__PURE__ */
|
|
54
|
+
children: [/* @__PURE__ */ _("span", {
|
|
48
55
|
className: "inline-flex items-center gap-2",
|
|
49
56
|
children: [
|
|
50
|
-
/* @__PURE__ */
|
|
57
|
+
/* @__PURE__ */ g(u, { className: "h-4 w-4 text-text-tertiary" }),
|
|
51
58
|
" ",
|
|
52
|
-
|
|
59
|
+
i(x.startsAt)
|
|
53
60
|
]
|
|
54
|
-
}), /* @__PURE__ */
|
|
61
|
+
}), /* @__PURE__ */ _("span", {
|
|
55
62
|
className: "inline-flex items-center gap-2",
|
|
56
|
-
children: [/* @__PURE__ */
|
|
63
|
+
children: [/* @__PURE__ */ g(k, { className: "h-4 w-4 text-text-tertiary" }), x.mode === "IN_PERSON" ? x.location || "In person" : x.mode === "HYBRID" ? `Hybrid${x.location ? ` · ${x.location}` : ""}` : "Online"]
|
|
57
64
|
})]
|
|
58
65
|
}),
|
|
59
|
-
/* @__PURE__ */
|
|
66
|
+
/* @__PURE__ */ _("div", {
|
|
67
|
+
className: "mt-3",
|
|
68
|
+
children: [/* @__PURE__ */ _("div", {
|
|
69
|
+
className: "flex items-center justify-between text-xs text-text-tertiary",
|
|
70
|
+
children: [/* @__PURE__ */ _("span", {
|
|
71
|
+
className: "inline-flex items-center gap-1",
|
|
72
|
+
children: [
|
|
73
|
+
/* @__PURE__ */ g(m, { className: "h-3.5 w-3.5" }),
|
|
74
|
+
" ",
|
|
75
|
+
a(x.rsvpCount),
|
|
76
|
+
x.capacity ? ` / ${a(x.capacity)}` : "",
|
|
77
|
+
" attending"
|
|
78
|
+
]
|
|
79
|
+
}), x.capacity && j && /* @__PURE__ */ g("span", {
|
|
80
|
+
className: e(A >= 100 ? "text-status-error-text" : "text-status-warning-text"),
|
|
81
|
+
children: A >= 100 ? "Full" : `${Math.round(A)}% full`
|
|
82
|
+
})]
|
|
83
|
+
}), x.capacity ? /* @__PURE__ */ g(c, {
|
|
84
|
+
value: A,
|
|
85
|
+
className: "mt-1.5",
|
|
86
|
+
height: 4,
|
|
87
|
+
barClassName: A >= 100 ? "bg-status-error-text" : j ? "bg-status-warning-text" : "bg-accent"
|
|
88
|
+
}) : null]
|
|
89
|
+
}),
|
|
90
|
+
/* @__PURE__ */ _("div", {
|
|
60
91
|
className: "mt-4 flex items-center justify-between gap-3 border-t border-border-seam pt-3",
|
|
61
|
-
children: [/* @__PURE__ */
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
" attending"
|
|
69
|
-
]
|
|
70
|
-
}), /* @__PURE__ */ f("div", {
|
|
92
|
+
children: [D && x.joinUrl ? /* @__PURE__ */ _("a", {
|
|
93
|
+
href: x.joinUrl,
|
|
94
|
+
target: "_blank",
|
|
95
|
+
rel: "noreferrer noopener",
|
|
96
|
+
className: "inline-flex items-center gap-1 text-xs font-medium text-accent hover:underline",
|
|
97
|
+
children: ["Join live ", /* @__PURE__ */ g(f, { className: "h-3 w-3" })]
|
|
98
|
+
}) : /* @__PURE__ */ g("span", {}), /* @__PURE__ */ g("div", {
|
|
71
99
|
className: "flex items-center gap-2",
|
|
72
|
-
children:
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
children: e.label
|
|
84
|
-
}, e.status))]
|
|
100
|
+
children: E && b.map((e) => {
|
|
101
|
+
let t = w === e.status;
|
|
102
|
+
return /* @__PURE__ */ _(v, {
|
|
103
|
+
size: "sm",
|
|
104
|
+
variant: t || e.status === "GOING" ? "default" : "outline",
|
|
105
|
+
onClick: () => O(e.status),
|
|
106
|
+
disabled: C.isPending,
|
|
107
|
+
"aria-pressed": t,
|
|
108
|
+
children: [t && /* @__PURE__ */ g(d, { className: "mr-1 h-3.5 w-3.5" }), e.label]
|
|
109
|
+
}, e.status);
|
|
110
|
+
})
|
|
85
111
|
})]
|
|
86
112
|
})
|
|
87
113
|
]
|
|
88
114
|
});
|
|
89
115
|
}
|
|
90
116
|
//#endregion
|
|
91
|
-
export {
|
|
117
|
+
export { x as EventCard };
|
|
92
118
|
|
|
93
119
|
//# sourceMappingURL=EventCard.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EventCard.js","names":[],"sources":["../../../src/comradecircle/components/EventCard.tsx"],"sourcesContent":["/**\n * EventCard — a tile for a community event with a quick RSVP control.\n * @module comradecircle/components\n *\n * Writes `comRsvpEvent`. Shows mode + lifecycle status,
|
|
1
|
+
{"version":3,"file":"EventCard.js","names":[],"sources":["../../../src/comradecircle/components/EventCard.tsx"],"sourcesContent":["/**\n * EventCard — a tile for a community event with a quick RSVP control.\n * @module comradecircle/components\n *\n * Writes `comRsvpEvent`. Shows mode + lifecycle status, a relative-time cue, a\n * capacity fill bar, the caller's selected RSVP (tracked client-side after a\n * successful mutation — the list query returns no viewer RSVP), and a live-join\n * link. LIVE events get an accent ring so they pop out of the grid.\n */\n\nimport { useState } from 'react';\nimport { Calendar, MapPin, Video, Users, ExternalLink, Check } from 'lucide-react';\nimport { GlassCard, Button } from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/cn';\nimport { MiniBar } from './MiniBar';\nimport { StatusBadge } from './StatusBadge';\nimport { useComRsvpEvent } from '../hooks';\nimport { formatDateTime, formatNumber, formatRelativeTime } from '../utils/formatters';\nimport { notify, describeError } from '../lib/toast';\nimport type { ComEvent, ComRsvpStatus } from '../types';\n\ninterface EventCardProps {\n event: ComEvent;\n onOpen: () => void;\n}\n\nconst RSVP_ACTIONS: { status: ComRsvpStatus; label: string }[] = [\n { status: 'GOING', label: 'Going' },\n { status: 'INTERESTED', label: 'Interested' },\n];\n\nexport function EventCard({ event, onOpen }: EventCardProps) {\n const rsvp = useComRsvpEvent();\n const [myStatus, setMyStatus] = useState<ComRsvpStatus | null>(null);\n const canRsvp = event.status === 'SCHEDULED' || event.status === 'LIVE';\n const isLive = event.status === 'LIVE';\n\n const doRsvp = async (status: ComRsvpStatus) => {\n try {\n await rsvp.mutateAsync({ eventId: event.id, status });\n setMyStatus(status);\n notify.success(`RSVP: ${status === 'GOING' ? 'Going' : 'Interested'}`, event.title);\n } catch (err) {\n notify.error('Could not RSVP', describeError(err));\n }\n };\n\n const ModeIcon = event.mode === 'IN_PERSON' ? MapPin : Video;\n const fillPct = event.capacity ? Math.min(100, (event.rsvpCount / event.capacity) * 100) : 0;\n const nearFull = fillPct >= 80;\n\n return (\n <GlassCard\n treatment=\"plain\"\n className={cn(\n 'flex flex-col p-5 transition-all duration-200 motion-safe:hover:-translate-y-0.5 hover:border-[var(--color-accent-soft)]',\n isLive && 'ring-1 ring-[var(--color-accent-soft)]'\n )}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <StatusBadge status={event.status} />\n {canRsvp && (\n <span className=\"text-xs font-medium text-text-tertiary\">\n {formatRelativeTime(event.startsAt)}\n </span>\n )}\n </div>\n\n <button\n type=\"button\"\n onClick={onOpen}\n className=\"mt-2 text-left text-base font-semibold text-text-primary transition-colors hover:text-accent\"\n >\n {event.title}\n </button>\n\n {event.description && (\n <p className=\"mt-1.5 line-clamp-2 text-sm text-text-secondary\">{event.description}</p>\n )}\n\n <div className=\"mt-3 flex flex-col gap-1.5 text-sm text-text-secondary\">\n <span className=\"inline-flex items-center gap-2\">\n <Calendar className=\"h-4 w-4 text-text-tertiary\" /> {formatDateTime(event.startsAt)}\n </span>\n <span className=\"inline-flex items-center gap-2\">\n <ModeIcon className=\"h-4 w-4 text-text-tertiary\" />\n {event.mode === 'IN_PERSON'\n ? event.location || 'In person'\n : event.mode === 'HYBRID'\n ? `Hybrid${event.location ? ` · ${event.location}` : ''}`\n : 'Online'}\n </span>\n </div>\n\n <div className=\"mt-3\">\n <div className=\"flex items-center justify-between text-xs text-text-tertiary\">\n <span className=\"inline-flex items-center gap-1\">\n <Users className=\"h-3.5 w-3.5\" /> {formatNumber(event.rsvpCount)}\n {event.capacity ? ` / ${formatNumber(event.capacity)}` : ''} attending\n </span>\n {event.capacity && nearFull && (\n <span\n className={cn(fillPct >= 100 ? 'text-status-error-text' : 'text-status-warning-text')}\n >\n {fillPct >= 100 ? 'Full' : `${Math.round(fillPct)}% full`}\n </span>\n )}\n </div>\n {event.capacity ? (\n <MiniBar\n value={fillPct}\n className=\"mt-1.5\"\n height={4}\n barClassName={\n fillPct >= 100\n ? 'bg-status-error-text'\n : nearFull\n ? 'bg-status-warning-text'\n : 'bg-accent'\n }\n />\n ) : null}\n </div>\n\n <div className=\"mt-4 flex items-center justify-between gap-3 border-t border-border-seam pt-3\">\n {isLive && event.joinUrl ? (\n <a\n href={event.joinUrl}\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n className=\"inline-flex items-center gap-1 text-xs font-medium text-accent hover:underline\"\n >\n Join live <ExternalLink className=\"h-3 w-3\" />\n </a>\n ) : (\n <span />\n )}\n <div className=\"flex items-center gap-2\">\n {canRsvp &&\n RSVP_ACTIONS.map((a) => {\n const active = myStatus === a.status;\n return (\n <Button\n key={a.status}\n size=\"sm\"\n variant={active || a.status === 'GOING' ? 'default' : 'outline'}\n onClick={() => doRsvp(a.status)}\n disabled={rsvp.isPending}\n aria-pressed={active}\n >\n {active && <Check className=\"mr-1 h-3.5 w-3.5\" />}\n {a.label}\n </Button>\n );\n })}\n </div>\n </div>\n </GlassCard>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FileImage — render a wspace-files-svc file id as an image.
|
|
3
|
+
* @module comradecircle/components
|
|
4
|
+
*
|
|
5
|
+
* Resolves the id to a presigned URL via {@link useFileUrl}. Shows a skeleton
|
|
6
|
+
* while resolving and renders nothing (so the caller's fallback shows) if the id
|
|
7
|
+
* is absent or the URL fails to resolve.
|
|
8
|
+
*/
|
|
9
|
+
interface FileImageProps {
|
|
10
|
+
fileId?: string | null;
|
|
11
|
+
alt: string;
|
|
12
|
+
className?: string;
|
|
13
|
+
/** Rendered when there is no fileId, resolution fails, or the image errors. */
|
|
14
|
+
fallback?: React.ReactNode;
|
|
15
|
+
}
|
|
16
|
+
export declare function FileImage({ fileId, alt, className, fallback }: FileImageProps): import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=FileImage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileImage.d.ts","sourceRoot":"","sources":["../../../src/comradecircle/components/FileImage.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,UAAU,cAAc;IACtB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAED,wBAAgB,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,QAAe,EAAE,EAAE,cAAc,2CAiBpF"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FilterTabs — a segmented status/enum filter control.
|
|
3
|
+
* @module comradecircle/components
|
|
4
|
+
*/
|
|
5
|
+
export interface FilterOption<V extends string> {
|
|
6
|
+
value: V;
|
|
7
|
+
label: string;
|
|
8
|
+
count?: number;
|
|
9
|
+
}
|
|
10
|
+
interface FilterTabsProps<V extends string> {
|
|
11
|
+
options: FilterOption<V>[];
|
|
12
|
+
value: V;
|
|
13
|
+
onChange: (value: V) => void;
|
|
14
|
+
className?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function FilterTabs<V extends string>({ options, value, onChange, className, }: FilterTabsProps<V>): import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=FilterTabs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FilterTabs.d.ts","sourceRoot":"","sources":["../../../src/comradecircle/components/FilterTabs.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,WAAW,YAAY,CAAC,CAAC,SAAS,MAAM;IAC5C,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,eAAe,CAAC,CAAC,SAAS,MAAM;IACxC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3B,KAAK,EAAE,CAAC,CAAC;IACT,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,EAC3C,OAAO,EACP,KAAK,EACL,QAAQ,EACR,SAAS,GACV,EAAE,eAAe,CAAC,CAAC,CAAC,2CAyCpB"}
|