-
Notifications
You must be signed in to change notification settings - Fork 310
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: show bot names and avatars in conversation (#3071)
sets up a provider model for getting Bot based data refactor to create a base class for stateful clients creates a new component for rendering chat avatars that can handle bots fix: stop creating two instances of the notification client fix: remove contenteditable attribute from emjoi html
- Loading branch information
1 parent
f78d197
commit c42aa19
Showing
19 changed files
with
626 additions
and
276 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { Person, ViewType } from '@microsoft/mgt-react'; | ||
import React, { FC, useEffect } from 'react'; | ||
import { useBotInfo } from '../../statefulClient/useBotInfo'; | ||
import { ChatAvatarProps } from './ChatAvatar'; | ||
|
||
type BotAvatarProps = ChatAvatarProps & { | ||
view?: ViewType; | ||
}; | ||
|
||
export const BotAvatar: FC<BotAvatarProps> = ({ chatId, avatarId, view = 'image' }) => { | ||
const botInfo = useBotInfo(); | ||
|
||
useEffect(() => { | ||
if (chatId && avatarId && !botInfo?.botInfo.has(avatarId)) { | ||
void botInfo?.loadBotInfo(chatId, avatarId); | ||
} | ||
}, [chatId, avatarId, botInfo]); | ||
|
||
return ( | ||
<div> | ||
<Person | ||
personDetails={{ | ||
id: avatarId, | ||
displayName: botInfo?.botInfo.has(avatarId) | ||
? botInfo.botInfo.get(avatarId)?.teamsAppDefinition?.displayName | ||
: '', | ||
personImage: botInfo?.botIcons.has(avatarId) ? botInfo.botIcons.get(avatarId) : '' | ||
}} | ||
avatarSize="small" | ||
personCardInteraction="none" | ||
view={view} | ||
showPresence={false} | ||
/> | ||
</div> | ||
); | ||
}; |
26 changes: 26 additions & 0 deletions
26
packages/mgt-chat/src/components/ChatAvatar/ChatAvatar.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { Person } from '@microsoft/mgt-react'; | ||
import React, { FC, memo } from 'react'; | ||
import { botPrefix } from '../../statefulClient/buildBotId'; | ||
import { BotAvatar } from './BotAvatar'; | ||
|
||
export interface ChatAvatarProps { | ||
/** | ||
* The chat id | ||
*/ | ||
chatId: string; | ||
/** | ||
* The id of the entity to get the avatar for | ||
* for bots this is prefixed with 'botId::' | ||
* | ||
*/ | ||
avatarId: string; | ||
} | ||
|
||
const AvatarSwitcher: FC<ChatAvatarProps> = ({ chatId, avatarId }) => | ||
avatarId.startsWith(botPrefix) ? ( | ||
<BotAvatar chatId={chatId} avatarId={avatarId.replace(botPrefix, '')} /> | ||
) : ( | ||
<Person userId={avatarId} avatarSize="small" personCardInteraction="hover" showPresence={true} /> | ||
); | ||
|
||
export const ChatAvatar = memo(AvatarSwitcher); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import { createContext } from 'react'; | ||
import { BotInfoClient } from '../../statefulClient/BotInfoClient'; | ||
|
||
export const BotInfoContext = createContext<BotInfoClient | undefined>(undefined); |
75 changes: 75 additions & 0 deletions
75
packages/mgt-chat/src/statefulClient/BaseStatefulClient.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import { BetaGraph, IGraph, Providers } from '@microsoft/mgt-element'; | ||
import { produce } from 'immer'; | ||
import { StatefulClient } from './StatefulClient'; | ||
import { graph } from '../utils/graph'; | ||
import { GraphConfig } from './GraphConfig'; | ||
|
||
export abstract class BaseStatefulClient<T> implements StatefulClient<T> { | ||
private _graph: IGraph | undefined; | ||
|
||
protected get graph(): IGraph | undefined { | ||
if (this._graph) return this._graph; | ||
if (Providers.globalProvider?.graph) { | ||
this._graph = graph('mgt-chat', GraphConfig.version); | ||
} | ||
return this._graph; | ||
} | ||
|
||
protected set graph(value: IGraph | undefined) { | ||
this._graph = value; | ||
} | ||
|
||
protected get betaGraph(): BetaGraph | undefined { | ||
const g = this.graph; | ||
if (g) return BetaGraph.fromGraph(g); | ||
|
||
return undefined; | ||
} | ||
|
||
private _subscribers: ((state: T) => void)[] = []; | ||
/** | ||
* Register a callback to receive state updates | ||
* | ||
* @param {(state: GraphChatClient) => void} handler | ||
* @memberof StatefulGraphChatClient | ||
*/ | ||
public onStateChange(handler: (state: T) => void): void { | ||
if (!this._subscribers.includes(handler)) { | ||
this._subscribers.push(handler); | ||
} | ||
} | ||
|
||
/** | ||
* Unregister a callback from receiving state updates | ||
* | ||
* @param {(state: GraphChatClient) => void} handler | ||
* @memberof StatefulGraphChatClient | ||
*/ | ||
public offStateChange(handler: (state: T) => void): void { | ||
const index = this._subscribers.indexOf(handler); | ||
if (index !== -1) { | ||
this._subscribers = this._subscribers.splice(index, 1); | ||
} | ||
} | ||
|
||
/** | ||
* Calls each subscriber with the next state to be emitted | ||
* | ||
* @param recipe - a function which produces the next state to be emitted | ||
*/ | ||
protected notifyStateChange(recipe: (draft: T) => void) { | ||
this.state = produce(this.state, recipe); | ||
this._subscribers.forEach(handler => handler(this.state)); | ||
} | ||
|
||
protected abstract state: T; | ||
/** | ||
* Return the current state of the chat client | ||
* | ||
* @return {{GraphChatClient} | ||
* @memberof StatefulGraphChatClient | ||
*/ | ||
public getState(): T { | ||
return this.state; | ||
} | ||
} |
Oops, something went wrong.