@burdenoff/microfe-comradecircle 2026.704.1 → 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.
Files changed (54) hide show
  1. package/dist/comradecircle/components/Avatar.js +52 -17
  2. package/dist/comradecircle/components/Avatar.js.map +1 -1
  3. package/dist/comradecircle/components/AvatarUploadField.js +91 -0
  4. package/dist/comradecircle/components/AvatarUploadField.js.map +1 -0
  5. package/dist/comradecircle/components/CircleCard.js +55 -52
  6. package/dist/comradecircle/components/CircleCard.js.map +1 -1
  7. package/dist/comradecircle/components/CommentThread.js +80 -64
  8. package/dist/comradecircle/components/CommentThread.js.map +1 -1
  9. package/dist/comradecircle/components/CreateCircleDialog.js +74 -63
  10. package/dist/comradecircle/components/CreateCircleDialog.js.map +1 -1
  11. package/dist/comradecircle/components/EventCard.js +84 -58
  12. package/dist/comradecircle/components/EventCard.js.map +1 -1
  13. package/dist/comradecircle/components/FileImage.js +20 -0
  14. package/dist/comradecircle/components/FileImage.js.map +1 -0
  15. package/dist/comradecircle/components/ImageAttachments.js +97 -0
  16. package/dist/comradecircle/components/ImageAttachments.js.map +1 -0
  17. package/dist/comradecircle/components/MemberIdentity.js +4 -2
  18. package/dist/comradecircle/components/MemberIdentity.js.map +1 -1
  19. package/dist/comradecircle/components/PollCard.js +65 -44
  20. package/dist/comradecircle/components/PollCard.js.map +1 -1
  21. package/dist/comradecircle/components/PostCard.js +8 -15
  22. package/dist/comradecircle/components/PostCard.js.map +1 -1
  23. package/dist/comradecircle/components/PostComposer.js +45 -35
  24. package/dist/comradecircle/components/PostComposer.js.map +1 -1
  25. package/dist/comradecircle/components/ReactionBar.js +1 -1
  26. package/dist/comradecircle/components/ReactionBar.js.map +1 -1
  27. package/dist/comradecircle/components/StateViews.js +1 -16
  28. package/dist/comradecircle/components/StateViews.js.map +1 -1
  29. package/dist/comradecircle/components/StatusBadge.js +1 -1
  30. package/dist/comradecircle/components/StatusBadge.js.map +1 -1
  31. package/dist/comradecircle/hooks/index.js +1 -0
  32. package/dist/comradecircle/hooks/useComradeCircleApi.js +244 -241
  33. package/dist/comradecircle/hooks/useComradeCircleApi.js.map +1 -1
  34. package/dist/comradecircle/hooks/useFiles.js +78 -0
  35. package/dist/comradecircle/hooks/useFiles.js.map +1 -0
  36. package/dist/comradecircle/lib/graphql-cache.js +9 -0
  37. package/dist/comradecircle/lib/graphql-cache.js.map +1 -0
  38. package/dist/comradecircle/pages/FeedPage.js +79 -33
  39. package/dist/comradecircle/pages/FeedPage.js.map +1 -1
  40. package/dist/comradecircle/pages/circles/CircleDetailPage.js +354 -242
  41. package/dist/comradecircle/pages/circles/CircleDetailPage.js.map +1 -1
  42. package/dist/comradecircle/pages/circles/CirclesPage.js +97 -47
  43. package/dist/comradecircle/pages/circles/CirclesPage.js.map +1 -1
  44. package/dist/comradecircle/pages/events/EventDetailPage.js +193 -126
  45. package/dist/comradecircle/pages/events/EventDetailPage.js.map +1 -1
  46. package/dist/comradecircle/pages/events/EventsPage.js +74 -34
  47. package/dist/comradecircle/pages/events/EventsPage.js.map +1 -1
  48. package/dist/comradecircle/pages/members/MemberProfilePage.js +154 -81
  49. package/dist/comradecircle/pages/members/MemberProfilePage.js.map +1 -1
  50. package/dist/comradecircle/pages/members/MembersPage.js +141 -71
  51. package/dist/comradecircle/pages/members/MembersPage.js.map +1 -1
  52. package/dist/comradecircle/pages/profile/MyProfilePage.js +298 -191
  53. package/dist/comradecircle/pages/profile/MyProfilePage.js.map +1 -1
  54. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"useComradeCircleApi.js","names":[],"sources":["../../../src/comradecircle/hooks/useComradeCircleApi.ts"],"sourcesContent":["/**\n * ComradeCircle API hooks\n * @module comradecircle/hooks\n *\n * React-Query hooks wired DIRECTLY to the real `wspace-comradecircle-svc`\n * federated GraphQL contract (the `com*` operations). Every query/mutation\n * below uses an inline gql string whose fields match the svc\n * `.hive-schema.graphql` exactly. No mock data.\n *\n * Transport: `graphqlFetch({ gateway: 'workspace', workspaceToken: true })` —\n * the host shell supplies the gateway base URL + a workspace-scoped token.\n *\n * IMPORTANT: `User`/`File` are id-only federation stubs in this subgraph. We\n * never select `author { firstName }` or `avatar { url }`. Display identity is\n * resolved through `ComProfile` (see `useComProfile`).\n */\n\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\nimport { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql';\n\nimport { useComradeCircle } from '../context';\nimport type {\n ComConnection,\n ComCircle,\n ComCircleStatus,\n ComCircleVisibility,\n ComChannel,\n ComComment,\n ComPost,\n ComPostStatus,\n ComPoll,\n ComPollStatus,\n ComPollOption,\n ComEvent,\n ComEventStatus,\n ComEventRsvp,\n ComRsvpStatus,\n ComProfile,\n ComMembership,\n ComMembershipStatus,\n ComMemberRole,\n ComFeedFollow,\n ComFollowTargetType,\n ComReaction,\n ComReactionType,\n ComCreateCircleInput,\n ComUpdateCircleInput,\n ComCreateChannelInput,\n ComUpdateChannelInput,\n ComCreatePostInput,\n ComUpdatePostInput,\n ComCreateCommentInput,\n ComCreateEventInput,\n ComUpdateEventInput,\n ComCreatePollInput,\n ComFollowInput,\n ComUpsertProfileInput,\n PaginationInput,\n} from '../types';\n\n// ============================================================================\n// Transport\n// ============================================================================\n\nconst comQuery = async <TData>(\n query: string,\n variables: Record<string, unknown>,\n baseUrl?: string\n): Promise<TData> => {\n const response = await graphqlFetch<TData>({\n gateway: 'workspace',\n baseUrl,\n query,\n variables,\n workspaceToken: true,\n });\n\n if (response.errors?.length) {\n throw new Error(response.errors[0]?.message ?? 'GraphQL request failed');\n }\n if (!response.data) {\n throw new Error('GraphQL response did not include data');\n }\n return response.data;\n};\n\n// React-Query key roots (one namespace per domain entity).\nconst KEY = {\n circles: ['comradecircle', 'circles'] as const,\n circle: (id: string) => ['comradecircle', 'circle', id] as const,\n channels: (circleId: string) => ['comradecircle', 'channels', circleId] as const,\n posts: (channelId: string) => ['comradecircle', 'posts', channelId] as const,\n post: (id: string) => ['comradecircle', 'post', id] as const,\n comments: (postId: string) => ['comradecircle', 'comments', postId] as const,\n feed: ['comradecircle', 'feed'] as const,\n follows: ['comradecircle', 'follows'] as const,\n events: ['comradecircle', 'events'] as const,\n event: (id: string) => ['comradecircle', 'event', id] as const,\n polls: (circleId: string) => ['comradecircle', 'polls', circleId] as const,\n poll: (id: string) => ['comradecircle', 'poll', id] as const,\n profiles: ['comradecircle', 'profiles'] as const,\n profile: (memberId: string) => ['comradecircle', 'profile', memberId] as const,\n memberships: ['comradecircle', 'memberships'] as const,\n};\n\nconst DEFAULT_PAGE: PaginationInput = { limit: 50 };\n\n/** Drop `cursor` when it is nullish so the svc never sees an explicit null. */\nconst page = (p?: PaginationInput): PaginationInput => {\n const base = p ?? DEFAULT_PAGE;\n const result: PaginationInput = { limit: base.limit ?? DEFAULT_PAGE.limit };\n if (base.offset != null) result.offset = base.offset;\n if (base.cursor != null) result.cursor = base.cursor;\n return result;\n};\n\n// ============================================================================\n// Reusable gql field selections (codegen-free strictness)\n// ============================================================================\n\nconst CHANNEL_FIELDS = `\n id workspaceId circleId name slug description type visibility position isArchived\n createdAt updatedAt\n`;\n\nconst CIRCLE_FIELDS = `\n id workspaceId name slug description topic tags status visibility memberCount\n avatar { id } createdAt updatedAt\n`;\n\nconst REACTION_FIELDS = `id postId memberId type createdAt`;\n\nconst COMMENT_FIELDS = `\n id workspaceId postId parentId authorId body isHidden createdAt updatedAt\n`;\n\nconst POST_FIELDS = `\n id workspaceId channelId authorId body status tags attachmentFileIds isPinned\n reactionCount commentCount reactions { ${REACTION_FIELDS} } createdAt updatedAt\n`;\n\nconst POLL_OPTION_FIELDS = `id workspaceId pollId label position voteCount createdAt`;\n\nconst POLL_FIELDS = `\n id workspaceId circleId question allowMultiple isAnonymous status closesAt\n options { ${POLL_OPTION_FIELDS} } createdAt updatedAt\n`;\n\nconst RSVP_FIELDS = `\n id workspaceId eventId memberId status note createdAt updatedAt\n`;\n\nconst EVENT_FIELDS = `\n id workspaceId circleId hostId title description mode status location joinUrl\n capacity startsAt endsAt tags rsvpCount createdAt updatedAt\n`;\n\nconst PROFILE_FIELDS = `\n id workspaceId memberId displayName headline bio avatar { id } interests skills\n presence discoverable createdAt updatedAt\n`;\n\nconst MEMBERSHIP_FIELDS = `\n id workspaceId circleId memberId role status joinedAt createdAt updatedAt\n`;\n\nconst FOLLOW_FIELDS = `\n id workspaceId followerId targetId targetType muted createdAt updatedAt\n`;\n\n// ============================================================================\n// Circles\n// ============================================================================\n\nexport interface CircleFilters {\n status?: ComCircleStatus;\n visibility?: ComCircleVisibility;\n pagination?: PaginationInput;\n}\n\nexport const useComCircles = (filters: CircleFilters = {}) => {\n const { apiGatewayUrl } = useComradeCircle();\n return useQuery({\n queryKey: [...KEY.circles, filters],\n queryFn: async () => {\n const result = await comQuery<{ comListCircles: ComConnection<ComCircle> }>(\n `query ComListCircles($status: ComCircleStatus, $visibility: ComCircleVisibility, $pagination: PaginationInput) {\n comListCircles(status: $status, visibility: $visibility, pagination: $pagination) {\n items { ${CIRCLE_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n status: filters.status,\n visibility: filters.visibility,\n pagination: page(filters.pagination),\n },\n apiGatewayUrl\n );\n return result.comListCircles;\n },\n });\n};\n\nexport const useComCircle = (id: string | undefined) => {\n const { apiGatewayUrl } = useComradeCircle();\n return useQuery({\n queryKey: KEY.circle(id ?? ''),\n enabled: Boolean(id),\n queryFn: async () => {\n const result = await comQuery<{ comCircle: ComCircle | null }>(\n `query ComCircle($id: ID!) {\n comCircle(id: $id) {\n ${CIRCLE_FIELDS}\n channels { ${CHANNEL_FIELDS} }\n memberships { ${MEMBERSHIP_FIELDS} }\n }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.comCircle;\n },\n });\n};\n\nexport const useComCreateCircle = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: ComCreateCircleInput) => {\n const result = await comQuery<{ comCreateCircle: ComCircle }>(\n `mutation ComCreateCircle($input: ComCreateCircleInput!) {\n comCreateCircle(input: $input) { ${CIRCLE_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.comCreateCircle;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.circles }),\n });\n};\n\nexport const useComUpdateCircle = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; input: ComUpdateCircleInput }) => {\n const result = await comQuery<{ comUpdateCircle: ComCircle }>(\n `mutation ComUpdateCircle($id: ID!, $input: ComUpdateCircleInput!) {\n comUpdateCircle(id: $id, input: $input) { ${CIRCLE_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.comUpdateCircle;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.circles });\n qc.invalidateQueries({ queryKey: KEY.circle(data.id) });\n },\n });\n};\n\nexport const useComArchiveCircle = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await comQuery<{ comArchiveCircle: boolean }>(\n `mutation ComArchiveCircle($id: ID!) { comArchiveCircle(id: $id) }`,\n { id },\n apiGatewayUrl\n );\n return result.comArchiveCircle;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.circles }),\n });\n};\n\nexport const useComJoinCircle = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (circleId: string) => {\n const result = await comQuery<{ comJoinCircle: ComMembership }>(\n `mutation ComJoinCircle($circleId: ID!) {\n comJoinCircle(circleId: $circleId) { ${MEMBERSHIP_FIELDS} }\n }`,\n { circleId },\n apiGatewayUrl\n );\n return result.comJoinCircle;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.circles });\n qc.invalidateQueries({ queryKey: KEY.circle(data.circleId) });\n qc.invalidateQueries({ queryKey: KEY.memberships });\n },\n });\n};\n\nexport const useComLeaveCircle = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (circleId: string) => {\n const result = await comQuery<{ comLeaveCircle: boolean }>(\n `mutation ComLeaveCircle($circleId: ID!) { comLeaveCircle(circleId: $circleId) }`,\n { circleId },\n apiGatewayUrl\n );\n return result.comLeaveCircle;\n },\n onSuccess: (_data, circleId) => {\n qc.invalidateQueries({ queryKey: KEY.circles });\n qc.invalidateQueries({ queryKey: KEY.circle(circleId) });\n qc.invalidateQueries({ queryKey: KEY.memberships });\n },\n });\n};\n\nexport const useComSetMemberRole = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { membershipId: string; role: ComMemberRole; circleId?: string }) => {\n const result = await comQuery<{ comSetMemberRole: ComMembership }>(\n `mutation ComSetMemberRole($membershipId: ID!, $role: ComMemberRole!) {\n comSetMemberRole(membershipId: $membershipId, role: $role) { ${MEMBERSHIP_FIELDS} }\n }`,\n { membershipId: vars.membershipId, role: vars.role },\n apiGatewayUrl\n );\n return result.comSetMemberRole;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.circle(data.circleId) });\n qc.invalidateQueries({ queryKey: KEY.memberships });\n },\n });\n};\n\nexport interface MembershipFilters {\n circleId?: string;\n status?: ComMembershipStatus;\n pagination?: PaginationInput;\n}\n\nexport const useComMemberships = (filters: MembershipFilters = {}) => {\n const { apiGatewayUrl } = useComradeCircle();\n return useQuery({\n queryKey: [...KEY.memberships, filters],\n queryFn: async () => {\n const result = await comQuery<{ comListMemberships: ComConnection<ComMembership> }>(\n `query ComListMemberships($circleId: ID, $status: ComMembershipStatus, $pagination: PaginationInput) {\n comListMemberships(circleId: $circleId, status: $status, pagination: $pagination) {\n items { ${MEMBERSHIP_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n circleId: filters.circleId,\n status: filters.status,\n pagination: page(filters.pagination),\n },\n apiGatewayUrl\n );\n return result.comListMemberships;\n },\n });\n};\n\n// ============================================================================\n// Channels\n// ============================================================================\n\nexport const useComChannels = (circleId: string | undefined) => {\n const { apiGatewayUrl } = useComradeCircle();\n return useQuery({\n queryKey: KEY.channels(circleId ?? ''),\n enabled: Boolean(circleId),\n queryFn: async () => {\n const result = await comQuery<{ comListChannels: ComChannel[] }>(\n `query ComListChannels($circleId: ID!) {\n comListChannels(circleId: $circleId) { ${CHANNEL_FIELDS} }\n }`,\n { circleId },\n apiGatewayUrl\n );\n return result.comListChannels;\n },\n });\n};\n\nexport const useComCreateChannel = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: ComCreateChannelInput) => {\n const result = await comQuery<{ comCreateChannel: ComChannel }>(\n `mutation ComCreateChannel($input: ComCreateChannelInput!) {\n comCreateChannel(input: $input) { ${CHANNEL_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.comCreateChannel;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.channels(data.circleId) });\n qc.invalidateQueries({ queryKey: KEY.circle(data.circleId) });\n },\n });\n};\n\nexport const useComUpdateChannel = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; input: ComUpdateChannelInput; circleId: string }) => {\n const result = await comQuery<{ comUpdateChannel: ComChannel }>(\n `mutation ComUpdateChannel($id: ID!, $input: ComUpdateChannelInput!) {\n comUpdateChannel(id: $id, input: $input) { ${CHANNEL_FIELDS} }\n }`,\n { id: vars.id, input: vars.input },\n apiGatewayUrl\n );\n return result.comUpdateChannel;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.channels(data.circleId) });\n qc.invalidateQueries({ queryKey: KEY.circle(data.circleId) });\n },\n });\n};\n\n// ============================================================================\n// Posts / Reactions / Comments\n// ============================================================================\n\nexport interface PostFilters {\n channelId?: string;\n status?: ComPostStatus;\n pagination?: PaginationInput;\n}\n\nexport const useComPosts = (filters: PostFilters = {}) => {\n const { apiGatewayUrl } = useComradeCircle();\n return useQuery({\n queryKey: [...KEY.posts(filters.channelId ?? 'all'), filters.status, filters.pagination],\n enabled: Boolean(filters.channelId),\n queryFn: async () => {\n const result = await comQuery<{ comListPosts: ComConnection<ComPost> }>(\n `query ComListPosts($channelId: ID, $status: ComPostStatus, $pagination: PaginationInput) {\n comListPosts(channelId: $channelId, status: $status, pagination: $pagination) {\n items { ${POST_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n channelId: filters.channelId,\n status: filters.status,\n pagination: page(filters.pagination),\n },\n apiGatewayUrl\n );\n return result.comListPosts;\n },\n });\n};\n\nexport const useComPost = (id: string | undefined) => {\n const { apiGatewayUrl } = useComradeCircle();\n return useQuery({\n queryKey: KEY.post(id ?? ''),\n enabled: Boolean(id),\n queryFn: async () => {\n const result = await comQuery<{ comPost: ComPost | null }>(\n `query ComPost($id: ID!) {\n comPost(id: $id) {\n ${POST_FIELDS}\n comments { ${COMMENT_FIELDS} }\n }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.comPost;\n },\n });\n};\n\nexport const useComMyFeed = (pagination?: PaginationInput) => {\n const { apiGatewayUrl } = useComradeCircle();\n return useQuery({\n queryKey: [...KEY.feed, pagination],\n queryFn: async () => {\n const result = await comQuery<{ comMyFeed: ComConnection<ComPost> }>(\n `query ComMyFeed($pagination: PaginationInput) {\n comMyFeed(pagination: $pagination) {\n items { ${POST_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { pagination: page(pagination) },\n apiGatewayUrl\n );\n return result.comMyFeed;\n },\n });\n};\n\nexport const useComCreatePost = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: ComCreatePostInput) => {\n const result = await comQuery<{ comCreatePost: ComPost }>(\n `mutation ComCreatePost($input: ComCreatePostInput!) {\n comCreatePost(input: $input) { ${POST_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.comCreatePost;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.posts(data.channelId) });\n qc.invalidateQueries({ queryKey: KEY.feed });\n },\n });\n};\n\nexport const useComUpdatePost = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; input: ComUpdatePostInput }) => {\n const result = await comQuery<{ comUpdatePost: ComPost }>(\n `mutation ComUpdatePost($id: ID!, $input: ComUpdatePostInput!) {\n comUpdatePost(id: $id, input: $input) { ${POST_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.comUpdatePost;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.posts(data.channelId) });\n qc.invalidateQueries({ queryKey: KEY.post(data.id) });\n qc.invalidateQueries({ queryKey: KEY.feed });\n },\n });\n};\n\nexport const useComRemovePost = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; channelId?: string }) => {\n const result = await comQuery<{ comRemovePost: boolean }>(\n `mutation ComRemovePost($id: ID!) { comRemovePost(id: $id) }`,\n { id: vars.id },\n apiGatewayUrl\n );\n return result.comRemovePost;\n },\n onSuccess: (_d, vars) => {\n if (vars.channelId) qc.invalidateQueries({ queryKey: KEY.posts(vars.channelId) });\n qc.invalidateQueries({ queryKey: KEY.feed });\n },\n });\n};\n\nexport const useComReactToPost = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { postId: string; type: ComReactionType }) => {\n const result = await comQuery<{ comReactToPost: ComPost }>(\n `mutation ComReactToPost($postId: ID!, $type: ComReactionType!) {\n comReactToPost(postId: $postId, type: $type) { ${POST_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.comReactToPost;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.posts(data.channelId) });\n qc.invalidateQueries({ queryKey: KEY.post(data.id) });\n qc.invalidateQueries({ queryKey: KEY.feed });\n },\n });\n};\n\nexport const useComComments = (postId: string | undefined) => {\n const { apiGatewayUrl } = useComradeCircle();\n return useQuery({\n queryKey: KEY.comments(postId ?? ''),\n enabled: Boolean(postId),\n queryFn: async () => {\n const result = await comQuery<{ comListComments: ComComment[] }>(\n `query ComListComments($postId: ID!) {\n comListComments(postId: $postId) { ${COMMENT_FIELDS} }\n }`,\n { postId },\n apiGatewayUrl\n );\n return result.comListComments;\n },\n });\n};\n\nexport const useComAddComment = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: ComCreateCommentInput) => {\n const result = await comQuery<{ comAddComment: ComComment }>(\n `mutation ComAddComment($input: ComCreateCommentInput!) {\n comAddComment(input: $input) { ${COMMENT_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.comAddComment;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.comments(data.postId) });\n qc.invalidateQueries({ queryKey: KEY.post(data.postId) });\n qc.invalidateQueries({ queryKey: KEY.feed });\n },\n });\n};\n\n// ============================================================================\n// Feed follows\n// ============================================================================\n\nexport const useComMyFollows = (targetType?: ComFollowTargetType) => {\n const { apiGatewayUrl } = useComradeCircle();\n return useQuery({\n queryKey: [...KEY.follows, targetType ?? 'all'],\n queryFn: async () => {\n const result = await comQuery<{ comMyFollows: ComFeedFollow[] }>(\n `query ComMyFollows($targetType: ComFollowTargetType) {\n comMyFollows(targetType: $targetType) { ${FOLLOW_FIELDS} }\n }`,\n { targetType },\n apiGatewayUrl\n );\n return result.comMyFollows;\n },\n });\n};\n\nexport const useComFollow = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: ComFollowInput) => {\n const result = await comQuery<{ comFollow: ComFeedFollow }>(\n `mutation ComFollow($input: ComFollowInput!) {\n comFollow(input: $input) { ${FOLLOW_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.comFollow;\n },\n onSuccess: () => {\n qc.invalidateQueries({ queryKey: KEY.follows });\n qc.invalidateQueries({ queryKey: KEY.feed });\n },\n });\n};\n\nexport const useComUnfollow = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: ComFollowInput) => {\n const result = await comQuery<{ comUnfollow: boolean }>(\n `mutation ComUnfollow($input: ComFollowInput!) { comUnfollow(input: $input) }`,\n { input },\n apiGatewayUrl\n );\n return result.comUnfollow;\n },\n onSuccess: () => {\n qc.invalidateQueries({ queryKey: KEY.follows });\n qc.invalidateQueries({ queryKey: KEY.feed });\n },\n });\n};\n\nexport const useComMuteFollow = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; muted: boolean }) => {\n const result = await comQuery<{ comMuteFollow: ComFeedFollow }>(\n `mutation ComMuteFollow($id: ID!, $muted: Boolean!) {\n comMuteFollow(id: $id, muted: $muted) { ${FOLLOW_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.comMuteFollow;\n },\n onSuccess: () => {\n qc.invalidateQueries({ queryKey: KEY.follows });\n qc.invalidateQueries({ queryKey: KEY.feed });\n },\n });\n};\n\n// ============================================================================\n// Events / RSVPs\n// ============================================================================\n\nexport interface EventFilters {\n circleId?: string;\n status?: ComEventStatus;\n pagination?: PaginationInput;\n}\n\nexport const useComEvents = (filters: EventFilters = {}) => {\n const { apiGatewayUrl } = useComradeCircle();\n return useQuery({\n queryKey: [...KEY.events, filters],\n queryFn: async () => {\n const result = await comQuery<{ comListEvents: ComConnection<ComEvent> }>(\n `query ComListEvents($circleId: ID, $status: ComEventStatus, $pagination: PaginationInput) {\n comListEvents(circleId: $circleId, status: $status, pagination: $pagination) {\n items { ${EVENT_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n circleId: filters.circleId,\n status: filters.status,\n pagination: page(filters.pagination),\n },\n apiGatewayUrl\n );\n return result.comListEvents;\n },\n });\n};\n\nexport const useComEvent = (id: string | undefined) => {\n const { apiGatewayUrl } = useComradeCircle();\n return useQuery({\n queryKey: KEY.event(id ?? ''),\n enabled: Boolean(id),\n queryFn: async () => {\n const result = await comQuery<{ comEvent: ComEvent | null }>(\n `query ComEvent($id: ID!) {\n comEvent(id: $id) {\n ${EVENT_FIELDS}\n rsvps { ${RSVP_FIELDS} }\n }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.comEvent;\n },\n });\n};\n\nexport const useComCreateEvent = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: ComCreateEventInput) => {\n const result = await comQuery<{ comCreateEvent: ComEvent }>(\n `mutation ComCreateEvent($input: ComCreateEventInput!) {\n comCreateEvent(input: $input) { ${EVENT_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.comCreateEvent;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.events }),\n });\n};\n\nexport const useComUpdateEvent = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; input: ComUpdateEventInput }) => {\n const result = await comQuery<{ comUpdateEvent: ComEvent }>(\n `mutation ComUpdateEvent($id: ID!, $input: ComUpdateEventInput!) {\n comUpdateEvent(id: $id, input: $input) { ${EVENT_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.comUpdateEvent;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.events });\n qc.invalidateQueries({ queryKey: KEY.event(data.id) });\n },\n });\n};\n\nexport const useComTransitionEvent = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; status: ComEventStatus }) => {\n const result = await comQuery<{ comTransitionEvent: ComEvent }>(\n `mutation ComTransitionEvent($id: ID!, $status: ComEventStatus!) {\n comTransitionEvent(id: $id, status: $status) { ${EVENT_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.comTransitionEvent;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.events });\n qc.invalidateQueries({ queryKey: KEY.event(data.id) });\n },\n });\n};\n\nexport const useComRsvpEvent = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { eventId: string; status: ComRsvpStatus; note?: string | null }) => {\n const result = await comQuery<{ comRsvpEvent: ComEventRsvp }>(\n `mutation ComRsvpEvent($eventId: ID!, $status: ComRsvpStatus!, $note: String) {\n comRsvpEvent(eventId: $eventId, status: $status, note: $note) { ${RSVP_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.comRsvpEvent;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.events });\n qc.invalidateQueries({ queryKey: KEY.event(data.eventId) });\n },\n });\n};\n\n// ============================================================================\n// Polls / Votes\n// ============================================================================\n\nexport const useComPolls = (circleId: string | undefined, status?: ComPollStatus) => {\n const { apiGatewayUrl } = useComradeCircle();\n return useQuery({\n queryKey: [...KEY.polls(circleId ?? ''), status ?? 'all'],\n enabled: Boolean(circleId),\n queryFn: async () => {\n const result = await comQuery<{ comListPolls: ComPoll[] }>(\n `query ComListPolls($circleId: ID!, $status: ComPollStatus) {\n comListPolls(circleId: $circleId, status: $status) { ${POLL_FIELDS} }\n }`,\n { circleId, status },\n apiGatewayUrl\n );\n return result.comListPolls;\n },\n });\n};\n\nexport const useComCreatePoll = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: ComCreatePollInput) => {\n const result = await comQuery<{ comCreatePoll: ComPoll }>(\n `mutation ComCreatePoll($input: ComCreatePollInput!) {\n comCreatePoll(input: $input) { ${POLL_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.comCreatePoll;\n },\n onSuccess: (data) => qc.invalidateQueries({ queryKey: KEY.polls(data.circleId) }),\n });\n};\n\nexport const useComClosePoll = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await comQuery<{ comClosePoll: ComPoll }>(\n `mutation ComClosePoll($id: ID!) { comClosePoll(id: $id) { ${POLL_FIELDS} } }`,\n { id },\n apiGatewayUrl\n );\n return result.comClosePoll;\n },\n onSuccess: (data) => qc.invalidateQueries({ queryKey: KEY.polls(data.circleId) }),\n });\n};\n\nexport const useComVotePoll = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { pollId: string; optionId: string; circleId?: string }) => {\n const result = await comQuery<{ comVotePoll: ComPollOption }>(\n `mutation ComVotePoll($pollId: ID!, $optionId: ID!) {\n comVotePoll(pollId: $pollId, optionId: $optionId) { ${POLL_OPTION_FIELDS} }\n }`,\n { pollId: vars.pollId, optionId: vars.optionId },\n apiGatewayUrl\n );\n return result.comVotePoll;\n },\n onSuccess: (_data, vars) => {\n if (vars.circleId) qc.invalidateQueries({ queryKey: KEY.polls(vars.circleId) });\n qc.invalidateQueries({ queryKey: KEY.poll(vars.pollId) });\n },\n });\n};\n\n// ============================================================================\n// Profiles (social identity layer)\n// ============================================================================\n\nexport interface ProfileFilters {\n discoverable?: boolean;\n pagination?: PaginationInput;\n}\n\nexport const useComProfiles = (filters: ProfileFilters = {}) => {\n const { apiGatewayUrl } = useComradeCircle();\n return useQuery({\n queryKey: [...KEY.profiles, filters],\n queryFn: async () => {\n const result = await comQuery<{ comListProfiles: ComConnection<ComProfile> }>(\n `query ComListProfiles($discoverable: Boolean, $pagination: PaginationInput) {\n comListProfiles(discoverable: $discoverable, pagination: $pagination) {\n items { ${PROFILE_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { discoverable: filters.discoverable, pagination: page(filters.pagination) },\n apiGatewayUrl\n );\n return result.comListProfiles;\n },\n });\n};\n\nexport const useComProfile = (memberId: string | undefined) => {\n const { apiGatewayUrl } = useComradeCircle();\n return useQuery({\n queryKey: KEY.profile(memberId ?? ''),\n enabled: Boolean(memberId),\n // Profiles change rarely; cache aggressively so feed identity lookups are cheap.\n staleTime: 10 * 60 * 1000,\n queryFn: async () => {\n const result = await comQuery<{ comProfile: ComProfile | null }>(\n `query ComProfile($memberId: ID!) {\n comProfile(memberId: $memberId) { ${PROFILE_FIELDS} }\n }`,\n { memberId },\n apiGatewayUrl\n );\n return result.comProfile;\n },\n });\n};\n\nexport const useComUpsertProfile = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: ComUpsertProfileInput) => {\n const result = await comQuery<{ comUpsertProfile: ComProfile }>(\n `mutation ComUpsertProfile($input: ComUpsertProfileInput!) {\n comUpsertProfile(input: $input) { ${PROFILE_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.comUpsertProfile;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.profiles });\n qc.invalidateQueries({ queryKey: KEY.profile(data.memberId) });\n },\n });\n};\n\n// Re-export commonly used reaction type for convenience.\nexport type { ComReaction };\n"],"mappings":"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"}
1
+ {"version":3,"file":"useComradeCircleApi.js","names":[],"sources":["../../../src/comradecircle/hooks/useComradeCircleApi.ts"],"sourcesContent":["/**\n * ComradeCircle API hooks\n * @module comradecircle/hooks\n *\n * React-Query hooks wired DIRECTLY to the real `wspace-comradecircle-svc`\n * federated GraphQL contract (the `com*` operations). Every query/mutation\n * below uses an inline gql string whose fields match the svc\n * `.hive-schema.graphql` exactly. No mock data.\n *\n * Transport: `graphqlFetch({ gateway: 'workspace', workspaceToken: true })` —\n * the host shell supplies the gateway base URL + a workspace-scoped token.\n *\n * IMPORTANT: `User`/`File` are id-only federation stubs in this subgraph. We\n * never select `author { firstName }` or `avatar { url }`. Display identity is\n * resolved through `ComProfile` (see `useComProfile`).\n */\n\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\nimport { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql';\n\nimport { useComradeCircle } from '../context';\nimport { clearGraphqlResponseCache } from '../lib/graphql-cache';\nimport type {\n ComConnection,\n ComCircle,\n ComCircleStatus,\n ComCircleVisibility,\n ComChannel,\n ComComment,\n ComPost,\n ComPostStatus,\n ComPoll,\n ComPollStatus,\n ComPollOption,\n ComEvent,\n ComEventStatus,\n ComEventRsvp,\n ComRsvpStatus,\n ComProfile,\n ComMembership,\n ComMembershipStatus,\n ComMemberRole,\n ComFeedFollow,\n ComFollowTargetType,\n ComReaction,\n ComReactionType,\n ComCreateCircleInput,\n ComUpdateCircleInput,\n ComCreateChannelInput,\n ComUpdateChannelInput,\n ComCreatePostInput,\n ComUpdatePostInput,\n ComCreateCommentInput,\n ComCreateEventInput,\n ComUpdateEventInput,\n ComCreatePollInput,\n ComFollowInput,\n ComUpsertProfileInput,\n PaginationInput,\n} from '../types';\n\n// ============================================================================\n// Transport\n// ============================================================================\n\nconst isMutation = (query: string): boolean => /^\\s*mutation\\b/.test(query);\n\nconst comQuery = async <TData>(\n query: string,\n variables: Record<string, unknown>,\n baseUrl?: string\n): Promise<TData> => {\n // A mutation's own request must never be served from (or coalesced onto) the\n // read cache, and the resolved read cache must be dropped once it commits so\n // the React-Query refetch that follows sees the new state — not a stale\n // pre-write response held for up to 15s. Clear before AND after the write.\n const mutating = isMutation(query);\n if (mutating) clearGraphqlResponseCache();\n\n const response = await graphqlFetch<TData>({\n gateway: 'workspace',\n baseUrl,\n query,\n variables,\n workspaceToken: true,\n });\n\n if (mutating) clearGraphqlResponseCache();\n\n if (response.errors?.length) {\n throw new Error(response.errors[0]?.message ?? 'GraphQL request failed');\n }\n if (!response.data) {\n throw new Error('GraphQL response did not include data');\n }\n return response.data;\n};\n\n// React-Query key roots (one namespace per domain entity).\nconst KEY = {\n circles: ['comradecircle', 'circles'] as const,\n circle: (id: string) => ['comradecircle', 'circle', id] as const,\n channels: (circleId: string) => ['comradecircle', 'channels', circleId] as const,\n posts: (channelId: string) => ['comradecircle', 'posts', channelId] as const,\n post: (id: string) => ['comradecircle', 'post', id] as const,\n comments: (postId: string) => ['comradecircle', 'comments', postId] as const,\n feed: ['comradecircle', 'feed'] as const,\n follows: ['comradecircle', 'follows'] as const,\n events: ['comradecircle', 'events'] as const,\n event: (id: string) => ['comradecircle', 'event', id] as const,\n polls: (circleId: string) => ['comradecircle', 'polls', circleId] as const,\n poll: (id: string) => ['comradecircle', 'poll', id] as const,\n profiles: ['comradecircle', 'profiles'] as const,\n profile: (memberId: string) => ['comradecircle', 'profile', memberId] as const,\n memberships: ['comradecircle', 'memberships'] as const,\n};\n\nconst DEFAULT_PAGE: PaginationInput = { limit: 50 };\n\n/** Drop `cursor` when it is nullish so the svc never sees an explicit null. */\nconst page = (p?: PaginationInput): PaginationInput => {\n const base = p ?? DEFAULT_PAGE;\n const result: PaginationInput = { limit: base.limit ?? DEFAULT_PAGE.limit };\n if (base.offset != null) result.offset = base.offset;\n if (base.cursor != null) result.cursor = base.cursor;\n return result;\n};\n\n// ============================================================================\n// Reusable gql field selections (codegen-free strictness)\n// ============================================================================\n\nconst CHANNEL_FIELDS = `\n id workspaceId circleId name slug description type visibility position isArchived\n createdAt updatedAt\n`;\n\nconst CIRCLE_FIELDS = `\n id workspaceId name slug description topic tags status visibility memberCount\n avatar { id } createdAt updatedAt\n`;\n\nconst REACTION_FIELDS = `id postId memberId type createdAt`;\n\nconst COMMENT_FIELDS = `\n id workspaceId postId parentId authorId body isHidden createdAt updatedAt\n`;\n\nconst POST_FIELDS = `\n id workspaceId channelId authorId body status tags attachmentFileIds isPinned\n reactionCount commentCount reactions { ${REACTION_FIELDS} } createdAt updatedAt\n`;\n\nconst POLL_OPTION_FIELDS = `id workspaceId pollId label position voteCount createdAt`;\n\nconst POLL_FIELDS = `\n id workspaceId circleId question allowMultiple isAnonymous status closesAt\n options { ${POLL_OPTION_FIELDS} } createdAt updatedAt\n`;\n\nconst RSVP_FIELDS = `\n id workspaceId eventId memberId status note createdAt updatedAt\n`;\n\nconst EVENT_FIELDS = `\n id workspaceId circleId hostId title description mode status location joinUrl\n capacity startsAt endsAt tags rsvpCount createdAt updatedAt\n`;\n\nconst PROFILE_FIELDS = `\n id workspaceId memberId displayName headline bio avatar { id } interests skills\n presence discoverable createdAt updatedAt\n`;\n\nconst MEMBERSHIP_FIELDS = `\n id workspaceId circleId memberId role status joinedAt createdAt updatedAt\n`;\n\nconst FOLLOW_FIELDS = `\n id workspaceId followerId targetId targetType muted createdAt updatedAt\n`;\n\n// ============================================================================\n// Circles\n// ============================================================================\n\nexport interface CircleFilters {\n status?: ComCircleStatus;\n visibility?: ComCircleVisibility;\n pagination?: PaginationInput;\n}\n\nexport const useComCircles = (filters: CircleFilters = {}) => {\n const { apiGatewayUrl } = useComradeCircle();\n return useQuery({\n queryKey: [...KEY.circles, filters],\n queryFn: async () => {\n const result = await comQuery<{ comListCircles: ComConnection<ComCircle> }>(\n `query ComListCircles($status: ComCircleStatus, $visibility: ComCircleVisibility, $pagination: PaginationInput) {\n comListCircles(status: $status, visibility: $visibility, pagination: $pagination) {\n items { ${CIRCLE_FIELDS} channels { id } }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n status: filters.status,\n visibility: filters.visibility,\n pagination: page(filters.pagination),\n },\n apiGatewayUrl\n );\n return result.comListCircles;\n },\n });\n};\n\nexport const useComCircle = (id: string | undefined) => {\n const { apiGatewayUrl } = useComradeCircle();\n return useQuery({\n queryKey: KEY.circle(id ?? ''),\n enabled: Boolean(id),\n queryFn: async () => {\n const result = await comQuery<{ comCircle: ComCircle | null }>(\n `query ComCircle($id: ID!) {\n comCircle(id: $id) {\n ${CIRCLE_FIELDS}\n channels { ${CHANNEL_FIELDS} }\n memberships { ${MEMBERSHIP_FIELDS} }\n }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.comCircle;\n },\n });\n};\n\nexport const useComCreateCircle = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: ComCreateCircleInput) => {\n const result = await comQuery<{ comCreateCircle: ComCircle }>(\n `mutation ComCreateCircle($input: ComCreateCircleInput!) {\n comCreateCircle(input: $input) { ${CIRCLE_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.comCreateCircle;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.circles }),\n });\n};\n\nexport const useComUpdateCircle = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; input: ComUpdateCircleInput }) => {\n const result = await comQuery<{ comUpdateCircle: ComCircle }>(\n `mutation ComUpdateCircle($id: ID!, $input: ComUpdateCircleInput!) {\n comUpdateCircle(id: $id, input: $input) { ${CIRCLE_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.comUpdateCircle;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.circles });\n qc.invalidateQueries({ queryKey: KEY.circle(data.id) });\n },\n });\n};\n\nexport const useComArchiveCircle = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await comQuery<{ comArchiveCircle: boolean }>(\n `mutation ComArchiveCircle($id: ID!) { comArchiveCircle(id: $id) }`,\n { id },\n apiGatewayUrl\n );\n return result.comArchiveCircle;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.circles }),\n });\n};\n\nexport const useComJoinCircle = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (circleId: string) => {\n const result = await comQuery<{ comJoinCircle: ComMembership }>(\n `mutation ComJoinCircle($circleId: ID!) {\n comJoinCircle(circleId: $circleId) { ${MEMBERSHIP_FIELDS} }\n }`,\n { circleId },\n apiGatewayUrl\n );\n return result.comJoinCircle;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.circles });\n qc.invalidateQueries({ queryKey: KEY.circle(data.circleId) });\n qc.invalidateQueries({ queryKey: KEY.memberships });\n },\n });\n};\n\nexport const useComLeaveCircle = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (circleId: string) => {\n const result = await comQuery<{ comLeaveCircle: boolean }>(\n `mutation ComLeaveCircle($circleId: ID!) { comLeaveCircle(circleId: $circleId) }`,\n { circleId },\n apiGatewayUrl\n );\n return result.comLeaveCircle;\n },\n onSuccess: (_data, circleId) => {\n qc.invalidateQueries({ queryKey: KEY.circles });\n qc.invalidateQueries({ queryKey: KEY.circle(circleId) });\n qc.invalidateQueries({ queryKey: KEY.memberships });\n },\n });\n};\n\nexport const useComSetMemberRole = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { membershipId: string; role: ComMemberRole; circleId?: string }) => {\n const result = await comQuery<{ comSetMemberRole: ComMembership }>(\n `mutation ComSetMemberRole($membershipId: ID!, $role: ComMemberRole!) {\n comSetMemberRole(membershipId: $membershipId, role: $role) { ${MEMBERSHIP_FIELDS} }\n }`,\n { membershipId: vars.membershipId, role: vars.role },\n apiGatewayUrl\n );\n return result.comSetMemberRole;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.circle(data.circleId) });\n qc.invalidateQueries({ queryKey: KEY.memberships });\n },\n });\n};\n\nexport interface MembershipFilters {\n circleId?: string;\n status?: ComMembershipStatus;\n pagination?: PaginationInput;\n}\n\nexport const useComMemberships = (filters: MembershipFilters = {}) => {\n const { apiGatewayUrl } = useComradeCircle();\n return useQuery({\n queryKey: [...KEY.memberships, filters],\n queryFn: async () => {\n const result = await comQuery<{ comListMemberships: ComConnection<ComMembership> }>(\n `query ComListMemberships($circleId: ID, $status: ComMembershipStatus, $pagination: PaginationInput) {\n comListMemberships(circleId: $circleId, status: $status, pagination: $pagination) {\n items { ${MEMBERSHIP_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n circleId: filters.circleId,\n status: filters.status,\n pagination: page(filters.pagination),\n },\n apiGatewayUrl\n );\n return result.comListMemberships;\n },\n });\n};\n\n// ============================================================================\n// Channels\n// ============================================================================\n\nexport const useComChannels = (circleId: string | undefined) => {\n const { apiGatewayUrl } = useComradeCircle();\n return useQuery({\n queryKey: KEY.channels(circleId ?? ''),\n enabled: Boolean(circleId),\n queryFn: async () => {\n const result = await comQuery<{ comListChannels: ComChannel[] }>(\n `query ComListChannels($circleId: ID!) {\n comListChannels(circleId: $circleId) { ${CHANNEL_FIELDS} }\n }`,\n { circleId },\n apiGatewayUrl\n );\n return result.comListChannels;\n },\n });\n};\n\nexport const useComCreateChannel = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: ComCreateChannelInput) => {\n const result = await comQuery<{ comCreateChannel: ComChannel }>(\n `mutation ComCreateChannel($input: ComCreateChannelInput!) {\n comCreateChannel(input: $input) { ${CHANNEL_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.comCreateChannel;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.channels(data.circleId) });\n qc.invalidateQueries({ queryKey: KEY.circle(data.circleId) });\n },\n });\n};\n\nexport const useComUpdateChannel = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; input: ComUpdateChannelInput; circleId: string }) => {\n const result = await comQuery<{ comUpdateChannel: ComChannel }>(\n `mutation ComUpdateChannel($id: ID!, $input: ComUpdateChannelInput!) {\n comUpdateChannel(id: $id, input: $input) { ${CHANNEL_FIELDS} }\n }`,\n { id: vars.id, input: vars.input },\n apiGatewayUrl\n );\n return result.comUpdateChannel;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.channels(data.circleId) });\n qc.invalidateQueries({ queryKey: KEY.circle(data.circleId) });\n },\n });\n};\n\n// ============================================================================\n// Posts / Reactions / Comments\n// ============================================================================\n\nexport interface PostFilters {\n channelId?: string;\n status?: ComPostStatus;\n pagination?: PaginationInput;\n}\n\nexport const useComPosts = (filters: PostFilters = {}) => {\n const { apiGatewayUrl } = useComradeCircle();\n return useQuery({\n queryKey: [...KEY.posts(filters.channelId ?? 'all'), filters.status, filters.pagination],\n enabled: Boolean(filters.channelId),\n queryFn: async () => {\n const result = await comQuery<{ comListPosts: ComConnection<ComPost> }>(\n `query ComListPosts($channelId: ID, $status: ComPostStatus, $pagination: PaginationInput) {\n comListPosts(channelId: $channelId, status: $status, pagination: $pagination) {\n items { ${POST_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n channelId: filters.channelId,\n status: filters.status,\n pagination: page(filters.pagination),\n },\n apiGatewayUrl\n );\n return result.comListPosts;\n },\n });\n};\n\nexport const useComPost = (id: string | undefined) => {\n const { apiGatewayUrl } = useComradeCircle();\n return useQuery({\n queryKey: KEY.post(id ?? ''),\n enabled: Boolean(id),\n queryFn: async () => {\n const result = await comQuery<{ comPost: ComPost | null }>(\n `query ComPost($id: ID!) {\n comPost(id: $id) {\n ${POST_FIELDS}\n comments { ${COMMENT_FIELDS} }\n }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.comPost;\n },\n });\n};\n\nexport const useComMyFeed = (pagination?: PaginationInput) => {\n const { apiGatewayUrl } = useComradeCircle();\n return useQuery({\n queryKey: [...KEY.feed, pagination],\n queryFn: async () => {\n const result = await comQuery<{ comMyFeed: ComConnection<ComPost> }>(\n `query ComMyFeed($pagination: PaginationInput) {\n comMyFeed(pagination: $pagination) {\n items { ${POST_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { pagination: page(pagination) },\n apiGatewayUrl\n );\n return result.comMyFeed;\n },\n });\n};\n\nexport const useComCreatePost = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: ComCreatePostInput) => {\n const result = await comQuery<{ comCreatePost: ComPost }>(\n `mutation ComCreatePost($input: ComCreatePostInput!) {\n comCreatePost(input: $input) { ${POST_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.comCreatePost;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.posts(data.channelId) });\n qc.invalidateQueries({ queryKey: KEY.feed });\n },\n });\n};\n\nexport const useComUpdatePost = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; input: ComUpdatePostInput }) => {\n const result = await comQuery<{ comUpdatePost: ComPost }>(\n `mutation ComUpdatePost($id: ID!, $input: ComUpdatePostInput!) {\n comUpdatePost(id: $id, input: $input) { ${POST_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.comUpdatePost;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.posts(data.channelId) });\n qc.invalidateQueries({ queryKey: KEY.post(data.id) });\n qc.invalidateQueries({ queryKey: KEY.feed });\n },\n });\n};\n\nexport const useComRemovePost = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; channelId?: string }) => {\n const result = await comQuery<{ comRemovePost: boolean }>(\n `mutation ComRemovePost($id: ID!) { comRemovePost(id: $id) }`,\n { id: vars.id },\n apiGatewayUrl\n );\n return result.comRemovePost;\n },\n onSuccess: (_d, vars) => {\n if (vars.channelId) qc.invalidateQueries({ queryKey: KEY.posts(vars.channelId) });\n qc.invalidateQueries({ queryKey: KEY.feed });\n },\n });\n};\n\nexport const useComReactToPost = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { postId: string; type: ComReactionType }) => {\n const result = await comQuery<{ comReactToPost: ComPost }>(\n `mutation ComReactToPost($postId: ID!, $type: ComReactionType!) {\n comReactToPost(postId: $postId, type: $type) { ${POST_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.comReactToPost;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.posts(data.channelId) });\n qc.invalidateQueries({ queryKey: KEY.post(data.id) });\n qc.invalidateQueries({ queryKey: KEY.feed });\n },\n });\n};\n\nexport const useComComments = (postId: string | undefined) => {\n const { apiGatewayUrl } = useComradeCircle();\n return useQuery({\n queryKey: KEY.comments(postId ?? ''),\n enabled: Boolean(postId),\n queryFn: async () => {\n const result = await comQuery<{ comListComments: ComComment[] }>(\n `query ComListComments($postId: ID!) {\n comListComments(postId: $postId) { ${COMMENT_FIELDS} }\n }`,\n { postId },\n apiGatewayUrl\n );\n return result.comListComments;\n },\n });\n};\n\nexport const useComAddComment = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: ComCreateCommentInput) => {\n const result = await comQuery<{ comAddComment: ComComment }>(\n `mutation ComAddComment($input: ComCreateCommentInput!) {\n comAddComment(input: $input) { ${COMMENT_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.comAddComment;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.comments(data.postId) });\n qc.invalidateQueries({ queryKey: KEY.post(data.postId) });\n qc.invalidateQueries({ queryKey: KEY.feed });\n },\n });\n};\n\n// ============================================================================\n// Feed follows\n// ============================================================================\n\nexport const useComMyFollows = (targetType?: ComFollowTargetType) => {\n const { apiGatewayUrl } = useComradeCircle();\n return useQuery({\n queryKey: [...KEY.follows, targetType ?? 'all'],\n queryFn: async () => {\n const result = await comQuery<{ comMyFollows: ComFeedFollow[] }>(\n `query ComMyFollows($targetType: ComFollowTargetType) {\n comMyFollows(targetType: $targetType) { ${FOLLOW_FIELDS} }\n }`,\n { targetType },\n apiGatewayUrl\n );\n return result.comMyFollows;\n },\n });\n};\n\nexport const useComFollow = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: ComFollowInput) => {\n const result = await comQuery<{ comFollow: ComFeedFollow }>(\n `mutation ComFollow($input: ComFollowInput!) {\n comFollow(input: $input) { ${FOLLOW_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.comFollow;\n },\n onSuccess: () => {\n qc.invalidateQueries({ queryKey: KEY.follows });\n qc.invalidateQueries({ queryKey: KEY.feed });\n },\n });\n};\n\nexport const useComUnfollow = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: ComFollowInput) => {\n const result = await comQuery<{ comUnfollow: boolean }>(\n `mutation ComUnfollow($input: ComFollowInput!) { comUnfollow(input: $input) }`,\n { input },\n apiGatewayUrl\n );\n return result.comUnfollow;\n },\n onSuccess: () => {\n qc.invalidateQueries({ queryKey: KEY.follows });\n qc.invalidateQueries({ queryKey: KEY.feed });\n },\n });\n};\n\nexport const useComMuteFollow = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; muted: boolean }) => {\n const result = await comQuery<{ comMuteFollow: ComFeedFollow }>(\n `mutation ComMuteFollow($id: ID!, $muted: Boolean!) {\n comMuteFollow(id: $id, muted: $muted) { ${FOLLOW_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.comMuteFollow;\n },\n onSuccess: () => {\n qc.invalidateQueries({ queryKey: KEY.follows });\n qc.invalidateQueries({ queryKey: KEY.feed });\n },\n });\n};\n\n// ============================================================================\n// Events / RSVPs\n// ============================================================================\n\nexport interface EventFilters {\n circleId?: string;\n status?: ComEventStatus;\n pagination?: PaginationInput;\n}\n\nexport const useComEvents = (filters: EventFilters = {}) => {\n const { apiGatewayUrl } = useComradeCircle();\n return useQuery({\n queryKey: [...KEY.events, filters],\n queryFn: async () => {\n const result = await comQuery<{ comListEvents: ComConnection<ComEvent> }>(\n `query ComListEvents($circleId: ID, $status: ComEventStatus, $pagination: PaginationInput) {\n comListEvents(circleId: $circleId, status: $status, pagination: $pagination) {\n items { ${EVENT_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n circleId: filters.circleId,\n status: filters.status,\n pagination: page(filters.pagination),\n },\n apiGatewayUrl\n );\n return result.comListEvents;\n },\n });\n};\n\nexport const useComEvent = (id: string | undefined) => {\n const { apiGatewayUrl } = useComradeCircle();\n return useQuery({\n queryKey: KEY.event(id ?? ''),\n enabled: Boolean(id),\n queryFn: async () => {\n const result = await comQuery<{ comEvent: ComEvent | null }>(\n `query ComEvent($id: ID!) {\n comEvent(id: $id) {\n ${EVENT_FIELDS}\n rsvps { ${RSVP_FIELDS} }\n }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.comEvent;\n },\n });\n};\n\nexport const useComCreateEvent = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: ComCreateEventInput) => {\n const result = await comQuery<{ comCreateEvent: ComEvent }>(\n `mutation ComCreateEvent($input: ComCreateEventInput!) {\n comCreateEvent(input: $input) { ${EVENT_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.comCreateEvent;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.events }),\n });\n};\n\nexport const useComUpdateEvent = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; input: ComUpdateEventInput }) => {\n const result = await comQuery<{ comUpdateEvent: ComEvent }>(\n `mutation ComUpdateEvent($id: ID!, $input: ComUpdateEventInput!) {\n comUpdateEvent(id: $id, input: $input) { ${EVENT_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.comUpdateEvent;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.events });\n qc.invalidateQueries({ queryKey: KEY.event(data.id) });\n },\n });\n};\n\nexport const useComTransitionEvent = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; status: ComEventStatus }) => {\n const result = await comQuery<{ comTransitionEvent: ComEvent }>(\n `mutation ComTransitionEvent($id: ID!, $status: ComEventStatus!) {\n comTransitionEvent(id: $id, status: $status) { ${EVENT_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.comTransitionEvent;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.events });\n qc.invalidateQueries({ queryKey: KEY.event(data.id) });\n },\n });\n};\n\nexport const useComRsvpEvent = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { eventId: string; status: ComRsvpStatus; note?: string | null }) => {\n const result = await comQuery<{ comRsvpEvent: ComEventRsvp }>(\n `mutation ComRsvpEvent($eventId: ID!, $status: ComRsvpStatus!, $note: String) {\n comRsvpEvent(eventId: $eventId, status: $status, note: $note) { ${RSVP_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.comRsvpEvent;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.events });\n qc.invalidateQueries({ queryKey: KEY.event(data.eventId) });\n },\n });\n};\n\n// ============================================================================\n// Polls / Votes\n// ============================================================================\n\nexport const useComPolls = (circleId: string | undefined, status?: ComPollStatus) => {\n const { apiGatewayUrl } = useComradeCircle();\n return useQuery({\n queryKey: [...KEY.polls(circleId ?? ''), status ?? 'all'],\n enabled: Boolean(circleId),\n queryFn: async () => {\n const result = await comQuery<{ comListPolls: ComPoll[] }>(\n `query ComListPolls($circleId: ID!, $status: ComPollStatus) {\n comListPolls(circleId: $circleId, status: $status) { ${POLL_FIELDS} }\n }`,\n { circleId, status },\n apiGatewayUrl\n );\n return result.comListPolls;\n },\n });\n};\n\nexport const useComCreatePoll = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: ComCreatePollInput) => {\n const result = await comQuery<{ comCreatePoll: ComPoll }>(\n `mutation ComCreatePoll($input: ComCreatePollInput!) {\n comCreatePoll(input: $input) { ${POLL_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.comCreatePoll;\n },\n onSuccess: (data) => qc.invalidateQueries({ queryKey: KEY.polls(data.circleId) }),\n });\n};\n\nexport const useComClosePoll = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await comQuery<{ comClosePoll: ComPoll }>(\n `mutation ComClosePoll($id: ID!) { comClosePoll(id: $id) { ${POLL_FIELDS} } }`,\n { id },\n apiGatewayUrl\n );\n return result.comClosePoll;\n },\n onSuccess: (data) => qc.invalidateQueries({ queryKey: KEY.polls(data.circleId) }),\n });\n};\n\nexport const useComVotePoll = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { pollId: string; optionId: string; circleId?: string }) => {\n const result = await comQuery<{ comVotePoll: ComPollOption }>(\n `mutation ComVotePoll($pollId: ID!, $optionId: ID!) {\n comVotePoll(pollId: $pollId, optionId: $optionId) { ${POLL_OPTION_FIELDS} }\n }`,\n { pollId: vars.pollId, optionId: vars.optionId },\n apiGatewayUrl\n );\n return result.comVotePoll;\n },\n onSuccess: (_data, vars) => {\n if (vars.circleId) qc.invalidateQueries({ queryKey: KEY.polls(vars.circleId) });\n qc.invalidateQueries({ queryKey: KEY.poll(vars.pollId) });\n },\n });\n};\n\n// ============================================================================\n// Profiles (social identity layer)\n// ============================================================================\n\nexport interface ProfileFilters {\n discoverable?: boolean;\n pagination?: PaginationInput;\n}\n\nexport const useComProfiles = (filters: ProfileFilters = {}) => {\n const { apiGatewayUrl } = useComradeCircle();\n return useQuery({\n queryKey: [...KEY.profiles, filters],\n queryFn: async () => {\n const result = await comQuery<{ comListProfiles: ComConnection<ComProfile> }>(\n `query ComListProfiles($discoverable: Boolean, $pagination: PaginationInput) {\n comListProfiles(discoverable: $discoverable, pagination: $pagination) {\n items { ${PROFILE_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { discoverable: filters.discoverable, pagination: page(filters.pagination) },\n apiGatewayUrl\n );\n return result.comListProfiles;\n },\n });\n};\n\nexport const useComProfile = (memberId: string | undefined) => {\n const { apiGatewayUrl } = useComradeCircle();\n return useQuery({\n queryKey: KEY.profile(memberId ?? ''),\n enabled: Boolean(memberId),\n // Profiles change rarely; cache aggressively so feed identity lookups are cheap.\n staleTime: 10 * 60 * 1000,\n queryFn: async () => {\n const result = await comQuery<{ comProfile: ComProfile | null }>(\n `query ComProfile($memberId: ID!) {\n comProfile(memberId: $memberId) { ${PROFILE_FIELDS} }\n }`,\n { memberId },\n apiGatewayUrl\n );\n return result.comProfile;\n },\n });\n};\n\nexport const useComUpsertProfile = () => {\n const { apiGatewayUrl } = useComradeCircle();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: ComUpsertProfileInput) => {\n const result = await comQuery<{ comUpsertProfile: ComProfile }>(\n `mutation ComUpsertProfile($input: ComUpsertProfileInput!) {\n comUpsertProfile(input: $input) { ${PROFILE_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.comUpsertProfile;\n },\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.profiles });\n qc.invalidateQueries({ queryKey: KEY.profile(data.memberId) });\n },\n });\n};\n\n// Re-export commonly used reaction type for convenience.\nexport type { ComReaction };\n"],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ import { useComradeCircle as e } from "../context/ComradeCircleContext.js";
2
+ import "../context/index.js";
3
+ import { useQuery as t } from "@tanstack/react-query";
4
+ import { getWorkspaceClient as n, gql as r, graphqlFetch as i } from "@burdenoff/fe-libs/shared/graphql";
5
+ import { uploadBlobToFiles as a } from "@burdenoff/fe-libs/storage";
6
+ //#region src/comradecircle/hooks/useFiles.ts
7
+ var o = 31536e3, s = {
8
+ avatars: "/ComradeCircle/Avatars",
9
+ posts: "/ComradeCircle/Posts"
10
+ }, c = r`
11
+ mutation ComEnsureFolder($path: String!) {
12
+ ensureFolderByPath(path: $path) {
13
+ id
14
+ }
15
+ }
16
+ `, l = r`
17
+ query ComGetFileDownloadUrl($id: ID!, $expiresIn: Int) {
18
+ getFileDownloadUrl(id: $id, expiresIn: $expiresIn)
19
+ }
20
+ `;
21
+ async function u(e, t) {
22
+ let r = n(), i = (await r.mutate({
23
+ mutation: c,
24
+ variables: { path: t }
25
+ })).data?.ensureFolderByPath?.id;
26
+ if (!i) throw Error("Could not resolve the upload folder.");
27
+ let s = await a({
28
+ client: r,
29
+ blob: e,
30
+ filename: e.name,
31
+ mimeType: e.type || "application/octet-stream",
32
+ folderId: i
33
+ }), u = (await r.query({
34
+ query: l,
35
+ variables: {
36
+ id: s.id,
37
+ expiresIn: o
38
+ },
39
+ fetchPolicy: "no-cache"
40
+ })).data?.getFileDownloadUrl;
41
+ if (!u) throw Error("The file was uploaded but no download URL was returned.");
42
+ return {
43
+ id: s.id,
44
+ url: u,
45
+ name: s.name
46
+ };
47
+ }
48
+ function d(n) {
49
+ let { apiGatewayUrl: r } = e();
50
+ return t({
51
+ queryKey: [
52
+ "comradecircle",
53
+ "file-url",
54
+ n ?? ""
55
+ ],
56
+ enabled: !!n,
57
+ staleTime: 1800 * 1e3,
58
+ retry: 1,
59
+ queryFn: async () => {
60
+ let e = await i({
61
+ gateway: "workspace",
62
+ baseUrl: r,
63
+ workspaceToken: !0,
64
+ query: "query ComFileUrl($id: ID!, $expiresIn: Int) { getFileDownloadUrl(id: $id, expiresIn: $expiresIn) }",
65
+ variables: {
66
+ id: n,
67
+ expiresIn: o
68
+ }
69
+ });
70
+ if (e.errors?.length) throw Error(e.errors[0]?.message ?? "Could not resolve file URL");
71
+ return e.data?.getFileDownloadUrl ?? null;
72
+ }
73
+ });
74
+ }
75
+ //#endregion
76
+ export { s as FILE_FOLDERS, u as uploadImageToFiles, d as useFileUrl };
77
+
78
+ //# sourceMappingURL=useFiles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFiles.js","names":[],"sources":["../../../src/comradecircle/hooks/useFiles.ts"],"sourcesContent":["/**\n * File hooks — attachments & avatars via wspace-files-svc (NO duplication).\n * @module comradecircle/hooks\n *\n * ComradeCircle never stores blobs. Posts keep `attachmentFileIds` and circles /\n * profiles keep `avatarFileId` — all pointing at files owned by wspace-files-svc.\n * Upload goes through the shared `uploadBlobToFiles` storage helper (presigned\n * 3-step upload) against the workspace Apollo client the shell initialises;\n * display resolves a file id to a presigned URL via `getFileDownloadUrl`.\n */\n\nimport { useQuery } from '@tanstack/react-query';\nimport { graphqlFetch, getWorkspaceClient, gql } from '@burdenoff/fe-libs/shared/graphql';\nimport { uploadBlobToFiles } from '@burdenoff/fe-libs/storage';\n\nimport { useComradeCircle } from '../context';\n\n/** One year — avatars/attachments are long-lived references, not ephemeral links. */\nconst DOWNLOAD_URL_TTL_SECONDS = 31_536_000;\n\nexport const FILE_FOLDERS = {\n avatars: '/ComradeCircle/Avatars',\n posts: '/ComradeCircle/Posts',\n} as const;\n\nconst ENSURE_FOLDER = gql`\n mutation ComEnsureFolder($path: String!) {\n ensureFolderByPath(path: $path) {\n id\n }\n }\n`;\n\nconst GET_FILE_DOWNLOAD_URL = gql`\n query ComGetFileDownloadUrl($id: ID!, $expiresIn: Int) {\n getFileDownloadUrl(id: $id, expiresIn: $expiresIn)\n }\n`;\n\nexport interface UploadedImage {\n id: string;\n url: string;\n name: string;\n}\n\ninterface EnsureFolderData {\n ensureFolderByPath?: { id: string } | null;\n}\ninterface DownloadUrlData {\n getFileDownloadUrl?: string | null;\n}\n\n/**\n * Upload an image to wspace-files-svc and return its id + a presigned URL.\n * The caller persists the id (attachmentFileIds / avatarFileId) via the entity's\n * own comradecircle mutation; the URL is used for an immediate preview.\n */\nexport async function uploadImageToFiles(file: File, folderPath: string): Promise<UploadedImage> {\n const client = getWorkspaceClient();\n\n const folderResult = await client.mutate<EnsureFolderData>({\n mutation: ENSURE_FOLDER,\n variables: { path: folderPath },\n });\n const folderId = folderResult.data?.ensureFolderByPath?.id;\n if (!folderId) {\n throw new Error('Could not resolve the upload folder.');\n }\n\n const uploaded = await uploadBlobToFiles({\n client,\n blob: file,\n filename: file.name,\n mimeType: file.type || 'application/octet-stream',\n folderId,\n });\n\n const urlResult = await client.query<DownloadUrlData>({\n query: GET_FILE_DOWNLOAD_URL,\n variables: { id: uploaded.id, expiresIn: DOWNLOAD_URL_TTL_SECONDS },\n fetchPolicy: 'no-cache',\n });\n const url = urlResult.data?.getFileDownloadUrl;\n if (!url) {\n throw new Error('The file was uploaded but no download URL was returned.');\n }\n\n return { id: uploaded.id, url, name: uploaded.name };\n}\n\n/** Resolve a wspace-files-svc file id to a presigned download URL for display. */\nexport function useFileUrl(fileId?: string | null) {\n const { apiGatewayUrl } = useComradeCircle();\n return useQuery({\n queryKey: ['comradecircle', 'file-url', fileId ?? ''],\n enabled: Boolean(fileId),\n staleTime: 30 * 60 * 1000,\n retry: 1,\n queryFn: async () => {\n const response = await graphqlFetch<{ getFileDownloadUrl: string | null }>({\n gateway: 'workspace',\n baseUrl: apiGatewayUrl,\n workspaceToken: true,\n query: `query ComFileUrl($id: ID!, $expiresIn: Int) { getFileDownloadUrl(id: $id, expiresIn: $expiresIn) }`,\n variables: { id: fileId, expiresIn: DOWNLOAD_URL_TTL_SECONDS },\n });\n if (response.errors?.length) {\n throw new Error(response.errors[0]?.message ?? 'Could not resolve file URL');\n }\n return response.data?.getFileDownloadUrl ?? null;\n },\n });\n}\n"],"mappings":";;;;;;AAkBA,IAAM,IAA2B,SAEpB,IAAe;CAC1B,SAAS;CACT,OAAO;CACR,EAEK,IAAgB,CAAG;;;;;;GAQnB,IAAwB,CAAG;;;;;AAwBjC,eAAsB,EAAmB,GAAY,GAA4C;CAC/F,IAAM,IAAS,GAAoB,EAM7B,KAJe,MAAM,EAAO,OAAyB;EACzD,UAAU;EACV,WAAW,EAAE,MAAM,GAAY;EAChC,CAAC,EAC4B,MAAM,oBAAoB;AACxD,KAAI,CAAC,EACH,OAAU,MAAM,uCAAuC;CAGzD,IAAM,IAAW,MAAM,EAAkB;EACvC;EACA,MAAM;EACN,UAAU,EAAK;EACf,UAAU,EAAK,QAAQ;EACvB;EACD,CAAC,EAOI,KALY,MAAM,EAAO,MAAuB;EACpD,OAAO;EACP,WAAW;GAAE,IAAI,EAAS;GAAI,WAAW;GAA0B;EACnE,aAAa;EACd,CAAC,EACoB,MAAM;AAC5B,KAAI,CAAC,EACH,OAAU,MAAM,0DAA0D;AAG5E,QAAO;EAAE,IAAI,EAAS;EAAI;EAAK,MAAM,EAAS;EAAM;;AAItD,SAAgB,EAAW,GAAwB;CACjD,IAAM,EAAE,qBAAkB,GAAkB;AAC5C,QAAO,EAAS;EACd,UAAU;GAAC;GAAiB;GAAY,KAAU;GAAG;EACrD,SAAS,EAAQ;EACjB,WAAW,OAAU;EACrB,OAAO;EACP,SAAS,YAAY;GACnB,IAAM,IAAW,MAAM,EAAoD;IACzE,SAAS;IACT,SAAS;IACT,gBAAgB;IAChB,OAAO;IACP,WAAW;KAAE,IAAI;KAAQ,WAAW;KAA0B;IAC/D,CAAC;AACF,OAAI,EAAS,QAAQ,OACnB,OAAU,MAAM,EAAS,OAAO,IAAI,WAAW,6BAA6B;AAE9E,UAAO,EAAS,MAAM,sBAAsB;;EAE/C,CAAC"}
@@ -0,0 +1,9 @@
1
+ //#region src/comradecircle/lib/graphql-cache.ts
2
+ function e() {
3
+ let e = globalThis;
4
+ e.__graphqlFetchResponseCache?.clear(), e.__graphqlFetchPendingResponses?.clear();
5
+ }
6
+ //#endregion
7
+ export { e as clearGraphqlResponseCache };
8
+
9
+ //# sourceMappingURL=graphql-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graphql-cache.js","names":[],"sources":["../../../src/comradecircle/lib/graphql-cache.ts"],"sourcesContent":["/**\n * graphql-cache — invalidate fe-libs' imperative-fetch response cache after writes.\n * @module comradecircle/lib\n *\n * `graphqlFetch` (from `@burdenoff/fe-libs/shared/graphql`) coalesces reads by\n * caching every RESOLVED `query` response for ~15s (keyed by operationName +\n * variables) and de-duping in-flight requests. A refetch issued right after a\n * mutation — which is exactly what our React-Query `invalidateQueries` triggers\n * — otherwise gets served the PRE-mutation response, so created/updated/deleted\n * rows stay invisible until a full page reload.\n *\n * fe-libs' own Apollo client fixes this by calling `clearGraphqlFetchResponseCache()`\n * on every mutation, but that helper is not re-exported from the package's public\n * entry, and we use the raw `graphqlFetch` transport (no Apollo client). The two\n * caches are plain `Map`s that fe-libs stores directly on `globalThis`\n * (`getGraphqlFetchGlobalState()` returns `globalThis`), so we clear the same two\n * globals here — mirroring `clearGraphqlFetchResponseCache` — to force every\n * post-write read back onto the network.\n */\n\ninterface GraphqlFetchGlobals {\n __graphqlFetchResponseCache?: { clear: () => void };\n __graphqlFetchPendingResponses?: { clear: () => void };\n}\n\n/**\n * Clear fe-libs' resolved-response cache and in-flight de-dupe map so the next\n * read of any query hits the gateway. Safe to call unconditionally; a no-op\n * before the caches have been created.\n */\nexport function clearGraphqlResponseCache(): void {\n const g = globalThis as unknown as GraphqlFetchGlobals;\n g.__graphqlFetchResponseCache?.clear();\n g.__graphqlFetchPendingResponses?.clear();\n}\n"],"mappings":";AA8BA,SAAgB,IAAkC;CAChD,IAAM,IAAI;AAEV,CADA,EAAE,6BAA6B,OAAO,EACtC,EAAE,gCAAgC,OAAO"}
@@ -6,60 +6,106 @@ import { useCursorPager as r } from "../hooks/useCursorPager.js";
6
6
  import "../hooks/index.js";
7
7
  import { PostCard as i } from "../components/PostCard.js";
8
8
  import { EmptyState as a } from "../components/EmptyState.js";
9
- import { ErrorView as o, LoadingView as s } from "../components/StateViews.js";
10
- import { Pagination as c } from "../components/Pagination.js";
11
- import { Compass as l, Newspaper as u, UsersRound as d } from "lucide-react";
12
- import { jsx as f, jsxs as p } from "react/jsx-runtime";
13
- import { Button as m } from "@burdenoff/fe-libs/ui";
9
+ import { ErrorView as o } from "../components/StateViews.js";
10
+ import { Pagination as s } from "../components/Pagination.js";
11
+ import { Compass as c, Newspaper as l, UsersRound as u } from "lucide-react";
12
+ import { jsx as d, jsxs as f } from "react/jsx-runtime";
13
+ import { Button as p, GlassCard as m, Skeleton as h } from "@burdenoff/fe-libs/ui";
14
14
  //#region src/comradecircle/pages/FeedPage.tsx
15
- var h = 20;
16
- function g() {
17
- let { navigateTo: g } = e(), _ = r(), { data: v, isLoading: y, isError: b, refetch: x } = n({
18
- limit: h,
19
- cursor: _.cursor
20
- }), S = v?.items ?? [];
21
- return /* @__PURE__ */ f(t, {
15
+ var g = 20, _ = "motion-safe:animate-in motion-safe:fade-in motion-safe:slide-in-from-bottom-3 motion-safe:duration-500 motion-safe:ease-out motion-safe:fill-mode-both", v = [
16
+ ["w-11/12", "w-3/4"],
17
+ [
18
+ "w-full",
19
+ "w-10/12",
20
+ "w-2/3"
21
+ ],
22
+ ["w-5/6", "w-1/2"]
23
+ ];
24
+ function y() {
25
+ return /* @__PURE__ */ d("div", {
26
+ className: "mx-auto flex max-w-2xl flex-col gap-4",
27
+ "aria-hidden": "true",
28
+ children: v.map((e, t) => /* @__PURE__ */ f(m, {
29
+ treatment: "plain",
30
+ className: "p-4",
31
+ children: [
32
+ /* @__PURE__ */ f("div", {
33
+ className: "flex items-start gap-3",
34
+ children: [/* @__PURE__ */ d(h, { className: "h-10 w-10 shrink-0 rounded-full" }), /* @__PURE__ */ f("div", {
35
+ className: "flex-1 space-y-2 pt-1",
36
+ children: [/* @__PURE__ */ d(h, { className: "h-3.5 w-32" }), /* @__PURE__ */ d(h, { className: "h-3 w-20" })]
37
+ })]
38
+ }),
39
+ /* @__PURE__ */ d("div", {
40
+ className: "mt-4 space-y-2.5",
41
+ children: e.map((e, t) => /* @__PURE__ */ d(h, { className: `h-3 ${e}` }, t))
42
+ }),
43
+ /* @__PURE__ */ f("div", {
44
+ className: "mt-4 flex items-center justify-between gap-3 border-t border-border-seam pt-3",
45
+ children: [/* @__PURE__ */ f("div", {
46
+ className: "flex items-center gap-2",
47
+ children: [
48
+ /* @__PURE__ */ d(h, { className: "h-7 w-14 rounded-full" }),
49
+ /* @__PURE__ */ d(h, { className: "h-7 w-14 rounded-full" }),
50
+ /* @__PURE__ */ d(h, { className: "h-7 w-14 rounded-full" })
51
+ ]
52
+ }), /* @__PURE__ */ d(h, { className: "h-7 w-24 rounded-full" })]
53
+ })
54
+ ]
55
+ }, t))
56
+ });
57
+ }
58
+ function b() {
59
+ let { navigateTo: m } = e(), h = r(), { data: v, isLoading: b, isError: x, refetch: S } = n({
60
+ limit: g,
61
+ cursor: h.cursor
62
+ }), C = v?.items ?? [];
63
+ return /* @__PURE__ */ d(t, {
22
64
  title: "Home",
23
65
  titleGradient: !0,
24
66
  aurora: !0,
25
67
  description: "Posts from the circles, channels, and members you follow — newest first.",
26
- actions: /* @__PURE__ */ p(m, {
68
+ actions: /* @__PURE__ */ f(p, {
27
69
  variant: "outline",
28
- onClick: () => g("circles"),
29
- children: [/* @__PURE__ */ f(l, { className: "mr-1.5 h-4 w-4" }), " Discover circles"]
70
+ onClick: () => m("circles"),
71
+ children: [/* @__PURE__ */ d(c, { className: "mr-1.5 h-4 w-4" }), " Discover circles"]
30
72
  }),
31
- children: y ? /* @__PURE__ */ f(s, { label: "Loading your feed…" }) : b ? /* @__PURE__ */ f(o, {
73
+ children: b ? /* @__PURE__ */ d(y, {}) : x ? /* @__PURE__ */ d(o, {
32
74
  message: "We couldn't load your feed.",
33
- onRetry: () => x()
34
- }) : S.length === 0 && _.page === 0 ? /* @__PURE__ */ f(a, {
75
+ onRetry: () => S()
76
+ }) : C.length === 0 && h.page === 0 ? /* @__PURE__ */ d(a, {
35
77
  illustration: "empty-notifications",
36
- icon: /* @__PURE__ */ f(u, { className: "h-10 w-10" }),
78
+ icon: /* @__PURE__ */ d(l, { className: "h-10 w-10" }),
37
79
  title: "Your feed is quiet",
38
80
  description: "Follow circles and members to fill your home feed with their latest posts, events, and discussions.",
39
- action: /* @__PURE__ */ p("div", {
81
+ action: /* @__PURE__ */ f("div", {
40
82
  className: "flex flex-wrap items-center justify-center gap-3",
41
- children: [/* @__PURE__ */ p(m, {
42
- onClick: () => g("circles"),
43
- children: [/* @__PURE__ */ f(l, { className: "mr-1.5 h-4 w-4" }), " Explore circles"]
44
- }), /* @__PURE__ */ p(m, {
83
+ children: [/* @__PURE__ */ f(p, {
84
+ onClick: () => m("circles"),
85
+ children: [/* @__PURE__ */ d(c, { className: "mr-1.5 h-4 w-4" }), " Explore circles"]
86
+ }), /* @__PURE__ */ f(p, {
45
87
  variant: "outline",
46
- onClick: () => g("members"),
47
- children: [/* @__PURE__ */ f(d, { className: "mr-1.5 h-4 w-4" }), " Find members"]
88
+ onClick: () => m("members"),
89
+ children: [/* @__PURE__ */ d(u, { className: "mr-1.5 h-4 w-4" }), " Find members"]
48
90
  })]
49
91
  })
50
- }) : /* @__PURE__ */ p("div", {
92
+ }) : /* @__PURE__ */ f("div", {
51
93
  className: "mx-auto flex max-w-2xl flex-col gap-4",
52
- children: [S.map((e) => /* @__PURE__ */ f(i, { post: e }, e.id)), /* @__PURE__ */ f(c, {
53
- page: _.page,
54
- pageSize: h,
55
- itemCount: S.length,
94
+ children: [C.map((e, t) => /* @__PURE__ */ d("div", {
95
+ className: _,
96
+ style: { animationDelay: `${Math.min(t, 8) * 70}ms` },
97
+ children: /* @__PURE__ */ d(i, { post: e })
98
+ }, e.id)), /* @__PURE__ */ d(s, {
99
+ page: h.page,
100
+ pageSize: g,
101
+ itemCount: C.length,
56
102
  hasMore: v?.pageInfo.hasMore ?? !1,
57
- onPageChange: (e) => _.onPageChange(e, v?.pageInfo.cursor)
103
+ onPageChange: (e) => h.onPageChange(e, v?.pageInfo.cursor)
58
104
  })]
59
105
  })
60
106
  });
61
107
  }
62
108
  //#endregion
63
- export { g as FeedPage };
109
+ export { b as FeedPage };
64
110
 
65
111
  //# sourceMappingURL=FeedPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"FeedPage.js","names":[],"sources":["../../../src/comradecircle/pages/FeedPage.tsx"],"sourcesContent":["/**\n * FeedPage — the member's unified home feed.\n * @module comradecircle/pages\n *\n * Reads `comMyFeed` (published posts from every channel, member, and circle the\n * caller follows, newest first). A new member with no follows sees a guided\n * empty state pointing at circle & member discovery.\n */\n\nimport { Newspaper, Compass, UsersRound } from 'lucide-react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { PostCard } from '../components/PostCard';\nimport { EmptyState } from '../components/EmptyState';\nimport { LoadingView, ErrorView } from '../components/StateViews';\nimport { Pagination } from '../components/Pagination';\nimport { useComMyFeed, useCursorPager } from '../hooks';\nimport { useComradeCircle } from '../context';\n\nconst PAGE_SIZE = 20;\n\nexport function FeedPage() {\n const { navigateTo } = useComradeCircle();\n const pager = useCursorPager();\n const { data, isLoading, isError, refetch } = useComMyFeed({\n limit: PAGE_SIZE,\n cursor: pager.cursor,\n });\n\n const posts = data?.items ?? [];\n\n return (\n <PageLayout\n title=\"Home\"\n titleGradient\n aurora\n description=\"Posts from the circles, channels, and members you follow — newest first.\"\n actions={\n <Button variant=\"outline\" onClick={() => navigateTo('circles')}>\n <Compass className=\"mr-1.5 h-4 w-4\" /> Discover circles\n </Button>\n }\n >\n {isLoading ? (\n <LoadingView label=\"Loading your feed…\" />\n ) : isError ? (\n <ErrorView message=\"We couldn't load your feed.\" onRetry={() => refetch()} />\n ) : posts.length === 0 && pager.page === 0 ? (\n <EmptyState\n illustration=\"empty-notifications\"\n icon={<Newspaper className=\"h-10 w-10\" />}\n title=\"Your feed is quiet\"\n description=\"Follow circles and members to fill your home feed with their latest posts, events, and discussions.\"\n action={\n <div className=\"flex flex-wrap items-center justify-center gap-3\">\n <Button onClick={() => navigateTo('circles')}>\n <Compass className=\"mr-1.5 h-4 w-4\" /> Explore circles\n </Button>\n <Button variant=\"outline\" onClick={() => navigateTo('members')}>\n <UsersRound className=\"mr-1.5 h-4 w-4\" /> Find members\n </Button>\n </div>\n }\n />\n ) : (\n <div className=\"mx-auto flex max-w-2xl flex-col gap-4\">\n {posts.map((post) => (\n <PostCard key={post.id} post={post} />\n ))}\n <Pagination\n page={pager.page}\n pageSize={PAGE_SIZE}\n itemCount={posts.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":";;;;;;;;;;;;;;AAmBA,IAAM,IAAY;AAElB,SAAgB,IAAW;CACzB,IAAM,EAAE,kBAAe,GAAkB,EACnC,IAAQ,GAAgB,EACxB,EAAE,SAAM,cAAW,YAAS,eAAY,EAAa;EACzD,OAAO;EACP,QAAQ,EAAM;EACf,CAAC,EAEI,IAAQ,GAAM,SAAS,EAAE;AAE/B,QACE,kBAAC,GAAD;EACE,OAAM;EACN,eAAA;EACA,QAAA;EACA,aAAY;EACZ,SACE,kBAAC,GAAD;GAAQ,SAAQ;GAAU,eAAe,EAAW,UAAU;aAA9D,CACE,kBAAC,GAAD,EAAS,WAAU,kBAAmB,CAAA,EAAA,oBAC/B;;YAGV,IACC,kBAAC,GAAD,EAAa,OAAM,sBAAuB,CAAA,GACxC,IACF,kBAAC,GAAD;GAAW,SAAQ;GAA8B,eAAe,GAAS;GAAI,CAAA,GAC3E,EAAM,WAAW,KAAK,EAAM,SAAS,IACvC,kBAAC,GAAD;GACE,cAAa;GACb,MAAM,kBAAC,GAAD,EAAW,WAAU,aAAc,CAAA;GACzC,OAAM;GACN,aAAY;GACZ,QACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KAAQ,eAAe,EAAW,UAAU;eAA5C,CACE,kBAAC,GAAD,EAAS,WAAU,kBAAmB,CAAA,EAAA,mBAC/B;QACT,kBAAC,GAAD;KAAQ,SAAQ;KAAU,eAAe,EAAW,UAAU;eAA9D,CACE,kBAAC,GAAD,EAAY,WAAU,kBAAmB,CAAA,EAAA,gBAClC;OACL;;GAER,CAAA,GAEF,kBAAC,OAAD;GAAK,WAAU;aAAf,CACG,EAAM,KAAK,MACV,kBAAC,GAAD,EAA8B,SAAQ,EAAvB,EAAK,GAAkB,CACtC,EACF,kBAAC,GAAD;IACE,MAAM,EAAM;IACZ,UAAU;IACV,WAAW,EAAM;IACjB,SAAS,GAAM,SAAS,WAAW;IACnC,eAAe,MAAW,EAAM,aAAa,GAAQ,GAAM,SAAS,OAAO;IAC3E,CAAA,CACE;;EAEG,CAAA"}
1
+ {"version":3,"file":"FeedPage.js","names":[],"sources":["../../../src/comradecircle/pages/FeedPage.tsx"],"sourcesContent":["/**\n * FeedPage — the member's unified home feed.\n * @module comradecircle/pages\n *\n * Reads `comMyFeed` (published posts from every channel, member, and circle the\n * caller follows, newest first). A new member with no follows sees a guided\n * empty state pointing at circle & member discovery.\n */\n\nimport { Newspaper, Compass, UsersRound } from 'lucide-react';\nimport { Button, GlassCard, Skeleton } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { PostCard } from '../components/PostCard';\nimport { EmptyState } from '../components/EmptyState';\nimport { ErrorView } from '../components/StateViews';\nimport { Pagination } from '../components/Pagination';\nimport { useComMyFeed, useCursorPager } from '../hooks';\nimport { useComradeCircle } from '../context';\n\nconst PAGE_SIZE = 20;\n\n/**\n * Motion for each post as the feed 'assembles' on arrival. Fully neutralised\n * under `prefers-reduced-motion` (every class is `motion-safe:`); `fill-mode-both`\n * holds the hidden start state through the per-card `animationDelay`.\n */\nconst POST_ENTER =\n 'motion-safe:animate-in motion-safe:fade-in motion-safe:slide-in-from-bottom-3 ' +\n 'motion-safe:duration-500 motion-safe:ease-out motion-safe:fill-mode-both';\n\n/** Widths that give each skeleton post a natural, non-uniform body. */\nconst SKELETON_LINES = [\n ['w-11/12', 'w-3/4'],\n ['w-full', 'w-10/12', 'w-2/3'],\n ['w-5/6', 'w-1/2'],\n] as const;\n\n/**\n * A stack of post-card-shaped skeletons that mirrors the final feed layout, so\n * the transition from loading → loaded doesn't shift the column.\n */\nfunction FeedSkeleton() {\n return (\n <div className=\"mx-auto flex max-w-2xl flex-col gap-4\" aria-hidden=\"true\">\n {SKELETON_LINES.map((lines, i) => (\n <GlassCard key={i} treatment=\"plain\" className=\"p-4\">\n <div className=\"flex items-start gap-3\">\n <Skeleton className=\"h-10 w-10 shrink-0 rounded-full\" />\n <div className=\"flex-1 space-y-2 pt-1\">\n <Skeleton className=\"h-3.5 w-32\" />\n <Skeleton className=\"h-3 w-20\" />\n </div>\n </div>\n <div className=\"mt-4 space-y-2.5\">\n {lines.map((w, j) => (\n <Skeleton key={j} className={`h-3 ${w}`} />\n ))}\n </div>\n <div className=\"mt-4 flex items-center justify-between gap-3 border-t border-border-seam pt-3\">\n <div className=\"flex items-center gap-2\">\n <Skeleton className=\"h-7 w-14 rounded-full\" />\n <Skeleton className=\"h-7 w-14 rounded-full\" />\n <Skeleton className=\"h-7 w-14 rounded-full\" />\n </div>\n <Skeleton className=\"h-7 w-24 rounded-full\" />\n </div>\n </GlassCard>\n ))}\n </div>\n );\n}\n\nexport function FeedPage() {\n const { navigateTo } = useComradeCircle();\n const pager = useCursorPager();\n const { data, isLoading, isError, refetch } = useComMyFeed({\n limit: PAGE_SIZE,\n cursor: pager.cursor,\n });\n\n const posts = data?.items ?? [];\n\n return (\n <PageLayout\n title=\"Home\"\n titleGradient\n aurora\n description=\"Posts from the circles, channels, and members you follow — newest first.\"\n actions={\n <Button variant=\"outline\" onClick={() => navigateTo('circles')}>\n <Compass className=\"mr-1.5 h-4 w-4\" /> Discover circles\n </Button>\n }\n >\n {isLoading ? (\n <FeedSkeleton />\n ) : isError ? (\n <ErrorView message=\"We couldn't load your feed.\" onRetry={() => refetch()} />\n ) : posts.length === 0 && pager.page === 0 ? (\n <EmptyState\n illustration=\"empty-notifications\"\n icon={<Newspaper className=\"h-10 w-10\" />}\n title=\"Your feed is quiet\"\n description=\"Follow circles and members to fill your home feed with their latest posts, events, and discussions.\"\n action={\n <div className=\"flex flex-wrap items-center justify-center gap-3\">\n <Button onClick={() => navigateTo('circles')}>\n <Compass className=\"mr-1.5 h-4 w-4\" /> Explore circles\n </Button>\n <Button variant=\"outline\" onClick={() => navigateTo('members')}>\n <UsersRound className=\"mr-1.5 h-4 w-4\" /> Find members\n </Button>\n </div>\n }\n />\n ) : (\n <div className=\"mx-auto flex max-w-2xl flex-col gap-4\">\n {posts.map((post, index) => (\n <div\n key={post.id}\n className={POST_ENTER}\n style={{ animationDelay: `${Math.min(index, 8) * 70}ms` }}\n >\n <PostCard post={post} />\n </div>\n ))}\n <Pagination\n page={pager.page}\n pageSize={PAGE_SIZE}\n itemCount={posts.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":";;;;;;;;;;;;;;AAmBA,IAAM,IAAY,IAOZ,IACJ,0JAII,IAAiB;CACrB,CAAC,WAAW,QAAQ;CACpB;EAAC;EAAU;EAAW;EAAQ;CAC9B,CAAC,SAAS,QAAQ;CACnB;AAMD,SAAS,IAAe;AACtB,QACE,kBAAC,OAAD;EAAK,WAAU;EAAwC,eAAY;YAChE,EAAe,KAAK,GAAO,MAC1B,kBAAC,GAAD;GAAmB,WAAU;GAAQ,WAAU;aAA/C;IACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAU,WAAU,mCAAoC,CAAA,EACxD,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD,EAAU,WAAU,cAAe,CAAA,EACnC,kBAAC,GAAD,EAAU,WAAU,YAAa,CAAA,CAC7B;QACF;;IACN,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAM,KAAK,GAAG,MACb,kBAAC,GAAD,EAAkB,WAAW,OAAO,KAAO,EAA5B,EAA4B,CAC3C;KACE,CAAA;IACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,GAAD,EAAU,WAAU,yBAA0B,CAAA;OAC9C,kBAAC,GAAD,EAAU,WAAU,yBAA0B,CAAA;OAC9C,kBAAC,GAAD,EAAU,WAAU,yBAA0B,CAAA;OAC1C;SACN,kBAAC,GAAD,EAAU,WAAU,yBAA0B,CAAA,CAC1C;;IACI;KArBI,EAqBJ,CACZ;EACE,CAAA;;AAIV,SAAgB,IAAW;CACzB,IAAM,EAAE,kBAAe,GAAkB,EACnC,IAAQ,GAAgB,EACxB,EAAE,SAAM,cAAW,YAAS,eAAY,EAAa;EACzD,OAAO;EACP,QAAQ,EAAM;EACf,CAAC,EAEI,IAAQ,GAAM,SAAS,EAAE;AAE/B,QACE,kBAAC,GAAD;EACE,OAAM;EACN,eAAA;EACA,QAAA;EACA,aAAY;EACZ,SACE,kBAAC,GAAD;GAAQ,SAAQ;GAAU,eAAe,EAAW,UAAU;aAA9D,CACE,kBAAC,GAAD,EAAS,WAAU,kBAAmB,CAAA,EAAA,oBAC/B;;YAGV,IACC,kBAAC,GAAD,EAAgB,CAAA,GACd,IACF,kBAAC,GAAD;GAAW,SAAQ;GAA8B,eAAe,GAAS;GAAI,CAAA,GAC3E,EAAM,WAAW,KAAK,EAAM,SAAS,IACvC,kBAAC,GAAD;GACE,cAAa;GACb,MAAM,kBAAC,GAAD,EAAW,WAAU,aAAc,CAAA;GACzC,OAAM;GACN,aAAY;GACZ,QACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KAAQ,eAAe,EAAW,UAAU;eAA5C,CACE,kBAAC,GAAD,EAAS,WAAU,kBAAmB,CAAA,EAAA,mBAC/B;QACT,kBAAC,GAAD;KAAQ,SAAQ;KAAU,eAAe,EAAW,UAAU;eAA9D,CACE,kBAAC,GAAD,EAAY,WAAU,kBAAmB,CAAA,EAAA,gBAClC;OACL;;GAER,CAAA,GAEF,kBAAC,OAAD;GAAK,WAAU;aAAf,CACG,EAAM,KAAK,GAAM,MAChB,kBAAC,OAAD;IAEE,WAAW;IACX,OAAO,EAAE,gBAAgB,GAAG,KAAK,IAAI,GAAO,EAAE,GAAG,GAAG,KAAK;cAEzD,kBAAC,GAAD,EAAgB,SAAQ,CAAA;IACpB,EALC,EAAK,GAKN,CACN,EACF,kBAAC,GAAD;IACE,MAAM,EAAM;IACZ,UAAU;IACV,WAAW,EAAM;IACjB,SAAS,GAAM,SAAS,WAAW;IACnC,eAAe,MAAW,EAAM,aAAa,GAAQ,GAAM,SAAS,OAAO;IAC3E,CAAA,CACE;;EAEG,CAAA"}