@argusoft/medplat-app-shell 1.0.6 → 1.0.7
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/package.json +139 -141
- package/src/GlobalErrorBoundary.jsx +31 -0
- package/src/SilentErrorFallback.jsx +68 -0
- package/src/TrackingProviderWrapper.jsx +40 -0
- package/src/_tests_/__mocks__/MockTranslationProvider.jsx +21 -0
- package/src/_tests_/__mocks__/ckeditor.js +45 -0
- package/src/_tests_/__mocks__/fileMock.js +1 -0
- package/src/_tests_/__mocks__/useranalytics.js +5 -0
- package/src/_tests_/views/components/Dashboard/DashboardUI.test.jsx +137 -0
- package/src/_tests_/views/components/Dashboard/DashboardUIMock.js +877 -0
- package/src/_tests_/views/components/ForgotPassword/ForgotPassword.test.jsx +314 -0
- package/src/_tests_/views/components/LocationDirective/LocationDirective.test.jsx.disable +229 -0
- package/src/_tests_/views/components/LocationDirective/mockLocationDirective.js +810 -0
- package/src/_tests_/views/components/LocationType/MockLocationType.js +42259 -0
- package/src/_tests_/views/components/LocationType/addlocationtype.test.jsx.disable +276 -0
- package/src/_tests_/views/components/LocationType/editlocationtype.test.jsx.disable +262 -0
- package/src/_tests_/views/components/LocationType/locationtype.test.jsx.disable +148 -0
- package/src/_tests_/views/components/Profile/UpdateProfileModalData.js +4396 -0
- package/src/_tests_/views/components/Profile/updateprofilemodal.test.jsx +282 -0
- package/src/_tests_/views/components/SideBar/MockSideBar.js +1379 -0
- package/src/_tests_/views/components/SideBar/SideBar.test.jsx +98 -0
- package/src/_tests_/views/components/SystemConfig/ManageSystemConfig/AddManageSystemConfig.test.jsx.disable +164 -0
- package/src/_tests_/views/components/SystemConfig/ManageSystemConfig/UpdateManageSystemConfig.test.jsx.disable +157 -0
- package/src/_tests_/views/components/SystemConfig/MockSystemConfig.js +1280 -0
- package/src/_tests_/views/components/SystemConfig/SystemConfig.test.jsx.disable +165 -0
- package/src/_tests_/views/components/login/Login.test.jsx +276 -0
- package/src/_tests_/views/components/login/MockAuthorise.js +2414 -0
- package/src/_tests_/views/components/login/ServiceResponse.js +595 -0
- package/src/_tests_/views/components/user/MockManageUser.js +7965 -0
- package/src/_tests_/views/components/user/manageuser.test.jsx.disable +989 -0
- package/src/_tests_/views/components/user/mockUsersData.js +582 -0
- package/src/assets/img/OASISLogin.png +0 -0
- package/src/assets/img/bahaarNew.png +0 -0
- package/src/assets/img/dnhdd4K.png +0 -0
- package/src/assets/img/govtofup.png +0 -0
- package/src/assets/img/sewarural4K.png +0 -0
- package/src/assets/img/techo4K.png +0 -0
- package/src/assets/img/up4K.png +0 -0
- package/src/common/HolidayList.jsx +573 -0
- package/src/common/MalaciaousInputUtil.js +23 -0
- package/src/common/SafeHtml.jsx +17 -0
- package/src/common/VersionManager.jsx +109 -0
- package/src/common/constants/PerformanceDashboard.js +514 -0
- package/src/common/constants/app.constant.js +781 -0
- package/src/common/constants/cccVerificationConstants.js +18 -0
- package/src/common/constants/fhsrConstant.js +33 -0
- package/src/common/constants/gvk-verification.constant.js +76 -0
- package/src/common/constants/search.constant.js +23 -0
- package/src/common/constants/teleconsulatationConstant.jsx +1339 -0
- package/src/common/directives/SearchTemplate.jsx +784 -0
- package/src/common/directives/SearchTemplate.scss +14 -0
- package/src/common/dynamicView/DynamicView.jsx +353 -0
- package/src/common/dynamicView/InputFieldComponent.jsx +1501 -0
- package/src/common/dynamicView/InputViewComponent.jsx +298 -0
- package/src/common/dynamicView/InputViewComponent.scss +15 -0
- package/src/common/env.js +5 -0
- package/src/common/filters/locationNameFilter.js +26 -0
- package/src/common/fontAwesomeIcons/FontAwesomeIcons.jsx +27 -0
- package/src/common/fontAwesomeIcons/FontAwesomeIconsNames.js +1968 -0
- package/src/common/fontPreferences/fontSizeProvider.jsx +34 -0
- package/src/common/fontPreferences/fontSizeSelector.jsx +116 -0
- package/src/common/getAssignedFeature/getAssignedFeature.js +32 -0
- package/src/common/interceptors/AxiosInterceptor.js +216 -0
- package/src/common/languageTranslator/TranslationContext.js +5 -0
- package/src/common/languageTranslator/TranslationProvider.jsx +24 -0
- package/src/common/languageTranslator/i18n.js +49 -0
- package/src/common/services/AuthenticateService.js +116 -0
- package/src/common/services/DownloadFile.js +35 -0
- package/src/common/services/ForgotPassword.js +18 -0
- package/src/common/services/FormConfiguratorService.js +195 -0
- package/src/common/services/GlobalApis.js +84 -0
- package/src/common/services/InterceptorNavigationService.js +17 -0
- package/src/common/services/LocationService.js +65 -0
- package/src/common/services/LocationType.js +11 -0
- package/src/common/services/QueryBuilder.js +36 -0
- package/src/common/services/Roles.js +28 -0
- package/src/common/services/SyncWithServer.js +15 -0
- package/src/common/services/SystemConfig.js +15 -0
- package/src/common/services/TranslationService.js +70 -0
- package/src/common/services/TwoFactorService.js +7 -0
- package/src/common/services/Users.js +91 -0
- package/src/common/services/Webtasks.js +27 -0
- package/src/common/services/util/Convert-pad-data-to-API-format.jsx +167 -0
- package/src/common/services/util/Convert-to-UI-format.jsx +82 -0
- package/src/common/services/util/EmptyPrescriptionPadData.jsx +11 -0
- package/src/common/services/util/GeneralUtil.js +456 -0
- package/src/common/services/util/Prescription-pad-util.js +339 -0
- package/src/common/services/util/PrescriptionPadData.js +67 -0
- package/src/common/services/util/PrescriptionpadCommonUtil.js +96 -0
- package/src/common/services/util/ReportFieldUtil.jsx +398 -0
- package/src/common/services/util/WebSocketContext.jsx +261 -0
- package/src/common/syncWithServer/SyncWithServerDialog.jsx +170 -0
- package/src/common/syncWithServer/SyncWithServerDialogSkeleton.jsx +67 -0
- package/src/common/tests/CustomWrapper.jsx +49 -0
- package/src/common/tests/TranslationWrapper.jsx +38 -0
- package/src/common/themeProvider/ColorInputs.jsx +97 -0
- package/src/common/themeProvider/EditableColorInput.jsx +128 -0
- package/src/common/themeProvider/ThemeEditor.jsx +319 -0
- package/src/common/themeProvider/ThemeProvider.jsx +210 -0
- package/src/common/themeProvider/themeConfig.js +558 -0
- package/src/common/toaster/toaster.jsx +30 -0
- package/src/firebaseConfig.js +24 -0
- package/src/global.scss +221 -0
- package/src/hooks/.gitkeep +0 -0
- package/src/hooks/useAESEncryption.js +56 -0
- package/src/hooks/useCaching.js +43 -0
- package/src/hooks/useDebounce.js +34 -0
- package/src/hooks/useDebounceFn.js +50 -0
- package/src/hooks/useDownloadPdf.js +358 -0
- package/src/hooks/useDownloadXlsx.js +55 -0
- package/src/hooks/useListValueFieldValues.js +30 -0
- package/src/hooks/useLocationHierarchies.js +63 -0
- package/src/hooks/useLocationHierarchyTranslate.js +16 -0
- package/src/hooks/useOnline.js +27 -0
- package/src/hooks/usePagination.js +63 -0
- package/src/hooks/useRefreshToken.js +87 -0
- package/src/hooks/useScript.js +25 -0
- package/src/hooks/useStopwatch.js +75 -0
- package/src/hooks/useTrackEvent.js +22 -0
- package/src/hooks/useWebAudioRecorder.js +115 -0
- package/src/layout/LoaderComponet.jsx +22 -0
- package/src/layout/LoaderContext.jsx +29 -0
- package/src/layout/mainLayout/AdaptiveZoom.jsx +27 -0
- package/src/layout/mainLayout/Chatbot.jsx +243 -0
- package/src/layout/mainLayout/Layout.jsx +445 -0
- package/src/layout/mainLayout/Profile/UpdateProfileModal.jsx +684 -0
- package/src/layout/mainLayout/header/LogoutModal.jsx +131 -0
- package/src/layout/mainLayout/header/Navbar.jsx +1677 -0
- package/src/layout/mainLayout/header/Navbar.scss +4 -0
- package/src/layout/mainLayout/header/index.js +0 -0
- package/src/layout/mainLayout/sidebar/SideBar.jsx +1402 -0
- package/src/layout/mainLayout/sidebar/Sidebar.css +159 -0
- package/src/layout/mainLayout/sidebar/index.js +0 -0
- package/src/logo.svg +1 -0
- package/src/reportWebVitals.js +13 -0
- package/src/setupFirebaseMessaging.js +28 -0
- package/src/setupTests.js +8 -0
- package/src/store/actions/AuthenticationActions.js +0 -0
- package/src/store/actions/ReportsActions.js +0 -0
- package/src/store/actions/TranslationAction.js +0 -0
- package/src/store/index.js +8 -0
- package/src/store/reducer.js +46 -0
- package/src/store/reducers/AuthenticationReducer.js +50 -0
- package/src/store/reducers/CalendarEventReducer.js +41 -0
- package/src/store/reducers/ConditionClipboardReducer.js +45 -0
- package/src/store/reducers/FeatureReducer.js +27 -0
- package/src/store/reducers/FormConfiguratorReducer.js +38 -0
- package/src/store/reducers/LoadingReducer.js +20 -0
- package/src/store/reducers/MembersAuthenticationReducer.js +28 -0
- package/src/store/reducers/PrescriptionPadReducer.js +329 -0
- package/src/store/reducers/QuestionaireReducer.js +29 -0
- package/src/store/reducers/ReportsReducer.js +24 -0
- package/src/store/reducers/SkeletonReducer.js +20 -0
- package/src/store/reducers/ThemeReducer.js +106 -0
- package/src/store/reducers/TranslationReducer.js +126 -0
- package/src/store/reducers/dashboardEditorSlice.js +77 -0
- package/src/store/reducers/districtHealthDashboardSlice.js +58 -0
- package/src/store/reducers/immunizationSlice.js +234 -0
- package/src/store/slices/dashboardPagesSlice.js +51 -0
- package/src/utils/.gitkeep +0 -0
- package/src/utils/FormConstants.js +2629 -0
- package/src/utils/GujaratTopoChart.jsx +483 -0
- package/src/utils/UUIDgenerator.js +8 -0
- package/src/utils/appointment-utils/appointment-utils.js +123 -0
- package/src/utils/feature.js +42 -0
- package/src/utils/getThemeColor.js +12 -0
- package/src/utils/localStorageHelper.js +11 -0
- package/src/utils/notifications/enable-push-notifications.js +27 -0
- package/src/utils/resolveAppliedStyle.js +11 -0
- package/src/utils/themeConfigs.js +1483 -0
- package/src/views/custom-components/.gitkeep +0 -0
- package/src/views/custom-components/AgIconButton/RIf.jsx +14 -0
- package/src/views/custom-components/AgIconButton/button.jsx +108 -0
- package/src/views/custom-components/AgIconButton/waterDrop.jsx +95 -0
- package/src/views/custom-components/AgIconButton/waterDrop.scss +37 -0
- package/src/views/custom-components/AlertPlaceholder.jsx +32 -0
- package/src/views/custom-components/AllFaIconsSelector.jsx +56 -0
- package/src/views/custom-components/CkEditor/CkEditor.js +102 -0
- package/src/views/custom-components/CustomAccordion.jsx +72 -0
- package/src/views/custom-components/CustomActionIcons.jsx +118 -0
- package/src/views/custom-components/CustomAutoComplete.jsx +188 -0
- package/src/views/custom-components/CustomCheckBox.jsx +60 -0
- package/src/views/custom-components/CustomConfirmationModal.jsx +118 -0
- package/src/views/custom-components/CustomCountrySelect.jsx +129 -0
- package/src/views/custom-components/CustomDatePicker.jsx +122 -0
- package/src/views/custom-components/CustomDropdown.jsx +191 -0
- package/src/views/custom-components/CustomFileUpload.jsx +387 -0
- package/src/views/custom-components/CustomFullCalendar.jsx +514 -0
- package/src/views/custom-components/CustomInfiniteScroll.jsx +126 -0
- package/src/views/custom-components/CustomRadioComponent.jsx +65 -0
- package/src/views/custom-components/CustomStatsComponent.jsx +114 -0
- package/src/views/custom-components/CustomSvgUpload.jsx +170 -0
- package/src/views/custom-components/CustomSwitch.jsx +37 -0
- package/src/views/custom-components/CustomTabPanel.jsx +19 -0
- package/src/views/custom-components/CustomTextArea.jsx +62 -0
- package/src/views/custom-components/CustomTextArea.scss +27 -0
- package/src/views/custom-components/CustomTextField.jsx +116 -0
- package/src/views/custom-components/CustomToggleSwitch.jsx +138 -0
- package/src/views/custom-components/CustomTooltip.jsx +51 -0
- package/src/views/custom-components/CustomZoomImage.jsx +134 -0
- package/src/views/custom-components/CustomizedTable/CustomizedTableV2.jsx +1407 -0
- package/src/views/custom-components/CustomizedTable/VirtualizeTableBody.jsx +295 -0
- package/src/views/custom-components/CustomizedTable/helper.jsx +159 -0
- package/src/views/custom-components/CustomizedTable.jsx +532 -0
- package/src/views/custom-components/EditInputField.jsx +174 -0
- package/src/views/custom-components/FieldDescription.jsx +22 -0
- package/src/views/custom-components/FileDisplayComponent.jsx +138 -0
- package/src/views/custom-components/FormItem.jsx +53 -0
- package/src/views/custom-components/GenericChart.jsx +80 -0
- package/src/views/custom-components/InfoBadge.jsx +60 -0
- package/src/views/custom-components/PostgresEditor.jsx +801 -0
- package/src/views/custom-components/ResizableEditAutocompleteField.jsx +249 -0
- package/src/views/custom-components/ResizableEditInputField.jsx +215 -0
- package/src/views/custom-components/ResizeableEditSelectField.jsx +197 -0
- package/src/views/custom-components/SideOverlay.jsx +113 -0
- package/src/views/custom-components/SideOverlay.scss +42 -0
- package/src/views/custom-components/calendar.scss +571 -0
- package/src/views/feature-components/.gitkeep +0 -0
- package/src/views/feature-components/Dashboard/DashboardUI.jsx +1043 -0
- package/src/views/feature-components/Dashboard/DhnddModal/AshaDataQualityVerificationModal.jsx +278 -0
- package/src/views/feature-components/Dashboard/PinFeatureModal.jsx +143 -0
- package/src/views/feature-components/Dashboard/QuickLinks.jsx +163 -0
- package/src/views/feature-components/Dashboard/Taskbar.jsx +56 -0
- package/src/views/feature-components/Dashboard/WebtasksFilterForm.jsx +109 -0
- package/src/views/feature-components/Dashboard/WidgetCard.jsx +161 -0
- package/src/views/feature-components/Dashboard/actionModal.jsx +263 -0
- package/src/views/feature-components/Dashboard/ekavachModal/HealthWorkerIncorrectDetailsModal.jsx +332 -0
- package/src/views/feature-components/Dashboard/ekavachModal/MoMaternalDeathVerifcationModal.jsx +275 -0
- package/src/views/feature-components/Dashboard/ekavachModal/MoVerficationForChildScreeningMoadal.jsx +566 -0
- package/src/views/feature-components/FeatureUsageAnalytics/FeatureUsageAnalytics.jsx +989 -0
- package/src/views/feature-components/Features/NewServerManagement.jsx +217 -0
- package/src/views/feature-components/Features/ServerManagement.scss +120 -0
- package/src/views/feature-components/ForgotPassword/ForgotPassword.jsx +226 -0
- package/src/views/feature-components/LocationDirective/LocationDirective.jsx +992 -0
- package/src/views/feature-components/LocationDirective/LocationDirectiveV2.jsx +909 -0
- package/src/views/feature-components/NotFound.jsx +66 -0
- package/src/views/feature-components/Onboarding/Onboarding.jsx +1400 -0
- package/src/views/feature-components/Skeletons.js +115 -0
- package/src/views/feature-components/Unauthorized.jsx +48 -0
- package/src/views/feature-components/VerifyRoute.jsx +88 -0
- package/src/views/feature-components/YearlyRecap/YearlyRecap.jsx +357 -0
- package/src/views/feature-components/YearlyRecap/components/RecapSlide.jsx +183 -0
- package/src/views/feature-components/YearlyRecap/languageTranslator/TranslationContext.js +5 -0
- package/src/views/feature-components/YearlyRecap/languageTranslator/TranslationProvider.jsx +26 -0
- package/src/views/feature-components/YearlyRecap/languageTranslator/i18n.js +46 -0
- package/src/views/feature-components/YearlyRecap/languageTranslator/translations.json +167 -0
- package/src/views/feature-components/YearlyRecap/slides/IntroSlide.jsx +233 -0
- package/src/views/feature-components/YearlyRecap/slides/MaternalHealthSlide.jsx +146 -0
- package/src/views/feature-components/YearlyRecap/slides/MetricSlide.jsx +227 -0
- package/src/views/feature-components/YearlyRecap/slides/OutroSlide.jsx +701 -0
- package/src/views/feature-components/YearlyRecap/slides/ReachSlide.jsx +273 -0
- package/src/views/feature-components/login/Login.jsx +840 -0
- package/src/views/feature-components/login/Login.scss +154 -0
- package/src/views/feature-components/login/LoginConfigurator.jsx +1149 -0
- package/src/views/feature-components/login/TwoFactorSetupModal.jsx +411 -0
- package/src/views/feature-components/login/simplifyMenu.js +45 -0
- package/src/views/feature-components/system-config/ManageSystemConfigs.jsx +284 -0
- package/src/views/feature-components/system-config/SystemConfig.jsx +299 -0
- package/src/views/feature-components/users/ChangePasswordModal.jsx +243 -0
- package/src/views/feature-components/users/PasswordField.jsx +56 -0
- package/dist/index.css +0 -1
- package/dist/index.js +0 -32001
- package/dist/index.js.map +0 -1
|
@@ -0,0 +1,989 @@
|
|
|
1
|
+
import { useSelector } from 'react-redux';
|
|
2
|
+
import { getUseSkeleton } from '@/store/reducers/SkeletonReducer';
|
|
3
|
+
import { useForm } from 'react-hook-form';
|
|
4
|
+
import Grid from '@mui/material/Grid2';
|
|
5
|
+
import { Card, FormControl } from '@mui/material';
|
|
6
|
+
import CustomAutocomplete from '@/views/custom-components/CustomAutoComplete';
|
|
7
|
+
import { showToast } from '@/common/toaster/toaster';
|
|
8
|
+
import { getAllRoleList } from '@/common/services/Roles';
|
|
9
|
+
import { useEffect, useState } from 'react';
|
|
10
|
+
import { execute } from '@/common/services/QueryBuilder';
|
|
11
|
+
import dayjs from 'dayjs';
|
|
12
|
+
import {
|
|
13
|
+
ScatterChart,
|
|
14
|
+
Scatter,
|
|
15
|
+
XAxis,
|
|
16
|
+
YAxis,
|
|
17
|
+
ZAxis,
|
|
18
|
+
Tooltip,
|
|
19
|
+
ResponsiveContainer,
|
|
20
|
+
LabelList,
|
|
21
|
+
Bar,
|
|
22
|
+
BarChart,
|
|
23
|
+
Legend,
|
|
24
|
+
} from 'recharts';
|
|
25
|
+
import PropTypes from 'prop-types';
|
|
26
|
+
import CustomDatePicker from '@/views/custom-components/CustomDatePicker';
|
|
27
|
+
import CustomizedTable from '@/views/custom-components/CustomizedTable/CustomizedTableV2';
|
|
28
|
+
const FeatureUsageAnalytics = () => {
|
|
29
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
30
|
+
const [chartDataLoading, setChartDataLoading] = useState(false);
|
|
31
|
+
const today = dayjs();
|
|
32
|
+
const oneMonthAgo = today.subtract(1, 'month');
|
|
33
|
+
const minDate = oneMonthAgo.format('YYYY-MM-DD');
|
|
34
|
+
const maxDate = today.format('YYYY-MM-DD');
|
|
35
|
+
const [roleList, setRoleList] = useState([]);
|
|
36
|
+
const [pageList, setPageList] = useState([]);
|
|
37
|
+
const [roleIds, setRoleIds] = useState(null);
|
|
38
|
+
const [filteredData, setFilteredData] = useState([]);
|
|
39
|
+
const [filteredpageList, setFilteredpageList] = useState([]);
|
|
40
|
+
const [transformedData, setTransformedData] = useState([]);
|
|
41
|
+
|
|
42
|
+
const [barChartData, setBarChartData] = useState([]);
|
|
43
|
+
const [rawDataTableData, setrawDataTableData] = useState([]);
|
|
44
|
+
const [top5ByPageCount, setTop5ByPageCount] = useState([]);
|
|
45
|
+
const [top5ByAvgTime, setTop5ByAvgTime] = useState([]);
|
|
46
|
+
const [bottom5ByPageCount, setBottom5ByPageCount] = useState([]);
|
|
47
|
+
const [bottom5ByAvgTime, setBottom5ByAvgTime] = useState([]);
|
|
48
|
+
|
|
49
|
+
const rawDataTableFields = [
|
|
50
|
+
{ field: 'Sr. No.', label: '#', align: 'left' },
|
|
51
|
+
{ field: 'menu_name', label: 'Page title' },
|
|
52
|
+
{ field: 'page_count', label: 'Number of time page visited' },
|
|
53
|
+
{ field: 'avg_time', label: 'Average time spent (in seconds)' },
|
|
54
|
+
{ field: 'user_count', label: 'Number of distinct users visited the page' },
|
|
55
|
+
{ field: 'percentvalue', label: 'Percentage of distinct users visited the page' },
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
const pageVisitedTableFields = [
|
|
59
|
+
{ field: 'menu_name', label: 'Page title' },
|
|
60
|
+
{ field: 'page_count', label: 'Number of time page visited' },
|
|
61
|
+
];
|
|
62
|
+
|
|
63
|
+
const averageTimeTableFields = [
|
|
64
|
+
{ field: 'menu_name', label: 'Page title' },
|
|
65
|
+
{ field: 'avg_time', label: 'Average time spent (in seconds)' },
|
|
66
|
+
];
|
|
67
|
+
const {
|
|
68
|
+
control,
|
|
69
|
+
watch,
|
|
70
|
+
setValue,
|
|
71
|
+
// handleSubmit,
|
|
72
|
+
// formState: { errors },
|
|
73
|
+
} = useForm({
|
|
74
|
+
defaultValues: {
|
|
75
|
+
fromDate: minDate,
|
|
76
|
+
endDate: maxDate,
|
|
77
|
+
},
|
|
78
|
+
// resolver: yupResolver(validationSchema),
|
|
79
|
+
mode: 'onChange', // Trigger validation on change
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* @function formatDate
|
|
84
|
+
* @description Formats a date into DD-MM-YYYY format.
|
|
85
|
+
* @param {string|Date} date - The input date to format.
|
|
86
|
+
* @returns {string} - The formatted date string.
|
|
87
|
+
*/
|
|
88
|
+
function formatDate(date) {
|
|
89
|
+
const dd = String(new Date(date).getDate()).padStart(2, '0');
|
|
90
|
+
const mm = String(new Date(date).getMonth() + 1).padStart(2, '0'); // Months are 0-based
|
|
91
|
+
const yyyy = new Date(date).getFullYear();
|
|
92
|
+
return `${dd}-${mm}-${yyyy}`;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* @function getFeatureUsageAnalyticsDetails
|
|
97
|
+
* @description Fetches analytics data based on selected roles and pages, processes it for charts and tables.
|
|
98
|
+
*/
|
|
99
|
+
const getFeatureUsageAnalyticsDetails = async () => {
|
|
100
|
+
try {
|
|
101
|
+
setChartDataLoading(true);
|
|
102
|
+
|
|
103
|
+
const from_date = formatDate(watch('fromDate'));
|
|
104
|
+
const end_date = formatDate(watch('endDate'));
|
|
105
|
+
let dtoUsage = {
|
|
106
|
+
code: 'feature_usage_analytics',
|
|
107
|
+
parameters: {
|
|
108
|
+
end_date,
|
|
109
|
+
from_date,
|
|
110
|
+
rids: roleIds,
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
const res = await execute(dtoUsage);
|
|
114
|
+
const data = res?.data?.result;
|
|
115
|
+
let rawDataTableData = [];
|
|
116
|
+
let filteredData = [];
|
|
117
|
+
let bubbleChartData = [];
|
|
118
|
+
let barChartData = [];
|
|
119
|
+
var xValues = [8, 5, 7, 9, 4, 2, 6, 3, 10, 1];
|
|
120
|
+
var yValues = [5, 9, 2, 10, 1, 4, 3, 6, 7, 8];
|
|
121
|
+
var bValues = [
|
|
122
|
+
'rgba(255,221,50,0.2)',
|
|
123
|
+
'rgba(60,186,159,0.2)',
|
|
124
|
+
'rgba(0,0,0,0.2)',
|
|
125
|
+
'rgba(193,46,12,0.2)',
|
|
126
|
+
'rgba(255,221,50,0.2)',
|
|
127
|
+
'rgba(60,186,159,0.2)',
|
|
128
|
+
'rgba(0,0,0,0.2)',
|
|
129
|
+
'rgba(193,46,12,0.2)',
|
|
130
|
+
'rgba(255,221,50,0.2)',
|
|
131
|
+
'rgba(60,186,159,0.2)',
|
|
132
|
+
];
|
|
133
|
+
var bdValues = [
|
|
134
|
+
'rgba(255,221,50,1)',
|
|
135
|
+
'rgba(60,186,159,1)',
|
|
136
|
+
'#000',
|
|
137
|
+
'rgba(193,46,12,1)',
|
|
138
|
+
'rgba(255,221,50,1)',
|
|
139
|
+
'rgba(60,186,159,1)',
|
|
140
|
+
'#000',
|
|
141
|
+
'rgba(193,46,12,1)',
|
|
142
|
+
'rgba(255,221,50,1)',
|
|
143
|
+
'rgba(60,186,159,1)',
|
|
144
|
+
];
|
|
145
|
+
var count = 0,
|
|
146
|
+
maxR = 80,
|
|
147
|
+
minR = 30;
|
|
148
|
+
let minValue = 0;
|
|
149
|
+
let maxValue = 0;
|
|
150
|
+
if (data?.length > 0) {
|
|
151
|
+
filteredData = data.filter((tmp) => {
|
|
152
|
+
return filteredpageList.some((t) => {
|
|
153
|
+
return t === tmp.menu_name;
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
setFilteredData(filteredData);
|
|
157
|
+
if (filteredData.length > 0) {
|
|
158
|
+
if (filteredData && filteredData.length >= 10) {
|
|
159
|
+
minValue = filteredData[9].page_count;
|
|
160
|
+
maxValue = filteredData[0].page_count;
|
|
161
|
+
} else if (filteredData && filteredData.length < 10) {
|
|
162
|
+
minValue = filteredData[filteredData.length - 1].page_count;
|
|
163
|
+
maxValue = filteredData[0].page_count;
|
|
164
|
+
} else if (!filteredData) {
|
|
165
|
+
minValue = 0;
|
|
166
|
+
maxValue = 0;
|
|
167
|
+
} else {
|
|
168
|
+
minValue = minR;
|
|
169
|
+
maxValue = maxR;
|
|
170
|
+
}
|
|
171
|
+
filteredData.forEach(function (value) {
|
|
172
|
+
rawDataTableData.push({
|
|
173
|
+
menu_name: value?.menu_name,
|
|
174
|
+
page_count: value?.page_count,
|
|
175
|
+
user_count: value?.user_count,
|
|
176
|
+
avg_time: parseInt((value.avg_time / 1000).toFixed(0)),
|
|
177
|
+
percentvalue: value.percentvalue.toFixed(2) + '%',
|
|
178
|
+
});
|
|
179
|
+
barChartData.push({
|
|
180
|
+
name: value.menu_name,
|
|
181
|
+
average: parseInt((value.avg_time / 1000).toFixed(0)),
|
|
182
|
+
maximum: parseInt((value.max_time / 1000).toFixed(0)),
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
if (filteredData.length >= 10) {
|
|
186
|
+
if (count < 10) {
|
|
187
|
+
bubbleChartData.push({
|
|
188
|
+
label: [
|
|
189
|
+
'Page Title : ' + value.menu_name,
|
|
190
|
+
'Number of times page visited : ' + value.page_count,
|
|
191
|
+
'Distinct number of users visited the page :' + value.user_count,
|
|
192
|
+
],
|
|
193
|
+
backgroundColor: bValues[count],
|
|
194
|
+
borderColor: bdValues[count],
|
|
195
|
+
title: value.menu_name,
|
|
196
|
+
hoverRadius: 0,
|
|
197
|
+
data: [
|
|
198
|
+
{
|
|
199
|
+
x: xValues[count],
|
|
200
|
+
y: yValues[count],
|
|
201
|
+
r:
|
|
202
|
+
maxValue !== minValue
|
|
203
|
+
? (((maxR - minR) * (value.page_count - minValue)) / (maxValue - minValue) + minR).toFixed(0)
|
|
204
|
+
: minR,
|
|
205
|
+
},
|
|
206
|
+
],
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
} else {
|
|
210
|
+
bubbleChartData.push({
|
|
211
|
+
label: [
|
|
212
|
+
'Page Title : ' + value.menu_name,
|
|
213
|
+
'Number of times page visited : ' + value.page_count,
|
|
214
|
+
'Distinct number of users visited the page :' + value.user_count,
|
|
215
|
+
],
|
|
216
|
+
backgroundColor: bValues[count],
|
|
217
|
+
borderColor: bdValues[count],
|
|
218
|
+
title: value.menu_name,
|
|
219
|
+
hoverRadius: 0,
|
|
220
|
+
data: [
|
|
221
|
+
{
|
|
222
|
+
x: xValues[count],
|
|
223
|
+
y: yValues[count],
|
|
224
|
+
r:
|
|
225
|
+
maxValue !== minValue
|
|
226
|
+
? (((maxR - minR) * (value.page_count - minValue)) / (maxValue - minValue) + minR).toFixed(0)
|
|
227
|
+
: minR,
|
|
228
|
+
},
|
|
229
|
+
],
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
count++;
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
} else {
|
|
236
|
+
setFilteredData([]);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
setrawDataTableData(rawDataTableData);
|
|
240
|
+
setBarChartData(barChartData);
|
|
241
|
+
setTransformedData(prepareChartData(bubbleChartData));
|
|
242
|
+
setChartDataLoading(false);
|
|
243
|
+
} catch (error) {
|
|
244
|
+
console.error(error);
|
|
245
|
+
showToast({ message: 'Error in getting Feature Usage Analytics data.', type: 'error' });
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* @description Side effect that processes raw table data to get top and bottom 5 lists.
|
|
251
|
+
*/
|
|
252
|
+
useEffect(() => {
|
|
253
|
+
if (!rawDataTableData?.length) return;
|
|
254
|
+
|
|
255
|
+
const sortedByPageCount = [...rawDataTableData].sort((a, b) => b.page_count - a.page_count);
|
|
256
|
+
const sortedByAvgTime = [...rawDataTableData].sort((a, b) => b.avg_time - a.avg_time);
|
|
257
|
+
|
|
258
|
+
setTop5ByPageCount(sortedByPageCount.slice(0, 5));
|
|
259
|
+
|
|
260
|
+
setTop5ByAvgTime(sortedByAvgTime.slice(0, 5));
|
|
261
|
+
|
|
262
|
+
const sortedByPageCountBottom = [...rawDataTableData].sort((a, b) => a.page_count - b.page_count);
|
|
263
|
+
const sortedByAvgTimeBottom = [...rawDataTableData].sort((a, b) => a.avg_time - b.avg_time);
|
|
264
|
+
setBottom5ByPageCount(sortedByPageCountBottom.slice(0, 5));
|
|
265
|
+
setBottom5ByAvgTime(sortedByAvgTimeBottom.slice(0, 5));
|
|
266
|
+
}, [rawDataTableData]);
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* @function CustomTooltip
|
|
270
|
+
* @description Tooltip component for Bubble chart points.
|
|
271
|
+
*/
|
|
272
|
+
const CustomTooltip = ({ active, payload }) => {
|
|
273
|
+
if (active && payload?.length) {
|
|
274
|
+
const d = payload[0].payload;
|
|
275
|
+
return (
|
|
276
|
+
<div className="bg-black/60 text-white p-2 rounded-md text-xs">
|
|
277
|
+
<div className="flex items-start gap-1">
|
|
278
|
+
<div
|
|
279
|
+
className="w-3 h-3 mt-0.5"
|
|
280
|
+
style={{
|
|
281
|
+
backgroundColor: d.backgroundColor, // Use the fill color for the average or fallback
|
|
282
|
+
border: `1px solid ${d.borderColor}`, // Use the stroke color for the border or fallback
|
|
283
|
+
}}
|
|
284
|
+
></div>
|
|
285
|
+
<div>
|
|
286
|
+
<div>
|
|
287
|
+
<strong>Page Title :</strong> {d.title}
|
|
288
|
+
</div>
|
|
289
|
+
<div>
|
|
290
|
+
<strong>Number of times page visited :</strong> {d.page_count}
|
|
291
|
+
</div>
|
|
292
|
+
<div>
|
|
293
|
+
<strong>Distinct number of users visited the page :</strong> {d.user_count}
|
|
294
|
+
</div>
|
|
295
|
+
</div>
|
|
296
|
+
</div>
|
|
297
|
+
</div>
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
return null;
|
|
301
|
+
};
|
|
302
|
+
CustomTooltip.propTypes = {
|
|
303
|
+
active: PropTypes.any,
|
|
304
|
+
payload: PropTypes.any,
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* @function CustomTooltipBarChart
|
|
309
|
+
* @description Tooltip component for Bar chart.
|
|
310
|
+
*/
|
|
311
|
+
const CustomTooltipBarChart = ({ active, payload }) => {
|
|
312
|
+
if (active && payload?.length) {
|
|
313
|
+
const d = payload[0]; // Directly access the item in payload
|
|
314
|
+
|
|
315
|
+
return (
|
|
316
|
+
<div className="bg-black/60 text-white p-2 rounded-md text-xs">
|
|
317
|
+
<div className="">
|
|
318
|
+
{/* Display for Average */}
|
|
319
|
+
<div>
|
|
320
|
+
<strong>{d.payload.name}</strong> {/* This will be Web Tasks, for example */}
|
|
321
|
+
</div>
|
|
322
|
+
|
|
323
|
+
<div>
|
|
324
|
+
<div className="flex items-center gap-1">
|
|
325
|
+
<div
|
|
326
|
+
className="w-3 h-3 mt-0.5"
|
|
327
|
+
style={{
|
|
328
|
+
backgroundColor: d.fill, // Use the fill color for the average or fallback
|
|
329
|
+
border: `1px solid ${d.stroke}`, // Use the stroke color for the border or fallback
|
|
330
|
+
}}
|
|
331
|
+
></div>
|
|
332
|
+
<div>
|
|
333
|
+
<strong>Average Usage:</strong> {d.payload?.average} {/* Access the average value */}
|
|
334
|
+
</div>
|
|
335
|
+
</div>
|
|
336
|
+
</div>
|
|
337
|
+
</div>
|
|
338
|
+
|
|
339
|
+
{/* Display for Maximum */}
|
|
340
|
+
<div className="flex items-start gap-1 ">
|
|
341
|
+
<div
|
|
342
|
+
className="w-3 h-3 mt-0.5"
|
|
343
|
+
style={{
|
|
344
|
+
backgroundColor: payload[1].fill || '#F4D8C6', // Use the fill color for the maximum or fallback
|
|
345
|
+
border: `1px solid ${payload[1].stroke || '#E65C00'}`, // Use the stroke color for the border or fallback
|
|
346
|
+
}}
|
|
347
|
+
></div>
|
|
348
|
+
<div>
|
|
349
|
+
<div>
|
|
350
|
+
<strong>Maximum Usage:</strong> {d.payload?.maximum} {/* Access the maximum value */}
|
|
351
|
+
</div>
|
|
352
|
+
</div>
|
|
353
|
+
</div>
|
|
354
|
+
</div>
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return null;
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
CustomTooltipBarChart.propTypes = {
|
|
362
|
+
active: PropTypes.any,
|
|
363
|
+
payload: PropTypes.any,
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* @function prepareChartData
|
|
368
|
+
* @description Converts raw bubble chart data into usable chart format.
|
|
369
|
+
* @param {Array} raw - Raw bubble chart data.
|
|
370
|
+
* @returns {Array} - Transformed chart data.
|
|
371
|
+
*/
|
|
372
|
+
const prepareChartData = (raw) => {
|
|
373
|
+
return raw.map((item) => {
|
|
374
|
+
const page_count = Number(item?.label[1]?.split(':')[1].trim());
|
|
375
|
+
const user_count = Number(item?.label[2]?.split(':')[1].trim());
|
|
376
|
+
|
|
377
|
+
return {
|
|
378
|
+
...item.data[0],
|
|
379
|
+
title: item.title,
|
|
380
|
+
page_count,
|
|
381
|
+
user_count,
|
|
382
|
+
backgroundColor: item.backgroundColor,
|
|
383
|
+
borderColor: item.borderColor,
|
|
384
|
+
};
|
|
385
|
+
});
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* @function fetchPages
|
|
390
|
+
* @description Fetches page list based on selected roles and triggers data fetch.
|
|
391
|
+
*/
|
|
392
|
+
const fetchPages = async () => {
|
|
393
|
+
try {
|
|
394
|
+
let dtoPage = {
|
|
395
|
+
code: 'menu_list_by_role_ids',
|
|
396
|
+
parameters: {
|
|
397
|
+
rids: roleIds,
|
|
398
|
+
},
|
|
399
|
+
};
|
|
400
|
+
const res = await execute(dtoPage);
|
|
401
|
+
setPageList(res?.data?.result || []);
|
|
402
|
+
const filteredpageList = [];
|
|
403
|
+
res?.data?.result?.forEach((page) => {
|
|
404
|
+
filteredpageList.push(page?.menu_name);
|
|
405
|
+
});
|
|
406
|
+
setFilteredpageList(filteredpageList);
|
|
407
|
+
await getFeatureUsageAnalyticsDetails();
|
|
408
|
+
} catch (error) {
|
|
409
|
+
console.error(error);
|
|
410
|
+
showToast({ message: 'Error in fetching pages', type: 'error' });
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* @function handleSelectedRoleChange
|
|
416
|
+
* @description Handles role selection change and updates related state.
|
|
417
|
+
* @param {*} _ - Event object (unused).
|
|
418
|
+
* @param {Array} value - Selected roles.
|
|
419
|
+
*/
|
|
420
|
+
const handleSelectedRoleChange = async (_, value) => {
|
|
421
|
+
setValue('selectPage', []);
|
|
422
|
+
let roleIds = [];
|
|
423
|
+
value?.forEach((role) => {
|
|
424
|
+
roleIds.push(role.id);
|
|
425
|
+
});
|
|
426
|
+
if (roleIds?.length > 0) {
|
|
427
|
+
setRoleIds(roleIds);
|
|
428
|
+
} else {
|
|
429
|
+
await loadInitial();
|
|
430
|
+
}
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* @function handleSelectedPageChange
|
|
435
|
+
* @description Handles page selection change and updates filtered pages.
|
|
436
|
+
* @param {*} _ - Event object (unused).
|
|
437
|
+
* @param {Array} value - Selected pages.
|
|
438
|
+
*/
|
|
439
|
+
const handleSelectedPageChange = async (_, value) => {
|
|
440
|
+
const selectedPages = [];
|
|
441
|
+
value?.forEach((page) => {
|
|
442
|
+
selectedPages.push(page?.menu_name);
|
|
443
|
+
});
|
|
444
|
+
const filteredpageList = pageList
|
|
445
|
+
?.filter((page) => {
|
|
446
|
+
return Array.isArray(selectedPages) && selectedPages.length ? selectedPages.includes(page.menu_name) : true;
|
|
447
|
+
})
|
|
448
|
+
.map((page) => page.menu_name);
|
|
449
|
+
setFilteredpageList(filteredpageList);
|
|
450
|
+
};
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* @function loadInitial
|
|
454
|
+
* @description Loads initial roles and sets roleIds.
|
|
455
|
+
*/
|
|
456
|
+
const loadInitial = async () => {
|
|
457
|
+
try {
|
|
458
|
+
const res = await getAllRoleList();
|
|
459
|
+
setRoleList(res?.data || []);
|
|
460
|
+
const roleIds = res?.data?.map((role) => role.id);
|
|
461
|
+
setRoleIds(roleIds);
|
|
462
|
+
} catch (error) {
|
|
463
|
+
console.error(error);
|
|
464
|
+
showToast({ message: 'Error in loading Feature Usage Analytics', type: 'error' });
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* @function CustomBarWithoutBottomStroke
|
|
470
|
+
* @description Custom Bar shape component excluding bottom stroke for styling.
|
|
471
|
+
*/
|
|
472
|
+
const CustomBarWithoutBottomStroke = (props) => {
|
|
473
|
+
const { x, y, width, height, fill, stroke } = props;
|
|
474
|
+
|
|
475
|
+
return (
|
|
476
|
+
<g>
|
|
477
|
+
<rect x={x} y={y} width={width} height={height} fill={fill} />
|
|
478
|
+
|
|
479
|
+
<line x1={x} y1={y} x2={x + width} y2={y} stroke={stroke} strokeWidth={2} />
|
|
480
|
+
|
|
481
|
+
<line x1={x} y1={y} x2={x} y2={y + height} stroke={stroke} strokeWidth={2} />
|
|
482
|
+
|
|
483
|
+
<line x1={x + width} y1={y} x2={x + width} y2={y + height} stroke={stroke} strokeWidth={2} />
|
|
484
|
+
</g>
|
|
485
|
+
);
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
CustomBarWithoutBottomStroke.propTypes = {
|
|
489
|
+
x: PropTypes.any,
|
|
490
|
+
y: PropTypes.any,
|
|
491
|
+
width: PropTypes.any,
|
|
492
|
+
height: PropTypes.any,
|
|
493
|
+
stroke: PropTypes.any,
|
|
494
|
+
fill: PropTypes.any,
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* @function CustomLegend
|
|
499
|
+
* @description Renders custom legend for charts.
|
|
500
|
+
*/
|
|
501
|
+
const CustomLegend = ({ payload }) => {
|
|
502
|
+
return (
|
|
503
|
+
<ul className="flex flex-wrap justify-center gap-6 mb-4">
|
|
504
|
+
{payload.map((entry, index) => (
|
|
505
|
+
<li key={`item-${index}`} className="flex items-center gap-2 text-black">
|
|
506
|
+
<svg width="50" height="15">
|
|
507
|
+
<rect width="50" height="15" fill={entry.color} stroke={entry.payload.stroke} strokeWidth="4" />
|
|
508
|
+
</svg>
|
|
509
|
+
<span className="text-sm">{entry.value}</span>
|
|
510
|
+
</li>
|
|
511
|
+
))}
|
|
512
|
+
</ul>
|
|
513
|
+
);
|
|
514
|
+
};
|
|
515
|
+
CustomLegend.propTypes = {
|
|
516
|
+
payload: PropTypes.any,
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* @description Initial effect to load roles.
|
|
521
|
+
*/
|
|
522
|
+
useEffect(() => {
|
|
523
|
+
setIsLoading(true);
|
|
524
|
+
loadInitial();
|
|
525
|
+
setIsLoading(false);
|
|
526
|
+
}, []);
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* @description Effect to fetch page list when roleIds change.
|
|
530
|
+
*/
|
|
531
|
+
useEffect(() => {
|
|
532
|
+
if (roleIds) {
|
|
533
|
+
fetchPages();
|
|
534
|
+
}
|
|
535
|
+
}, [roleIds]);
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* @description Effect to fetch analytics data whenever the filtered page list changes.
|
|
539
|
+
*/
|
|
540
|
+
useEffect(() => {
|
|
541
|
+
getFeatureUsageAnalyticsDetails();
|
|
542
|
+
}, [filteredpageList]);
|
|
543
|
+
|
|
544
|
+
return (
|
|
545
|
+
<FeatureUsageAnalyticsSkeleton isLoading={isLoading}>
|
|
546
|
+
<Card variant="elevation" container className="mt-6 p-3 shadow-2xl">
|
|
547
|
+
<Grid item size={{ xs: 12 }}>
|
|
548
|
+
<Grid container spacing={2} component="form" className="w-full">
|
|
549
|
+
<Grid item size={{ xs: 12, md: 3 }}>
|
|
550
|
+
<FormControl variant="outlined" className="w-full">
|
|
551
|
+
<label>Select Role</label>
|
|
552
|
+
<CustomAutocomplete
|
|
553
|
+
options={roleList || []}
|
|
554
|
+
control={control}
|
|
555
|
+
// value={canDelete}
|
|
556
|
+
name="selectRole"
|
|
557
|
+
getOptionLabel={(option) => option?.name}
|
|
558
|
+
onChange={handleSelectedRoleChange}
|
|
559
|
+
dataTestId="feature-usage-analytics-select-role"
|
|
560
|
+
/>
|
|
561
|
+
</FormControl>
|
|
562
|
+
</Grid>
|
|
563
|
+
<Grid item size={{ xs: 12, md: 3 }}>
|
|
564
|
+
<FormControl variant="outlined" className="w-full">
|
|
565
|
+
<label>Select Page</label>
|
|
566
|
+
<CustomAutocomplete
|
|
567
|
+
options={pageList || []}
|
|
568
|
+
control={control}
|
|
569
|
+
checkEquality="menu_name"
|
|
570
|
+
name="selectPage"
|
|
571
|
+
getOptionLabel={(option) => option?.menu_name}
|
|
572
|
+
onChange={handleSelectedPageChange}
|
|
573
|
+
dataTestId="feature-usage-analytics-select-page"
|
|
574
|
+
/>
|
|
575
|
+
</FormControl>
|
|
576
|
+
</Grid>
|
|
577
|
+
<Grid item size={{ xs: 12, md: 3 }}>
|
|
578
|
+
<FormControl variant="outlined" className="w-full">
|
|
579
|
+
<label>Select From Date</label>
|
|
580
|
+
<CustomDatePicker
|
|
581
|
+
name="fromDate"
|
|
582
|
+
format="DD/MM/YYYY"
|
|
583
|
+
control={control}
|
|
584
|
+
onChange={() => {
|
|
585
|
+
getFeatureUsageAnalyticsDetails(); // pass dayjs object for validation
|
|
586
|
+
}}
|
|
587
|
+
maxDate={watch('endDate') ? dayjs(watch('endDate')) : null}
|
|
588
|
+
dataTestId="sohchartconfiguration-datepicker-input-to date"
|
|
589
|
+
/>
|
|
590
|
+
</FormControl>
|
|
591
|
+
</Grid>
|
|
592
|
+
<Grid item size={{ xs: 12, md: 3 }}>
|
|
593
|
+
<FormControl variant="outlined" className="w-full">
|
|
594
|
+
<label>Select To Date</label>
|
|
595
|
+
<CustomDatePicker
|
|
596
|
+
name="endDate"
|
|
597
|
+
format="DD/MM/YYYY"
|
|
598
|
+
control={control}
|
|
599
|
+
onChange={() => {
|
|
600
|
+
getFeatureUsageAnalyticsDetails(); // pass dayjs object for validation
|
|
601
|
+
}}
|
|
602
|
+
minDate={watch('fromDate') ? dayjs(watch('fromDate')) : null}
|
|
603
|
+
dataTestId="sohchartconfiguration-datepicker-input-to date"
|
|
604
|
+
/>
|
|
605
|
+
{/* <Controller
|
|
606
|
+
name="endDate"
|
|
607
|
+
control={control}
|
|
608
|
+
// defaultValue={today}
|
|
609
|
+
render={({ field }) => (
|
|
610
|
+
<TextField
|
|
611
|
+
{...field}
|
|
612
|
+
type="date"
|
|
613
|
+
className="bg-white"
|
|
614
|
+
slotProps={{
|
|
615
|
+
inputLabel: {
|
|
616
|
+
shrink: true, // Keeps the label visible even when the input is filled
|
|
617
|
+
},
|
|
618
|
+
htmlInput: {
|
|
619
|
+
// min: dayjs().subtract(1, 'month').format('YYYY-MM-DD'),
|
|
620
|
+
min: watch('fromDate') ? dayjs(watch('fromDate')).format('YYYY-MM-DD') : null,
|
|
621
|
+
},
|
|
622
|
+
}}
|
|
623
|
+
// InputLabelProps={{
|
|
624
|
+
// shrink: true, // Keeps the label visible even when the input is filled
|
|
625
|
+
// }}
|
|
626
|
+
|
|
627
|
+
onChange={async (e) => {
|
|
628
|
+
const dateValue = e.target.value;
|
|
629
|
+
field.onChange(dateValue);
|
|
630
|
+
getFeatureUsageAnalyticsDetails(); // Custom validation logic
|
|
631
|
+
}}
|
|
632
|
+
value={field.value || ''}
|
|
633
|
+
size="small"
|
|
634
|
+
dataTestId="feature-usage-analytics-to-date"
|
|
635
|
+
/>
|
|
636
|
+
)}
|
|
637
|
+
/> */}
|
|
638
|
+
</FormControl>
|
|
639
|
+
</Grid>
|
|
640
|
+
</Grid>
|
|
641
|
+
</Grid>
|
|
642
|
+
<Grid item size={{ xs: 12 }}>
|
|
643
|
+
<ChartDataSkeleton isLoading={chartDataLoading}>
|
|
644
|
+
{filteredData.length > 0 ? (
|
|
645
|
+
<Grid container>
|
|
646
|
+
<Grid item size={{ xs: 12 }} className="h-fit w-full">
|
|
647
|
+
<Grid container justifyContent="center" alignItems="center" className="h-fit w-full mt-5">
|
|
648
|
+
<Grid item size={{ xs: 12 }} className="text-center text-base font-semibold">
|
|
649
|
+
Top 10 usage based on number of times page visited
|
|
650
|
+
</Grid>
|
|
651
|
+
<Grid
|
|
652
|
+
item
|
|
653
|
+
size={{ xs: 12, md: 9 }}
|
|
654
|
+
className="h-45 sm:h-60 md:h-75 lg:h-110 xl:h-120 2xl:h-140"
|
|
655
|
+
style={{ border: '2px solid black' }}
|
|
656
|
+
>
|
|
657
|
+
<ResponsiveContainer className="h-full w-full">
|
|
658
|
+
<ScatterChart
|
|
659
|
+
className="h-full w-full"
|
|
660
|
+
margin={{ top: 50, left: -70 }}
|
|
661
|
+
dataTestId="feature-usage-analytics-bubble-chart"
|
|
662
|
+
>
|
|
663
|
+
<XAxis type="number" dataKey="x" name="X" tick={false} axisLine={false} domain={[0, 12]} />
|
|
664
|
+
<YAxis type="number" dataKey="y" name="Y" tick={false} axisLine={false} domain={[0, 10]} />
|
|
665
|
+
<ZAxis type="number" dataKey="r" range={[10, 80]} />
|
|
666
|
+
<Tooltip content={<CustomTooltip />} cursor={false} />
|
|
667
|
+
<Scatter
|
|
668
|
+
data={transformedData}
|
|
669
|
+
shape={(props) => {
|
|
670
|
+
// eslint-disable-next-line react/prop-types
|
|
671
|
+
const { cx, cy, r, payload } = props;
|
|
672
|
+
return (
|
|
673
|
+
<circle
|
|
674
|
+
cx={cx}
|
|
675
|
+
cy={cy}
|
|
676
|
+
r={r}
|
|
677
|
+
// eslint-disable-next-line react/prop-types
|
|
678
|
+
fill={payload.backgroundColor}
|
|
679
|
+
// eslint-disable-next-line react/prop-types
|
|
680
|
+
stroke={payload.borderColor}
|
|
681
|
+
strokeWidth={1}
|
|
682
|
+
fillOpacity={1}
|
|
683
|
+
/>
|
|
684
|
+
);
|
|
685
|
+
}}
|
|
686
|
+
>
|
|
687
|
+
<LabelList
|
|
688
|
+
dataKey="title"
|
|
689
|
+
content={({ x, y, value }) => (
|
|
690
|
+
<foreignObject x={x + 10} y={y - 10} width={120} height={40}>
|
|
691
|
+
<div className="text-left text-[12px] text-[#333] break-words whitespace-normal leading-[1.2]">
|
|
692
|
+
{value}
|
|
693
|
+
</div>
|
|
694
|
+
</foreignObject>
|
|
695
|
+
)}
|
|
696
|
+
/>
|
|
697
|
+
</Scatter>
|
|
698
|
+
</ScatterChart>
|
|
699
|
+
</ResponsiveContainer>
|
|
700
|
+
</Grid>
|
|
701
|
+
</Grid>
|
|
702
|
+
|
|
703
|
+
<Grid container justifyContent="center" alignItems="center" className="h-fit w-full mt-10">
|
|
704
|
+
<Grid item size={{ xs: 12 }} className="text-center text-base font-semibold">
|
|
705
|
+
User engagement graph
|
|
706
|
+
</Grid>
|
|
707
|
+
<Grid item size={{ xs: 12, md: 9 }} className="h-140" style={{ border: '2px solid black' }}>
|
|
708
|
+
<ResponsiveContainer className="h-full w-full barchart-analytics">
|
|
709
|
+
<BarChart
|
|
710
|
+
data={barChartData}
|
|
711
|
+
margin={{ top: 30, right: 30, left: 30, bottom: 100 }}
|
|
712
|
+
className="h-full w-full"
|
|
713
|
+
dataTestId="feature-usage-analytics-bar-chart"
|
|
714
|
+
>
|
|
715
|
+
<Legend
|
|
716
|
+
layout="horizontal"
|
|
717
|
+
verticalAlign="top"
|
|
718
|
+
align="center"
|
|
719
|
+
wrapperStyle={{ paddingBottom: 20 }}
|
|
720
|
+
content={<CustomLegend />}
|
|
721
|
+
/>
|
|
722
|
+
<XAxis
|
|
723
|
+
dataKey="name"
|
|
724
|
+
angle={-45}
|
|
725
|
+
textAnchor="end"
|
|
726
|
+
interval={0}
|
|
727
|
+
height={100}
|
|
728
|
+
axisLine={false}
|
|
729
|
+
tickLine={false}
|
|
730
|
+
className="text-sm font-normal"
|
|
731
|
+
/>
|
|
732
|
+
<YAxis
|
|
733
|
+
label={{
|
|
734
|
+
value: 'Time in seconds',
|
|
735
|
+
angle: -90,
|
|
736
|
+
position: 'insideLeft',
|
|
737
|
+
dy: 50,
|
|
738
|
+
dx: -20,
|
|
739
|
+
}}
|
|
740
|
+
axisLine={false}
|
|
741
|
+
tickLine={false}
|
|
742
|
+
className="text-sm font-normal"
|
|
743
|
+
/>
|
|
744
|
+
<Tooltip content={<CustomTooltipBarChart />} cursor={false} />
|
|
745
|
+
<Bar
|
|
746
|
+
dataKey="average"
|
|
747
|
+
name="Average usage of all visits"
|
|
748
|
+
fill="#C6DCF2"
|
|
749
|
+
stackId="stack1"
|
|
750
|
+
stroke="#2B7DCE"
|
|
751
|
+
shape={<CustomBarWithoutBottomStroke stroke="#2B7DCE" />}
|
|
752
|
+
/>
|
|
753
|
+
<Bar
|
|
754
|
+
dataKey="maximum"
|
|
755
|
+
name="Maximum usage of all visits"
|
|
756
|
+
fill="#F4D8C6"
|
|
757
|
+
stackId="stack1"
|
|
758
|
+
stroke="#E65C00"
|
|
759
|
+
shape={<CustomBarWithoutBottomStroke stroke="#E65C00" />}
|
|
760
|
+
/>
|
|
761
|
+
</BarChart>
|
|
762
|
+
</ResponsiveContainer>
|
|
763
|
+
</Grid>
|
|
764
|
+
</Grid>
|
|
765
|
+
<Grid container justifyContent="center" alignItems="center" className="h-fit w-full mt-10">
|
|
766
|
+
<Grid item size={{ xs: 12 }} className="text-center text-base font-semibold">
|
|
767
|
+
Page/Feature usage raw data
|
|
768
|
+
</Grid>
|
|
769
|
+
<Grid item size={{ xs: 12, md: 9 }}>
|
|
770
|
+
<CustomizedTable
|
|
771
|
+
styleConfig={{ tableStyle: { maxHeight: 120 } }}
|
|
772
|
+
columns={rawDataTableFields}
|
|
773
|
+
tableData={rawDataTableData}
|
|
774
|
+
paginationConfig={{ pagination: false }}
|
|
775
|
+
dataTestId="feature-usage-analytics-raw-data"
|
|
776
|
+
/>
|
|
777
|
+
</Grid>
|
|
778
|
+
</Grid>
|
|
779
|
+
|
|
780
|
+
{filteredData?.length > 9 && (
|
|
781
|
+
<Grid container justifyContent="space-between" alignItems="center" className="h-fit w-full mt-10">
|
|
782
|
+
<Grid item size={{ xs: 12 }} className="text-center text-base font-semibold">
|
|
783
|
+
Page/Feature usage overview
|
|
784
|
+
</Grid>
|
|
785
|
+
|
|
786
|
+
<Grid item size={{ xs: 12, md: 5.5 }} className="mt-5">
|
|
787
|
+
<Grid container>
|
|
788
|
+
<Grid item size={{ xs: 12 }}>
|
|
789
|
+
Top 5 usage based on number of time page visited
|
|
790
|
+
</Grid>
|
|
791
|
+
<Grid item size={{ xs: 12 }}>
|
|
792
|
+
<CustomizedTable
|
|
793
|
+
styleConfig={{ tableStyle: { maxHeight: 200 } }}
|
|
794
|
+
columns={pageVisitedTableFields}
|
|
795
|
+
tableData={top5ByPageCount}
|
|
796
|
+
paginationConfig={{ pagination: false }}
|
|
797
|
+
dataTestId="feature-usage-analytics-top-5-page-visited"
|
|
798
|
+
/>
|
|
799
|
+
</Grid>
|
|
800
|
+
</Grid>
|
|
801
|
+
</Grid>
|
|
802
|
+
<Grid item size={{ xs: 12, md: 5.5 }} className="mt-5">
|
|
803
|
+
<Grid container>
|
|
804
|
+
<Grid item size={{ xs: 12 }}>
|
|
805
|
+
Top 5 usage based on average time (in seconds)
|
|
806
|
+
</Grid>
|
|
807
|
+
<Grid item size={{ xs: 12 }}>
|
|
808
|
+
<CustomizedTable
|
|
809
|
+
styleConfig={{ tableStyle: { maxHeight: 200 } }}
|
|
810
|
+
columns={averageTimeTableFields}
|
|
811
|
+
tableData={top5ByAvgTime}
|
|
812
|
+
paginationConfig={{ pagination: false }}
|
|
813
|
+
dataTestId="feature-usage-analytics-top-5-avg-time"
|
|
814
|
+
/>
|
|
815
|
+
</Grid>
|
|
816
|
+
</Grid>
|
|
817
|
+
</Grid>
|
|
818
|
+
<Grid item size={{ xs: 12, md: 5.5 }} className="mt-10">
|
|
819
|
+
<Grid container>
|
|
820
|
+
<Grid item size={{ xs: 12 }}>
|
|
821
|
+
Bottom 5 usage based on number of time page visited
|
|
822
|
+
</Grid>
|
|
823
|
+
<Grid item size={{ xs: 12 }}>
|
|
824
|
+
<CustomizedTable
|
|
825
|
+
styleConfig={{ tableStyle: { maxHeight: 200 } }}
|
|
826
|
+
columns={pageVisitedTableFields}
|
|
827
|
+
tableData={bottom5ByPageCount}
|
|
828
|
+
paginationConfig={{ pagination: false }}
|
|
829
|
+
dataTestId="feature-usage-analytics-bottom-5-page-visited"
|
|
830
|
+
/>
|
|
831
|
+
</Grid>
|
|
832
|
+
</Grid>
|
|
833
|
+
</Grid>
|
|
834
|
+
<Grid item size={{ xs: 12, md: 5.5 }} className="mt-10">
|
|
835
|
+
<Grid container>
|
|
836
|
+
<Grid item size={{ xs: 12 }}>
|
|
837
|
+
Bottom 5 usage based on average time (in seconds)
|
|
838
|
+
</Grid>
|
|
839
|
+
<Grid item size={{ xs: 12 }}>
|
|
840
|
+
<CustomizedTable
|
|
841
|
+
styleConfig={{ tableStyle: { maxHeight: 200 } }}
|
|
842
|
+
columns={averageTimeTableFields}
|
|
843
|
+
tableData={bottom5ByAvgTime}
|
|
844
|
+
paginationConfig={{ pagination: false }}
|
|
845
|
+
dataTestId="feature-usage-analytics-bottom-5-avg-time"
|
|
846
|
+
/>
|
|
847
|
+
</Grid>
|
|
848
|
+
</Grid>
|
|
849
|
+
</Grid>
|
|
850
|
+
</Grid>
|
|
851
|
+
)}
|
|
852
|
+
</Grid>
|
|
853
|
+
</Grid>
|
|
854
|
+
) : (
|
|
855
|
+
<Grid container>
|
|
856
|
+
<Grid
|
|
857
|
+
item
|
|
858
|
+
size={{ xs: 12 }}
|
|
859
|
+
className="mt-10 bg-[#F8D7DA] p-1 text-center text-[0.8rem] text-[#722E59]"
|
|
860
|
+
>
|
|
861
|
+
Sorry !! no data to display !! kindly try modifying the filter
|
|
862
|
+
</Grid>
|
|
863
|
+
</Grid>
|
|
864
|
+
)}
|
|
865
|
+
</ChartDataSkeleton>
|
|
866
|
+
</Grid>
|
|
867
|
+
</Card>
|
|
868
|
+
</FeatureUsageAnalyticsSkeleton>
|
|
869
|
+
);
|
|
870
|
+
};
|
|
871
|
+
|
|
872
|
+
export default FeatureUsageAnalytics;
|
|
873
|
+
|
|
874
|
+
export const FeatureUsageAnalyticsSkeleton = ({ children, isLoading }) => {
|
|
875
|
+
const useSkeleton = useSelector(getUseSkeleton);
|
|
876
|
+
if (!useSkeleton) {
|
|
877
|
+
return children;
|
|
878
|
+
}
|
|
879
|
+
if (!isLoading) {
|
|
880
|
+
return children;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
return (
|
|
884
|
+
<div className="pl-20 pr-20 pt-5 mb-10 animate-pulse">
|
|
885
|
+
<div className="grid grid-cols-1 md:grid-cols-4 gap-4 w-full">
|
|
886
|
+
{/* Select Role */}
|
|
887
|
+
<div className="space-y-2">
|
|
888
|
+
<div className="h-4 bg-gray-300 rounded w-1/2"></div>
|
|
889
|
+
<div className="h-10 bg-gray-300 rounded w-full"></div>
|
|
890
|
+
</div>
|
|
891
|
+
|
|
892
|
+
{/* Select Page */}
|
|
893
|
+
<div className="space-y-2">
|
|
894
|
+
<div className="h-4 bg-gray-300 rounded w-1/2"></div>
|
|
895
|
+
<div className="h-10 bg-gray-300 rounded w-full"></div>
|
|
896
|
+
</div>
|
|
897
|
+
|
|
898
|
+
{/* From Date */}
|
|
899
|
+
<div className="space-y-2">
|
|
900
|
+
<div className="h-4 bg-gray-300 rounded w-1/2"></div>
|
|
901
|
+
<div className="h-10 bg-gray-300 rounded w-full"></div>
|
|
902
|
+
</div>
|
|
903
|
+
|
|
904
|
+
{/* To Date */}
|
|
905
|
+
<div className="space-y-2">
|
|
906
|
+
<div className="h-4 bg-gray-300 rounded w-1/2"></div>
|
|
907
|
+
<div className="h-10 bg-gray-300 rounded w-full"></div>
|
|
908
|
+
</div>
|
|
909
|
+
</div>
|
|
910
|
+
</div>
|
|
911
|
+
);
|
|
912
|
+
};
|
|
913
|
+
|
|
914
|
+
FeatureUsageAnalyticsSkeleton.propTypes = {
|
|
915
|
+
children: PropTypes.any,
|
|
916
|
+
loading: PropTypes.any,
|
|
917
|
+
isLoading: PropTypes.any,
|
|
918
|
+
};
|
|
919
|
+
|
|
920
|
+
const SkeletonBox = ({ height = 'h-10', width = 'w-full' }) => (
|
|
921
|
+
<div className={`bg-gray-300 animate-pulse rounded ${height} ${width}`}></div>
|
|
922
|
+
);
|
|
923
|
+
|
|
924
|
+
SkeletonBox.propTypes = {
|
|
925
|
+
height: PropTypes.any,
|
|
926
|
+
width: PropTypes.any,
|
|
927
|
+
};
|
|
928
|
+
|
|
929
|
+
export const ChartDataSkeleton = ({ children, isLoading }) => {
|
|
930
|
+
const useSkeleton = useSelector(getUseSkeleton);
|
|
931
|
+
if (!useSkeleton) {
|
|
932
|
+
return children;
|
|
933
|
+
}
|
|
934
|
+
if (!isLoading) {
|
|
935
|
+
return children;
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
return (
|
|
939
|
+
<div className="p-4 space-y-10">
|
|
940
|
+
{/* Top 10 usage */}
|
|
941
|
+
<div className="text-center text-base font-semibold">
|
|
942
|
+
<SkeletonBox height="h-6" width="w-2/3 mx-auto" />
|
|
943
|
+
</div>
|
|
944
|
+
<div className="border-2 h-60 md:h-75 lg:h-110 xl:h-120 2xl:h-140">
|
|
945
|
+
<SkeletonBox height="h-full" />
|
|
946
|
+
</div>
|
|
947
|
+
|
|
948
|
+
{/* Bar Chart */}
|
|
949
|
+
<div className="text-center text-base font-semibold">
|
|
950
|
+
<SkeletonBox height="h-6" width="w-2/3 mx-auto" />
|
|
951
|
+
</div>
|
|
952
|
+
<div className="border-2 h-140">
|
|
953
|
+
<SkeletonBox height="h-full" />
|
|
954
|
+
</div>
|
|
955
|
+
|
|
956
|
+
{/* Raw Data Table */}
|
|
957
|
+
<div className="text-center text-base font-semibold">
|
|
958
|
+
<SkeletonBox height="h-6" width="w-1/2 mx-auto" />
|
|
959
|
+
</div>
|
|
960
|
+
<div className="space-y-2">
|
|
961
|
+
{[...Array(5)].map((_, i) => (
|
|
962
|
+
<SkeletonBox key={i} height="h-6" />
|
|
963
|
+
))}
|
|
964
|
+
</div>
|
|
965
|
+
|
|
966
|
+
{/* Overview Section - Top 5 / Bottom 5 */}
|
|
967
|
+
<div className="text-center text-base font-semibold">
|
|
968
|
+
<SkeletonBox height="h-6" width="w-1/2 mx-auto" />
|
|
969
|
+
</div>
|
|
970
|
+
|
|
971
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 mt-5">
|
|
972
|
+
{[...Array(4)].map((_, i) => (
|
|
973
|
+
<div key={i} className="space-y-2">
|
|
974
|
+
<SkeletonBox height="h-5" width="w-3/4" />
|
|
975
|
+
{[...Array(5)].map((_, j) => (
|
|
976
|
+
<SkeletonBox key={j} height="h-6" />
|
|
977
|
+
))}
|
|
978
|
+
</div>
|
|
979
|
+
))}
|
|
980
|
+
</div>
|
|
981
|
+
</div>
|
|
982
|
+
);
|
|
983
|
+
};
|
|
984
|
+
|
|
985
|
+
ChartDataSkeleton.propTypes = {
|
|
986
|
+
children: PropTypes.any,
|
|
987
|
+
loading: PropTypes.any,
|
|
988
|
+
isLoading: PropTypes.any,
|
|
989
|
+
};
|