@burdenoff/microfe-comradecircle 2026.704.2 → 2026.704.3
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/Avatar.js +40 -17
- package/dist/comradecircle/components/Avatar.js.map +1 -1
- package/dist/comradecircle/components/AvatarUploadField.js +25 -14
- package/dist/comradecircle/components/AvatarUploadField.js.map +1 -1
- package/dist/comradecircle/components/CircleCard.js +54 -52
- package/dist/comradecircle/components/CircleCard.js.map +1 -1
- package/dist/comradecircle/components/CommentThread.js +80 -64
- package/dist/comradecircle/components/CommentThread.js.map +1 -1
- package/dist/comradecircle/components/EventCard.js +84 -58
- package/dist/comradecircle/components/EventCard.js.map +1 -1
- package/dist/comradecircle/components/MemberIdentity.js +2 -1
- package/dist/comradecircle/components/MemberIdentity.js.map +1 -1
- package/dist/comradecircle/components/PollCard.js +65 -44
- package/dist/comradecircle/components/PollCard.js.map +1 -1
- package/dist/comradecircle/components/PostCard.js +1 -1
- package/dist/comradecircle/components/PostCard.js.map +1 -1
- package/dist/comradecircle/components/ReactionBar.js +1 -1
- package/dist/comradecircle/components/ReactionBar.js.map +1 -1
- package/dist/comradecircle/components/StateViews.js +1 -16
- package/dist/comradecircle/components/StateViews.js.map +1 -1
- package/dist/comradecircle/components/StatusBadge.js +1 -1
- package/dist/comradecircle/components/StatusBadge.js.map +1 -1
- package/dist/comradecircle/hooks/useComradeCircleApi.js +1 -1
- package/dist/comradecircle/hooks/useComradeCircleApi.js.map +1 -1
- package/dist/comradecircle/pages/FeedPage.js +79 -33
- package/dist/comradecircle/pages/FeedPage.js.map +1 -1
- 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.js +97 -47
- package/dist/comradecircle/pages/circles/CirclesPage.js.map +1 -1
- 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.js +74 -34
- package/dist/comradecircle/pages/events/EventsPage.js.map +1 -1
- 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.js +140 -71
- package/dist/comradecircle/pages/members/MembersPage.js.map +1 -1
- package/dist/comradecircle/pages/profile/MyProfilePage.js +298 -202
- package/dist/comradecircle/pages/profile/MyProfilePage.js.map +1 -1
- package/package.json +1 -1
|
@@ -7,147 +7,216 @@ import "../../hooks/index.js";
|
|
|
7
7
|
import { Avatar as s } from "../../components/Avatar.js";
|
|
8
8
|
import { describeError as c, notify as l } from "../../lib/toast.js";
|
|
9
9
|
import { EmptyState as u } from "../../components/EmptyState.js";
|
|
10
|
-
import { ErrorView as d
|
|
11
|
-
import { Pagination as
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import { Button as S, GlassCard as C, Input as w } from "@burdenoff/fe-libs/ui";
|
|
10
|
+
import { ErrorView as d } from "../../components/StateViews.js";
|
|
11
|
+
import { Pagination as f } from "../../components/Pagination.js";
|
|
12
|
+
import { useMemo as p, useState as m } from "react";
|
|
13
|
+
import { Check as h, Loader2 as g, Search as _, UserMinus as v, UserPlus as y } from "lucide-react";
|
|
14
|
+
import { Fragment as b, jsx as x, jsxs as S } from "react/jsx-runtime";
|
|
15
|
+
import { Button as C, GlassCard as w, Input as T, Skeleton as E } from "@burdenoff/fe-libs/ui";
|
|
17
16
|
//#region src/comradecircle/pages/members/MembersPage.tsx
|
|
18
|
-
var
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
var D = 12, O = [
|
|
18
|
+
"s1",
|
|
19
|
+
"s2",
|
|
20
|
+
"s3",
|
|
21
|
+
"s4",
|
|
22
|
+
"s5",
|
|
23
|
+
"s6",
|
|
24
|
+
"s7",
|
|
25
|
+
"s8"
|
|
26
|
+
];
|
|
27
|
+
function k() {
|
|
28
|
+
return /* @__PURE__ */ S(w, {
|
|
29
|
+
treatment: "plain",
|
|
30
|
+
className: "flex flex-col p-5",
|
|
31
|
+
children: [
|
|
32
|
+
/* @__PURE__ */ S("div", {
|
|
33
|
+
className: "flex items-start gap-3",
|
|
34
|
+
children: [/* @__PURE__ */ x(E, { className: "h-14 w-14 rounded-full" }), /* @__PURE__ */ S("div", {
|
|
35
|
+
className: "min-w-0 flex-1 space-y-2 py-1",
|
|
36
|
+
children: [
|
|
37
|
+
/* @__PURE__ */ x(E, { className: "h-4 w-2/3" }),
|
|
38
|
+
/* @__PURE__ */ x(E, { className: "h-3 w-1/2" }),
|
|
39
|
+
/* @__PURE__ */ x(E, { className: "h-3 w-4/5" })
|
|
40
|
+
]
|
|
41
|
+
})]
|
|
42
|
+
}),
|
|
43
|
+
/* @__PURE__ */ S("div", {
|
|
44
|
+
className: "mt-3 flex flex-wrap gap-1.5",
|
|
45
|
+
children: [/* @__PURE__ */ x(E, { className: "h-5 w-16 rounded-full" }), /* @__PURE__ */ x(E, { className: "h-5 w-20 rounded-full" })]
|
|
46
|
+
}),
|
|
47
|
+
/* @__PURE__ */ x("div", {
|
|
48
|
+
className: "mt-4 flex justify-end border-t border-border-seam pt-3",
|
|
49
|
+
children: /* @__PURE__ */ x(E, { className: "h-8 w-28 rounded-button" })
|
|
50
|
+
})
|
|
51
|
+
]
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
function A() {
|
|
55
|
+
let { navigateTo: A, currentUser: j } = e(), M = o(), [N, P] = m(""), [F, I] = m(null), { data: L, isLoading: R, isError: z, refetch: B } = i({
|
|
21
56
|
discoverable: !0,
|
|
22
57
|
pagination: {
|
|
23
|
-
limit:
|
|
24
|
-
cursor:
|
|
58
|
+
limit: D,
|
|
59
|
+
cursor: M.cursor
|
|
25
60
|
}
|
|
26
|
-
}), { data:
|
|
27
|
-
let e =
|
|
28
|
-
return e ?
|
|
61
|
+
}), { data: V } = r("MEMBER"), H = n(), U = a(), W = p(() => new Set((V ?? []).map((e) => e.targetId)), [V]), G = p(() => L?.items ?? [], [L]), K = p(() => {
|
|
62
|
+
let e = N.trim().toLowerCase();
|
|
63
|
+
return e ? G.filter((t) => [
|
|
29
64
|
t.displayName,
|
|
30
65
|
t.headline ?? "",
|
|
31
66
|
...t.skills,
|
|
32
67
|
...t.interests
|
|
33
|
-
].join(" ").toLowerCase().includes(e)) :
|
|
34
|
-
}, [
|
|
35
|
-
let t =
|
|
68
|
+
].join(" ").toLowerCase().includes(e)) : G;
|
|
69
|
+
}, [G, N]), q = async (e) => {
|
|
70
|
+
let t = W.has(e.memberId), n = {
|
|
36
71
|
targetId: e.memberId,
|
|
37
72
|
targetType: "MEMBER"
|
|
38
73
|
};
|
|
39
|
-
|
|
74
|
+
I(e.memberId);
|
|
40
75
|
try {
|
|
41
|
-
t ? (await
|
|
76
|
+
t ? (await U.mutateAsync(n), l.success("Unfollowed", e.displayName)) : (await H.mutateAsync(n), l.success("Following", e.displayName));
|
|
42
77
|
} catch (e) {
|
|
43
78
|
l.error(t ? "Could not unfollow" : "Could not follow", c(e));
|
|
44
79
|
} finally {
|
|
45
|
-
|
|
80
|
+
I(null);
|
|
46
81
|
}
|
|
47
82
|
};
|
|
48
|
-
return /* @__PURE__ */
|
|
83
|
+
return /* @__PURE__ */ x(t, {
|
|
49
84
|
title: "Members",
|
|
50
85
|
description: "Discover and follow people across your circles — search by name, headline, or skills.",
|
|
51
|
-
children:
|
|
86
|
+
children: R ? /* @__PURE__ */ S("div", {
|
|
87
|
+
className: "flex flex-col gap-5",
|
|
88
|
+
children: [/* @__PURE__ */ x(E, { className: "h-9 w-full max-w-sm rounded-button" }), /* @__PURE__ */ x("div", {
|
|
89
|
+
className: "grid gap-4 sm:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4",
|
|
90
|
+
children: O.map((e) => /* @__PURE__ */ x(k, {}, e))
|
|
91
|
+
})]
|
|
92
|
+
}) : z ? /* @__PURE__ */ x(d, {
|
|
52
93
|
message: "We couldn't load the member directory.",
|
|
53
|
-
onRetry: () =>
|
|
54
|
-
}) :
|
|
94
|
+
onRetry: () => B()
|
|
95
|
+
}) : G.length === 0 && M.page === 0 ? /* @__PURE__ */ x(u, {
|
|
55
96
|
illustration: "empty-people",
|
|
56
97
|
title: "No members to discover yet",
|
|
57
98
|
description: "When members make their profiles discoverable, they'll show up here for you to follow."
|
|
58
|
-
}) : /* @__PURE__ */
|
|
99
|
+
}) : /* @__PURE__ */ S("div", {
|
|
59
100
|
className: "flex flex-col gap-5",
|
|
60
101
|
children: [
|
|
61
|
-
/* @__PURE__ */
|
|
102
|
+
/* @__PURE__ */ S("div", {
|
|
62
103
|
className: "relative w-full max-w-sm",
|
|
63
|
-
children: [/* @__PURE__ */
|
|
104
|
+
children: [/* @__PURE__ */ x(_, {
|
|
64
105
|
className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-tertiary",
|
|
65
106
|
"aria-hidden": "true"
|
|
66
|
-
}), /* @__PURE__ */
|
|
67
|
-
value:
|
|
68
|
-
onChange: (e) =>
|
|
107
|
+
}), /* @__PURE__ */ x(T, {
|
|
108
|
+
value: N,
|
|
109
|
+
onChange: (e) => P(e.target.value),
|
|
69
110
|
placeholder: "Search by name, headline, or skills",
|
|
70
111
|
"aria-label": "Search members",
|
|
71
112
|
className: "pl-9"
|
|
72
113
|
})]
|
|
73
114
|
}),
|
|
74
|
-
|
|
75
|
-
icon: /* @__PURE__ */
|
|
115
|
+
K.length === 0 ? /* @__PURE__ */ x(u, {
|
|
116
|
+
icon: /* @__PURE__ */ x(_, { className: "h-9 w-9" }),
|
|
76
117
|
title: "No matches on this page",
|
|
77
118
|
description: "No members on this page match your search. Try a different term or browse another page."
|
|
78
|
-
}) : /* @__PURE__ */ b("
|
|
79
|
-
className: "
|
|
80
|
-
children:
|
|
81
|
-
|
|
82
|
-
|
|
119
|
+
}) : /* @__PURE__ */ S(b, { children: [/* @__PURE__ */ S("p", {
|
|
120
|
+
className: "text-xs font-medium text-text-tertiary",
|
|
121
|
+
children: [
|
|
122
|
+
"Showing ",
|
|
123
|
+
K.length,
|
|
124
|
+
" member",
|
|
125
|
+
K.length === 1 ? "" : "s"
|
|
126
|
+
]
|
|
127
|
+
}), /* @__PURE__ */ x("div", {
|
|
128
|
+
className: "grid gap-4 sm:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4",
|
|
129
|
+
children: K.map((e) => {
|
|
130
|
+
let t = !!(j?.id && e.memberId === j.id), n = W.has(e.memberId), r = F === e.memberId, i = Array.from(new Set([...e.skills, ...e.interests])).slice(0, 4);
|
|
131
|
+
return /* @__PURE__ */ S(w, {
|
|
83
132
|
treatment: "plain",
|
|
84
|
-
className: "flex flex-col p-5",
|
|
133
|
+
className: "flex flex-col p-5 transition-all duration-200 motion-safe:hover:-translate-y-0.5 hover:border-[var(--color-accent-soft)]",
|
|
85
134
|
children: [
|
|
86
|
-
/* @__PURE__ */
|
|
87
|
-
|
|
88
|
-
|
|
135
|
+
/* @__PURE__ */ S("button", {
|
|
136
|
+
type: "button",
|
|
137
|
+
onClick: () => A(`members/${e.memberId}`),
|
|
138
|
+
"aria-label": `View ${e.displayName}'s profile`,
|
|
139
|
+
className: "group/head flex w-full items-start gap-3 rounded-lg text-left outline-none focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]",
|
|
140
|
+
children: [/* @__PURE__ */ x(s, {
|
|
89
141
|
name: e.displayName,
|
|
90
142
|
presence: e.presence,
|
|
91
143
|
size: "lg",
|
|
92
|
-
fileId: e.avatar?.id
|
|
93
|
-
|
|
144
|
+
fileId: e.avatar?.id,
|
|
145
|
+
seed: e.memberId
|
|
146
|
+
}), /* @__PURE__ */ S("div", {
|
|
94
147
|
className: "min-w-0 flex-1",
|
|
95
148
|
children: [
|
|
96
|
-
/* @__PURE__ */
|
|
97
|
-
|
|
98
|
-
onClick: () => E(`members/${e.memberId}`),
|
|
99
|
-
className: "block max-w-full truncate text-left text-base font-semibold text-text-primary hover:underline",
|
|
149
|
+
/* @__PURE__ */ x("span", {
|
|
150
|
+
className: "block max-w-full truncate text-base font-semibold text-text-primary group-hover/head:underline",
|
|
100
151
|
children: e.displayName
|
|
101
152
|
}),
|
|
102
|
-
e.headline && /* @__PURE__ */
|
|
153
|
+
e.headline && /* @__PURE__ */ x("p", {
|
|
103
154
|
className: "truncate text-sm text-text-secondary",
|
|
104
155
|
children: e.headline
|
|
105
156
|
}),
|
|
106
|
-
/* @__PURE__ */
|
|
107
|
-
className: "mt-
|
|
108
|
-
children:
|
|
157
|
+
e.bio && /* @__PURE__ */ x("p", {
|
|
158
|
+
className: "mt-0.5 line-clamp-1 text-xs text-text-tertiary",
|
|
159
|
+
children: e.bio
|
|
109
160
|
})
|
|
110
161
|
]
|
|
111
162
|
})]
|
|
112
163
|
}),
|
|
113
|
-
|
|
164
|
+
i.length > 0 && /* @__PURE__ */ x("div", {
|
|
114
165
|
className: "mt-3 flex flex-wrap gap-1.5",
|
|
115
|
-
children:
|
|
166
|
+
children: i.map((e) => /* @__PURE__ */ x("span", {
|
|
116
167
|
className: "rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary",
|
|
117
168
|
children: e
|
|
118
169
|
}, e))
|
|
119
170
|
}),
|
|
120
|
-
!t && /* @__PURE__ */
|
|
171
|
+
!t && /* @__PURE__ */ x("div", {
|
|
121
172
|
className: "mt-4 flex items-center justify-end border-t border-border-seam pt-3",
|
|
122
|
-
children: n ? /* @__PURE__ */ x(
|
|
173
|
+
children: n ? /* @__PURE__ */ x(C, {
|
|
123
174
|
size: "sm",
|
|
124
175
|
variant: "outline",
|
|
125
|
-
onClick: () =>
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
176
|
+
onClick: (t) => {
|
|
177
|
+
t.stopPropagation(), q(e);
|
|
178
|
+
},
|
|
179
|
+
disabled: r,
|
|
180
|
+
"aria-label": `Following ${e.displayName}. Activate to unfollow.`,
|
|
181
|
+
className: "group/follow min-w-[7.5rem] justify-center hover:border-status-error-border hover:bg-status-error-bg-subtle hover:text-status-error-text",
|
|
182
|
+
children: r ? /* @__PURE__ */ S(b, { children: [/* @__PURE__ */ x(g, { className: "motion-safe:animate-spin" }), /* @__PURE__ */ x("span", { children: "Following" })] }) : /* @__PURE__ */ S(b, { children: [
|
|
183
|
+
/* @__PURE__ */ x(h, { className: "group-hover/follow:hidden" }),
|
|
184
|
+
/* @__PURE__ */ x(v, { className: "hidden group-hover/follow:inline" }),
|
|
185
|
+
/* @__PURE__ */ x("span", {
|
|
186
|
+
className: "group-hover/follow:hidden",
|
|
187
|
+
children: "Following"
|
|
188
|
+
}),
|
|
189
|
+
/* @__PURE__ */ x("span", {
|
|
190
|
+
className: "hidden group-hover/follow:inline",
|
|
191
|
+
children: "Unfollow"
|
|
192
|
+
})
|
|
193
|
+
] })
|
|
194
|
+
}) : /* @__PURE__ */ S(C, {
|
|
129
195
|
size: "sm",
|
|
130
|
-
onClick: () =>
|
|
131
|
-
|
|
132
|
-
|
|
196
|
+
onClick: (t) => {
|
|
197
|
+
t.stopPropagation(), q(e);
|
|
198
|
+
},
|
|
199
|
+
disabled: r,
|
|
200
|
+
className: "min-w-[7.5rem] justify-center",
|
|
201
|
+
children: [r ? /* @__PURE__ */ x(g, { className: "motion-safe:animate-spin" }) : /* @__PURE__ */ x(y, {}), "Follow"]
|
|
133
202
|
})
|
|
134
203
|
})
|
|
135
204
|
]
|
|
136
205
|
}, e.id);
|
|
137
206
|
})
|
|
138
|
-
}),
|
|
139
|
-
/* @__PURE__ */
|
|
140
|
-
page:
|
|
141
|
-
pageSize:
|
|
142
|
-
itemCount:
|
|
143
|
-
hasMore:
|
|
144
|
-
onPageChange: (e) =>
|
|
207
|
+
})] }),
|
|
208
|
+
/* @__PURE__ */ x(f, {
|
|
209
|
+
page: M.page,
|
|
210
|
+
pageSize: D,
|
|
211
|
+
itemCount: G.length,
|
|
212
|
+
hasMore: L?.pageInfo.hasMore ?? !1,
|
|
213
|
+
onPageChange: (e) => M.onPageChange(e, L?.pageInfo.cursor)
|
|
145
214
|
})
|
|
146
215
|
]
|
|
147
216
|
})
|
|
148
217
|
});
|
|
149
218
|
}
|
|
150
219
|
//#endregion
|
|
151
|
-
export {
|
|
220
|
+
export { A as MembersPage };
|
|
152
221
|
|
|
153
222
|
//# sourceMappingURL=MembersPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MembersPage.js","names":[],"sources":["../../../../src/comradecircle/pages/members/MembersPage.tsx"],"sourcesContent":["/**\n * MembersPage — the discoverable member directory.\n * @module comradecircle/pages/members\n *\n * Reads `comListProfiles(discoverable: true)` — every member who has opted into\n * discovery via their {@link ComProfile}. Each card resolves display identity\n * from the social-identity layer (never a raw actor id), links to the member's\n * public profile, and offers a Follow/Following toggle wired to `comFollow` /\n * `comUnfollow` (targetType MEMBER). An optional client-side search narrows the\n * current page by name, headline, skills, or interests.\n */\n\nimport { useMemo, useState } from 'react';\nimport { Search, UserPlus, Check } from 'lucide-react';\nimport { GlassCard, Button, Input } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { Avatar } from '../../components/Avatar';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { Pagination } from '../../components/Pagination';\nimport {\n useComProfiles,\n useComMyFollows,\n useComFollow,\n useComUnfollow,\n useCursorPager,\n} from '../../hooks';\nimport { useComradeCircle } from '../../context';\nimport { notify, describeError } from '../../lib/toast';\nimport type { ComProfile } from '../../types';\n\nconst PAGE_SIZE = 12;\n\nexport function MembersPage() {\n const { navigateTo, currentUser } = useComradeCircle();\n const pager = useCursorPager();\n const [search, setSearch] = useState('');\n const [pendingId, setPendingId] = useState<string | null>(null);\n\n const { data, isLoading, isError, refetch } = useComProfiles({\n discoverable: true,\n pagination: { limit: PAGE_SIZE, cursor: pager.cursor },\n });\n\n const { data: follows } = useComMyFollows('MEMBER');\n const follow = useComFollow();\n const unfollow = useComUnfollow();\n\n const followSet = useMemo(() => new Set((follows ?? []).map((f) => f.targetId)), [follows]);\n\n const profiles = useMemo(() => data?.items ?? [], [data]);\n\n const visible = useMemo(() => {\n const q = search.trim().toLowerCase();\n if (!q) return profiles;\n return profiles.filter((p) => {\n const haystack = [p.displayName, p.headline ?? '', ...p.skills, ...p.interests]\n .join(' ')\n .toLowerCase();\n return haystack.includes(q);\n });\n }, [profiles, search]);\n\n const toggleFollow = async (profile: ComProfile) => {\n const wasFollowing = followSet.has(profile.memberId);\n const input = { targetId: profile.memberId, targetType: 'MEMBER' as const };\n setPendingId(profile.memberId);\n try {\n if (wasFollowing) {\n await unfollow.mutateAsync(input);\n notify.success('Unfollowed', profile.displayName);\n } else {\n await follow.mutateAsync(input);\n notify.success('Following', profile.displayName);\n }\n } catch (err) {\n notify.error(wasFollowing ? 'Could not unfollow' : 'Could not follow', describeError(err));\n } finally {\n setPendingId(null);\n }\n };\n\n return (\n <PageLayout\n title=\"Members\"\n description=\"Discover and follow people across your circles — search by name, headline, or skills.\"\n >\n {isLoading ? (\n <LoadingView label=\"Loading members…\" />\n ) : isError ? (\n <ErrorView message=\"We couldn't load the member directory.\" onRetry={() => refetch()} />\n ) : profiles.length === 0 && pager.page === 0 ? (\n <EmptyState\n illustration=\"empty-people\"\n title=\"No members to discover yet\"\n description=\"When members make their profiles discoverable, they'll show up here for you to follow.\"\n />\n ) : (\n <div className=\"flex flex-col gap-5\">\n <div className=\"relative w-full max-w-sm\">\n <Search\n className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-tertiary\"\n aria-hidden=\"true\"\n />\n <Input\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n placeholder=\"Search by name, headline, or skills\"\n aria-label=\"Search members\"\n className=\"pl-9\"\n />\n </div>\n\n {visible.length === 0 ? (\n <EmptyState\n icon={<Search className=\"h-9 w-9\" />}\n title=\"No matches on this page\"\n description=\"No members on this page match your search. Try a different term or browse another page.\"\n />\n ) : (\n <div className=\"grid gap-4 sm:grid-cols-2 xl:grid-cols-3\">\n {visible.map((p) => {\n const isSelf = Boolean(currentUser?.id && p.memberId === currentUser.id);\n const isFollowing = followSet.has(p.memberId);\n const chips = Array.from(new Set([...p.skills, ...p.interests])).slice(0, 4);\n\n return (\n <GlassCard key={p.id} treatment=\"plain\" className=\"flex flex-col p-5\">\n <div className=\"flex items-start gap-3\">\n <Avatar\n name={p.displayName}\n presence={p.presence}\n size=\"lg\"\n fileId={p.avatar?.id}\n />\n <div className=\"min-w-0 flex-1\">\n <button\n type=\"button\"\n onClick={() => navigateTo(`members/${p.memberId}`)}\n className=\"block max-w-full truncate text-left text-base font-semibold text-text-primary hover:underline\"\n >\n {p.displayName}\n </button>\n {p.headline && (\n <p className=\"truncate text-sm text-text-secondary\">{p.headline}</p>\n )}\n <div className=\"mt-1.5\">\n <StatusBadge status={p.presence} />\n </div>\n </div>\n </div>\n\n {chips.length > 0 && (\n <div className=\"mt-3 flex flex-wrap gap-1.5\">\n {chips.map((chip) => (\n <span\n key={chip}\n className=\"rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary\"\n >\n {chip}\n </span>\n ))}\n </div>\n )}\n\n {!isSelf && (\n <div className=\"mt-4 flex items-center justify-end border-t border-border-seam pt-3\">\n {isFollowing ? (\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => toggleFollow(p)}\n disabled={pendingId === p.memberId}\n >\n <Check className=\"mr-1.5 h-4 w-4\" /> Following\n </Button>\n ) : (\n <Button\n size=\"sm\"\n onClick={() => toggleFollow(p)}\n disabled={pendingId === p.memberId}\n >\n <UserPlus className=\"mr-1.5 h-4 w-4\" /> Follow\n </Button>\n )}\n </div>\n )}\n </GlassCard>\n );\n })}\n </div>\n )}\n\n <Pagination\n page={pager.page}\n pageSize={PAGE_SIZE}\n itemCount={profiles.length}\n hasMore={data?.pageInfo.hasMore ?? false}\n onPageChange={(target) => pager.onPageChange(target, data?.pageInfo.cursor)}\n />\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MembersPage.js","names":[],"sources":["../../../../src/comradecircle/pages/members/MembersPage.tsx"],"sourcesContent":["/**\n * MembersPage — the discoverable member directory.\n * @module comradecircle/pages/members\n *\n * Reads `comListProfiles(discoverable: true)` — every member who has opted into\n * discovery via their {@link ComProfile}. Each card resolves display identity\n * from the social-identity layer (never a raw actor id), links to the member's\n * public profile, and offers a Follow/Following toggle wired to `comFollow` /\n * `comUnfollow` (targetType MEMBER). An optional client-side search narrows the\n * current page by name, headline, skills, or interests.\n */\n\nimport { useMemo, useState } from 'react';\nimport { Search, UserPlus, UserMinus, Check, Loader2 } from 'lucide-react';\nimport { GlassCard, Button, Input, Skeleton } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { Avatar } from '../../components/Avatar';\nimport { EmptyState } from '../../components/EmptyState';\nimport { ErrorView } from '../../components/StateViews';\nimport { Pagination } from '../../components/Pagination';\nimport {\n useComProfiles,\n useComMyFollows,\n useComFollow,\n useComUnfollow,\n useCursorPager,\n} from '../../hooks';\nimport { useComradeCircle } from '../../context';\nimport { notify, describeError } from '../../lib/toast';\nimport type { ComProfile } from '../../types';\n\nconst PAGE_SIZE = 12;\n\nconst SKELETON_KEYS = ['s1', 's2', 's3', 's4', 's5', 's6', 's7', 's8'] as const;\n\n/** Card-shaped placeholder that mirrors the member card while the page loads. */\nfunction MemberCardSkeleton() {\n return (\n <GlassCard treatment=\"plain\" className=\"flex flex-col p-5\">\n <div className=\"flex items-start gap-3\">\n <Skeleton className=\"h-14 w-14 rounded-full\" />\n <div className=\"min-w-0 flex-1 space-y-2 py-1\">\n <Skeleton className=\"h-4 w-2/3\" />\n <Skeleton className=\"h-3 w-1/2\" />\n <Skeleton className=\"h-3 w-4/5\" />\n </div>\n </div>\n <div className=\"mt-3 flex flex-wrap gap-1.5\">\n <Skeleton className=\"h-5 w-16 rounded-full\" />\n <Skeleton className=\"h-5 w-20 rounded-full\" />\n </div>\n <div className=\"mt-4 flex justify-end border-t border-border-seam pt-3\">\n <Skeleton className=\"h-8 w-28 rounded-button\" />\n </div>\n </GlassCard>\n );\n}\n\nexport function MembersPage() {\n const { navigateTo, currentUser } = useComradeCircle();\n const pager = useCursorPager();\n const [search, setSearch] = useState('');\n const [pendingId, setPendingId] = useState<string | null>(null);\n\n const { data, isLoading, isError, refetch } = useComProfiles({\n discoverable: true,\n pagination: { limit: PAGE_SIZE, cursor: pager.cursor },\n });\n\n const { data: follows } = useComMyFollows('MEMBER');\n const follow = useComFollow();\n const unfollow = useComUnfollow();\n\n const followSet = useMemo(() => new Set((follows ?? []).map((f) => f.targetId)), [follows]);\n\n const profiles = useMemo(() => data?.items ?? [], [data]);\n\n const visible = useMemo(() => {\n const q = search.trim().toLowerCase();\n if (!q) return profiles;\n return profiles.filter((p) => {\n const haystack = [p.displayName, p.headline ?? '', ...p.skills, ...p.interests]\n .join(' ')\n .toLowerCase();\n return haystack.includes(q);\n });\n }, [profiles, search]);\n\n const toggleFollow = async (profile: ComProfile) => {\n const wasFollowing = followSet.has(profile.memberId);\n const input = { targetId: profile.memberId, targetType: 'MEMBER' as const };\n setPendingId(profile.memberId);\n try {\n if (wasFollowing) {\n await unfollow.mutateAsync(input);\n notify.success('Unfollowed', profile.displayName);\n } else {\n await follow.mutateAsync(input);\n notify.success('Following', profile.displayName);\n }\n } catch (err) {\n notify.error(wasFollowing ? 'Could not unfollow' : 'Could not follow', describeError(err));\n } finally {\n setPendingId(null);\n }\n };\n\n return (\n <PageLayout\n title=\"Members\"\n description=\"Discover and follow people across your circles — search by name, headline, or skills.\"\n >\n {isLoading ? (\n <div className=\"flex flex-col gap-5\">\n <Skeleton className=\"h-9 w-full max-w-sm rounded-button\" />\n <div className=\"grid gap-4 sm:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4\">\n {SKELETON_KEYS.map((key) => (\n <MemberCardSkeleton key={key} />\n ))}\n </div>\n </div>\n ) : isError ? (\n <ErrorView message=\"We couldn't load the member directory.\" onRetry={() => refetch()} />\n ) : profiles.length === 0 && pager.page === 0 ? (\n <EmptyState\n illustration=\"empty-people\"\n title=\"No members to discover yet\"\n description=\"When members make their profiles discoverable, they'll show up here for you to follow.\"\n />\n ) : (\n <div className=\"flex flex-col gap-5\">\n <div className=\"relative w-full max-w-sm\">\n <Search\n className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-tertiary\"\n aria-hidden=\"true\"\n />\n <Input\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n placeholder=\"Search by name, headline, or skills\"\n aria-label=\"Search members\"\n className=\"pl-9\"\n />\n </div>\n\n {visible.length === 0 ? (\n <EmptyState\n icon={<Search className=\"h-9 w-9\" />}\n title=\"No matches on this page\"\n description=\"No members on this page match your search. Try a different term or browse another page.\"\n />\n ) : (\n <>\n <p className=\"text-xs font-medium text-text-tertiary\">\n Showing {visible.length} member{visible.length === 1 ? '' : 's'}\n </p>\n\n <div className=\"grid gap-4 sm:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4\">\n {visible.map((p) => {\n const isSelf = Boolean(currentUser?.id && p.memberId === currentUser.id);\n const isFollowing = followSet.has(p.memberId);\n const isPending = pendingId === p.memberId;\n const chips = Array.from(new Set([...p.skills, ...p.interests])).slice(0, 4);\n\n return (\n <GlassCard\n key={p.id}\n treatment=\"plain\"\n className=\"flex flex-col p-5 transition-all duration-200 motion-safe:hover:-translate-y-0.5 hover:border-[var(--color-accent-soft)]\"\n >\n <button\n type=\"button\"\n onClick={() => navigateTo(`members/${p.memberId}`)}\n aria-label={`View ${p.displayName}'s profile`}\n className=\"group/head flex w-full items-start gap-3 rounded-lg text-left outline-none focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <Avatar\n name={p.displayName}\n presence={p.presence}\n size=\"lg\"\n fileId={p.avatar?.id}\n seed={p.memberId}\n />\n <div className=\"min-w-0 flex-1\">\n <span className=\"block max-w-full truncate text-base font-semibold text-text-primary group-hover/head:underline\">\n {p.displayName}\n </span>\n {p.headline && (\n <p className=\"truncate text-sm text-text-secondary\">{p.headline}</p>\n )}\n {p.bio && (\n <p className=\"mt-0.5 line-clamp-1 text-xs text-text-tertiary\">\n {p.bio}\n </p>\n )}\n </div>\n </button>\n\n {chips.length > 0 && (\n <div className=\"mt-3 flex flex-wrap gap-1.5\">\n {chips.map((chip) => (\n <span\n key={chip}\n className=\"rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary\"\n >\n {chip}\n </span>\n ))}\n </div>\n )}\n\n {!isSelf && (\n <div className=\"mt-4 flex items-center justify-end border-t border-border-seam pt-3\">\n {isFollowing ? (\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={(e) => {\n e.stopPropagation();\n void toggleFollow(p);\n }}\n disabled={isPending}\n aria-label={`Following ${p.displayName}. Activate to unfollow.`}\n className=\"group/follow min-w-[7.5rem] justify-center hover:border-status-error-border hover:bg-status-error-bg-subtle hover:text-status-error-text\"\n >\n {isPending ? (\n <>\n <Loader2 className=\"motion-safe:animate-spin\" />\n <span>Following</span>\n </>\n ) : (\n <>\n <Check className=\"group-hover/follow:hidden\" />\n <UserMinus className=\"hidden group-hover/follow:inline\" />\n <span className=\"group-hover/follow:hidden\">Following</span>\n <span className=\"hidden group-hover/follow:inline\">Unfollow</span>\n </>\n )}\n </Button>\n ) : (\n <Button\n size=\"sm\"\n onClick={(e) => {\n e.stopPropagation();\n void toggleFollow(p);\n }}\n disabled={isPending}\n className=\"min-w-[7.5rem] justify-center\"\n >\n {isPending ? (\n <Loader2 className=\"motion-safe:animate-spin\" />\n ) : (\n <UserPlus />\n )}\n Follow\n </Button>\n )}\n </div>\n )}\n </GlassCard>\n );\n })}\n </div>\n </>\n )}\n\n <Pagination\n page={pager.page}\n pageSize={PAGE_SIZE}\n itemCount={profiles.length}\n hasMore={data?.pageInfo.hasMore ?? false}\n onPageChange={(target) => pager.onPageChange(target, data?.pageInfo.cursor)}\n />\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|