@argusoft/medplat-app-shell 1.0.5 → 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.
Files changed (263) hide show
  1. package/package.json +139 -141
  2. package/src/GlobalErrorBoundary.jsx +31 -0
  3. package/src/SilentErrorFallback.jsx +68 -0
  4. package/src/TrackingProviderWrapper.jsx +40 -0
  5. package/src/_tests_/__mocks__/MockTranslationProvider.jsx +21 -0
  6. package/src/_tests_/__mocks__/ckeditor.js +45 -0
  7. package/src/_tests_/__mocks__/fileMock.js +1 -0
  8. package/src/_tests_/__mocks__/useranalytics.js +5 -0
  9. package/src/_tests_/views/components/Dashboard/DashboardUI.test.jsx +137 -0
  10. package/src/_tests_/views/components/Dashboard/DashboardUIMock.js +877 -0
  11. package/src/_tests_/views/components/ForgotPassword/ForgotPassword.test.jsx +314 -0
  12. package/src/_tests_/views/components/LocationDirective/LocationDirective.test.jsx.disable +229 -0
  13. package/src/_tests_/views/components/LocationDirective/mockLocationDirective.js +810 -0
  14. package/src/_tests_/views/components/LocationType/MockLocationType.js +42259 -0
  15. package/src/_tests_/views/components/LocationType/addlocationtype.test.jsx.disable +276 -0
  16. package/src/_tests_/views/components/LocationType/editlocationtype.test.jsx.disable +262 -0
  17. package/src/_tests_/views/components/LocationType/locationtype.test.jsx.disable +148 -0
  18. package/src/_tests_/views/components/Profile/UpdateProfileModalData.js +4396 -0
  19. package/src/_tests_/views/components/Profile/updateprofilemodal.test.jsx +282 -0
  20. package/src/_tests_/views/components/SideBar/MockSideBar.js +1379 -0
  21. package/src/_tests_/views/components/SideBar/SideBar.test.jsx +98 -0
  22. package/src/_tests_/views/components/SystemConfig/ManageSystemConfig/AddManageSystemConfig.test.jsx.disable +164 -0
  23. package/src/_tests_/views/components/SystemConfig/ManageSystemConfig/UpdateManageSystemConfig.test.jsx.disable +157 -0
  24. package/src/_tests_/views/components/SystemConfig/MockSystemConfig.js +1280 -0
  25. package/src/_tests_/views/components/SystemConfig/SystemConfig.test.jsx.disable +165 -0
  26. package/src/_tests_/views/components/login/Login.test.jsx +276 -0
  27. package/src/_tests_/views/components/login/MockAuthorise.js +2414 -0
  28. package/src/_tests_/views/components/login/ServiceResponse.js +595 -0
  29. package/src/_tests_/views/components/user/MockManageUser.js +7965 -0
  30. package/src/_tests_/views/components/user/manageuser.test.jsx.disable +989 -0
  31. package/src/_tests_/views/components/user/mockUsersData.js +582 -0
  32. package/src/assets/img/OASISLogin.png +0 -0
  33. package/src/assets/img/bahaarNew.png +0 -0
  34. package/src/assets/img/dnhdd4K.png +0 -0
  35. package/src/assets/img/govtofup.png +0 -0
  36. package/src/assets/img/sewarural4K.png +0 -0
  37. package/src/assets/img/techo4K.png +0 -0
  38. package/src/assets/img/up4K.png +0 -0
  39. package/src/common/HolidayList.jsx +573 -0
  40. package/src/common/MalaciaousInputUtil.js +23 -0
  41. package/src/common/SafeHtml.jsx +17 -0
  42. package/src/common/VersionManager.jsx +109 -0
  43. package/src/common/constants/PerformanceDashboard.js +514 -0
  44. package/src/common/constants/app.constant.js +781 -0
  45. package/src/common/constants/cccVerificationConstants.js +18 -0
  46. package/src/common/constants/fhsrConstant.js +33 -0
  47. package/src/common/constants/gvk-verification.constant.js +76 -0
  48. package/src/common/constants/search.constant.js +23 -0
  49. package/src/common/constants/teleconsulatationConstant.jsx +1339 -0
  50. package/src/common/directives/SearchTemplate.jsx +784 -0
  51. package/src/common/directives/SearchTemplate.scss +14 -0
  52. package/src/common/dynamicView/DynamicView.jsx +353 -0
  53. package/src/common/dynamicView/InputFieldComponent.jsx +1501 -0
  54. package/src/common/dynamicView/InputViewComponent.jsx +298 -0
  55. package/src/common/dynamicView/InputViewComponent.scss +15 -0
  56. package/src/common/env.js +5 -0
  57. package/src/common/filters/locationNameFilter.js +26 -0
  58. package/src/common/fontAwesomeIcons/FontAwesomeIcons.jsx +27 -0
  59. package/src/common/fontAwesomeIcons/FontAwesomeIconsNames.js +1968 -0
  60. package/src/common/fontPreferences/fontSizeProvider.jsx +34 -0
  61. package/src/common/fontPreferences/fontSizeSelector.jsx +116 -0
  62. package/src/common/getAssignedFeature/getAssignedFeature.js +32 -0
  63. package/src/common/interceptors/AxiosInterceptor.js +216 -0
  64. package/src/common/languageTranslator/TranslationContext.js +5 -0
  65. package/src/common/languageTranslator/TranslationProvider.jsx +24 -0
  66. package/src/common/languageTranslator/i18n.js +49 -0
  67. package/src/common/services/AuthenticateService.js +116 -0
  68. package/src/common/services/DownloadFile.js +35 -0
  69. package/src/common/services/ForgotPassword.js +18 -0
  70. package/src/common/services/FormConfiguratorService.js +195 -0
  71. package/src/common/services/GlobalApis.js +84 -0
  72. package/src/common/services/InterceptorNavigationService.js +17 -0
  73. package/src/common/services/LocationService.js +65 -0
  74. package/src/common/services/LocationType.js +11 -0
  75. package/src/common/services/QueryBuilder.js +36 -0
  76. package/src/common/services/Roles.js +28 -0
  77. package/src/common/services/SyncWithServer.js +15 -0
  78. package/src/common/services/SystemConfig.js +15 -0
  79. package/src/common/services/TranslationService.js +70 -0
  80. package/src/common/services/TwoFactorService.js +7 -0
  81. package/src/common/services/Users.js +91 -0
  82. package/src/common/services/Webtasks.js +27 -0
  83. package/src/common/services/util/Convert-pad-data-to-API-format.jsx +167 -0
  84. package/src/common/services/util/Convert-to-UI-format.jsx +82 -0
  85. package/src/common/services/util/EmptyPrescriptionPadData.jsx +11 -0
  86. package/src/common/services/util/GeneralUtil.js +456 -0
  87. package/src/common/services/util/Prescription-pad-util.js +339 -0
  88. package/src/common/services/util/PrescriptionPadData.js +67 -0
  89. package/src/common/services/util/PrescriptionpadCommonUtil.js +96 -0
  90. package/src/common/services/util/ReportFieldUtil.jsx +398 -0
  91. package/src/common/services/util/WebSocketContext.jsx +261 -0
  92. package/src/common/syncWithServer/SyncWithServerDialog.jsx +170 -0
  93. package/src/common/syncWithServer/SyncWithServerDialogSkeleton.jsx +67 -0
  94. package/src/common/tests/CustomWrapper.jsx +49 -0
  95. package/src/common/tests/TranslationWrapper.jsx +38 -0
  96. package/src/common/themeProvider/ColorInputs.jsx +97 -0
  97. package/src/common/themeProvider/EditableColorInput.jsx +128 -0
  98. package/src/common/themeProvider/ThemeEditor.jsx +319 -0
  99. package/src/common/themeProvider/ThemeProvider.jsx +210 -0
  100. package/src/common/themeProvider/themeConfig.js +558 -0
  101. package/src/common/toaster/toaster.jsx +30 -0
  102. package/src/firebaseConfig.js +24 -0
  103. package/src/global.scss +221 -0
  104. package/src/hooks/.gitkeep +0 -0
  105. package/src/hooks/useAESEncryption.js +56 -0
  106. package/src/hooks/useCaching.js +43 -0
  107. package/src/hooks/useDebounce.js +34 -0
  108. package/src/hooks/useDebounceFn.js +50 -0
  109. package/src/hooks/useDownloadPdf.js +358 -0
  110. package/src/hooks/useDownloadXlsx.js +55 -0
  111. package/src/hooks/useListValueFieldValues.js +30 -0
  112. package/src/hooks/useLocationHierarchies.js +63 -0
  113. package/src/hooks/useLocationHierarchyTranslate.js +16 -0
  114. package/src/hooks/useOnline.js +27 -0
  115. package/src/hooks/usePagination.js +63 -0
  116. package/src/hooks/useRefreshToken.js +87 -0
  117. package/src/hooks/useScript.js +25 -0
  118. package/src/hooks/useStopwatch.js +75 -0
  119. package/src/hooks/useTrackEvent.js +22 -0
  120. package/src/hooks/useWebAudioRecorder.js +115 -0
  121. package/src/layout/LoaderComponet.jsx +22 -0
  122. package/src/layout/LoaderContext.jsx +29 -0
  123. package/src/layout/mainLayout/AdaptiveZoom.jsx +27 -0
  124. package/src/layout/mainLayout/Chatbot.jsx +243 -0
  125. package/src/layout/mainLayout/Layout.jsx +445 -0
  126. package/src/layout/mainLayout/Profile/UpdateProfileModal.jsx +684 -0
  127. package/src/layout/mainLayout/header/LogoutModal.jsx +131 -0
  128. package/src/layout/mainLayout/header/Navbar.jsx +1677 -0
  129. package/src/layout/mainLayout/header/Navbar.scss +4 -0
  130. package/src/layout/mainLayout/header/index.js +0 -0
  131. package/src/layout/mainLayout/sidebar/SideBar.jsx +1402 -0
  132. package/src/layout/mainLayout/sidebar/Sidebar.css +159 -0
  133. package/src/layout/mainLayout/sidebar/index.js +0 -0
  134. package/src/logo.svg +1 -0
  135. package/src/reportWebVitals.js +13 -0
  136. package/src/setupFirebaseMessaging.js +28 -0
  137. package/src/setupTests.js +8 -0
  138. package/src/store/actions/AuthenticationActions.js +0 -0
  139. package/src/store/actions/ReportsActions.js +0 -0
  140. package/src/store/actions/TranslationAction.js +0 -0
  141. package/src/store/index.js +8 -0
  142. package/src/store/reducer.js +46 -0
  143. package/src/store/reducers/AuthenticationReducer.js +50 -0
  144. package/src/store/reducers/CalendarEventReducer.js +41 -0
  145. package/src/store/reducers/ConditionClipboardReducer.js +45 -0
  146. package/src/store/reducers/FeatureReducer.js +27 -0
  147. package/src/store/reducers/FormConfiguratorReducer.js +38 -0
  148. package/src/store/reducers/LoadingReducer.js +20 -0
  149. package/src/store/reducers/MembersAuthenticationReducer.js +28 -0
  150. package/src/store/reducers/PrescriptionPadReducer.js +329 -0
  151. package/src/store/reducers/QuestionaireReducer.js +29 -0
  152. package/src/store/reducers/ReportsReducer.js +24 -0
  153. package/src/store/reducers/SkeletonReducer.js +20 -0
  154. package/src/store/reducers/ThemeReducer.js +106 -0
  155. package/src/store/reducers/TranslationReducer.js +126 -0
  156. package/src/store/reducers/dashboardEditorSlice.js +77 -0
  157. package/src/store/reducers/districtHealthDashboardSlice.js +58 -0
  158. package/src/store/reducers/immunizationSlice.js +234 -0
  159. package/src/store/slices/dashboardPagesSlice.js +51 -0
  160. package/src/utils/.gitkeep +0 -0
  161. package/src/utils/FormConstants.js +2629 -0
  162. package/src/utils/GujaratTopoChart.jsx +483 -0
  163. package/src/utils/UUIDgenerator.js +8 -0
  164. package/src/utils/appointment-utils/appointment-utils.js +123 -0
  165. package/src/utils/feature.js +42 -0
  166. package/src/utils/getThemeColor.js +12 -0
  167. package/src/utils/localStorageHelper.js +11 -0
  168. package/src/utils/notifications/enable-push-notifications.js +27 -0
  169. package/src/utils/resolveAppliedStyle.js +11 -0
  170. package/src/utils/themeConfigs.js +1483 -0
  171. package/src/views/custom-components/.gitkeep +0 -0
  172. package/src/views/custom-components/AgIconButton/RIf.jsx +14 -0
  173. package/src/views/custom-components/AgIconButton/button.jsx +108 -0
  174. package/src/views/custom-components/AgIconButton/waterDrop.jsx +95 -0
  175. package/src/views/custom-components/AgIconButton/waterDrop.scss +37 -0
  176. package/src/views/custom-components/AlertPlaceholder.jsx +32 -0
  177. package/src/views/custom-components/AllFaIconsSelector.jsx +56 -0
  178. package/src/views/custom-components/CkEditor/CkEditor.js +102 -0
  179. package/src/views/custom-components/CustomAccordion.jsx +72 -0
  180. package/src/views/custom-components/CustomActionIcons.jsx +118 -0
  181. package/src/views/custom-components/CustomAutoComplete.jsx +188 -0
  182. package/src/views/custom-components/CustomCheckBox.jsx +60 -0
  183. package/src/views/custom-components/CustomConfirmationModal.jsx +118 -0
  184. package/src/views/custom-components/CustomCountrySelect.jsx +129 -0
  185. package/src/views/custom-components/CustomDatePicker.jsx +122 -0
  186. package/src/views/custom-components/CustomDropdown.jsx +191 -0
  187. package/src/views/custom-components/CustomFileUpload.jsx +387 -0
  188. package/src/views/custom-components/CustomFullCalendar.jsx +514 -0
  189. package/src/views/custom-components/CustomInfiniteScroll.jsx +126 -0
  190. package/src/views/custom-components/CustomRadioComponent.jsx +65 -0
  191. package/src/views/custom-components/CustomStatsComponent.jsx +114 -0
  192. package/src/views/custom-components/CustomSvgUpload.jsx +170 -0
  193. package/src/views/custom-components/CustomSwitch.jsx +37 -0
  194. package/src/views/custom-components/CustomTabPanel.jsx +19 -0
  195. package/src/views/custom-components/CustomTextArea.jsx +62 -0
  196. package/src/views/custom-components/CustomTextArea.scss +27 -0
  197. package/src/views/custom-components/CustomTextField.jsx +116 -0
  198. package/src/views/custom-components/CustomToggleSwitch.jsx +138 -0
  199. package/src/views/custom-components/CustomTooltip.jsx +51 -0
  200. package/src/views/custom-components/CustomZoomImage.jsx +134 -0
  201. package/src/views/custom-components/CustomizedTable/CustomizedTableV2.jsx +1407 -0
  202. package/src/views/custom-components/CustomizedTable/VirtualizeTableBody.jsx +295 -0
  203. package/src/views/custom-components/CustomizedTable/helper.jsx +159 -0
  204. package/src/views/custom-components/CustomizedTable.jsx +532 -0
  205. package/src/views/custom-components/EditInputField.jsx +174 -0
  206. package/src/views/custom-components/FieldDescription.jsx +22 -0
  207. package/src/views/custom-components/FileDisplayComponent.jsx +138 -0
  208. package/src/views/custom-components/FormItem.jsx +53 -0
  209. package/src/views/custom-components/GenericChart.jsx +80 -0
  210. package/src/views/custom-components/InfoBadge.jsx +60 -0
  211. package/src/views/custom-components/PostgresEditor.jsx +801 -0
  212. package/src/views/custom-components/ResizableEditAutocompleteField.jsx +249 -0
  213. package/src/views/custom-components/ResizableEditInputField.jsx +215 -0
  214. package/src/views/custom-components/ResizeableEditSelectField.jsx +197 -0
  215. package/src/views/custom-components/SideOverlay.jsx +113 -0
  216. package/src/views/custom-components/SideOverlay.scss +42 -0
  217. package/src/views/custom-components/calendar.scss +571 -0
  218. package/src/views/feature-components/.gitkeep +0 -0
  219. package/src/views/feature-components/Dashboard/DashboardUI.jsx +1043 -0
  220. package/src/views/feature-components/Dashboard/DhnddModal/AshaDataQualityVerificationModal.jsx +278 -0
  221. package/src/views/feature-components/Dashboard/PinFeatureModal.jsx +143 -0
  222. package/src/views/feature-components/Dashboard/QuickLinks.jsx +163 -0
  223. package/src/views/feature-components/Dashboard/Taskbar.jsx +56 -0
  224. package/src/views/feature-components/Dashboard/WebtasksFilterForm.jsx +109 -0
  225. package/src/views/feature-components/Dashboard/WidgetCard.jsx +161 -0
  226. package/src/views/feature-components/Dashboard/actionModal.jsx +263 -0
  227. package/src/views/feature-components/Dashboard/ekavachModal/HealthWorkerIncorrectDetailsModal.jsx +332 -0
  228. package/src/views/feature-components/Dashboard/ekavachModal/MoMaternalDeathVerifcationModal.jsx +275 -0
  229. package/src/views/feature-components/Dashboard/ekavachModal/MoVerficationForChildScreeningMoadal.jsx +566 -0
  230. package/src/views/feature-components/FeatureUsageAnalytics/FeatureUsageAnalytics.jsx +989 -0
  231. package/src/views/feature-components/Features/NewServerManagement.jsx +217 -0
  232. package/src/views/feature-components/Features/ServerManagement.scss +120 -0
  233. package/src/views/feature-components/ForgotPassword/ForgotPassword.jsx +226 -0
  234. package/src/views/feature-components/LocationDirective/LocationDirective.jsx +992 -0
  235. package/src/views/feature-components/LocationDirective/LocationDirectiveV2.jsx +909 -0
  236. package/src/views/feature-components/NotFound.jsx +66 -0
  237. package/src/views/feature-components/Onboarding/Onboarding.jsx +1400 -0
  238. package/src/views/feature-components/Skeletons.js +115 -0
  239. package/src/views/feature-components/Unauthorized.jsx +48 -0
  240. package/src/views/feature-components/VerifyRoute.jsx +88 -0
  241. package/src/views/feature-components/YearlyRecap/YearlyRecap.jsx +357 -0
  242. package/src/views/feature-components/YearlyRecap/components/RecapSlide.jsx +183 -0
  243. package/src/views/feature-components/YearlyRecap/languageTranslator/TranslationContext.js +5 -0
  244. package/src/views/feature-components/YearlyRecap/languageTranslator/TranslationProvider.jsx +26 -0
  245. package/src/views/feature-components/YearlyRecap/languageTranslator/i18n.js +46 -0
  246. package/src/views/feature-components/YearlyRecap/languageTranslator/translations.json +167 -0
  247. package/src/views/feature-components/YearlyRecap/slides/IntroSlide.jsx +233 -0
  248. package/src/views/feature-components/YearlyRecap/slides/MaternalHealthSlide.jsx +146 -0
  249. package/src/views/feature-components/YearlyRecap/slides/MetricSlide.jsx +227 -0
  250. package/src/views/feature-components/YearlyRecap/slides/OutroSlide.jsx +701 -0
  251. package/src/views/feature-components/YearlyRecap/slides/ReachSlide.jsx +273 -0
  252. package/src/views/feature-components/login/Login.jsx +840 -0
  253. package/src/views/feature-components/login/Login.scss +154 -0
  254. package/src/views/feature-components/login/LoginConfigurator.jsx +1149 -0
  255. package/src/views/feature-components/login/TwoFactorSetupModal.jsx +411 -0
  256. package/src/views/feature-components/login/simplifyMenu.js +45 -0
  257. package/src/views/feature-components/system-config/ManageSystemConfigs.jsx +284 -0
  258. package/src/views/feature-components/system-config/SystemConfig.jsx +299 -0
  259. package/src/views/feature-components/users/ChangePasswordModal.jsx +243 -0
  260. package/src/views/feature-components/users/PasswordField.jsx +56 -0
  261. package/dist/index.css +0 -1
  262. package/dist/index.js +0 -32001
  263. 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
+ };