UNPKG

@atlaskit/profilecard

Version:

A React component to display a card with user information.

376 lines (375 loc) 12.9 kB
import _extends from "@babel/runtime/helpers/extends"; import _defineProperty from "@babel/runtime/helpers/defineProperty"; import React, { Suspense } from 'react'; import { FormattedMessage, injectIntl } from 'react-intl-next'; import { withAnalyticsEvents } from '@atlaskit/analytics-next'; import { GiveKudosLauncherLazy, KudosType } from '@atlaskit/give-kudos'; import { fg } from '@atlaskit/platform-feature-flags'; import Popup from '@atlaskit/popup'; import { Box } from '@atlaskit/primitives'; import { layers } from '@atlaskit/theme/constants'; import filterActions from '../../internal/filterActions'; import messages from '../../messages'; import { cardTriggered, fireEvent, profileCardRendered } from '../../util/analytics'; import { isBasicClick } from '../../util/click'; import { DELAY_MS_HIDE, DELAY_MS_SHOW } from '../../util/config'; import { getPageTime } from '../../util/performance'; import { ErrorBoundary } from '../Error'; import { TeamProfileCardLazy } from './lazyTeamProfileCard'; import TeamLoadingState from './TeamLoadingState'; export class TeamProfileCardTriggerInternal extends React.PureComponent { constructor(...args) { super(...args); _defineProperty(this, "_isMounted", false); _defineProperty(this, "showTimer", 0); _defineProperty(this, "hideTimer", 0); _defineProperty(this, "openedByHover", false); _defineProperty(this, "openTime", 0); _defineProperty(this, "fireAnalytics", payload => { // Don't fire any analytics if the component is unmounted if (!this._isMounted) { return; } if (this.props.createAnalyticsEvent) { fireEvent(this.props.createAnalyticsEvent, payload); } }); _defineProperty(this, "fireAnalyticsWithDuration", generator => { const event = generator(getPageTime() - this.openTime); this.fireAnalytics(event); }); _defineProperty(this, "hideProfilecard", (delay = 0) => { clearTimeout(this.showTimer); clearTimeout(this.hideTimer); this.hideTimer = window.setTimeout(() => { this.setState({ visible: false }); }, delay); }); _defineProperty(this, "showProfilecard", (delay = 0) => { clearTimeout(this.hideTimer); clearTimeout(this.showTimer); this.showTimer = window.setTimeout(() => { if (!this.state.visible) { this.clientFetchProfile(); this.openTime = getPageTime(); this.setState({ visible: true }); } }, delay); }); _defineProperty(this, "onClick", event => { if (this.props.triggerLinkType === 'link') { // We want to prevent navigation occurring on basic click, but it's important that // cmd+click, ctrl+click, etc. still work as expected. if (isBasicClick(event)) { event.preventDefault(); } } if (this.props.triggerLinkType === 'clickable-link') { if (this.props.viewProfileOnClick) { this.props.viewProfileOnClick(event); } } if (this.props.trigger !== 'hover') { this.openedByHover = false; this.showProfilecard(0); if (!this.state.visible) { this.fireAnalytics(cardTriggered('team', 'click', this.props.teamId)); } } }); _defineProperty(this, "onMouseEnter", () => { if (this.props.trigger === 'click') { return; } if (!this.state.visible) { this.openedByHover = true; this.fireAnalytics(cardTriggered('team', 'hover', this.props.teamId)); } this.showProfilecard(DELAY_MS_SHOW); }); _defineProperty(this, "onMouseLeave", () => { if (this.props.trigger === 'click') { return; } if (this.openedByHover) { this.hideProfilecard(DELAY_MS_HIDE); } }); _defineProperty(this, "onKeyPress", event => { if (event.key === 'Enter' || event.key === ' ') { event.preventDefault(); this.setState({ isTriggeredByKeyboard: true }); this.showProfilecard(0); if (!this.state.visible) { this.fireAnalytics(cardTriggered('team', 'click', this.props.teamId)); } } }); _defineProperty(this, "onClose", () => { this.hideProfilecard(); this.setState({ isTriggeredByKeyboard: false }); }); _defineProperty(this, "openKudosDrawer", () => { this.hideProfilecard(DELAY_MS_HIDE); this.setState({ kudosDrawerOpen: true }); }); _defineProperty(this, "closeKudosDrawer", () => { this.setState({ kudosDrawerOpen: false }); }); _defineProperty(this, "kudosUrl", () => { const recipientId = this.props.teamId && `&recipientId=${this.props.teamId}` || ''; const cloudId = this.props.cloudId && `&cloudId=${this.props.cloudId}` || ''; return `${this.state.teamCentralBaseUrl}/kudos/give?type=team${recipientId}${cloudId}`; }); _defineProperty(this, "stopPropagation", event => { // We need to stop propagation when users click on the card, so that it // doesn't trigger any special effects that occur when clicking the trigger. event.stopPropagation(); }); _defineProperty(this, "triggerListeners", { onClick: this.onClick, onMouseEnter: this.onMouseEnter, onMouseLeave: this.onMouseLeave }); _defineProperty(this, "cardListeners", { onClick: this.stopPropagation, onMouseEnter: this.onMouseEnter, onMouseLeave: this.onMouseLeave }); _defineProperty(this, "state", { visible: false, isLoading: undefined, hasError: false, error: null, data: null, shouldShowGiveKudos: false, teamCentralBaseUrl: undefined, kudosDrawerOpen: false, isTriggeredByKeyboard: false }); _defineProperty(this, "clientFetchProfile", () => { const { orgId, teamId } = this.props; const { isLoading } = this.state; if (isLoading === true) { // don't fetch data when fetching is in process return; } this.setState({ isLoading: true, data: null }, () => { const fireEvent = event => { this.fireAnalytics(event); }; const requests = Promise.all([this.props.resourceClient.getTeamProfile(teamId, orgId, fireEvent), this.props.resourceClient.shouldShowGiveKudos(), this.props.resourceClient.getTeamCentralBaseUrl({ withOrgContext: true, withSiteContext: true })]); requests.then(res => this.handleClientSuccess(...res), err => this.handleClientError(err)).catch(err => this.handleClientError(err)); }); }); _defineProperty(this, "onErrorBoundary", () => { this.fireAnalytics(profileCardRendered('team', 'errorBoundary', { duration: 0 })); this.setState({ renderError: true }); }); _defineProperty(this, "renderProfileCard", () => { const { generateUserLink, onUserClick, viewingUserId, viewProfileLink, viewProfileOnClick } = this.props; const { data, error, hasError, isLoading } = this.state; const newProps = { clientFetchProfile: this.clientFetchProfile, actions: this.filterActions(), analytics: this.fireAnalyticsWithDuration, team: data || undefined, generateUserLink, onUserClick, viewingUserId, viewProfileLink, viewProfileOnClick }; return /*#__PURE__*/React.createElement("div", this.cardListeners, this.state.visible && /*#__PURE__*/React.createElement(Suspense, { fallback: /*#__PURE__*/React.createElement(TeamLoadingState, { analytics: this.fireAnalyticsWithDuration }) }, /*#__PURE__*/React.createElement(TeamProfileCardLazy, _extends({}, newProps, { isLoading: isLoading, hasError: hasError, errorType: error, isTriggeredByKeyboard: this.state.isTriggeredByKeyboard })))); }); _defineProperty(this, "renderKudosLauncher", () => { return this.state.shouldShowGiveKudos && /*#__PURE__*/React.createElement(Suspense, { fallback: null }, /*#__PURE__*/React.createElement(GiveKudosLauncherLazy, { isOpen: this.state.kudosDrawerOpen, recipient: { type: KudosType.TEAM, recipientId: this.props.teamId }, analyticsSource: "team-profile-card", teamCentralBaseUrl: this.state.teamCentralBaseUrl, cloudId: this.props.cloudId || '', addFlag: this.props.addFlag, onClose: this.closeKudosDrawer })); }); _defineProperty(this, "renderTrigger", triggerProps => { const { children, intl, triggerLinkType, viewProfileLink } = this.props; if (triggerLinkType === 'none') { return /*#__PURE__*/React.createElement(React.Fragment, null, this.renderKudosLauncher(), fg('enable_team_profilecard_toggletip_a11y_fix') ? /*#__PURE__*/React.createElement(Box, _extends({ as: "span", role: "button", testId: "team-profilecard-trigger-wrapper", tabIndex: 0, "aria-label": intl.formatMessage(messages.teamProfileCardAriaLabel), onKeyUp: this.onKeyPress }, triggerProps, this.triggerListeners), children) : /*#__PURE__*/React.createElement("span", _extends({ "data-testid": "team-profilecard-trigger-wrapper" }, triggerProps, this.triggerListeners), children)); } return /*#__PURE__*/React.createElement(React.Fragment, null, this.renderKudosLauncher(), /*#__PURE__*/React.createElement("a", _extends({ "data-testid": "team-profilecard-trigger-wrapper" // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 , style: { color: 'initial', textDecoration: 'none' }, href: viewProfileLink }, triggerProps, { ref: triggerProps.ref }, this.triggerListeners), children)); }); } componentDidMount() { this._isMounted = true; } componentDidUpdate(prevProps) { const { orgId, teamId, resourceClient } = this.props; const { visible } = this.state; // just re-fetching data when the card opens if (visible && (teamId !== prevProps.teamId || orgId !== prevProps.orgId || resourceClient !== prevProps.resourceClient)) { this.setState({ isLoading: undefined }, this.clientFetchProfile); } } componentWillUnmount() { this._isMounted = false; clearTimeout(this.showTimer); clearTimeout(this.hideTimer); } handleClientSuccess(team, shouldShowGiveKudos, teamCentralBaseUrl) { if (!this._isMounted) { return; } this.setState({ isLoading: false, hasError: false, data: team, shouldShowGiveKudos, teamCentralBaseUrl }); } handleClientError(err) { if (!this._isMounted) { return; } this.setState({ isLoading: false, hasError: true, error: err }); } filterActions() { const actions = filterActions(this.props.actions, this.state.data); if (this.state.shouldShowGiveKudos) { const kudosAction = { label: /*#__PURE__*/React.createElement(FormattedMessage, messages.giveKudosButton), id: 'give-kudos', callback: () => { this.openKudosDrawer(); }, link: this.kudosUrl() }; return actions.concat([kudosAction]); } return actions; } renderPopup() { if (this.state.renderError) { return this.props.children; } return /*#__PURE__*/React.createElement(ErrorBoundary, { onError: this.onErrorBoundary }, /*#__PURE__*/React.createElement(Popup, { isOpen: !!this.state.visible, onClose: this.onClose, placement: this.props.position, content: this.renderProfileCard, trigger: triggerProps => this.renderTrigger(triggerProps), zIndex: layers.modal(), shouldFlip: true, autoFocus: this.props.trigger !== 'hover' && !this.openedByHover, shouldRenderToParent: fg('enable_appropriate_reading_order_in_profile_card') && this.props.shouldRenderToParent })); } render() { if (this.props.children) { return this.renderPopup(); } else { throw new Error('Component "TeamProfileCardTrigger" must have "children" property'); } } } _defineProperty(TeamProfileCardTriggerInternal, "defaultProps", { actions: [], trigger: 'hover', position: 'bottom-start', triggerLinkType: 'link', shouldRenderToParent: true }); export default withAnalyticsEvents()(injectIntl(TeamProfileCardTriggerInternal));