@strapi/admin 4.0.8 → 4.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/admin/src/components/AuthenticatedApp/index.js +25 -3
- package/admin/src/components/AuthenticatedApp/utils/api.js +15 -1
- package/admin/src/components/GuidedTour/Homepage/components/Step.js +61 -0
- package/admin/src/components/GuidedTour/Homepage/components/Stepper.js +58 -0
- package/admin/src/components/GuidedTour/Homepage/index.js +63 -0
- package/admin/src/components/GuidedTour/Modal/components/Content.js +50 -0
- package/admin/src/components/GuidedTour/Modal/components/Modal.js +75 -0
- package/admin/src/components/GuidedTour/Modal/components/StepNumberWithPadding.js +24 -0
- package/admin/src/components/GuidedTour/Modal/components/Stepper.js +119 -0
- package/admin/src/components/GuidedTour/Modal/index.js +90 -0
- package/admin/src/components/GuidedTour/Modal/reducer.js +29 -0
- package/admin/src/components/GuidedTour/Stepper/StepLine.js +27 -0
- package/admin/src/components/GuidedTour/Stepper/StepNumber.js +71 -0
- package/admin/src/components/GuidedTour/constants.js +3 -0
- package/admin/src/components/GuidedTour/index.js +100 -0
- package/admin/src/components/GuidedTour/init.js +36 -0
- package/admin/src/components/GuidedTour/layout.js +153 -0
- package/admin/src/components/GuidedTour/reducer.js +50 -0
- package/admin/src/components/GuidedTour/utils/arePreviousSectionsDone.js +13 -0
- package/admin/src/components/GuidedTour/utils/arePreviousStepsDone.js +12 -0
- package/admin/src/components/GuidedTour/utils/isGuidedTourCompleted.js +6 -0
- package/admin/src/components/GuidedTour/utils/persistStateToLocaleStorage.js +34 -0
- package/admin/src/components/Providers/index.js +4 -1
- package/admin/src/content-manager/components/CollectionTypeFormWrapper/index.js +14 -1
- package/admin/src/content-manager/components/DynamicTable/CellContent/CellValue.js +2 -1
- package/admin/src/content-manager/components/SingleTypeFormWrapper/index.js +5 -1
- package/admin/src/content-manager/pages/App/index.js +15 -2
- package/admin/src/content-manager/pages/ListSettingsView/components/DraggableCard.js +1 -1
- package/admin/src/content-manager/pages/ListSettingsView/components/SortDisplayedFields.js +22 -4
- package/admin/src/content-manager/pages/ListSettingsView/reducer.js +1 -1
- package/admin/src/pages/Admin/index.js +2 -0
- package/admin/src/pages/AuthPage/components/Register/index.js +11 -6
- package/admin/src/pages/AuthPage/index.js +15 -1
- package/admin/src/pages/HomePage/index.js +8 -2
- package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/ContentBox/index.js +1 -1
- package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/index.js +3 -0
- package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/index.js +10 -1
- package/admin/src/pages/SettingsPage/pages/Roles/ListPage/components/RoleRow/index.js +2 -2
- package/admin/src/translations/ar.json +0 -4
- package/admin/src/translations/cs.json +0 -6
- package/admin/src/translations/de.json +0 -12
- package/admin/src/translations/dk.json +158 -170
- package/admin/src/translations/en.json +43 -29
- package/admin/src/translations/es.json +15 -25
- package/admin/src/translations/fr.json +158 -169
- package/admin/src/translations/he.json +0 -10
- package/admin/src/translations/hu.json +16 -26
- package/admin/src/translations/id.json +0 -12
- package/admin/src/translations/it.json +0 -12
- package/admin/src/translations/ja.json +16 -28
- package/admin/src/translations/ko.json +663 -670
- package/admin/src/translations/ms.json +0 -6
- package/admin/src/translations/nl.json +16 -30
- package/admin/src/translations/no.json +0 -10
- package/admin/src/translations/pl.json +0 -12
- package/admin/src/translations/pt-BR.json +19 -29
- package/admin/src/translations/pt.json +0 -4
- package/admin/src/translations/ru.json +0 -12
- package/admin/src/translations/sk.json +0 -12
- package/admin/src/translations/sv.json +0 -4
- package/admin/src/translations/th.json +0 -12
- package/admin/src/translations/tr.json +0 -4
- package/admin/src/translations/uk.json +0 -6
- package/admin/src/translations/vi.json +0 -4
- package/admin/src/translations/zh-Hans.json +15 -25
- package/admin/src/translations/zh.json +24 -27
- package/build/2736.ee6e45c9.chunk.js +2 -0
- package/build/{460.639962f0.chunk.js.LICENSE.txt → 2736.ee6e45c9.chunk.js.LICENSE.txt} +0 -0
- package/build/4362.d0c1a04a.chunk.js +1 -0
- package/build/4800.18e59c83.chunk.js +1 -0
- package/build/{3215.4d042146.chunk.js → 8042.9b85175a.chunk.js} +2 -2
- package/build/{3215.4d042146.chunk.js.LICENSE.txt → 8042.9b85175a.chunk.js.LICENSE.txt} +0 -0
- package/build/9988.b4229043.chunk.js +2 -0
- package/build/{4741.c2bfe032.chunk.js.LICENSE.txt → 9988.b4229043.chunk.js.LICENSE.txt} +0 -0
- package/build/Admin-authenticatedApp.013e2774.chunk.js +1 -0
- package/build/Admin_homePage.e4779166.chunk.js +1 -0
- package/build/{Admin_settingsPage.05877e0b.chunk.js → Admin_settingsPage.2d0d2cca.chunk.js} +1 -1
- package/build/api-tokens-create-page.0981141a.chunk.js +1 -0
- package/build/api-tokens-edit-page.3faf1af1.chunk.js +1 -0
- package/build/{api-tokens-list-page.e071058b.chunk.js → api-tokens-list-page.26a05a21.chunk.js} +1 -1
- package/build/ar-json.6a2565af.chunk.js +1 -0
- package/build/content-manager.141d110d.chunk.js +1 -0
- package/build/{content-type-builder-translation-cs-json.2f7e2289.chunk.js → content-type-builder-translation-cs-json.89f7272e.chunk.js} +1 -1
- package/build/{content-type-builder-translation-de-json.46017754.chunk.js → content-type-builder-translation-de-json.0205697c.chunk.js} +1 -1
- package/build/content-type-builder-translation-dk-json.235ff56e.chunk.js +1 -0
- package/build/{content-type-builder-translation-en-json.d70fc3af.chunk.js → content-type-builder-translation-en-json.b3d8e9d4.chunk.js} +1 -1
- package/build/{content-type-builder-translation-es-json.20c177ee.chunk.js → content-type-builder-translation-es-json.13b2e2aa.chunk.js} +1 -1
- package/build/{content-type-builder-translation-fr-json.8f66eb66.chunk.js → content-type-builder-translation-fr-json.bee621f7.chunk.js} +1 -1
- package/build/{content-type-builder-translation-id-json.aab2f426.chunk.js → content-type-builder-translation-id-json.2fbf4f8c.chunk.js} +1 -1
- package/build/{content-type-builder-translation-it-json.4c91e895.chunk.js → content-type-builder-translation-it-json.a1afd7a9.chunk.js} +1 -1
- package/build/{content-type-builder-translation-ja-json.c239ba90.chunk.js → content-type-builder-translation-ja-json.1459fb88.chunk.js} +1 -1
- package/build/content-type-builder-translation-ko-json.d2080111.chunk.js +1 -0
- package/build/{content-type-builder-translation-ms-json.124be88c.chunk.js → content-type-builder-translation-ms-json.048122eb.chunk.js} +1 -1
- package/build/{content-type-builder-translation-nl-json.98a240b8.chunk.js → content-type-builder-translation-nl-json.8d59e86b.chunk.js} +1 -1
- package/build/{content-type-builder-translation-pl-json.2abc61bd.chunk.js → content-type-builder-translation-pl-json.01dc068c.chunk.js} +1 -1
- package/build/{content-type-builder-translation-pt-BR-json.c0415545.chunk.js → content-type-builder-translation-pt-BR-json.d311d056.chunk.js} +1 -1
- package/build/{content-type-builder-translation-pt-json.ab3e086d.chunk.js → content-type-builder-translation-pt-json.4893266f.chunk.js} +1 -1
- package/build/{content-type-builder-translation-ru-json.1a6779fd.chunk.js → content-type-builder-translation-ru-json.1285874d.chunk.js} +1 -1
- package/build/{content-type-builder-translation-sk-json.5c82f020.chunk.js → content-type-builder-translation-sk-json.0064156b.chunk.js} +1 -1
- package/build/{content-type-builder-translation-th-json.24ee19eb.chunk.js → content-type-builder-translation-th-json.5f690524.chunk.js} +1 -1
- package/build/{content-type-builder-translation-tr-json.30434835.chunk.js → content-type-builder-translation-tr-json.696283a5.chunk.js} +1 -1
- package/build/{content-type-builder-translation-uk-json.771662ef.chunk.js → content-type-builder-translation-uk-json.87496bf9.chunk.js} +1 -1
- package/build/{content-type-builder-translation-zh-Hans-json.070020ae.chunk.js → content-type-builder-translation-zh-Hans-json.283c640e.chunk.js} +1 -1
- package/build/{content-type-builder-translation-zh-json.9708310d.chunk.js → content-type-builder-translation-zh-json.77aa2275.chunk.js} +1 -1
- package/build/content-type-builder.f1cef05c.chunk.js +1 -0
- package/build/cs-json.8df09876.chunk.js +1 -0
- package/build/de-json.6e14f607.chunk.js +1 -0
- package/build/dk-json.be388470.chunk.js +1 -0
- package/build/en-json.bb614bb0.chunk.js +1 -0
- package/build/es-json.61553168.chunk.js +1 -0
- package/build/fr-json.a9ce0700.chunk.js +1 -0
- package/build/he-json.1742494e.chunk.js +1 -0
- package/build/hu-json.e667d285.chunk.js +1 -0
- package/build/i18n-translation-dk-json.ecf02d28.chunk.js +1 -0
- package/build/i18n-translation-en-json.4d823f62.chunk.js +1 -0
- package/build/i18n-translation-es-json.7049afa2.chunk.js +1 -0
- package/build/i18n-translation-fr-json.c6367bc9.chunk.js +1 -0
- package/build/i18n-translation-ko-json.aecb7e01.chunk.js +1 -0
- package/build/i18n-translation-zh-Hans-json.258b2e1a.chunk.js +1 -0
- package/build/id-json.d87ebb20.chunk.js +1 -0
- package/build/index.html +1 -1
- package/build/it-json.a2880b81.chunk.js +1 -0
- package/build/ja-json.46e29f04.chunk.js +1 -0
- package/build/ko-json.dd36fdc0.chunk.js +1 -0
- package/build/{main.59b96514.js → main.fc123ed7.js} +2 -2
- package/build/{main.59b96514.js.LICENSE.txt → main.fc123ed7.js.LICENSE.txt} +0 -0
- package/build/ms-json.3a062984.chunk.js +1 -0
- package/build/nl-json.30ce02cb.chunk.js +1 -0
- package/build/no-json.9af40e9d.chunk.js +1 -0
- package/build/pl-json.fd373053.chunk.js +1 -0
- package/build/pt-BR-json.30e2d716.chunk.js +1 -0
- package/build/pt-json.3aaf9e05.chunk.js +1 -0
- package/build/ru-json.78c56e1c.chunk.js +1 -0
- package/build/{runtime~main.75c67df1.js → runtime~main.0866074a.js} +1 -1
- package/build/sk-json.c0bf144c.chunk.js +1 -0
- package/build/sv-json.aad187b9.chunk.js +1 -0
- package/build/th-json.e2b4a0fb.chunk.js +1 -0
- package/build/tr-json.0add11cd.chunk.js +1 -0
- package/build/uk-json.eb78e77e.chunk.js +1 -0
- package/build/{upload-settings.62631a39.chunk.js → upload-settings.8e7cbc3b.chunk.js} +1 -1
- package/build/{upload-translation-de-json.00f90715.chunk.js → upload-translation-de-json.1308dce5.chunk.js} +1 -1
- package/build/upload-translation-dk-json.0d4e855f.chunk.js +1 -0
- package/build/upload-translation-en-json.c3373c8d.chunk.js +1 -0
- package/build/upload-translation-es-json.81b13eac.chunk.js +1 -0
- package/build/{upload-translation-fr-json.ccb4ad8b.chunk.js → upload-translation-fr-json.1bec79ec.chunk.js} +1 -1
- package/build/upload-translation-he-json.1d28982f.chunk.js +1 -0
- package/build/{upload-translation-it-json.c1809a47.chunk.js → upload-translation-it-json.7d4bdc5a.chunk.js} +1 -1
- package/build/{upload-translation-ja-json.71aa85eb.chunk.js → upload-translation-ja-json.97fcacd8.chunk.js} +1 -1
- package/build/upload-translation-ko-json.d7345fe1.chunk.js +1 -0
- package/build/{upload-translation-ms-json.be669f81.chunk.js → upload-translation-ms-json.081effd5.chunk.js} +1 -1
- package/build/{upload-translation-pl-json.67685825.chunk.js → upload-translation-pl-json.2dfe78bb.chunk.js} +1 -1
- package/build/{upload-translation-pt-BR-json.f7b1133d.chunk.js → upload-translation-pt-BR-json.65936d7b.chunk.js} +1 -1
- package/build/{upload-translation-ru-json.54c031aa.chunk.js → upload-translation-ru-json.2d3b6f69.chunk.js} +1 -1
- package/build/{upload-translation-sk-json.f643dfc2.chunk.js → upload-translation-sk-json.f15c7fd6.chunk.js} +1 -1
- package/build/upload-translation-th-json.6d3c2370.chunk.js +1 -0
- package/build/{upload-translation-uk-json.1a90e73c.chunk.js → upload-translation-uk-json.a6c38449.chunk.js} +1 -1
- package/build/{upload-translation-zh-Hans-json.ac1dc0b9.chunk.js → upload-translation-zh-Hans-json.f6b26c45.chunk.js} +1 -1
- package/build/{upload-translation-zh-json.164ac601.chunk.js → upload-translation-zh-json.06052336.chunk.js} +1 -1
- package/build/users-permissions-translation-dk-json.89d41c4b.chunk.js +1 -0
- package/build/vi-json.55a11ac0.chunk.js +1 -0
- package/build/zh-Hans-json.55f6475b.chunk.js +1 -0
- package/build/zh-json.c3c2b225.chunk.js +1 -0
- package/package.json +6 -6
- package/build/4362.e3d2d72b.chunk.js +0 -1
- package/build/460.639962f0.chunk.js +0 -2
- package/build/4741.c2bfe032.chunk.js +0 -2
- package/build/Admin-authenticatedApp.f65c428a.chunk.js +0 -1
- package/build/Admin_homePage.a20b5e76.chunk.js +0 -1
- package/build/api-tokens-create-page.10586e16.chunk.js +0 -1
- package/build/api-tokens-edit-page.f9e3038d.chunk.js +0 -1
- package/build/ar-json.d79e4709.chunk.js +0 -1
- package/build/content-manager.07db1dd9.chunk.js +0 -1
- package/build/content-type-builder-translation-dk-json.098bd218.chunk.js +0 -1
- package/build/content-type-builder-translation-ko-json.2a5e0769.chunk.js +0 -1
- package/build/content-type-builder.52f5975c.chunk.js +0 -1
- package/build/cs-json.b8ba75b8.chunk.js +0 -1
- package/build/de-json.e01bdeae.chunk.js +0 -1
- package/build/dk-json.7356ea4b.chunk.js +0 -1
- package/build/en-json.3422a59e.chunk.js +0 -1
- package/build/es-json.ed9c8bef.chunk.js +0 -1
- package/build/fr-json.390bcdeb.chunk.js +0 -1
- package/build/he-json.86f9e663.chunk.js +0 -1
- package/build/hu-json.a741d263.chunk.js +0 -1
- package/build/i18n-translation-dk-json.932d3cc2.chunk.js +0 -1
- package/build/i18n-translation-en-json.239b740f.chunk.js +0 -1
- package/build/i18n-translation-es-json.347904f3.chunk.js +0 -1
- package/build/i18n-translation-fr-json.b52474fc.chunk.js +0 -1
- package/build/i18n-translation-ko-json.e88e11ef.chunk.js +0 -1
- package/build/i18n-translation-zh-Hans-json.4c17fed0.chunk.js +0 -1
- package/build/id-json.0b0c9731.chunk.js +0 -1
- package/build/it-json.939916bc.chunk.js +0 -1
- package/build/ja-json.52581a2a.chunk.js +0 -1
- package/build/ko-json.29633034.chunk.js +0 -1
- package/build/ms-json.5e5d12f9.chunk.js +0 -1
- package/build/nl-json.ac661b7f.chunk.js +0 -1
- package/build/no-json.ff46b126.chunk.js +0 -1
- package/build/pl-json.6bff1d54.chunk.js +0 -1
- package/build/pt-BR-json.8b3f799d.chunk.js +0 -1
- package/build/pt-json.b23d9a79.chunk.js +0 -1
- package/build/ru-json.bff93229.chunk.js +0 -1
- package/build/sk-json.a40bc2c8.chunk.js +0 -1
- package/build/sv-json.8ac61ecf.chunk.js +0 -1
- package/build/th-json.6e4502a3.chunk.js +0 -1
- package/build/tr-json.eaca955b.chunk.js +0 -1
- package/build/uk-json.da2ed14e.chunk.js +0 -1
- package/build/upload-translation-dk-json.bc6af8b4.chunk.js +0 -1
- package/build/upload-translation-en-json.6b529046.chunk.js +0 -1
- package/build/upload-translation-es-json.b53d6641.chunk.js +0 -1
- package/build/upload-translation-he-json.5dc34ea8.chunk.js +0 -1
- package/build/upload-translation-ko-json.da369eef.chunk.js +0 -1
- package/build/upload-translation-th-json.88ee2090.chunk.js +0 -1
- package/build/users-permissions-translation-dk-json.3e0295e5.chunk.js +0 -1
- package/build/vi-json.e993857a.chunk.js +0 -1
- package/build/zh-Hans-json.5843950b.chunk.js +0 -1
- package/build/zh-json.2e4c9ef4.chunk.js +0 -1
|
@@ -1,19 +1,26 @@
|
|
|
1
|
-
import React, { useMemo, useState } from 'react';
|
|
1
|
+
import React, { useMemo, useState, useEffect, useRef } from 'react';
|
|
2
2
|
// TODO: DS add loader
|
|
3
|
-
import { auth, LoadingIndicatorPage, AppInfosContext } from '@strapi/helper-plugin';
|
|
3
|
+
import { auth, LoadingIndicatorPage, AppInfosContext, useGuidedTour } from '@strapi/helper-plugin';
|
|
4
4
|
import { useQueries } from 'react-query';
|
|
5
5
|
import get from 'lodash/get';
|
|
6
6
|
import packageJSON from '../../../../package.json';
|
|
7
7
|
import { useConfigurations } from '../../hooks';
|
|
8
8
|
import PluginsInitializer from '../PluginsInitializer';
|
|
9
9
|
import RBACProvider from '../RBACProvider';
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
fetchAppInfo,
|
|
12
|
+
fetchCurrentUserPermissions,
|
|
13
|
+
fetchStrapiLatestRelease,
|
|
14
|
+
fetchUserRoles,
|
|
15
|
+
} from './utils/api';
|
|
11
16
|
import checkLatestStrapiVersion from './utils/checkLatestStrapiVersion';
|
|
12
17
|
import { getFullName } from '../../utils';
|
|
13
18
|
|
|
14
19
|
const strapiVersion = packageJSON.version;
|
|
15
20
|
|
|
16
21
|
const AuthenticatedApp = () => {
|
|
22
|
+
const { setGuidedTourVisibility } = useGuidedTour();
|
|
23
|
+
const setGuidedTourVisibilityRef = useRef(setGuidedTourVisibility);
|
|
17
24
|
const userInfo = auth.getUserInfo();
|
|
18
25
|
const userName = get(userInfo, 'username') || getFullName(userInfo.firstname, userInfo.lastname);
|
|
19
26
|
const [userDisplayName, setUserDisplayName] = useState(userName);
|
|
@@ -22,6 +29,7 @@ const AuthenticatedApp = () => {
|
|
|
22
29
|
{ data: appInfos, status },
|
|
23
30
|
{ data: tag_name, isLoading },
|
|
24
31
|
{ data: permissions, status: fetchPermissionsStatus, refetch, isFetched, isFetching },
|
|
32
|
+
{ data: userRoles },
|
|
25
33
|
] = useQueries([
|
|
26
34
|
{ queryKey: 'app-infos', queryFn: fetchAppInfo },
|
|
27
35
|
{
|
|
@@ -35,12 +43,26 @@ const AuthenticatedApp = () => {
|
|
|
35
43
|
queryFn: fetchCurrentUserPermissions,
|
|
36
44
|
initialData: [],
|
|
37
45
|
},
|
|
46
|
+
{
|
|
47
|
+
queryKey: 'user-roles',
|
|
48
|
+
queryFn: fetchUserRoles,
|
|
49
|
+
},
|
|
38
50
|
]);
|
|
39
51
|
|
|
40
52
|
const shouldUpdateStrapi = useMemo(() => checkLatestStrapiVersion(strapiVersion, tag_name), [
|
|
41
53
|
tag_name,
|
|
42
54
|
]);
|
|
43
55
|
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
if (userRoles) {
|
|
58
|
+
const isUserSuperAdmin = userRoles.find(({ code }) => code === 'strapi-super-admin');
|
|
59
|
+
|
|
60
|
+
if (isUserSuperAdmin) {
|
|
61
|
+
setGuidedTourVisibilityRef.current(true);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}, [userRoles]);
|
|
65
|
+
|
|
44
66
|
// We don't need to wait for the release query to be fetched before rendering the plugins
|
|
45
67
|
// however, we need the appInfos and the permissions
|
|
46
68
|
const shouldShowNotDependentQueriesLoader =
|
|
@@ -45,4 +45,18 @@ const fetchCurrentUserPermissions = async () => {
|
|
|
45
45
|
}
|
|
46
46
|
};
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
const fetchUserRoles = async () => {
|
|
49
|
+
try {
|
|
50
|
+
const {
|
|
51
|
+
data: {
|
|
52
|
+
data: { roles },
|
|
53
|
+
},
|
|
54
|
+
} = await axiosInstance.get('/admin/users/me');
|
|
55
|
+
|
|
56
|
+
return roles;
|
|
57
|
+
} catch (err) {
|
|
58
|
+
throw new Error(err);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export { fetchAppInfo, fetchCurrentUserPermissions, fetchStrapiLatestRelease, fetchUserRoles };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useIntl } from 'react-intl';
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
import { pxToRem } from '@strapi/helper-plugin';
|
|
5
|
+
import { Typography } from '@strapi/design-system/Typography';
|
|
6
|
+
import { Box } from '@strapi/design-system/Box';
|
|
7
|
+
import { Flex } from '@strapi/design-system/Flex';
|
|
8
|
+
import StepNumber from '../../Stepper/StepNumber';
|
|
9
|
+
import StepLine from '../../Stepper/StepLine';
|
|
10
|
+
import { IS_DONE, IS_ACTIVE, IS_NOT_DONE } from '../../constants';
|
|
11
|
+
|
|
12
|
+
const StepHomepage = ({ type, title, number, content, hasLine }) => {
|
|
13
|
+
const { formatMessage } = useIntl();
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<Box>
|
|
17
|
+
<Flex>
|
|
18
|
+
<Box minWidth={pxToRem(30)} marginRight={5}>
|
|
19
|
+
<StepNumber type={type} number={number} />
|
|
20
|
+
</Box>
|
|
21
|
+
<Typography variant="delta" as="h3">
|
|
22
|
+
{formatMessage(title)}
|
|
23
|
+
</Typography>
|
|
24
|
+
</Flex>
|
|
25
|
+
<Flex alignItems="flex-start">
|
|
26
|
+
<Flex
|
|
27
|
+
justifyContent="center"
|
|
28
|
+
minWidth={pxToRem(30)}
|
|
29
|
+
marginBottom={3}
|
|
30
|
+
marginTop={3}
|
|
31
|
+
marginRight={5}
|
|
32
|
+
>
|
|
33
|
+
{hasLine && (
|
|
34
|
+
<StepLine type={type} minHeight={type === IS_ACTIVE ? pxToRem(85) : pxToRem(65)} />
|
|
35
|
+
)}
|
|
36
|
+
</Flex>
|
|
37
|
+
<Box marginTop={2}>{type === IS_ACTIVE && content}</Box>
|
|
38
|
+
</Flex>
|
|
39
|
+
</Box>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
StepHomepage.defaultProps = {
|
|
44
|
+
content: undefined,
|
|
45
|
+
number: undefined,
|
|
46
|
+
type: IS_NOT_DONE,
|
|
47
|
+
hasLine: true,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
StepHomepage.propTypes = {
|
|
51
|
+
content: PropTypes.node,
|
|
52
|
+
number: PropTypes.number,
|
|
53
|
+
title: PropTypes.shape({
|
|
54
|
+
id: PropTypes.string,
|
|
55
|
+
defaultMessage: PropTypes.string,
|
|
56
|
+
}).isRequired,
|
|
57
|
+
type: PropTypes.oneOf([IS_ACTIVE, IS_DONE, IS_NOT_DONE]),
|
|
58
|
+
hasLine: PropTypes.bool,
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export default StepHomepage;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { Box } from '@strapi/design-system/Box';
|
|
4
|
+
import StepHomepage from './Step';
|
|
5
|
+
import { IS_DONE, IS_ACTIVE, IS_NOT_DONE } from '../../constants';
|
|
6
|
+
|
|
7
|
+
const getType = (activeSectionIndex, index) => {
|
|
8
|
+
if (activeSectionIndex === -1) {
|
|
9
|
+
return IS_DONE;
|
|
10
|
+
}
|
|
11
|
+
if (index < activeSectionIndex) {
|
|
12
|
+
return IS_DONE;
|
|
13
|
+
}
|
|
14
|
+
if (index > activeSectionIndex) {
|
|
15
|
+
return IS_NOT_DONE;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return IS_ACTIVE;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const StepperHomepage = ({ sections, currentSectionKey }) => {
|
|
22
|
+
const activeSectionIndex = sections.findIndex(section => section.key === currentSectionKey);
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<Box>
|
|
26
|
+
{sections.map((section, index) => (
|
|
27
|
+
<StepHomepage
|
|
28
|
+
key={section.key}
|
|
29
|
+
title={section.title}
|
|
30
|
+
content={section.content}
|
|
31
|
+
number={index + 1}
|
|
32
|
+
type={getType(activeSectionIndex, index)}
|
|
33
|
+
hasLine={index !== sections.length - 1}
|
|
34
|
+
/>
|
|
35
|
+
))}
|
|
36
|
+
</Box>
|
|
37
|
+
);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
StepperHomepage.defaultProps = {
|
|
41
|
+
currentSectionKey: undefined,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
StepperHomepage.propTypes = {
|
|
45
|
+
sections: PropTypes.arrayOf(
|
|
46
|
+
PropTypes.shape({
|
|
47
|
+
key: PropTypes.string.isRequired,
|
|
48
|
+
title: PropTypes.shape({
|
|
49
|
+
id: PropTypes.string,
|
|
50
|
+
defaultMessage: PropTypes.string,
|
|
51
|
+
}).isRequired,
|
|
52
|
+
content: PropTypes.node,
|
|
53
|
+
})
|
|
54
|
+
).isRequired,
|
|
55
|
+
currentSectionKey: PropTypes.string,
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export default StepperHomepage;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useGuidedTour } from '@strapi/helper-plugin';
|
|
3
|
+
import { useIntl } from 'react-intl';
|
|
4
|
+
import { Stack } from '@strapi/design-system/Stack';
|
|
5
|
+
import { Flex } from '@strapi/design-system/Flex';
|
|
6
|
+
import { Box } from '@strapi/design-system/Box';
|
|
7
|
+
import { Typography } from '@strapi/design-system/Typography';
|
|
8
|
+
import { LinkButton } from '@strapi/design-system/LinkButton';
|
|
9
|
+
import { Button } from '@strapi/design-system/Button';
|
|
10
|
+
import ArrowRight from '@strapi/icons/ArrowRight';
|
|
11
|
+
import StepperHomepage from './components/Stepper';
|
|
12
|
+
import layout from '../layout';
|
|
13
|
+
|
|
14
|
+
const GuidedTourHomepage = () => {
|
|
15
|
+
const { guidedTourState, setSkipped } = useGuidedTour();
|
|
16
|
+
const { formatMessage } = useIntl();
|
|
17
|
+
|
|
18
|
+
const sections = Object.entries(layout).map(([key, val]) => ({
|
|
19
|
+
key,
|
|
20
|
+
title: val.home.title,
|
|
21
|
+
content: (
|
|
22
|
+
<LinkButton to={val.home.cta.target} endIcon={<ArrowRight />}>
|
|
23
|
+
{formatMessage(val.home.cta.title)}
|
|
24
|
+
</LinkButton>
|
|
25
|
+
),
|
|
26
|
+
}));
|
|
27
|
+
|
|
28
|
+
const enrichedSections = sections.map(section => ({
|
|
29
|
+
isDone: Object.entries(guidedTourState[section.key]).every(([, value]) => value),
|
|
30
|
+
...section,
|
|
31
|
+
}));
|
|
32
|
+
|
|
33
|
+
const activeSection = enrichedSections.find(section => !section.isDone)?.key;
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<Box
|
|
37
|
+
hasRadius
|
|
38
|
+
shadow="tableShadow"
|
|
39
|
+
paddingTop={7}
|
|
40
|
+
paddingRight={4}
|
|
41
|
+
paddingLeft={7}
|
|
42
|
+
paddingBottom={4}
|
|
43
|
+
background="neutral0"
|
|
44
|
+
>
|
|
45
|
+
<Stack size={6}>
|
|
46
|
+
<Typography variant="beta" as="h2">
|
|
47
|
+
{formatMessage({
|
|
48
|
+
id: 'app.components.GuidedTour.title',
|
|
49
|
+
defaultMessage: '3 steps to get started',
|
|
50
|
+
})}
|
|
51
|
+
</Typography>
|
|
52
|
+
<StepperHomepage sections={sections} currentSectionKey={activeSection} />
|
|
53
|
+
</Stack>
|
|
54
|
+
<Flex justifyContent="flex-end">
|
|
55
|
+
<Button variant="tertiary" onClick={() => setSkipped(true)}>
|
|
56
|
+
{formatMessage({ id: 'app.components.GuidedTour.skip', defaultMessage: 'Skip the tour' })}
|
|
57
|
+
</Button>
|
|
58
|
+
</Flex>
|
|
59
|
+
</Box>
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export default GuidedTourHomepage;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
import { Stack } from '@strapi/design-system/Stack';
|
|
5
|
+
import { Box } from '@strapi/design-system/Box';
|
|
6
|
+
import { Typography } from '@strapi/design-system/Typography';
|
|
7
|
+
import { useIntl } from 'react-intl';
|
|
8
|
+
|
|
9
|
+
const LiStyled = styled.li`
|
|
10
|
+
list-style: disc;
|
|
11
|
+
`;
|
|
12
|
+
|
|
13
|
+
const Content = ({ id, defaultMessage }) => {
|
|
14
|
+
const { formatMessage } = useIntl();
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<Stack size={4} paddingBottom={6}>
|
|
18
|
+
{formatMessage(
|
|
19
|
+
{ id, defaultMessage },
|
|
20
|
+
{
|
|
21
|
+
documentationLink: children => (
|
|
22
|
+
<a
|
|
23
|
+
target="_blank"
|
|
24
|
+
rel="noopener noreferrer"
|
|
25
|
+
href="https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest-api.html#api-parameters"
|
|
26
|
+
>
|
|
27
|
+
{children}
|
|
28
|
+
</a>
|
|
29
|
+
),
|
|
30
|
+
b: children => <Typography fontWeight="semiBold">{children}</Typography>,
|
|
31
|
+
p: children => <Typography>{children}</Typography>,
|
|
32
|
+
light: children => <Typography textColor="neutral600">{children}</Typography>,
|
|
33
|
+
ul: children => (
|
|
34
|
+
<Box paddingLeft={6}>
|
|
35
|
+
<ul>{children}</ul>
|
|
36
|
+
</Box>
|
|
37
|
+
),
|
|
38
|
+
li: children => <LiStyled>{children}</LiStyled>,
|
|
39
|
+
}
|
|
40
|
+
)}
|
|
41
|
+
</Stack>
|
|
42
|
+
);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
Content.propTypes = {
|
|
46
|
+
id: PropTypes.string.isRequired,
|
|
47
|
+
defaultMessage: PropTypes.string.isRequired,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export default Content;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
import { useIntl } from 'react-intl';
|
|
5
|
+
import { pxToRem } from '@strapi/helper-plugin';
|
|
6
|
+
import { Portal } from '@strapi/design-system/Portal';
|
|
7
|
+
import { FocusTrap } from '@strapi/design-system/FocusTrap';
|
|
8
|
+
import { Flex } from '@strapi/design-system/Flex';
|
|
9
|
+
import { Box } from '@strapi/design-system/Box';
|
|
10
|
+
import { Stack } from '@strapi/design-system/Stack';
|
|
11
|
+
import { IconButton } from '@strapi/design-system/IconButton';
|
|
12
|
+
import { Button } from '@strapi/design-system/Button';
|
|
13
|
+
import Cross from '@strapi/icons/Cross';
|
|
14
|
+
|
|
15
|
+
const ModalWrapper = styled(Flex)`
|
|
16
|
+
position: fixed;
|
|
17
|
+
z-index: 4;
|
|
18
|
+
inset: 0;
|
|
19
|
+
/* this is theme.colors.neutral800 with opacity */
|
|
20
|
+
background: ${({ theme }) => `${theme.colors.neutral800}33`};
|
|
21
|
+
`;
|
|
22
|
+
|
|
23
|
+
const Modal = ({ onClose, onSkip, children, hideSkip }) => {
|
|
24
|
+
const { formatMessage } = useIntl();
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<Portal>
|
|
28
|
+
<ModalWrapper onClick={onClose} padding={8} justifyContent="center">
|
|
29
|
+
<FocusTrap onEscape={onClose}>
|
|
30
|
+
<Stack
|
|
31
|
+
background="neutral0"
|
|
32
|
+
width={pxToRem(660)}
|
|
33
|
+
shadow="popupShadow"
|
|
34
|
+
hasRadius
|
|
35
|
+
padding={4}
|
|
36
|
+
size={8}
|
|
37
|
+
role="dialog"
|
|
38
|
+
aria-modal
|
|
39
|
+
onClick={e => e.stopPropagation()}
|
|
40
|
+
>
|
|
41
|
+
<Flex justifyContent="flex-end">
|
|
42
|
+
<IconButton
|
|
43
|
+
onClick={onClose}
|
|
44
|
+
aria-label={formatMessage({ id: 'app.utils.close-label', defaultMessage: 'Close' })}
|
|
45
|
+
icon={<Cross />}
|
|
46
|
+
/>
|
|
47
|
+
</Flex>
|
|
48
|
+
<Box paddingLeft={7} paddingRight={7} paddingBottom={hideSkip ? 8 : 0}>
|
|
49
|
+
{children}
|
|
50
|
+
</Box>
|
|
51
|
+
{!hideSkip && (
|
|
52
|
+
<Flex justifyContent="flex-end">
|
|
53
|
+
<Button variant="tertiary" onClick={onSkip}>
|
|
54
|
+
{formatMessage({
|
|
55
|
+
id: 'app.components.GuidedTour.skip',
|
|
56
|
+
defaultMessage: 'Skip the tour',
|
|
57
|
+
})}
|
|
58
|
+
</Button>
|
|
59
|
+
</Flex>
|
|
60
|
+
)}
|
|
61
|
+
</Stack>
|
|
62
|
+
</FocusTrap>
|
|
63
|
+
</ModalWrapper>
|
|
64
|
+
</Portal>
|
|
65
|
+
);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
Modal.propTypes = {
|
|
69
|
+
children: PropTypes.node.isRequired,
|
|
70
|
+
onClose: PropTypes.func.isRequired,
|
|
71
|
+
onSkip: PropTypes.func.isRequired,
|
|
72
|
+
hideSkip: PropTypes.bool.isRequired,
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export default Modal;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { Box } from '@strapi/design-system/Box';
|
|
4
|
+
import StepNumber from '../../Stepper/StepNumber';
|
|
5
|
+
|
|
6
|
+
const StepNumberWithPadding = ({ number, last, type }) => (
|
|
7
|
+
<Box paddingTop={3} paddingBottom={last ? 0 : 3}>
|
|
8
|
+
<StepNumber number={number} type={type} />
|
|
9
|
+
</Box>
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
StepNumberWithPadding.defaultProps = {
|
|
13
|
+
number: undefined,
|
|
14
|
+
last: false,
|
|
15
|
+
type: '',
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
StepNumberWithPadding.propTypes = {
|
|
19
|
+
number: PropTypes.number,
|
|
20
|
+
last: PropTypes.bool,
|
|
21
|
+
type: PropTypes.string,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export default StepNumberWithPadding;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { useIntl } from 'react-intl';
|
|
4
|
+
import { pxToRem } from '@strapi/helper-plugin';
|
|
5
|
+
import { Typography } from '@strapi/design-system/Typography';
|
|
6
|
+
import { Button } from '@strapi/design-system/Button';
|
|
7
|
+
import { LinkButton } from '@strapi/design-system/LinkButton';
|
|
8
|
+
import { Box } from '@strapi/design-system/Box';
|
|
9
|
+
import { Flex } from '@strapi/design-system/Flex';
|
|
10
|
+
import ArrowRight from '@strapi/icons/ArrowRight';
|
|
11
|
+
import Content from './Content';
|
|
12
|
+
import StepLine from '../../Stepper/StepLine';
|
|
13
|
+
import StepNumberWithPadding from './StepNumberWithPadding';
|
|
14
|
+
import { IS_DONE, IS_ACTIVE } from '../../constants';
|
|
15
|
+
|
|
16
|
+
const StepperModal = ({
|
|
17
|
+
title,
|
|
18
|
+
content,
|
|
19
|
+
cta,
|
|
20
|
+
onCtaClick,
|
|
21
|
+
sectionIndex,
|
|
22
|
+
stepIndex,
|
|
23
|
+
hasSectionAfter,
|
|
24
|
+
}) => {
|
|
25
|
+
const { formatMessage } = useIntl();
|
|
26
|
+
|
|
27
|
+
const hasSectionBefore = sectionIndex > 0;
|
|
28
|
+
const hasStepsBefore = stepIndex > 0;
|
|
29
|
+
const nextSectionIndex = sectionIndex + 1;
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<>
|
|
33
|
+
<Flex alignItems="stretch">
|
|
34
|
+
<Flex marginRight={8} justifyContent="center" minWidth={pxToRem(30)}>
|
|
35
|
+
{hasSectionBefore && <StepLine type={IS_DONE} minHeight={pxToRem(24)} />}
|
|
36
|
+
</Flex>
|
|
37
|
+
<Typography variant="sigma" textColor="primary600">
|
|
38
|
+
{formatMessage({
|
|
39
|
+
id: 'app.components.GuidedTour.title',
|
|
40
|
+
defaultMessage: '3 steps to get started',
|
|
41
|
+
})}
|
|
42
|
+
</Typography>
|
|
43
|
+
</Flex>
|
|
44
|
+
<Flex>
|
|
45
|
+
<Flex marginRight={8} minWidth={pxToRem(30)}>
|
|
46
|
+
<StepNumberWithPadding
|
|
47
|
+
number={sectionIndex + 1}
|
|
48
|
+
type={hasStepsBefore ? IS_DONE : IS_ACTIVE}
|
|
49
|
+
/>
|
|
50
|
+
</Flex>
|
|
51
|
+
<Typography variant="alpha" fontWeight="bold" textColor="neutral800" as="h3" id="title">
|
|
52
|
+
{formatMessage(title)}
|
|
53
|
+
</Typography>
|
|
54
|
+
</Flex>
|
|
55
|
+
<Flex alignItems="stretch">
|
|
56
|
+
<Flex marginRight={8} direction="column" justifyContent="center" minWidth={pxToRem(30)}>
|
|
57
|
+
{hasSectionAfter && (
|
|
58
|
+
<>
|
|
59
|
+
<StepLine type={IS_DONE} />
|
|
60
|
+
{hasStepsBefore && (
|
|
61
|
+
<StepNumberWithPadding number={nextSectionIndex + 1} type={IS_ACTIVE} last />
|
|
62
|
+
)}
|
|
63
|
+
</>
|
|
64
|
+
)}
|
|
65
|
+
</Flex>
|
|
66
|
+
<Box>
|
|
67
|
+
<Content {...content} />
|
|
68
|
+
{cta &&
|
|
69
|
+
(cta.target ? (
|
|
70
|
+
<LinkButton endIcon={<ArrowRight />} onClick={onCtaClick} to={cta.target}>
|
|
71
|
+
{formatMessage(cta.title)}
|
|
72
|
+
</LinkButton>
|
|
73
|
+
) : (
|
|
74
|
+
<Button endIcon={<ArrowRight />} onClick={onCtaClick}>
|
|
75
|
+
{formatMessage(cta.title)}
|
|
76
|
+
</Button>
|
|
77
|
+
))}
|
|
78
|
+
</Box>
|
|
79
|
+
</Flex>
|
|
80
|
+
{hasStepsBefore && hasSectionAfter && (
|
|
81
|
+
<Box paddingTop={3}>
|
|
82
|
+
<Flex marginRight={8} justifyContent="center" width={pxToRem(30)}>
|
|
83
|
+
<StepLine type={IS_DONE} minHeight={pxToRem(24)} />
|
|
84
|
+
</Flex>
|
|
85
|
+
</Box>
|
|
86
|
+
)}
|
|
87
|
+
</>
|
|
88
|
+
);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
StepperModal.defaultProps = {
|
|
92
|
+
currentStep: null,
|
|
93
|
+
cta: undefined,
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
StepperModal.propTypes = {
|
|
97
|
+
sectionIndex: PropTypes.number.isRequired,
|
|
98
|
+
stepIndex: PropTypes.number.isRequired,
|
|
99
|
+
hasSectionAfter: PropTypes.bool.isRequired,
|
|
100
|
+
content: PropTypes.shape({
|
|
101
|
+
id: PropTypes.string.isRequired,
|
|
102
|
+
defaultMessage: PropTypes.string.isRequired,
|
|
103
|
+
}).isRequired,
|
|
104
|
+
cta: PropTypes.shape({
|
|
105
|
+
target: PropTypes.string,
|
|
106
|
+
title: PropTypes.shape({
|
|
107
|
+
id: PropTypes.string.isRequired,
|
|
108
|
+
defaultMessage: PropTypes.string.isRequired,
|
|
109
|
+
}),
|
|
110
|
+
}),
|
|
111
|
+
currentStep: PropTypes.string,
|
|
112
|
+
onCtaClick: PropTypes.func.isRequired,
|
|
113
|
+
title: PropTypes.shape({
|
|
114
|
+
id: PropTypes.string.isRequired,
|
|
115
|
+
defaultMessage: PropTypes.string.isRequired,
|
|
116
|
+
}).isRequired,
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
export default StepperModal;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import React, { useEffect, useState, useReducer } from 'react';
|
|
2
|
+
import at from 'lodash/at';
|
|
3
|
+
import { useGuidedTour } from '@strapi/helper-plugin';
|
|
4
|
+
import layout from '../layout';
|
|
5
|
+
import Modal from './components/Modal';
|
|
6
|
+
import reducer, { initialState } from './reducer';
|
|
7
|
+
import StepperModal from './components/Stepper';
|
|
8
|
+
|
|
9
|
+
const GuidedTourModal = () => {
|
|
10
|
+
const {
|
|
11
|
+
currentStep,
|
|
12
|
+
guidedTourState,
|
|
13
|
+
setCurrentStep,
|
|
14
|
+
setStepState,
|
|
15
|
+
isGuidedTourVisible,
|
|
16
|
+
setSkipped,
|
|
17
|
+
} = useGuidedTour();
|
|
18
|
+
const [isVisible, setIsVisible] = useState(currentStep);
|
|
19
|
+
const [
|
|
20
|
+
{ stepContent, sectionIndex, stepIndex, hasSectionAfter, hasStepAfter },
|
|
21
|
+
dispatch,
|
|
22
|
+
] = useReducer(reducer, initialState);
|
|
23
|
+
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (!currentStep) {
|
|
26
|
+
setIsVisible(false);
|
|
27
|
+
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const [isStepDone] = at(guidedTourState, currentStep);
|
|
32
|
+
|
|
33
|
+
setIsVisible(!isStepDone && isGuidedTourVisible);
|
|
34
|
+
}, [currentStep, guidedTourState, isGuidedTourVisible]);
|
|
35
|
+
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
if (currentStep) {
|
|
38
|
+
const [content] = at(layout, currentStep);
|
|
39
|
+
const sectionKeys = Object.keys(guidedTourState);
|
|
40
|
+
const [sectionName, stepName] = currentStep.split('.');
|
|
41
|
+
const newSectionIndex = sectionKeys.indexOf(sectionName);
|
|
42
|
+
const newStepIndex = Object.keys(guidedTourState[sectionName]).indexOf(stepName);
|
|
43
|
+
const newHasSectionAfter = newSectionIndex < sectionKeys.length - 1;
|
|
44
|
+
const newHasStepAfter = newStepIndex < Object.keys(guidedTourState[sectionName]).length - 1;
|
|
45
|
+
|
|
46
|
+
dispatch({
|
|
47
|
+
type: 'UPDATE_MODAL',
|
|
48
|
+
content,
|
|
49
|
+
newSectionIndex,
|
|
50
|
+
newStepIndex,
|
|
51
|
+
newHasSectionAfter,
|
|
52
|
+
newHasStepAfter,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}, [currentStep, guidedTourState]);
|
|
56
|
+
|
|
57
|
+
const handleCtaClick = () => {
|
|
58
|
+
setStepState(currentStep, true);
|
|
59
|
+
|
|
60
|
+
setCurrentStep(null);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const handleSkip = () => {
|
|
64
|
+
setSkipped(true);
|
|
65
|
+
setCurrentStep(null);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
if (isVisible && stepContent) {
|
|
69
|
+
return (
|
|
70
|
+
<Modal
|
|
71
|
+
hideSkip={!hasStepAfter && !hasSectionAfter}
|
|
72
|
+
onSkip={handleSkip}
|
|
73
|
+
onClose={handleCtaClick}
|
|
74
|
+
>
|
|
75
|
+
<StepperModal
|
|
76
|
+
{...stepContent}
|
|
77
|
+
onCtaClick={handleCtaClick}
|
|
78
|
+
currentStep={currentStep}
|
|
79
|
+
sectionIndex={sectionIndex}
|
|
80
|
+
stepIndex={stepIndex}
|
|
81
|
+
hasSectionAfter={hasSectionAfter}
|
|
82
|
+
/>
|
|
83
|
+
</Modal>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return null;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export default GuidedTourModal;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/* eslint-disable consistent-return */
|
|
2
|
+
import produce from 'immer';
|
|
3
|
+
|
|
4
|
+
export const initialState = {
|
|
5
|
+
stepContent: null,
|
|
6
|
+
sectionIndex: null,
|
|
7
|
+
stepIndex: null,
|
|
8
|
+
hasSectionAfter: false,
|
|
9
|
+
hasStepAfter: false,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const reducer = (state = initialState, action) =>
|
|
13
|
+
produce(state, draftState => {
|
|
14
|
+
switch (action.type) {
|
|
15
|
+
case 'UPDATE_MODAL': {
|
|
16
|
+
draftState.stepContent = action.content;
|
|
17
|
+
draftState.sectionIndex = action.newSectionIndex;
|
|
18
|
+
draftState.stepIndex = action.newStepIndex;
|
|
19
|
+
draftState.hasSectionAfter = action.newHasSectionAfter;
|
|
20
|
+
draftState.hasStepAfter = action.newHasStepAfter;
|
|
21
|
+
break;
|
|
22
|
+
}
|
|
23
|
+
default: {
|
|
24
|
+
return draftState;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
export default reducer;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { pxToRem } from '@strapi/helper-plugin';
|
|
4
|
+
import { Box } from '@strapi/design-system/Box';
|
|
5
|
+
import { IS_DONE, IS_ACTIVE, IS_NOT_DONE } from '../constants';
|
|
6
|
+
|
|
7
|
+
const StepLine = ({ type, ...props }) => {
|
|
8
|
+
return (
|
|
9
|
+
<Box
|
|
10
|
+
width={pxToRem(2)}
|
|
11
|
+
height="100%"
|
|
12
|
+
background={type === IS_NOT_DONE ? 'neutral300' : 'primary500'}
|
|
13
|
+
hasRadius
|
|
14
|
+
{...props}
|
|
15
|
+
/>
|
|
16
|
+
);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
StepLine.defaultProps = {
|
|
20
|
+
type: IS_NOT_DONE,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
StepLine.propTypes = {
|
|
24
|
+
type: PropTypes.oneOf([IS_ACTIVE, IS_DONE, IS_NOT_DONE]),
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export default StepLine;
|