From 5623497e3248578abd8b440ab59a419da2ca96b9 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Tue, 12 Mar 2024 10:48:27 -0400 Subject: [PATCH] Add sample JoyRide walkthrough. --- client/package-lock.json | 151 ++++++++++++++++++ client/package.json | 1 + .../components/header/header.component.jsx | 2 + .../jobs-list/jobs-list.component.jsx | 120 ++++++++------ .../pages/manage/manage.page.component.jsx | 134 ++++++++++------ .../redux/application/application.actions.js | 8 + .../redux/application/application.reducer.js | 8 + .../application/application.selectors.js | 8 + .../redux/application/application.types.js | 4 +- 9 files changed, 339 insertions(+), 97 deletions(-) diff --git a/client/package-lock.json b/client/package-lock.json index 7ac51e2b5..116868638 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -66,6 +66,7 @@ "react-icons": "^5.0.1", "react-image-lightbox": "^5.1.4", "react-intersection-observer": "^9.8.1", + "react-joyride": "^2.7.4", "react-markdown": "^9.0.1", "react-number-format": "^5.1.4", "react-redux": "^9.1.0", @@ -3459,6 +3460,39 @@ "version": "0.10.5", "license": "Apache-2.0" }, + "node_modules/@gilbarbara/deep-equal": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@gilbarbara/deep-equal/-/deep-equal-0.3.1.tgz", + "integrity": "sha512-I7xWjLs2YSVMc5gGx1Z3ZG1lgFpITPndpi8Ku55GeEIKpACCPQNS/OTqQbxgTCfq0Ncvcc+CrFov96itVh6Qvw==" + }, + "node_modules/@gilbarbara/helpers": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@gilbarbara/helpers/-/helpers-0.9.2.tgz", + "integrity": "sha512-vrydO6+8jOpzPaJ9Om2Ta6BStbpxBlg7j0uV27NnokG+k6bI95ys7rrw7P4hOcRYajkp+K/XpyLufFUUfYrKTQ==", + "dependencies": { + "@gilbarbara/types": "^0.2.2", + "is-lite": "^1.2.1" + } + }, + "node_modules/@gilbarbara/types": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@gilbarbara/types/-/types-0.2.2.tgz", + "integrity": "sha512-QuQDBRRcm1Q8AbSac2W1YElurOhprj3Iko/o+P1fJxUWS4rOGKMVli98OXS7uo4z+cKAif6a+L9bcZFSyauQpQ==", + "dependencies": { + "type-fest": "^4.1.0" + } + }, + "node_modules/@gilbarbara/types/node_modules/type-fest": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.12.0.tgz", + "integrity": "sha512-5Y2/pp2wtJk8o08G0CMkuFPCO354FGwk/vbidxrdhRGZfd0tFnb4Qb8anp9XxXriwBgVPjdWbKpGl4J9lJY2jQ==", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@graphql-typed-document-node/core": { "version": "3.2.0", "license": "MIT", @@ -15011,6 +15045,11 @@ "node": ">=8" } }, + "node_modules/is-lite": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-lite/-/is-lite-1.2.1.tgz", + "integrity": "sha512-pgF+L5bxC+10hLBgf6R2P4ZZUBOQIIacbdo8YvuCP8/JvsWxG7aZ9p10DYuLtifFci4l3VITphhMlMV4Y+urPw==" + }, "node_modules/is-map": { "version": "2.0.2", "license": "MIT", @@ -20194,6 +20233,16 @@ "node": ">=4" } }, + "node_modules/popper.js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", + "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==", + "deprecated": "You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/possible-typed-array-names": { "version": "1.0.0", "license": "MIT", @@ -22642,6 +22691,41 @@ "version": "6.0.11", "license": "MIT" }, + "node_modules/react-floater": { + "version": "0.7.9", + "resolved": "https://registry.npmjs.org/react-floater/-/react-floater-0.7.9.tgz", + "integrity": "sha512-NXqyp9o8FAXOATOEo0ZpyaQ2KPb4cmPMXGWkx377QtJkIXHlHRAGer7ai0r0C1kG5gf+KJ6Gy+gdNIiosvSicg==", + "dependencies": { + "deepmerge": "^4.3.1", + "is-lite": "^0.8.2", + "popper.js": "^1.16.0", + "prop-types": "^15.8.1", + "tree-changes": "^0.9.1" + }, + "peerDependencies": { + "react": "15 - 18", + "react-dom": "15 - 18" + } + }, + "node_modules/react-floater/node_modules/@gilbarbara/deep-equal": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@gilbarbara/deep-equal/-/deep-equal-0.1.2.tgz", + "integrity": "sha512-jk+qzItoEb0D0xSSmrKDDzf9sheQj/BAPxlgNxgmOaA3mxpUa6ndJLYGZKsJnIVEQSD8zcTbyILz7I0HcnBCRA==" + }, + "node_modules/react-floater/node_modules/is-lite": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/is-lite/-/is-lite-0.8.2.tgz", + "integrity": "sha512-JZfH47qTsslwaAsqbMI3Q6HNNjUuq6Cmzzww50TdP5Esb6e1y2sK2UAaZZuzfAzpoI2AkxoPQapZdlDuP6Vlsw==" + }, + "node_modules/react-floater/node_modules/tree-changes": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/tree-changes/-/tree-changes-0.9.3.tgz", + "integrity": "sha512-vvvS+O6kEeGRzMglTKbc19ltLWNtmNt1cpBoSYLj/iEcPVvpJasemKOlxBrmZaCtDJoF+4bwv3m01UKYi8mukQ==", + "dependencies": { + "@gilbarbara/deep-equal": "^0.1.1", + "is-lite": "^0.8.2" + } + }, "node_modules/react-grid-gallery": { "version": "1.0.0", "license": "MIT", @@ -22703,6 +22787,15 @@ "react-dom": "16.x || 17.x" } }, + "node_modules/react-innertext": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/react-innertext/-/react-innertext-1.1.5.tgz", + "integrity": "sha512-PWAqdqhxhHIv80dT9znP2KvS+hfkbRovFp4zFYHFFlOoQLRiawIic81gKb3U1wEyJZgMwgs3JoLtwryASRWP3Q==", + "peerDependencies": { + "@types/react": ">=0.0.0 <=99", + "react": ">=0.0.0 <=99" + } + }, "node_modules/react-intersection-observer": { "version": "9.8.1", "license": "MIT", @@ -22720,6 +22813,45 @@ "version": "16.13.1", "license": "MIT" }, + "node_modules/react-joyride": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/react-joyride/-/react-joyride-2.7.4.tgz", + "integrity": "sha512-7MPuqM/z3g9iqCJZnmKNM2RArNgqYBpM8iknny4KjrHp/2wXlPtFL0LpqGiBhtiC0dCC2xe3pNpD9GdLZ2NxMA==", + "dependencies": { + "@gilbarbara/deep-equal": "^0.3.1", + "@gilbarbara/helpers": "^0.9.2", + "deep-diff": "^1.0.2", + "deepmerge": "^4.3.1", + "is-lite": "^1.2.1", + "react-floater": "^0.7.9", + "react-innertext": "^1.1.5", + "react-is": "^16.13.1", + "scroll": "^3.0.1", + "scrollparent": "^2.1.0", + "tree-changes": "^0.11.2", + "type-fest": "^4.10.2" + }, + "peerDependencies": { + "react": "15 - 18", + "react-dom": "15 - 18" + } + }, + "node_modules/react-joyride/node_modules/deep-diff": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/deep-diff/-/deep-diff-1.0.2.tgz", + "integrity": "sha512-aWS3UIVH+NPGCD1kki+DCU9Dua032iSsO43LqQpcs4R3+dVv7tX0qBGjiVHJHjplsoUM2XRO/KB92glqc68awg==" + }, + "node_modules/react-joyride/node_modules/type-fest": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.12.0.tgz", + "integrity": "sha512-5Y2/pp2wtJk8o08G0CMkuFPCO354FGwk/vbidxrdhRGZfd0tFnb4Qb8anp9XxXriwBgVPjdWbKpGl4J9lJY2jQ==", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/react-lifecycles-compat": { "version": "3.0.4", "license": "MIT" @@ -23946,6 +24078,11 @@ "version": "0.4.1", "license": "MIT" }, + "node_modules/scroll": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scroll/-/scroll-3.0.1.tgz", + "integrity": "sha512-pz7y517OVls1maEzlirKO5nPYle9AXsFzTMNJrRGmT951mzpIBy7sNHOg5o/0MQd/NqliCiWnAi0kZneMPFLcg==" + }, "node_modules/scroll-into-view-if-needed": { "version": "3.1.0", "license": "MIT", @@ -23953,6 +24090,11 @@ "compute-scroll-into-view": "^3.0.2" } }, + "node_modules/scrollparent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/scrollparent/-/scrollparent-2.1.0.tgz", + "integrity": "sha512-bnnvJL28/Rtz/kz2+4wpBjHzWoEzXhVg/TE8BeVGJHUqE8THNIRnDxDWMktwM+qahvlRdvlLdsQfYe+cuqfZeA==" + }, "node_modules/seedrandom": { "version": "3.0.5", "license": "MIT" @@ -25834,6 +25976,15 @@ "version": "0.0.3", "license": "MIT" }, + "node_modules/tree-changes": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/tree-changes/-/tree-changes-0.11.2.tgz", + "integrity": "sha512-4gXlUthrl+RabZw6lLvcCDl6KfJOCmrC16BC5CRdut1EAH509Omgg0BfKLY+ViRlzrvYOTWR0FMS2SQTwzumrw==", + "dependencies": { + "@gilbarbara/deep-equal": "^0.3.1", + "is-lite": "^1.2.0" + } + }, "node_modules/trim-lines": { "version": "3.0.1", "license": "MIT", diff --git a/client/package.json b/client/package.json index 35e93f763..260c6bcda 100644 --- a/client/package.json +++ b/client/package.json @@ -66,6 +66,7 @@ "react-icons": "^5.0.1", "react-image-lightbox": "^5.1.4", "react-intersection-observer": "^9.8.1", + "react-joyride": "^2.7.4", "react-markdown": "^9.0.1", "react-number-format": "^5.1.4", "react-redux": "^9.1.0", diff --git a/client/src/components/header/header.component.jsx b/client/src/components/header/header.component.jsx index dbe4bb026..20dae0de5 100644 --- a/client/src/components/header/header.component.jsx +++ b/client/src/components/header/header.component.jsx @@ -299,6 +299,7 @@ function Header({ }, { key: 'jobssubmenu', + id: 'header-jobs', icon: , label: t('menus.header.jobs'), children: [ @@ -319,6 +320,7 @@ function Header({ }, { key: 'availablejobs', + id: 'header-jobs-available', icon: , label: {t('menus.header.availablejobs')}, }, diff --git a/client/src/components/jobs-list/jobs-list.component.jsx b/client/src/components/jobs-list/jobs-list.component.jsx index e5b708fed..80dcd512f 100644 --- a/client/src/components/jobs-list/jobs-list.component.jsx +++ b/client/src/components/jobs-list/jobs-list.component.jsx @@ -16,12 +16,18 @@ import useLocalStorage from "../../utils/useLocalStorage"; import AlertComponent from "../alert/alert.component"; import ChatOpenButton from "../chat-open-button/chat-open-button.component"; import OwnerNameDisplay from "../owner-name-display/owner-name-display.component"; +import { setJoyRideSteps } from "../../redux/application/application.actions"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, }); -export function JobsList({bodyshop}) { +const mapDispatchToProps = (dispatch) => ({ + setJoyRideSteps: (steps) => dispatch(setJoyRideSteps(steps)), + +}); + +export function JobsList({bodyshop,setJoyRideSteps}) { const searchParams = queryString.parse(useLocation().search); const {selected} = searchParams; const selectedBreakpoint = Object.entries(Grid.useBreakpoint()) @@ -352,51 +358,75 @@ export function JobsList({bodyshop}) { }; return ( - - - { - setSearchText(e.target.value); - }} - value={searchText} - enterButton - /> - - } - > - { - handleOnRowClick(record); - }, - selectedRowKeys: [selected], - type: "radio", - }} - onChange={handleTableChange} - onRow={(record, rowIndex) => { - return { - onClick: (event) => { - handleOnRowClick(record); - }, - }; - }} + + + + { + setSearchText(e.target.value); + }} + value={searchText} + enterButton /> - + + } + > +
{ + handleOnRowClick(record); + }, + selectedRowKeys: [selected], + type: 'radio', + }} + onChange={handleTableChange} + onRow={(record, rowIndex) => { + return { + onClick: (event) => { + handleOnRowClick(record); + }, + }; + }} + /> + ); } -export default connect(mapStateToProps, null)(JobsList); +export default connect(mapStateToProps, mapDispatchToProps)(JobsList); diff --git a/client/src/pages/manage/manage.page.component.jsx b/client/src/pages/manage/manage.page.component.jsx index 801b46f4d..3dd482974 100644 --- a/client/src/pages/manage/manage.page.component.jsx +++ b/client/src/pages/manage/manage.page.component.jsx @@ -1,29 +1,32 @@ -import {FloatButton, Layout, Spin} from "antd"; +import { FloatButton, Layout, Spin } from "antd"; // import preval from "preval.macro"; -import React, {lazy, Suspense, useEffect, useState} from "react"; -import {useTranslation} from "react-i18next"; -import {connect} from "react-redux"; -import {Link, Route, Routes} from "react-router-dom"; -import {createStructuredSelector} from "reselect"; +import React, { lazy, Suspense, useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { connect } from "react-redux"; +import { Link, Route, Routes } from "react-router-dom"; +import { createStructuredSelector } from "reselect"; import BreadCrumbs from "../../components/breadcrumbs/breadcrumbs.component"; import ChatAffixContainer from "../../components/chat-affix/chat-affix.container"; import ConflictComponent from "../../components/conflict/conflict.component"; import ErrorBoundary from "../../components/error-boundary/error-boundary.component"; //import FooterComponent from "../../components/footer/footer.component"; //Component Imports +import * as Sentry from "@sentry/react"; +import Joyride from 'react-joyride'; +import TestComponent from "../../components/_test/test.page"; import HeaderContainer from "../../components/header/header.container"; import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component"; import PartnerPingComponent from "../../components/partner-ping/partner-ping.component"; import PrintCenterModalContainer from "../../components/print-center-modal/print-center-modal.container"; import ShopSubStatusComponent from "../../components/shop-sub-status/shop-sub-status.component"; -import TestComponent from "../../components/_test/test.page"; -import {requestForToken} from "../../firebase/firebase.utils"; -import {selectBodyshop, selectInstanceConflict,} from "../../redux/user/user.selectors"; -import * as Sentry from "@sentry/react"; +import { requestForToken } from "../../firebase/firebase.utils"; +import { selectBodyshop, selectInstanceConflict, } from "../../redux/user/user.selectors"; -import "./manage.page.styles.scss"; import UpdateAlert from "../../components/update-alert/update-alert.component"; +import { setJoyRideFinished } from "../../redux/application/application.actions.js"; +import { selectEnableJoyRide, selectJoyRideSteps } from "../../redux/application/application.selectors.js"; import InstanceRenderManager from "../../utils/instanceRenderMgr.js"; +import "./manage.page.styles.scss"; const JobsPage = lazy(() => import("../jobs/jobs.page")); @@ -179,12 +182,22 @@ const TtApprovals = lazy(() => const {Content, Footer} = Layout; + + const mapStateToProps = createStructuredSelector({ conflict: selectInstanceConflict, bodyshop: selectBodyshop, + enableJoyRide: selectEnableJoyRide, + joyRideSteps: selectJoyRideSteps }); -export function Manage({conflict, bodyshop}) { + +const mapDispatchToProps = (dispatch) => ({ + setJoyRideFinished: (steps) => dispatch(setJoyRideFinished(steps)), + +}); + +export function Manage({conflict, bodyshop,enableJoyRide,joyRideSteps,setJoyRideFinished}) { const {t} = useTranslation(); const [chatVisible] = useState(false); @@ -469,46 +482,65 @@ export function Manage({conflict, bodyshop}) { else PageContent = AppRouteTable; return ( - <> - - - - - - - } showDialog> - {PageContent} - + <> + + + + + + { + if (props.action === 'reset') { + setJoyRideFinished(); + } + }} + /> + + } showDialog> + {PageContent} + - - - -
-
-
-
- {`${InstanceRenderManager({imex: t("titles.imexonline"), rome: t("titles.romeonline"), promanager:t("titles.promanager")})} ${ - import.meta.env.VITE_APP_GIT_SHA || 'Local Build' - } - ${import.meta.env.VITE_APP_GIT_SHA_DATE}`} -
-
-
- - Disclaimer & Notices - -
-
-
- + +
+
+
+
+ {`Joy Ride Status: ${enableJoyRide}`} +
+ {`${InstanceRenderManager({ + imex: t('titles.imexonline'), + rome: t('titles.romeonline'), + promanager: t('titles.promanager'), + })} ${import.meta.env.VITE_APP_GIT_SHA || 'Local Build'} - ${ + import.meta.env.VITE_APP_GIT_SHA_DATE + }`} +
+
+
+ + Disclaimer & Notices + +
+
+
+ ); } -export default connect(mapStateToProps, null)(Manage); +export default connect(mapStateToProps, mapDispatchToProps)(Manage); diff --git a/client/src/redux/application/application.actions.js b/client/src/redux/application/application.actions.js index df1813a9b..350585ff9 100644 --- a/client/src/redux/application/application.actions.js +++ b/client/src/redux/application/application.actions.js @@ -67,3 +67,11 @@ export const setUpdateAvailable = (isUpdateAvailable) => ({ type: ApplicationActionTypes.SET_UPDATE_AVAILABLE, payload: isUpdateAvailable, }); +export const setJoyRideSteps = (steps) => ({ + type: ApplicationActionTypes.SET_JOYRIDE_STEPS, + payload: steps, +}); +export const setJoyRideFinished = () => ({ + type: ApplicationActionTypes.SET_JOYRIDE_FINISHED, + //payload: isUpdateAvailable, +}); diff --git a/client/src/redux/application/application.reducer.js b/client/src/redux/application/application.reducer.js index e9f66a910..79fb829e2 100644 --- a/client/src/redux/application/application.reducer.js +++ b/client/src/redux/application/application.reducer.js @@ -15,6 +15,8 @@ const INITIAL_STATE = { }, jobReadOnly: false, partnerVersion: null, + enableJoyRide: false, + joyRideSteps: [] }; const applicationReducer = (state = INITIAL_STATE, action) => { @@ -87,6 +89,12 @@ const applicationReducer = (state = INITIAL_STATE, action) => { case ApplicationActionTypes.SET_PROBLEM_JOBS: { return {...state, problemJobs: action.payload}; } + case ApplicationActionTypes.SET_JOYRIDE_STEPS: { + return {...state, enableJoyRide:true, joyRideSteps: action.payload} + } + case ApplicationActionTypes.SET_JOYRIDE_FINISHED: { + return {...state, enableJoyRide:false, joyRideSteps: []} + } default: return state; } diff --git a/client/src/redux/application/application.selectors.js b/client/src/redux/application/application.selectors.js index 44d81950e..9bf486a1e 100644 --- a/client/src/redux/application/application.selectors.js +++ b/client/src/redux/application/application.selectors.js @@ -52,3 +52,11 @@ export const selectUpdateAvailable = createSelector( [selectApplication], (application) => application.updateAvailable ); +export const selectEnableJoyRide= createSelector( + [selectApplication], + (application) => application.enableJoyRide +); +export const selectJoyRideSteps= createSelector( + [selectApplication], + (application) => application.joyRideSteps +); diff --git a/client/src/redux/application/application.types.js b/client/src/redux/application/application.types.js index 874327bc7..d5e977734 100644 --- a/client/src/redux/application/application.types.js +++ b/client/src/redux/application/application.types.js @@ -12,6 +12,8 @@ const ApplicationActionTypes = { SET_ONLINE_STATUS: "SET_ONLINE_STATUS", INSERT_AUDIT_TRAIL: "INSERT_AUDIT_TRAIL", SET_PROBLEM_JOBS: "SET_PROBLEM_JOBS", - SET_UPDATE_AVAILABLE: "SET_UPDATE_AVAILABLE" + SET_UPDATE_AVAILABLE: "SET_UPDATE_AVAILABLE", + SET_JOYRIDE_STEPS: "SET_JOYRIDE_STEPS", + SET_JOYRIDE_FINISHED:"SET_JOYRIDE_FINISHED" }; export default ApplicationActionTypes;