Skip to content

Commit

Permalink
feat: fullscreen status messages (#2948)
Browse files Browse the repository at this point in the history
Render an error when there are no messages for a chat
Update the StatefulGraphChatClient to set the notificationClient to avoid type errors due to an as yet incomplete promise in a void context
Disable the SendBox if there is no chatId
Refactor status into an exportable type
Downgrades @azure/communication-react to Use v1.8.0-beta.1 to fix missing beta imports
  • Loading branch information
musale authored Jan 30, 2024
1 parent 7223112 commit 511f6ea
Show file tree
Hide file tree
Showing 42 changed files with 668 additions and 131 deletions.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
10 changes: 5 additions & 5 deletions packages/mgt-chat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@
"typescript": "^4.9.5"
},
"dependencies": {
"@azure/communication-calling": "1.16.3",
"@azure/communication-calling": "1.20.1",
"@azure/communication-calling-effects": "1.0.1",
"@azure/communication-chat": "1.3.2",
"@azure/communication-common": "2.2.1",
"@azure/communication-identity": "1.2.0",
"@azure/communication-react": "1.7.0-beta.2",
"@azure/communication-chat": "1.4.0",
"@azure/communication-common": "2.3.0",
"@azure/communication-identity": "1.3.0",
"@azure/communication-react": "1.8.0-beta.1",
"@azure/msal-browser": "2.33.0",
"@fluentui/react": "~8.106.1",
"@fluentui/react-components": "^9.19.1",
Expand Down
41 changes: 29 additions & 12 deletions packages/mgt-chat/src/components/Chat/Chat.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import { ErrorBar, FluentThemeProvider, MessageThread, SendBox, MessageThreadStyles } from '@azure/communication-react';
import { FluentTheme, MessageBarType } from '@fluentui/react';
import { FluentTheme } from '@fluentui/react';
import { FluentProvider, makeStyles, shorthands, webLightTheme } from '@fluentui/react-components';
import { Person, PersonCardInteraction, Spinner } from '@microsoft/mgt-react';
import React, { useEffect, useState } from 'react';
import { StatefulGraphChatClient } from '../../statefulClient/StatefulGraphChatClient';
import { useGraphChatClient } from '../../statefulClient/useGraphChatClient';
import { onRenderMessage } from '../../utils/chat';
import ChatMessageBar from '../ChatMessageBar/ChatMessageBar';
import { renderMGTMention } from '../../utils/mentions';
import { registerAppIcons } from '../styles/registerIcons';
import { ChatHeader } from '../ChatHeader/ChatHeader';
import { Error } from '../Error/Error';
import { LoadingMessagesErrorIcon } from '../Error/LoadingMessageErrorIcon';
import { OpenTeamsLinkError } from '../Error/OpenTeams';
import { RequireValidChatId } from '../Error/RequireAValidChatId';
import { TypeANewMessage } from '../Error/TypeANewMessage';

registerAppIcons();

Expand All @@ -23,7 +27,8 @@ const useStyles = makeStyles({
flexDirection: 'column',
height: '100%',
...shorthands.overflow('auto'),
paddingBlockEnd: '12px'
paddingBlockEnd: '12px',
backgroundColor: 'var(--Neutral-Background-2-Rest, #FAFAFA)'
},
chatMessages: {
height: 'auto',
Expand All @@ -42,6 +47,9 @@ const useStyles = makeStyles({
'& ul': {
...shorthands.paddingInline('40px', '0px')
}
},
'& .fui-Chat': {
maxWidth: 'unset'
}
},
chatInput: {
Expand Down Expand Up @@ -110,13 +118,16 @@ export const Chat = ({ chatId }: IMgtChatProps) => {
chatState.status
);

const disabled = !chatId || !!chatState.activeErrorMessages.length;
const placeholderText = disabled ? 'You cannot send a message' : 'Type a message...';

return (
<FluentThemeProvider fluentTheme={FluentTheme}>
<FluentProvider theme={webLightTheme} className={styles.fullHeight}>
<FluentProvider id="fluentui" theme={webLightTheme} className={styles.fullHeight}>
<div className={styles.chat}>
<ChatHeader chatState={chatState} />
{chatState.userId && chatId && chatState.messages.length > 0 ? (
<>
<ChatHeader chatState={chatState} />
<div className={styles.chatMessages}>
<MessageThread
userId={chatState.userId}
Expand Down Expand Up @@ -153,9 +164,8 @@ export const Chat = ({ chatId }: IMgtChatProps) => {
/>
</div>
<div className={styles.chatInput}>
<SendBox onSendMessage={chatState.onSendMessage} />
<SendBox onSendMessage={chatState.onSendMessage} strings={{ placeholderText }} />
</div>
<ErrorBar activeErrorMessages={chatState.activeErrorMessages} />
</>
) : (
<>
Expand All @@ -166,14 +176,21 @@ export const Chat = ({ chatId }: IMgtChatProps) => {
</div>
)}
{chatState.status === 'no messages' && (
<ChatMessageBar
messageBarType={MessageBarType.error}
message={`No messages were found for the id ${chatId}.`}
/>
<Error
icon={LoadingMessagesErrorIcon}
message="No messages were found for this chat."
subheading={TypeANewMessage}
></Error>
)}
{chatState.status === 'no chat id' && (
<ChatMessageBar messageBarType={MessageBarType.error} message={'A valid chat id is required.'} />
<Error message="No chat id has been provided." subheading={RequireValidChatId}></Error>
)}
{chatState.status === 'error' && (
<Error message="We're sorry—we've run into an issue.." subheading={OpenTeamsLinkError}></Error>
)}
<div className={styles.chatInput}>
<SendBox disabled={disabled} onSendMessage={chatState.onSendMessage} strings={{ placeholderText }} />
</div>
</>
)}
</div>
Expand Down
40 changes: 21 additions & 19 deletions packages/mgt-chat/src/components/ChatHeader/GroupChatHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,26 +78,28 @@ export const GroupChatHeader = ({ chat, currentUserId, onRenameChat }: ChatHeade
<>
<ChatIcon chatType={chat?.chatType} />
<span className={styles.chatTitle}>{chatTitle}</span>
<Popover {...popoverProps}>
<PopoverTrigger>
<Button appearance="transparent" icon={<EditIcon />} aria-label="Name group chat"></Button>
</PopoverTrigger>
<PopoverSurface>
<div className={styles.container}>
<Field label="Group name">
<Input placeholder="Enter group name" onChange={onChatNameChanged} value={chatName || ''} />
</Field>
<div className={styles.formButtons}>
<Button appearance="secondary" onClick={onCancelClicked}>
Cancel
</Button>
<Button appearance="primary" disabled={chatName === chat?.topic} onClick={renameChat}>
Send
</Button>
{chat?.id && (
<Popover {...popoverProps}>
<PopoverTrigger>
<Button appearance="transparent" icon={<EditIcon />} aria-label="Name group chat"></Button>
</PopoverTrigger>
<PopoverSurface>
<div className={styles.container}>
<Field label="Group name">
<Input placeholder="Enter group name" onChange={onChatNameChanged} value={chatName || ''} />
</Field>
<div className={styles.formButtons}>
<Button appearance="secondary" onClick={onCancelClicked}>
Cancel
</Button>
<Button appearance="primary" disabled={chatName === chat?.topic} onClick={renameChat}>
Send
</Button>
</div>
</div>
</div>
</PopoverSurface>
</Popover>
</PopoverSurface>
</Popover>
)}
</>
);
};
20 changes: 14 additions & 6 deletions packages/mgt-chat/src/components/ChatIcon/ChatIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import React from 'react';
import { Chat } from '@microsoft/microsoft-graph-types';
import { Calendar16Regular, PeopleTeam16Regular, bundleIcon } from '@fluentui/react-icons';
import { error } from '@microsoft/mgt-element';
import {
Calendar16Regular,
PeopleTeam16Regular,
bundleIcon,
Person16Regular,
Person16Filled
} from '@fluentui/react-icons';
import { Circle } from '../Circle/Circle';

const MeetingIcon = bundleIcon(Calendar16Regular, Calendar16Regular);
const GroupIcon = bundleIcon(PeopleTeam16Regular, PeopleTeam16Regular);
export const ChatIcon = ({ chatType }: Chat): JSX.Element | null => {
if (!chatType) return null;
const PersonIcon = bundleIcon(Person16Filled, Person16Regular);

export const ChatIcon = ({ chatType }: Chat): JSX.Element | null => {
const iconColor = 'var(--colorBrandForeground2)';

switch (chatType) {
Expand All @@ -25,7 +30,10 @@ export const ChatIcon = ({ chatType }: Chat): JSX.Element | null => {
</Circle>
);
default:
error(`Attempted to render an icon for chat of type: ${chatType}`);
return null;
return (
<Circle>
<PersonIcon color={iconColor} />
</Circle>
);
}
};
89 changes: 89 additions & 0 deletions packages/mgt-chat/src/components/Error/Error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/**
* -------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License.
* See License in the project root for license information.
* -------------------------------------------------------------------------------------------
*/

import React from 'react';
import { makeStyles, shorthands } from '@fluentui/react-components';
import { GenericErrorIcon } from './GenericErrorIcon';

const useStyles = makeStyles({
container: {
backgroundColor: 'var(--Neutral-Background-2-Rest, #FAFAFA)',
display: 'flex',
flexWrap: 'wrap',
flexDirection: 'column',
alignContent: 'center',
justifyContent: 'center',
width: '100%',
height: '100%',
fontFamily: 'Segoe UI',
...shorthands.paddingInline('0 16px'),
...shorthands.gap('24px')
},
icon: {
display: 'flex',
flexWrap: 'wrap',
justifyContent: 'center',
alignContent: 'center'
},
messageContainer: {},
message: {
color: 'var(--Neutral-Foreground-1-Rest, #242424)',
textAlign: 'center',
fontSize: '16px',
fontStyle: 'normal',
fontWeight: '600',
lineHeight: '22px'
},
subheading: {
color: 'var(--Neutral-Foreground-2-Rest, #424242)',
textAlign: 'center',
fontSize: '14px',
fontStyle: 'normal',
fontWeight: '400',
lineHeight: '20px'
}
});
/**
* Error message component props
*/
interface IMGTErrorProps {
icon?: React.FC;
message: string;
subheading?: React.FC;
}

const EmptySubheading = () => {
return <p></p>;
};

/**
* Renders a full screen error message.
* @returns
*/
const Error = ({ icon = GenericErrorIcon, message, subheading }: IMGTErrorProps): JSX.Element => {
const styles = useStyles();
const IconTemplate = icon;
const SubheadingTemplate = subheading ? subheading : EmptySubheading;

return (
<div className={styles.container}>
<div className={styles.icon}>
<IconTemplate />
</div>
<div className={styles.messageContainer}>
<div className={styles.message}>{message}</div>
{subheading && (
<div className={styles.subheading}>
<SubheadingTemplate />
</div>
)}
</div>
</div>
);
};

export { Error };
75 changes: 75 additions & 0 deletions packages/mgt-chat/src/components/Error/GenericErrorIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/**
* -------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License.
* See License in the project root for license information.
* -------------------------------------------------------------------------------------------
*/

import React from 'react';

export const GenericErrorIcon = () => {
return (
<svg xmlns="http://www.w3.org/2000/svg" width="68" height="68" viewBox="0 0 68 68" fill="none">
<path
d="M58.0129 27.6675L43.4354 42.3725C42.5854 43.2225 42.9679 44.71 44.1579 45.0075L64.1754 50.32C65.3654 50.6175 66.4279 49.555 66.1304 48.365L60.6904 28.39C60.3079 27.2 58.8629 26.775 58.0129 27.6675Z"
fill="url(#paint0_linear_11292_9370)"
/>
<path
d="M15.5978 11.0075L6.92782 29.835C6.41782 30.94 7.31032 32.1725 8.50032 32.0875L29.1128 30.175C30.3453 30.0475 30.9828 28.6875 30.2603 27.6675L18.3178 10.7525C17.5953 9.73251 16.1078 9.90251 15.5978 11.0075Z"
fill="url(#paint1_linear_11292_9370)"
/>
<path
d="M32.0877 13.6423L7.05516 50.7448C5.56766 52.9123 7.01266 55.8873 9.64766 56.0998L54.3152 59.2448C56.9502 59.4148 58.7777 56.6948 57.6302 54.3148L37.9952 14.0673C36.8477 11.6873 33.5752 11.4748 32.0877 13.6423Z"
fill="#FFD590"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M58.8201 35.5298C58.5651 36.4223 59.0751 37.3998 59.9676 37.6548C60.8601 37.9523 61.7951 37.4423 62.0501 36.5498L65.7476 24.3098C66.0026 23.4173 65.4926 22.4398 64.6001 22.1848C63.7076 21.9298 62.7301 22.4398 62.4751 23.3323L58.8201 35.5298ZM60.6902 41.5648C60.6902 42.621 59.834 43.4773 58.7777 43.4773C57.7215 43.4773 56.8652 42.621 56.8652 41.5648C56.8652 40.5085 57.7215 39.6523 58.7777 39.6523C59.834 39.6523 60.6902 40.5085 60.6902 41.5648Z"
fill="#3E8EED"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M31.3668 41.9901C31.2818 42.9251 32.0043 43.7326 32.9393 43.8176C33.8743 43.8601 34.6818 43.1801 34.7668 42.2451L35.9993 24.8626C36.0843 23.9276 35.3618 23.1201 34.4268 23.0351C33.4918 22.9501 32.6843 23.6726 32.5993 24.6076L31.3668 41.9901ZM34.5965 47.8551C34.5965 48.9114 33.7402 49.7676 32.684 49.7676C31.6277 49.7676 30.7715 48.9114 30.7715 47.8551C30.7715 46.7989 31.6277 45.9426 32.684 45.9426C33.7402 45.9426 34.5965 46.7989 34.5965 47.8551Z"
fill="white"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M11.3473 21.6326C11.6023 22.5676 12.5373 23.0776 13.4298 22.8226C14.3223 22.5676 14.8323 21.6326 14.6198 20.7401L11.1348 8.45757C10.8798 7.52257 9.94479 7.01257 9.05229 7.26757C8.11729 7.52257 7.60729 8.45757 7.86229 9.35007L11.3473 21.6326ZM16.4472 26.7327C16.4472 27.7889 15.5909 28.6452 14.5347 28.6452C13.4784 28.6452 12.6222 27.7889 12.6222 26.7327C12.6222 25.6764 13.4784 24.8202 14.5347 24.8202C15.5909 24.8202 16.4472 25.6764 16.4472 26.7327Z"
fill="#28C2D1"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M34.3818 8.75509C34.2118 8.58509 34.1268 8.37259 34.0843 8.16009L33.6593 5.44009C33.5743 4.84509 33.9993 4.33509 34.5518 4.25009C34.8493 4.20759 35.1468 4.29259 35.3593 4.46259C35.5718 4.63259 35.6993 4.88759 35.7418 5.14259L36.1243 7.86259C36.2093 8.45759 35.7843 8.96759 35.2318 9.05259C34.9343 9.09509 34.5943 8.96759 34.3818 8.75509ZM39.2694 9.09522C39.0144 9.52022 39.0994 10.0302 39.4394 10.3702C39.4819 10.4127 39.5669 10.4977 39.6519 10.4977C40.1619 10.7952 40.7994 10.6252 41.0544 10.1577L42.3719 7.94772C42.4994 7.69272 42.5419 7.43772 42.4994 7.14022C42.4569 6.92772 42.3294 6.71522 42.1594 6.58772C42.1382 6.56647 42.1169 6.55584 42.0957 6.54522C42.0744 6.53459 42.0532 6.52397 42.0319 6.50272C41.5219 6.20522 40.8844 6.37522 40.6294 6.84272L39.2694 9.09522ZM43.3069 13.8126C43.3494 13.8976 43.4344 14.0251 43.5194 14.1101C43.8594 14.4076 44.3269 14.4926 44.7094 14.2801L46.9194 13.1751C47.1744 13.0476 47.3444 12.8351 47.4294 12.5801C47.5144 12.3251 47.5144 12.0276 47.3869 11.7726L47.3869 11.7726C47.3019 11.6451 47.2169 11.5176 47.0894 11.4326C47.0244 11.3677 46.9347 11.3276 46.8581 11.2933L46.858 11.2933C46.8344 11.2827 46.8119 11.2727 46.7919 11.2626C46.5369 11.1776 46.2394 11.1776 45.9844 11.3051L43.7744 12.4101C43.5194 12.5376 43.3494 12.7501 43.2644 13.0051C43.1794 13.3026 43.1794 13.5576 43.3069 13.8126Z"
fill="#E1DFDD"
/>
<defs>
<linearGradient
id="paint0_linear_11292_9370"
x1="42.1229"
y1="42.8716"
x2="57.8851"
y2="39.5913"
gradientUnits="userSpaceOnUse"
>
<stop offset="0.000984252" stopColor="#72ACF1" />
<stop offset="1" stopColor="#A7CBF6" />
</linearGradient>
<linearGradient
id="paint1_linear_11292_9370"
x1="28.8553"
y1="30.7359"
x2="17.0695"
y2="23.6816"
gradientUnits="userSpaceOnUse"
>
<stop offset="0.000984252" stopColor="#7BDDEF" />
<stop offset="1" stopColor="#C3F2F4" />
</linearGradient>
</defs>
</svg>
);
};
Loading

0 comments on commit 511f6ea

Please sign in to comment.