diff --git a/packages/feeds-client/__integration-tests__/docs-snippets/activities.test.ts b/packages/feeds-client/__integration-tests__/docs-snippets/activities.test.ts index 5465dad4..c79ec12b 100644 --- a/packages/feeds-client/__integration-tests__/docs-snippets/activities.test.ts +++ b/packages/feeds-client/__integration-tests__/docs-snippets/activities.test.ts @@ -68,6 +68,14 @@ describe('Activities page', () => { console.log(response.activity?.parent); }); + it(`restrict replies`, async () => { + await feed.addActivity({ + type: 'post', + text: 'apple stock will go up', + restrict_replies: 'people_i_follow', // Options: "everyone", "people_i_follow", "nobody" + }); + }); + it('restricted visibility', async () => { const response = await feed.addActivity({ type: 'post', diff --git a/packages/feeds-client/__integration-tests__/docs-snippets/comments.test.ts b/packages/feeds-client/__integration-tests__/docs-snippets/comments.test.ts index 736a1536..4ab65745 100644 --- a/packages/feeds-client/__integration-tests__/docs-snippets/comments.test.ts +++ b/packages/feeds-client/__integration-tests__/docs-snippets/comments.test.ts @@ -156,6 +156,21 @@ describe('Comments page', () => { }); }); + it(`Show/hide comment input`, async () => { + // Lists follow relationships where + // - target feed is owned by current user + // - source feed is owned by activity author + const currentFeed = client.feed( + activity.current_feed?.group_id!, + activity.current_feed?.id!, + ); + console.log(currentFeed.currentState.own_followings); + + await feed.getOrCreate({ + enrichment_options: { enrich_own_followings: true }, + }); + }); + it('Deleting comments', async () => { await client.deleteComment({ id: comment.id, diff --git a/packages/feeds-client/src/activity-with-state-updates/activity-with-state-updates.ts b/packages/feeds-client/src/activity-with-state-updates/activity-with-state-updates.ts index 26e2065d..a929ae30 100644 --- a/packages/feeds-client/src/activity-with-state-updates/activity-with-state-updates.ts +++ b/packages/feeds-client/src/activity-with-state-updates/activity-with-state-updates.ts @@ -1,5 +1,5 @@ import { StateStore } from '@stream-io/state-store'; -import type { Feed, FeedState } from '../feed'; +import { addActivitiesToState, type Feed, type FeedState } from '../feed'; import type { FeedsClient } from '../feeds-client'; import type { ActivityResponse } from '../gen/models'; import { @@ -164,8 +164,13 @@ export class ActivityWithStateUpdates { }) { this.feed = connectActivityToFeed.call(this.feedsClient, { fid }); + const { activities } = addActivitiesToState.bind(this.feed)( + [initialState], + [], + 'start', + ); this.feed?.state.partialNext({ - activities: [initialState], + activities, }); } diff --git a/packages/feeds-client/src/bindings/react/hooks/feed-state-hooks/index.ts b/packages/feeds-client/src/bindings/react/hooks/feed-state-hooks/index.ts index 5ce3c1aa..1fe63ef5 100644 --- a/packages/feeds-client/src/bindings/react/hooks/feed-state-hooks/index.ts +++ b/packages/feeds-client/src/bindings/react/hooks/feed-state-hooks/index.ts @@ -10,3 +10,4 @@ export * from './useAggregatedActivities'; export * from './useIsAggregatedActivityRead'; export * from './useIsAggregatedActivitySeen'; export * from './useActivityComments'; +export * from './useOwnFollowings'; diff --git a/packages/feeds-client/src/bindings/react/hooks/feed-state-hooks/useOwnFollowings.ts b/packages/feeds-client/src/bindings/react/hooks/feed-state-hooks/useOwnFollowings.ts new file mode 100644 index 00000000..60a68f82 --- /dev/null +++ b/packages/feeds-client/src/bindings/react/hooks/feed-state-hooks/useOwnFollowings.ts @@ -0,0 +1,18 @@ +import { useStateStore } from '@stream-io/state-store/react-bindings'; + +import { useFeedContext } from '../../contexts/StreamFeedContext'; +import type { Feed, FeedState } from '../../../../feed'; + +/** + * A React hook that returns a reactive array of feeds that the feeds's owner is following and is owned by the current user. + */ +export const useOwnFollowings = (feedFromProps?: Feed) => { + const feedFromContext = useFeedContext(); + const feed = feedFromProps ?? feedFromContext; + + return useStateStore(feed?.state, selector); +}; + +const selector = ({ own_followings }: FeedState) => ({ + own_followings, +}); diff --git a/sample-apps/react-sample-app/app/activity/[id]/page.tsx b/sample-apps/react-sample-app/app/activity/[id]/page.tsx index 70b35664..90c79a8c 100644 --- a/sample-apps/react-sample-app/app/activity/[id]/page.tsx +++ b/sample-apps/react-sample-app/app/activity/[id]/page.tsx @@ -9,6 +9,7 @@ import type { } from '@stream-io/feeds-react-sdk'; import { FeedOwnCapability, + useClientConnectedUser, useFeedsClient, useOwnCapabilities, useStateStore, @@ -41,6 +42,7 @@ export default function ActivityPage() { function ActivityPageContent() { const params = useParams<{ id: string }>(); const client = useFeedsClient(); + const user = useClientConnectedUser(); const { logErrorAndDisplayNotification, logError } = useErrorContext(); const [editedActivityText, setEditedActivityText] = useState(''); const [isEditing, setIsEditing] = useState(false); @@ -66,7 +68,7 @@ function ActivityPageContent() { }, [client, params?.id]); useEffect(() => { - if (!activityWithStateUpdates) { + if (!activityWithStateUpdates || !user?.id) { return; } @@ -79,7 +81,11 @@ function ActivityPageContent() { const [group, id] = fid.split(':'); _feed = client?.feed(group, id); setFeed(_feed); - if (!_feed?.currentState.watch && !_feed?.currentState.is_loading) { + if ( + !(_feed?.id === user.id) && + !_feed?.currentState.watch && + !_feed?.currentState.is_loading + ) { shouldStopWatching = true; return _feed ?.getOrCreate({ @@ -103,6 +109,7 @@ function ActivityPageContent() { logError, activityWithStateUpdates, client, + user?.id, ]); const ownCapabilities = useOwnCapabilities(feed); diff --git a/sample-apps/react-sample-app/app/components/NewActivity.tsx b/sample-apps/react-sample-app/app/components/NewActivity.tsx index 8f52f9a6..4aed8074 100644 --- a/sample-apps/react-sample-app/app/components/NewActivity.tsx +++ b/sample-apps/react-sample-app/app/components/NewActivity.tsx @@ -6,7 +6,7 @@ import { useOwnCapabilities, } from '@stream-io/feeds-react-sdk'; import { useErrorContext } from '../error-context'; -import type { FormEvent} from 'react'; +import type { FormEvent } from 'react'; import { useMemo, useState } from 'react'; import { ActivityComposer } from './activity/ActivityComposer'; import { LoadingIndicator } from './LoadingIndicator'; @@ -18,6 +18,9 @@ export const NewActivity = () => { const [isSending, setIsSending] = useState(false); const [activityText, setActivityText] = useState(''); const [files, setFiles] = useState(null); + const [restrictReplies, setRestrictReplies] = useState< + 'everyone' | 'people_i_follow' | 'nobody' + >('everyone'); const ownCapabilities = useOwnCapabilities(); const canPost = useMemo( @@ -51,6 +54,7 @@ export const NewActivity = () => { await feed?.addActivity({ type: 'post', text: activityText, + restrict_replies: restrictReplies, attachments: fileResponses.map((response, index) => { const isImage = isImageFile(files![index]); return { @@ -90,6 +94,25 @@ export const NewActivity = () => { } }} /> +
+ + +
+ + + + )} + +
+
+ +