Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

### Changed

- Added a tag attribute for from object for typing indicator
- Bumped all dependencies to the latest versions, by [@compulim](https://github.com/compulim) in PR [#4195](https://github.com/microsoft/BotFramework-WebChat/pull/4195)
- Production dependencies
- [`@babel/runtime@7.17.2`](https://npmjs.com/package/@babel/runtime)
Expand Down
21 changes: 14 additions & 7 deletions __tests__/hooks/useActiveTyping.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ test('getter should represent bot and user typing respectively', async () => {
at: 0,
expireAt: 5000,
name: 'Happy Web Chat user',
role: 'user'
role: 'user',
tag: null
}
]);

Expand All @@ -51,7 +52,8 @@ test('getter should represent bot and user typing respectively', async () => {
at: 0,
expireAt: 5000,
name: 'bot',
role: 'bot'
role: 'bot',
tag: null
}
]);

Expand All @@ -64,13 +66,15 @@ test('getter should represent bot and user typing respectively', async () => {
at: 0,
expireAt: 5000,
name: 'bot',
role: 'bot'
role: 'bot',
tag: null
},
{
at: 0,
expireAt: 5000,
name: 'Happy Web Chat user',
role: 'user'
role: 'user',
tag: null
}
]);
});
Expand Down Expand Up @@ -102,7 +106,8 @@ test('getter should filter out inactive typing', async () => {
at: 0,
expireAt: 5000,
name: 'Happy Web Chat user',
role: 'user'
role: 'user',
tag: null
}
]);

Expand All @@ -121,7 +126,8 @@ test('getter should filter out inactive typing', async () => {
at: 3000,
expireAt: 8000,
name: 'Happy Web Chat user',
role: 'user'
role: 'user',
tag: null
}
]);

Expand All @@ -137,7 +143,8 @@ test('getter should filter out inactive typing', async () => {
at: 3000,
expireAt: 13000,
name: 'Happy Web Chat user',
role: 'user'
role: 'user',
tag: null
}
]);
});
Expand Down
4 changes: 3 additions & 1 deletion docs/HOOKS.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,13 +137,14 @@ interface Typing {
expireAt: number;
name: string;
role: 'bot' | 'user';
tag: string;
}

useActiveTyping(expireAfter?: number): [{ [id: string]: Typing }]
```
<!-- prettier-ignore-end -->

This hook will return a list of participants who are actively typing, including the start typing time (`at`) and expiration time (`expireAt`), the name and the role of the participant.
This hook will return a list of participants who are actively typing, including the start typing time (`at`) and expiration time (`expireAt`), the name and the role of the participant and a (`tag`) as an additional property we wish to pass to receiver..

If the participant sends a message after the typing activity, the participant will be explicitly removed from the list. If no messages or typing activities are received, the participant is considered inactive and not listed in the result. To keep the typing indicator active, participants should continuously send the typing activity.

Expand Down Expand Up @@ -906,6 +907,7 @@ interface Typing {
expireAt: number;
name: string;
role: 'bot' | 'user';
tag: string;
}

useRenderTypingIndicator():
Expand Down
8 changes: 5 additions & 3 deletions packages/api/src/hooks/useActiveTyping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,20 @@ function useActiveTyping(expireAfter?: number): [{ [userId: string]: Typing }] {

const [{ typingAnimationDuration }] = useStyleOptions();
const forceRender = useForceRender();
const typing: { [userId: string]: { at: number; name: string; role: string } } = useSelector(({ typing }) => typing);
const typing: { [userId: string]: { at: number; name: string; role: string; tag?: string } } = useSelector(
({ typing }) => typing
);

if (typeof expireAfter !== 'number') {
expireAfter = typingAnimationDuration;
}

const activeTyping: { [userId: string]: Typing } = Object.entries(typing).reduce(
(activeTyping, [id, { at, name, role }]) => {
(activeTyping, [id, { at, name, role, tag }]) => {
const until = at + expireAfter;

if (until > now) {
return { ...activeTyping, [id]: { at, expireAt: until, name, role } };
return { ...activeTyping, [id]: { at, expireAt: until, name, role, tag } };
}

return activeTyping;
Expand Down
1 change: 1 addition & 0 deletions packages/api/src/types/Typing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ type Typing = {
expireAt: number;
name: string;
role: 'bot' | 'user';
tag?: string;
};

export default Typing;
5 changes: 3 additions & 2 deletions packages/core/src/reducers/typing.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default function lastTyping(state = DEFAULT_STATE, { payload, type }) {
if (type === INCOMING_ACTIVITY || type === POST_ACTIVITY_PENDING) {
const {
activity: {
from: { id, name, role },
from: { id, name, role, tag },
type: activityType
}
} = payload;
Expand All @@ -21,7 +21,8 @@ export default function lastTyping(state = DEFAULT_STATE, { payload, type }) {
state = updateIn(state, [id], () => ({
at: Date.now(),
name,
role
role,
tag
}));
} else if (activityType === 'message') {
state = updateIn(state, [id]);
Expand Down