Skip to content

Commit ac53900

Browse files
committed
RTC: Add session activity notifications
Collaborators had no way to know when others joined, left, or saved the post. This adds snackbar notices for all four events, broadcast via a new `lastSaveEvent` field on the Yjs awareness state. Notification types can be toggled via the `editor.collaborationNotifications` WordPress filter.
1 parent 1470b56 commit ac53900

File tree

7 files changed

+953
-1
lines changed

7 files changed

+953
-1
lines changed

packages/core-data/src/awareness/post-editor-awareness.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ export class PostEditorAwareness extends BaseAwarenessState< PostEditorState > {
3636
protected equalityFieldChecks = {
3737
...baseEqualityFieldChecks,
3838
editorState: this.areEditorStatesEqual,
39+
lastSaveEvent: (
40+
a?: PostEditorState[ 'lastSaveEvent' ],
41+
b?: PostEditorState[ 'lastSaveEvent' ]
42+
) => a?.savedAt === b?.savedAt,
3943
};
4044

4145
public constructor(

packages/core-data/src/awareness/types.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,22 @@ export interface EditorState {
3333
selection: SelectionState;
3434
}
3535

36+
/**
37+
* Represents a save event broadcast via the awareness system.
38+
* `status` is the WordPress post status at the time of the save.
39+
*/
40+
export interface SaveEvent {
41+
savedAt: number;
42+
status: string;
43+
}
44+
3645
/**
3746
* The post editor state extends the base state with information used to render
3847
* presence indicators in the post editor.
3948
*/
4049
export interface PostEditorState extends BaseState {
4150
editorState?: EditorState;
51+
lastSaveEvent?: SaveEvent;
4252
}
4353

4454
/**

packages/core-data/src/hooks/use-post-editor-awareness-state.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* External dependencies
33
*/
4-
import { useEffect, useState } from '@wordpress/element';
4+
import { useCallback, useEffect, useState } from '@wordpress/element';
55

66
/**
77
* Internal dependencies
@@ -156,3 +156,36 @@ export function useIsDisconnected(
156156
return usePostEditorAwarenessState( postId, postType )
157157
.isCurrentCollaboratorDisconnected;
158158
}
159+
160+
/**
161+
* Hook that returns a callback to broadcast a save event to all collaborators
162+
* via the awareness system. When called, it sets the `lastSaveEvent` field on
163+
* the local awareness state so that other collaborators can display a notification.
164+
*
165+
* @param postId The ID of the post.
166+
* @param postType The type of the post.
167+
*/
168+
export function useBroadcastSaveEvent(
169+
postId: number | null,
170+
postType: string | null
171+
): ( status: string ) => void {
172+
return useCallback(
173+
( status: string ) => {
174+
if ( null === postId || null === postType ) {
175+
return;
176+
}
177+
178+
const awareness =
179+
getSyncManager()?.getAwareness< PostEditorAwareness >(
180+
`postType/${ postType }`,
181+
postId.toString()
182+
);
183+
184+
awareness?.setLocalStateField( 'lastSaveEvent', {
185+
savedAt: Date.now(),
186+
status,
187+
} );
188+
},
189+
[ postId, postType ]
190+
);
191+
}

packages/core-data/src/private-apis.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { RECEIVE_INTERMEDIATE_RESULTS } from './utils';
66
import {
77
useActiveCollaborators,
88
useResolvedSelection,
9+
useBroadcastSaveEvent,
910
} from './hooks/use-post-editor-awareness-state';
1011
import { lock } from './lock-unlock';
1112

@@ -15,4 +16,5 @@ lock( privateApis, {
1516
RECEIVE_INTERMEDIATE_RESULTS,
1617
useActiveCollaborators,
1718
useResolvedSelection,
19+
useBroadcastSaveEvent,
1820
} );

0 commit comments

Comments
 (0)