Skip to content

Commit

Permalink
chore: adding support for chat scenarios in react-contoso (#2620)
Browse files Browse the repository at this point in the history
Adding the Chat components
Removing random text from the Chat component
  • Loading branch information
sebastienlevert authored Jul 19, 2023
1 parent 5cf7961 commit 46b0d0f
Show file tree
Hide file tree
Showing 9 changed files with 410 additions and 40 deletions.
1 change: 0 additions & 1 deletion packages/mgt-chat/src/components/Chat/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ export const Chat = ({ chatId }: IMgtChatProps) => {
addChatMembers={chatState.onAddChatMembers}
/>
)}
asdfasdf
<div className={styles.chatMessages}>
<MessageThread
userId={chatState.userId}
Expand Down
6 changes: 4 additions & 2 deletions samples/react-contoso/.env.sample
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
BROWSER="none"
SKIP_PREFLIGHT_CHECK=true
FAST_REFRESH = false
FAST_REFRESH=false
REACT_APP_SITE_NAME="Contoso Dashboard"
REACT_APP_CLIENT_ID="ed072e38-e76e-45ae-ab76-073cb95495bb"
REACT_APP_CLIENT_ID="00000000-0000-0000-0000-000000000000"
REACT_APP_URL_AZURE_FUNCTION="https://contoso.azurewebsites.net"
REACT_APP_BACKEND_CLIENT_ID="00000000-0000-0000-0000-000000000000"

4 changes: 2 additions & 2 deletions samples/react-contoso/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This project was bootstrapped with [Create React App](https://github.com/faceboo
In the root directory for the repository:

```
yarn && yarn build && yarn watch:react`
yarn && yarn build && yarn watch:react
```

This will:
Expand All @@ -18,4 +18,4 @@ This will:
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.

The page will reload if you make edits.
You will also see any lint errors in the console.
You will also see any lint errors in the console.
10 changes: 10 additions & 0 deletions samples/react-contoso/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { App } from './App';
import { mergeStyles } from '@fluentui/react';
import { Msal2Provider } from '@microsoft/mgt-msal2-provider';
import { Providers, LoginType } from '@microsoft/mgt-element';
import { brokerSettings } from '@microsoft/mgt-chat';

// Inject some global styles
mergeStyles({
Expand All @@ -14,13 +15,22 @@ mergeStyles({
}
});

brokerSettings.functionHost = process.env.REACT_APP_URL_AZURE_FUNCTION!;
brokerSettings.appId = process.env.REACT_APP_BACKEND_CLIENT_ID!;

Providers.globalProvider = new Msal2Provider({
clientId: process.env.REACT_APP_CLIENT_ID!,
loginType: LoginType.Redirect,
redirectUri: window.location.protocol + '//' + window.location.host,
scopes: [
'Bookmark.Read.All',
'Calendars.Read',
'Chat.Create',
'Chat.Read',
'Chat.ReadBasic',
'Chat.ReadWrite',
'ChatMember.ReadWrite',
'ChatMessage.Send',
'ExternalItem.Read.All',
'Files.Read',
'Files.Read.All',
Expand Down
137 changes: 137 additions & 0 deletions samples/react-contoso/src/pages/ChatPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import * as React from 'react';
import { PageHeader } from '../components/PageHeader';
import { Get } from '@microsoft/mgt-react';
import { Loading } from '../components/Loading';
import {
shorthands,
makeStyles,
mergeClasses,
Button,
Dialog,
DialogTrigger,
DialogSurface,
DialogBody,
DialogTitle
} from '@fluentui/react-components';
import { Chat as GraphChat } from '@microsoft/microsoft-graph-types';
import { Chat, NewChat } from '@microsoft/mgt-chat';
import ChatListTemplate from './Chats/ChatListTemplate';

const useStyles = makeStyles({
container: {
display: 'flex',
flexDirection: 'row'
},
panels: {
...shorthands.padding('10px')
},
main: {
display: 'flex',
flexDirection: 'column',
flexWrap: 'nowrap',
width: '300px',
minWidth: '300px',
...shorthands.overflow('auto'),
maxHeight: '80vh',
borderRightColor: 'var(--neutral-stroke-rest)',
borderRightStyle: 'solid',
borderRightWidth: '1px'
},
side: {
display: 'flex',
flexDirection: 'column',
flexWrap: 'nowrap',
width: '80%',
...shorthands.overflow('auto'),
maxHeight: '80vh',
height: '100%'
},
newChat: {
paddingBottom: '10px',
marginRight: '0px',
marginLeft: 'auto'
},
dialog: {
display: 'block'
}
});

export const ChatPage: React.FunctionComponent = () => {
const styles = useStyles();
const [selectedChat, setSelectedChat] = React.useState<GraphChat>();
const [isNewChatOpen, setIsNewChatOpen] = React.useState(false);

const chatSelected = (e: GraphChat) => {
if (e.id !== selectedChat?.id && isNewChatOpen) {
setIsNewChatOpen(false);
}
setSelectedChat(e);
};

return (
<>
<PageHeader
title={'Chats'}
description={'Stay in touch with your teammates and navigate your chats'}
></PageHeader>

<div className={styles.container}>
<div className={mergeClasses(styles.panels, styles.main)}>
<div className={styles.newChat}>
<Dialog open={isNewChatOpen}>
<DialogTrigger disableButtonEnhancement>
<Button appearance="primary" onClick={() => setIsNewChatOpen(true)}>
New Chat
</Button>
</DialogTrigger>
<DialogSurface>
<DialogBody className={styles.dialog}>
<DialogTitle>New Chat</DialogTitle>
<NewChat
onChatCreated={chatSelected}
onCancelClicked={() => {
setIsNewChatOpen(false);
}}
hideTitle={true}
></NewChat>
</DialogBody>
</DialogSurface>
</Dialog>
</div>
<ChatList chatSelected={selectedChat} onChatSelected={setSelectedChat}></ChatList>
</div>
<div className={styles.side}>{selectedChat && <Chat chatId={selectedChat.id!}></Chat>}</div>
</div>
</>
);
};

interface ChatListProps {
onChatSelected: (e: GraphChat) => void;
chatSelected: GraphChat | undefined;
}

const ChatList = React.memo((props: ChatListProps) => {
const getPreviousDate = (months: number) => {
const date = new Date();
date.setMonth(date.getMonth() - months);
return date.toISOString();
};

return (
<Get
resource={`me/chats?$expand=members,lastMessagePreview&$orderBy=lastMessagePreview/createdDateTime desc&$filter=viewpoint/lastMessageReadDateTime ge ${getPreviousDate(
9
)}`}
scopes={['chat.read']}
cacheEnabled={true}
>
<ChatListTemplate
template="default"
onSelected={props.onChatSelected}
selectedChat={props.chatSelected}
></ChatListTemplate>
<Loading template="loading" message={'Loading your chats...'}></Loading>
</Get>
);
});
161 changes: 161 additions & 0 deletions samples/react-contoso/src/pages/Chats/ChatItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import { Persona, makeStyles, mergeClasses, shorthands } from '@fluentui/react-components';
import { Providers } from '@microsoft/mgt-element';
import { MgtTemplateProps, Person, ViewType } from '@microsoft/mgt-react';
import { Chat, AadUserConversationMember } from '@microsoft/microsoft-graph-types';
import React, { useCallback, useEffect, useState } from 'react';
import { PeopleCommunityRegular, CalendarMonthRegular } from '@fluentui/react-icons';

const useStyles = makeStyles({
chat: {
paddingLeft: '5px',
paddingRight: '5px',
display: 'flex',
alignItems: 'center',
height: '50px',
cursor: 'pointer',
':hover': {
backgroundColor: 'var(--colorNeutralBackground1Hover)'
}
},
active: {
backgroundColor: 'var(--colorNeutralBackground1Selected)'
},
person: {
'--person-avatar-size-small': '40px',
'& .fui-Persona__primaryText': {
fontSize: 'var(--fontSizeBase300);'
},
'& .fui-Persona__secondaryText': {
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
width: '200px',
display: 'inline-block',
...shorthands.overflow('hidden')
}
},
messagePreview: {
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
width: '200px',
display: 'inline-block',
...shorthands.overflow('hidden')
}
});

export interface ChatInteractionProps {
onSelected: (selected: Chat) => void;
selectedChat?: Chat;
}

interface ChatItemProps {
chat: Chat;
isSelected?: boolean;
}

const getMessagePreview = (chat: Chat) => {
return chat?.lastMessagePreview?.body?.contentType === 'text' ? chat?.lastMessagePreview?.body?.content : '...';
};

const ChatItem = ({ chat, isSelected, onSelected }: ChatItemProps & ChatInteractionProps) => {
const styles = useStyles();
const [myId, setMyId] = useState<string>();

useEffect(() => {
const getMyId = async () => {
const me = await Providers.me();
setMyId(me.id);
};
if (!myId) {
void getMyId();
}
}, [myId]);

const getOtherParticipantId = useCallback(
(chat: Chat) => {
const member = chat.members?.find(m => (m as AadUserConversationMember).userId !== myId);

if (member) {
console.log('member', member);
return (member as AadUserConversationMember).userId as string;
} else if (chat.members?.length === 1 && (chat.members[0] as AadUserConversationMember).userId === myId) {
return myId;
}

return undefined;
},
[myId]
);

const getGroupTitle = useCallback((chat: Chat) => {
let groupTitle: string | undefined = '';
if (chat.topic) {
groupTitle = chat.topic;
} else {
groupTitle = chat.members
?.map(member => {
return member.displayName?.split(' ')[0];
})
.join(', ');
}

return groupTitle;
}, []);

return (
<>
{myId && (
<div className={mergeClasses(styles.chat, `${isSelected && styles.active}`)}>
{chat.chatType === 'oneOnOne' && (
<Person
userId={getOtherParticipantId(chat)}
view={ViewType.twolines}
avatarSize="auto"
showPresence={true}
onClick={() => onSelected(chat)}
className={styles.person}
>
<MessagePreview template="line2" chat={chat} />
</Person>
)}
{chat.chatType === 'group' && (
<div onClick={() => onSelected(chat)}>
<Persona
textAlignment="center"
size="extra-large"
name={getGroupTitle(chat)}
secondaryText={getMessagePreview(chat)}
avatar={{ icon: <PeopleCommunityRegular />, initials: null }}
className={styles.person}
/>
<span></span>
</div>
)}
{chat.chatType === 'meeting' && (
<div onClick={() => onSelected(chat)}>
<Persona
textAlignment="center"
size="extra-large"
className={styles.person}
avatar={{ icon: <CalendarMonthRegular />, initials: null }}
name={getGroupTitle(chat)}
secondaryText={getMessagePreview(chat)}
/>
</div>
)}
</div>
)}
</>
);
};

const MessagePreview = (props: MgtTemplateProps & ChatItemProps) => {
const styles = useStyles();

return (
<>
<span className={styles.messagePreview}>{getMessagePreview(props.chat)}</span>
</>
);
};

export default ChatItem;
Loading

0 comments on commit 46b0d0f

Please sign in to comment.