MM-47849 - show worktemplate tourtip only once (#22703)
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
b892fe0555
Коммит
5a76d20a1a
@@ -4,6 +4,8 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {FormattedMessage, useIntl} from 'react-intl';
|
import {FormattedMessage, useIntl} from 'react-intl';
|
||||||
|
|
||||||
|
import {useMeasurePunchouts} from '@mattermost/components';
|
||||||
|
|
||||||
import OnboardingWorkTemplateTourTip from './worktemplate_explore_tour_tip';
|
import OnboardingWorkTemplateTourTip from './worktemplate_explore_tour_tip';
|
||||||
import {useShowTourTip} from './useShowTourTip';
|
import {useShowTourTip} from './useShowTourTip';
|
||||||
|
|
||||||
@@ -11,6 +13,7 @@ export const BoardsTourTip = (): JSX.Element | null => {
|
|||||||
const {formatMessage} = useIntl();
|
const {formatMessage} = useIntl();
|
||||||
|
|
||||||
const {playbooksCount, boardsCount, showBoardsTour} = useShowTourTip();
|
const {playbooksCount, boardsCount, showBoardsTour} = useShowTourTip();
|
||||||
|
const overlayPunchOut = useMeasurePunchouts(['sidebar-right'], []);
|
||||||
|
|
||||||
if (!showBoardsTour) {
|
if (!showBoardsTour) {
|
||||||
return null;
|
return null;
|
||||||
@@ -50,11 +53,11 @@ export const BoardsTourTip = (): JSX.Element | null => {
|
|||||||
return (
|
return (
|
||||||
<OnboardingWorkTemplateTourTip
|
<OnboardingWorkTemplateTourTip
|
||||||
pulsatingDotPlacement={'left'}
|
pulsatingDotPlacement={'left'}
|
||||||
pulsatingDotTranslate={{x: 10, y: -140}}
|
pulsatingDotTranslate={{x: 10, y: -350}}
|
||||||
title={title}
|
title={title}
|
||||||
screen={screen}
|
screen={screen}
|
||||||
|
overlayPunchOut={overlayPunchOut}
|
||||||
singleTip={playbooksCount === 0}
|
singleTip={playbooksCount === 0}
|
||||||
overlayPunchOut={null}
|
|
||||||
placement='left-start'
|
placement='left-start'
|
||||||
showOptOut={false}
|
showOptOut={false}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -4,12 +4,15 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {FormattedMessage, useIntl} from 'react-intl';
|
import {FormattedMessage, useIntl} from 'react-intl';
|
||||||
|
|
||||||
|
import {useMeasurePunchouts} from '@mattermost/components';
|
||||||
|
|
||||||
import {useShowTourTip} from './useShowTourTip';
|
import {useShowTourTip} from './useShowTourTip';
|
||||||
import OnboardingWorkTemplateTourTip from './worktemplate_explore_tour_tip';
|
import OnboardingWorkTemplateTourTip from './worktemplate_explore_tour_tip';
|
||||||
|
|
||||||
export const PlaybooksTourTip = (): JSX.Element | null => {
|
export const PlaybooksTourTip = (): JSX.Element | null => {
|
||||||
const {formatMessage} = useIntl();
|
const {formatMessage} = useIntl();
|
||||||
const {playbooksCount, boardsCount, showPlaybooksTour} = useShowTourTip();
|
const {playbooksCount, boardsCount, showPlaybooksTour} = useShowTourTip();
|
||||||
|
const overlayPunchOut = useMeasurePunchouts(['sidebar-right'], []);
|
||||||
|
|
||||||
if (!showPlaybooksTour) {
|
if (!showPlaybooksTour) {
|
||||||
return null;
|
return null;
|
||||||
@@ -53,7 +56,7 @@ export const PlaybooksTourTip = (): JSX.Element | null => {
|
|||||||
title={title}
|
title={title}
|
||||||
screen={screen}
|
screen={screen}
|
||||||
singleTip={boardsCount === 0}
|
singleTip={boardsCount === 0}
|
||||||
overlayPunchOut={null}
|
overlayPunchOut={overlayPunchOut}
|
||||||
placement='left-start'
|
placement='left-start'
|
||||||
showOptOut={false}
|
showOptOut={false}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
import {useSelector} from 'react-redux';
|
import {useSelector} from 'react-redux';
|
||||||
|
|
||||||
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/common';
|
import {getCurrentChannelId, getCurrentUserId} from 'mattermost-redux/selectors/entities/common';
|
||||||
import {getConfig, getWorkTemplatesLinkedProducts} from 'mattermost-redux/selectors/entities/general';
|
import {getConfig, getWorkTemplatesLinkedProducts} from 'mattermost-redux/selectors/entities/general';
|
||||||
import {getInt} from 'mattermost-redux/selectors/entities/preferences';
|
import {getInt} from 'mattermost-redux/selectors/entities/preferences';
|
||||||
|
|
||||||
@@ -17,18 +17,22 @@ export const useShowTourTip = () => {
|
|||||||
const activeRhsComponent = useSelector(getActiveRhsComponent);
|
const activeRhsComponent = useSelector(getActiveRhsComponent);
|
||||||
const pluginId = activeRhsComponent?.pluginId || '';
|
const pluginId = activeRhsComponent?.pluginId || '';
|
||||||
|
|
||||||
|
const currentChannelId = useSelector(getCurrentChannelId);
|
||||||
const currentUserId = useSelector(getCurrentUserId);
|
const currentUserId = useSelector(getCurrentUserId);
|
||||||
|
|
||||||
const enableTutorial = useSelector(getConfig).EnableTutorial === 'true';
|
const enableTutorial = useSelector(getConfig).EnableTutorial === 'true';
|
||||||
|
|
||||||
const tutorialStep = useSelector((state: GlobalState) => getInt(state, TutorialTourName.WORK_TEMPLATE_TUTORIAL, currentUserId, 0));
|
const tutorialStep = useSelector((state: GlobalState) => getInt(state, TutorialTourName.WORK_TEMPLATE_TUTORIAL, currentUserId, 0));
|
||||||
|
|
||||||
const workTemplateTourTipShown = tutorialStep === WorkTemplateTourSteps.FINISHED;
|
const workTemplateTourTipShown = tutorialStep === WorkTemplateTourSteps.FINISHED;
|
||||||
const showProductTour = !workTemplateTourTipShown && enableTutorial;
|
|
||||||
|
|
||||||
const channelLinkedItems = useSelector(getWorkTemplatesLinkedProducts);
|
const channelLinkedItems = useSelector(getWorkTemplatesLinkedProducts);
|
||||||
|
|
||||||
const boardsCount = channelLinkedItems?.boards || 0;
|
const boardsCount = channelLinkedItems?.boards || 0;
|
||||||
const playbooksCount = channelLinkedItems?.playbooks || 0;
|
const playbooksCount = channelLinkedItems?.playbooks || 0;
|
||||||
|
const channelId = channelLinkedItems?.channelId || null;
|
||||||
|
|
||||||
|
const showProductTour = channelId && channelId === currentChannelId && !workTemplateTourTipShown && enableTutorial;
|
||||||
|
|
||||||
const showBoardsTour = showProductTour && pluginId === suitePluginIds.boards && boardsCount > 0;
|
const showBoardsTour = showProductTour && pluginId === suitePluginIds.boards && boardsCount > 0;
|
||||||
const showPlaybooksTour = showProductTour && pluginId === suitePluginIds.playbooks && playbooksCount > 0;
|
const showPlaybooksTour = showProductTour && pluginId === suitePluginIds.playbooks && playbooksCount > 0;
|
||||||
@@ -38,5 +42,6 @@ export const useShowTourTip = () => {
|
|||||||
showPlaybooksTour,
|
showPlaybooksTour,
|
||||||
boardsCount,
|
boardsCount,
|
||||||
playbooksCount,
|
playbooksCount,
|
||||||
|
showProductTour,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {useDispatch, useSelector} from 'react-redux';
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
import LocalizedIcon from 'components/localized_icon';
|
import LocalizedIcon from 'components/localized_icon';
|
||||||
import {TTNameMapToATStatusKey, TutorialTourName, WorkTemplateTourSteps} from 'components/tours/constant';
|
import {TTNameMapToATStatusKey, TutorialTourName} from 'components/tours/constant';
|
||||||
|
|
||||||
import {closeModal as closeModalAction} from 'actions/views/modals';
|
import {closeModal as closeModalAction} from 'actions/views/modals';
|
||||||
import {trackEvent} from 'actions/telemetry_actions';
|
import {trackEvent} from 'actions/telemetry_actions';
|
||||||
@@ -195,18 +195,15 @@ const WorkTemplateModal = () => {
|
|||||||
* Creates the necessary data in the global store as long storing in DB preferences the tourtip information
|
* Creates the necessary data in the global store as long storing in DB preferences the tourtip information
|
||||||
* @param template current used worktempplate
|
* @param template current used worktempplate
|
||||||
*/
|
*/
|
||||||
const tourTipActions = async (template: WorkTemplate) => {
|
const tourTipActions = async (template: WorkTemplate, firstChannelId: string) => {
|
||||||
const linkedProductsCount = getContentCount(template, playbookTemplates);
|
const linkedProductsCount = getContentCount(template, playbookTemplates, firstChannelId);
|
||||||
|
|
||||||
// stepValue and pluginId are used for showing the tourtip for the used template
|
// stepValue and pluginId are used for showing the tourtip for the used template
|
||||||
let stepValue = 0;
|
|
||||||
let pluginId;
|
let pluginId;
|
||||||
if (linkedProductsCount.playbooks) {
|
if (linkedProductsCount.playbooks) {
|
||||||
pluginId = rhsPluggableIds.get(suitePluginIds.playbooks);
|
pluginId = rhsPluggableIds.get(suitePluginIds.playbooks);
|
||||||
stepValue = WorkTemplateTourSteps.PLAYBOOKS_TOUR_TIP;
|
|
||||||
} else {
|
} else {
|
||||||
pluginId = rhsPluggableIds.get(suitePluginIds.boards);
|
pluginId = rhsPluggableIds.get(suitePluginIds.boards);
|
||||||
stepValue = WorkTemplateTourSteps.BOARDS_TOUR_TIP;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pluginId) {
|
if (!pluginId) {
|
||||||
@@ -219,17 +216,8 @@ const WorkTemplateModal = () => {
|
|||||||
|
|
||||||
// store the required preferences for the tourtip
|
// store the required preferences for the tourtip
|
||||||
const tourCategory = TutorialTourName.WORK_TEMPLATE_TUTORIAL;
|
const tourCategory = TutorialTourName.WORK_TEMPLATE_TUTORIAL;
|
||||||
|
|
||||||
const preferences = [
|
const preferences = [
|
||||||
|
|
||||||
// here reset the step value to be able to show the tour again (if we dedide to show the tour only once, this must be removed)
|
|
||||||
{
|
|
||||||
user_id: currentUserId,
|
|
||||||
category: tourCategory,
|
|
||||||
name: currentUserId,
|
|
||||||
value: stepValue.toString(),
|
|
||||||
},
|
|
||||||
|
|
||||||
// this one is for defining the auto tour start for the tour tip
|
|
||||||
{
|
{
|
||||||
user_id: currentUserId,
|
user_id: currentUserId,
|
||||||
category: tourCategory,
|
category: tourCategory,
|
||||||
@@ -237,7 +225,6 @@ const WorkTemplateModal = () => {
|
|||||||
value: String(AutoTourStatus.ENABLED),
|
value: String(AutoTourStatus.ENABLED),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
await dispatch(savePreferences(currentUserId, preferences));
|
await dispatch(savePreferences(currentUserId, preferences));
|
||||||
|
|
||||||
dispatch(showRHSPlugin(pluginId));
|
dispatch(showRHSPlugin(pluginId));
|
||||||
@@ -285,7 +272,7 @@ const WorkTemplateModal = () => {
|
|||||||
dispatch(loadIfNecessaryAndSwitchToChannelById(firstChannelId));
|
dispatch(loadIfNecessaryAndSwitchToChannelById(firstChannelId));
|
||||||
}
|
}
|
||||||
|
|
||||||
await tourTipActions(template);
|
await tourTipActions(template, firstChannelId);
|
||||||
|
|
||||||
setIsCreating(false);
|
setIsCreating(false);
|
||||||
closeModal();
|
closeModal();
|
||||||
|
|||||||
@@ -31,10 +31,11 @@ export function getTemplateDefaultIllustration(template: WorkTemplate): string {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getContentCount = (template: WorkTemplate, playbookTemplates: PlaybookTemplateType[]) => {
|
export const getContentCount = (template: WorkTemplate, playbookTemplates: PlaybookTemplateType[], channelId: string) => {
|
||||||
const res = {
|
const res = {
|
||||||
playbooks: 0,
|
playbooks: 0,
|
||||||
boards: 0,
|
boards: 0,
|
||||||
|
channelId,
|
||||||
};
|
};
|
||||||
for (const item of template.content) {
|
for (const item of template.content) {
|
||||||
if (item.playbook) {
|
if (item.playbook) {
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export function clearWorkTemplates(): ActionFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// stores the linked product information in the state so it can be used to show the tourtip
|
// stores the linked product information in the state so it can be used to show the tourtip
|
||||||
export function onExecuteSuccess(data: Record<string, number>): ActionFunc {
|
export function onExecuteSuccess(data: Record<string, string | number>): ActionFunc {
|
||||||
return async (dispatch) => {
|
return async (dispatch) => {
|
||||||
dispatch({type: WorkTemplatesType.EXECUTE_SUCCESS, data});
|
dispatch({type: WorkTemplatesType.EXECUTE_SUCCESS, data});
|
||||||
return [];
|
return [];
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export type WorkTemplatesState = {
|
|||||||
categories: Category[];
|
categories: Category[];
|
||||||
templatesInCategory: Record<string, WorkTemplate[]>;
|
templatesInCategory: Record<string, WorkTemplate[]>;
|
||||||
playbookTemplates: PlaybookTemplateType[];
|
playbookTemplates: PlaybookTemplateType[];
|
||||||
linkedProducts: Record<string, number>;
|
linkedProducts: Record<string, string | number>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PlaybookTemplateType {
|
export interface PlaybookTemplateType {
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user