From d1edde8a3c5ba45b1aeb048dd32898226fb28266 Mon Sep 17 00:00:00 2001 From: Benjamin Kinga Date: Wed, 30 Mar 2022 13:27:18 -0500 Subject: [PATCH 1/2] feat(WebexMember): split component into space members and meeting participant --- .storybook/preview.js | 5 +- .../WebexMeetingParticipant.jsx | 89 ++++ .../WebexMeetingParticipant.scss | 55 +++ .../WebexMeetingParticipant.stories.js | 34 ++ .../WebexMeetingParticipant.stories.storyshot | 383 +++++++++++++++++ src/components/WebexMember/WebexMember.jsx | 34 +- src/components/WebexMember/WebexMember.scss | 18 - .../WebexMember/WebexMember.stories.js | 39 +- .../WebexMember.stories.storyshot | 388 +----------------- src/components/_components.scss | 1 + src/components/index.js | 1 + 11 files changed, 581 insertions(+), 466 deletions(-) create mode 100644 src/components/WebexMeetingParticipant/WebexMeetingParticipant.jsx create mode 100644 src/components/WebexMeetingParticipant/WebexMeetingParticipant.scss create mode 100644 src/components/WebexMeetingParticipant/WebexMeetingParticipant.stories.js create mode 100644 src/components/WebexMeetingParticipant/__snapshots__/WebexMeetingParticipant.stories.storyshot diff --git a/.storybook/preview.js b/.storybook/preview.js index 1d273c529..b03539917 100644 --- a/.storybook/preview.js +++ b/.storybook/preview.js @@ -42,13 +42,13 @@ export const parameters = { [ 'Webex Avatar', 'Webex Member Roster', - 'Webex Member', ], 'Messaging', [ 'Webex Messaging', 'Webex Activity Stream', 'Webex Activity', + 'Webex Member', ], 'Meetings', [ @@ -58,7 +58,8 @@ export const parameters = { 'Webex In-Meeting', 'Webex Local Media', 'Webex Remote Media', - 'Webex Meeting Control' + 'Webex Meeting Control', + 'Webex Meeting Participant', ], ], }, diff --git a/src/components/WebexMeetingParticipant/WebexMeetingParticipant.jsx b/src/components/WebexMeetingParticipant/WebexMeetingParticipant.jsx new file mode 100644 index 000000000..e98ca0b80 --- /dev/null +++ b/src/components/WebexMeetingParticipant/WebexMeetingParticipant.jsx @@ -0,0 +1,89 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import {DestinationType} from '@webex/component-adapter-interfaces'; +import Spinner from '../generic/Spinner/Spinner'; +import Icon from '../generic/Icon/Icon'; +import { + useMembers, + useMe, + useOrganization, + usePerson, +} from '../hooks'; +import WebexAvatar from '../WebexAvatar/WebexAvatar'; +import webexComponentClasses from '../helpers'; + +/** + * Displays a webex meeting participant. + * + * @param {object} props Data passed to the component + * @param {string} props.className Custom CSS class to apply + * @param {string} props.meetingID ID of the meeting for which to get members + * @param {boolean} props.displayStatus Whether or not to display the user's status + * @param {string} props.personID ID of the member for which to display avatar + * @param {object} props.style Custom style to apply + * @returns {object} JSX of the component + * + */ +export default function WebexMeetingParticipant({ + className, + meetingID, + displayStatus, + personID, + style, +}) { + const {displayName, orgID, emails} = usePerson(personID); + const me = useMe(); + const members = useMembers(meetingID, DestinationType.MEETING); + const member = members + .find((itemMember) => itemMember.ID === personID); + const organization = useOrganization(orgID); + + const isMuted = member?.muted; + const isSpeaking = member?.speaking; + const isExternal = orgID !== undefined && me.orgID !== undefined && me.orgID !== orgID; + const isSharing = member?.sharing; + const isInMeeting = member?.inMeeting; + const showMe = me.ID === personID; + const isHost = member?.host; + const isGuest = member?.guest; + + const roles = [ + showMe && 'You', + isHost && 'Host', + isSharing && 'Presenter', + ].filter((role) => role); + const emailDomain = emails?.[0]?.split('@')[1] || Unknown organization; + + const [cssClasses, sc] = webexComponentClasses('meeting-participant', className); + + return ( +
+ +
+
+ {(displayName ?? ) || Name not available} + {isGuest && (Guest)} +
+ {roles.length > 0 &&
{roles.join(', ')}
} + {isExternal &&
{organization.name || emailDomain}
} +
+ {isInMeeting && isSharing && } + {isInMeeting && isSpeaking && } + {isInMeeting && isMuted && } +
+ ); +} + +WebexMeetingParticipant.propTypes = { + className: PropTypes.string, + meetingID: PropTypes.string.isRequired, + displayStatus: PropTypes.bool, + personID: PropTypes.string.isRequired, + style: PropTypes.shape(), +}; + +WebexMeetingParticipant.defaultProps = { + className: '', + displayStatus: false, + style: undefined, +}; diff --git a/src/components/WebexMeetingParticipant/WebexMeetingParticipant.scss b/src/components/WebexMeetingParticipant/WebexMeetingParticipant.scss new file mode 100644 index 000000000..0024d3942 --- /dev/null +++ b/src/components/WebexMeetingParticipant/WebexMeetingParticipant.scss @@ -0,0 +1,55 @@ +$C: #{$WEBEX_COMPONENTS_CLASS_PREFIX}-meeting-participant; + +.#{$C} { + display: flex; + align-items: center; + color: var(--wxc-text-color); + + .#{$C}__avatar { + height: 2rem; + width: 2rem; + margin-top: 0.5rem; + margin-bottom: 0.5rem; + } + + .#{$C}__details { + flex: 1; + min-width: 0; + margin-left: 0.75rem; + } + + .#{$C}__name { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + margin-top: 0.063rem; + + .#{$C}__guest { + color: var(--wxc-secondary-text-color); + } + } + + .#{$C}__roles { + font-size: 0.875rem; + line-height: 1rem; + color: var(--wxc-secondary-text-color); + } + + .#{$C}__organization { + font-size: 0.875rem; + line-height: 1rem; + color: var(--wxc-warning-color); + } + + .#{$C}__sharing { + margin-right: 2.5rem; + } + + .#{$C}__speaking { + color: var(--wxc-speaking-color); + } + + .#{$C}__muted { + color: var(--wxc-muted-color); + } +} diff --git a/src/components/WebexMeetingParticipant/WebexMeetingParticipant.stories.js b/src/components/WebexMeetingParticipant/WebexMeetingParticipant.stories.js new file mode 100644 index 000000000..4a53f7200 --- /dev/null +++ b/src/components/WebexMeetingParticipant/WebexMeetingParticipant.stories.js @@ -0,0 +1,34 @@ +import React from 'react'; +import WebexMeetingParticipant from './WebexMeetingParticipant'; + +export default { + title: 'Meetings/Webex Meeting Participant', + component: WebexMeetingParticipant, + decorators: [(Story) =>
], +}; + +const Template = (args) => ; + +export const Muted = Template.bind({}); +Muted.args = { + meetingID: 'meeting2', + personID: 'user2', +}; + +export const Host = Template.bind({}); +Host.args = { + meetingID: 'meeting2', + personID: 'user4', +}; + +export const Guest = Template.bind({}); +Guest.args = { + meetingID: 'meeting2', + personID: 'user6', +}; + +export const ScreenSharing = Template.bind({}); +ScreenSharing.args = { + meetingID: 'meeting2', + personID: 'user3', +}; diff --git a/src/components/WebexMeetingParticipant/__snapshots__/WebexMeetingParticipant.stories.storyshot b/src/components/WebexMeetingParticipant/__snapshots__/WebexMeetingParticipant.stories.storyshot new file mode 100644 index 000000000..f08f74248 --- /dev/null +++ b/src/components/WebexMeetingParticipant/__snapshots__/WebexMeetingParticipant.stories.storyshot @@ -0,0 +1,383 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Storyshots Meetings/Webex Meeting Participant Guest 1`] = ` +Array [ +
+
+
+
+ + + MR + + + avatar +
+
+
+
+ Maria Rossi + + (Guest) + +
+
+ Gmail.com +
+
+
+
, +