@argusoft/medplat-app-shell 1.0.6 → 1.0.8

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 (264) 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/store/slices/dashboardSlice.js +14 -0
  161. package/src/utils/.gitkeep +0 -0
  162. package/src/utils/FormConstants.js +2629 -0
  163. package/src/utils/GujaratTopoChart.jsx +483 -0
  164. package/src/utils/UUIDgenerator.js +8 -0
  165. package/src/utils/appointment-utils/appointment-utils.js +123 -0
  166. package/src/utils/feature.js +42 -0
  167. package/src/utils/getThemeColor.js +12 -0
  168. package/src/utils/localStorageHelper.js +11 -0
  169. package/src/utils/notifications/enable-push-notifications.js +27 -0
  170. package/src/utils/resolveAppliedStyle.js +11 -0
  171. package/src/utils/themeConfigs.js +1483 -0
  172. package/src/views/custom-components/.gitkeep +0 -0
  173. package/src/views/custom-components/AgIconButton/RIf.jsx +14 -0
  174. package/src/views/custom-components/AgIconButton/button.jsx +108 -0
  175. package/src/views/custom-components/AgIconButton/waterDrop.jsx +95 -0
  176. package/src/views/custom-components/AgIconButton/waterDrop.scss +37 -0
  177. package/src/views/custom-components/AlertPlaceholder.jsx +32 -0
  178. package/src/views/custom-components/AllFaIconsSelector.jsx +56 -0
  179. package/src/views/custom-components/CkEditor/CkEditor.js +102 -0
  180. package/src/views/custom-components/CustomAccordion.jsx +72 -0
  181. package/src/views/custom-components/CustomActionIcons.jsx +118 -0
  182. package/src/views/custom-components/CustomAutoComplete.jsx +188 -0
  183. package/src/views/custom-components/CustomCheckBox.jsx +60 -0
  184. package/src/views/custom-components/CustomConfirmationModal.jsx +118 -0
  185. package/src/views/custom-components/CustomCountrySelect.jsx +129 -0
  186. package/src/views/custom-components/CustomDatePicker.jsx +122 -0
  187. package/src/views/custom-components/CustomDropdown.jsx +191 -0
  188. package/src/views/custom-components/CustomFileUpload.jsx +387 -0
  189. package/src/views/custom-components/CustomFullCalendar.jsx +514 -0
  190. package/src/views/custom-components/CustomInfiniteScroll.jsx +126 -0
  191. package/src/views/custom-components/CustomRadioComponent.jsx +65 -0
  192. package/src/views/custom-components/CustomStatsComponent.jsx +114 -0
  193. package/src/views/custom-components/CustomSvgUpload.jsx +170 -0
  194. package/src/views/custom-components/CustomSwitch.jsx +37 -0
  195. package/src/views/custom-components/CustomTabPanel.jsx +19 -0
  196. package/src/views/custom-components/CustomTextArea.jsx +62 -0
  197. package/src/views/custom-components/CustomTextArea.scss +27 -0
  198. package/src/views/custom-components/CustomTextField.jsx +116 -0
  199. package/src/views/custom-components/CustomToggleSwitch.jsx +138 -0
  200. package/src/views/custom-components/CustomTooltip.jsx +51 -0
  201. package/src/views/custom-components/CustomZoomImage.jsx +134 -0
  202. package/src/views/custom-components/CustomizedTable/CustomizedTableV2.jsx +1407 -0
  203. package/src/views/custom-components/CustomizedTable/VirtualizeTableBody.jsx +295 -0
  204. package/src/views/custom-components/CustomizedTable/helper.jsx +159 -0
  205. package/src/views/custom-components/CustomizedTable.jsx +532 -0
  206. package/src/views/custom-components/EditInputField.jsx +174 -0
  207. package/src/views/custom-components/FieldDescription.jsx +22 -0
  208. package/src/views/custom-components/FileDisplayComponent.jsx +138 -0
  209. package/src/views/custom-components/FormItem.jsx +53 -0
  210. package/src/views/custom-components/GenericChart.jsx +80 -0
  211. package/src/views/custom-components/InfoBadge.jsx +60 -0
  212. package/src/views/custom-components/PostgresEditor.jsx +801 -0
  213. package/src/views/custom-components/ResizableEditAutocompleteField.jsx +249 -0
  214. package/src/views/custom-components/ResizableEditInputField.jsx +215 -0
  215. package/src/views/custom-components/ResizeableEditSelectField.jsx +197 -0
  216. package/src/views/custom-components/SideOverlay.jsx +113 -0
  217. package/src/views/custom-components/SideOverlay.scss +42 -0
  218. package/src/views/custom-components/calendar.scss +571 -0
  219. package/src/views/feature-components/.gitkeep +0 -0
  220. package/src/views/feature-components/Dashboard/DashboardUI.jsx +1043 -0
  221. package/src/views/feature-components/Dashboard/DhnddModal/AshaDataQualityVerificationModal.jsx +278 -0
  222. package/src/views/feature-components/Dashboard/PinFeatureModal.jsx +143 -0
  223. package/src/views/feature-components/Dashboard/QuickLinks.jsx +163 -0
  224. package/src/views/feature-components/Dashboard/Taskbar.jsx +56 -0
  225. package/src/views/feature-components/Dashboard/WebtasksFilterForm.jsx +109 -0
  226. package/src/views/feature-components/Dashboard/WidgetCard.jsx +161 -0
  227. package/src/views/feature-components/Dashboard/actionModal.jsx +263 -0
  228. package/src/views/feature-components/Dashboard/ekavachModal/HealthWorkerIncorrectDetailsModal.jsx +332 -0
  229. package/src/views/feature-components/Dashboard/ekavachModal/MoMaternalDeathVerifcationModal.jsx +275 -0
  230. package/src/views/feature-components/Dashboard/ekavachModal/MoVerficationForChildScreeningMoadal.jsx +566 -0
  231. package/src/views/feature-components/FeatureUsageAnalytics/FeatureUsageAnalytics.jsx +989 -0
  232. package/src/views/feature-components/Features/NewServerManagement.jsx +217 -0
  233. package/src/views/feature-components/Features/ServerManagement.scss +120 -0
  234. package/src/views/feature-components/ForgotPassword/ForgotPassword.jsx +226 -0
  235. package/src/views/feature-components/LocationDirective/LocationDirective.jsx +992 -0
  236. package/src/views/feature-components/LocationDirective/LocationDirectiveV2.jsx +909 -0
  237. package/src/views/feature-components/NotFound.jsx +66 -0
  238. package/src/views/feature-components/Onboarding/Onboarding.jsx +1400 -0
  239. package/src/views/feature-components/Skeletons.js +115 -0
  240. package/src/views/feature-components/Unauthorized.jsx +48 -0
  241. package/src/views/feature-components/VerifyRoute.jsx +88 -0
  242. package/src/views/feature-components/YearlyRecap/YearlyRecap.jsx +357 -0
  243. package/src/views/feature-components/YearlyRecap/components/RecapSlide.jsx +183 -0
  244. package/src/views/feature-components/YearlyRecap/languageTranslator/TranslationContext.js +5 -0
  245. package/src/views/feature-components/YearlyRecap/languageTranslator/TranslationProvider.jsx +26 -0
  246. package/src/views/feature-components/YearlyRecap/languageTranslator/i18n.js +46 -0
  247. package/src/views/feature-components/YearlyRecap/languageTranslator/translations.json +167 -0
  248. package/src/views/feature-components/YearlyRecap/slides/IntroSlide.jsx +233 -0
  249. package/src/views/feature-components/YearlyRecap/slides/MaternalHealthSlide.jsx +146 -0
  250. package/src/views/feature-components/YearlyRecap/slides/MetricSlide.jsx +227 -0
  251. package/src/views/feature-components/YearlyRecap/slides/OutroSlide.jsx +701 -0
  252. package/src/views/feature-components/YearlyRecap/slides/ReachSlide.jsx +273 -0
  253. package/src/views/feature-components/login/Login.jsx +840 -0
  254. package/src/views/feature-components/login/Login.scss +154 -0
  255. package/src/views/feature-components/login/LoginConfigurator.jsx +1149 -0
  256. package/src/views/feature-components/login/TwoFactorSetupModal.jsx +411 -0
  257. package/src/views/feature-components/login/simplifyMenu.js +45 -0
  258. package/src/views/feature-components/system-config/ManageSystemConfigs.jsx +284 -0
  259. package/src/views/feature-components/system-config/SystemConfig.jsx +299 -0
  260. package/src/views/feature-components/users/ChangePasswordModal.jsx +243 -0
  261. package/src/views/feature-components/users/PasswordField.jsx +56 -0
  262. package/dist/index.css +0 -1
  263. package/dist/index.js +0 -32001
  264. package/dist/index.js.map +0 -1
@@ -0,0 +1,1043 @@
1
+ import React, { lazy, Suspense, useEffect, useRef, useState } from 'react';
2
+ import {
3
+ getCount,
4
+ getWebTasksBasketDetails,
5
+ retrieveBasketPreferenceByUserId,
6
+ saveBasketPreferenceByUserId,
7
+ } from '@/common/services/Webtasks';
8
+ import SideOverlay from '@/views/custom-components/SideOverlay';
9
+ import { getAssignedFeatures } from '@/utils/feature';
10
+ const ActionModal = lazy(() => import('@/views/feature-components/Dashboard/actionModal'));
11
+ const Taskbar = lazy(() => import('@/views/feature-components/Dashboard/Taskbar'));
12
+ import WebtasksFilterForm from '@/views/feature-components/Dashboard/WebtasksFilterForm';
13
+ const WidgetCard = lazy(() => import('@/views/feature-components/Dashboard/WidgetCard'));
14
+ import QuickLinks from './QuickLinks';
15
+ import { Card, IconButton, Popover, Typography, Chip } from '@mui/material';
16
+ import Grid from '@mui/material/Grid2';
17
+ import { Box } from '@mui/system';
18
+ import { saveAs } from 'file-saver';
19
+ import { useDispatch, useSelector } from 'react-redux';
20
+ import useTrackEvent from '@/hooks/useTrackEvent';
21
+ import * as XLSX from 'xlsx-js-style';
22
+ import { showToast } from '@/common/toaster/toaster';
23
+ import CustomizedTable from '@/views/custom-components/CustomizedTable/CustomizedTableV2';
24
+ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
25
+ import { faBars, faEllipsisVertical, faFileExcel } from '@fortawesome/free-solid-svg-icons';
26
+ import { setHeaderTitle } from '@/store/reducers/AuthenticationReducer';
27
+ import { useNavigate } from 'react-router';
28
+ import GeneralUtil from '@/common/services/util/GeneralUtil';
29
+ import HealthWorkerIncorrectDetailsModal from './ekavachModal/HealthWorkerIncorrectDetailsModal';
30
+ import MoMaternalDeathVerifcationModal from './ekavachModal/MoMaternalDeathVerifcationModal';
31
+ import { saveAction } from '@/common/services/Webtasks';
32
+ import MoVerficationForChildScreeningMoadal from './ekavachModal/MoVerficationForChildScreeningMoadal';
33
+ import AshaScreenedMembersModal from './DhnddModal/AshaDataQualityVerificationModal';
34
+ import { useTheme } from '@mui/material/styles';
35
+ import { alpha } from '@mui/material/styles';
36
+ import { execute } from '@/common/services/QueryBuilder';
37
+
38
+ const Dashboard = () => {
39
+ const defaultColors = ['#dd4b39', '#00a65a', '#f39c12', '#00c0ef', '#333333', '#ffc90e'];
40
+ const [widgetData, setWidgetData] = useState([]);
41
+ const [open, setOpen] = useState(false);
42
+ const [modalName, setModalName] = useState('');
43
+ const [hiddenWidgetData, setHiddenWidgetData] = useState([]);
44
+ const [showTaskbar, setShowTaskbar] = useState(null);
45
+ const [showFilter, setShowFilter] = useState(false);
46
+ const [rights, setRights] = useState({});
47
+ const [isLoading, setIsLoading] = useState(false);
48
+ const [webTasksData, setWebTasksData] = useState([]);
49
+ const [selectedWidgetData, setSelectedWidgetData] = useState({});
50
+ const [overlayOpen, setOverlayOpen] = useState(false);
51
+ const [hasMore, setHasMore] = useState(true);
52
+ const [showActionModal, setShowActionModal] = useState(false);
53
+ const [basketPreference, setBasketPreference] = useState({});
54
+ const [taskData, setTaskData] = useState({});
55
+ const [basketData, setBasketData] = useState([]);
56
+ const [selectedLocation, setSelectedLocation] = useState({});
57
+ const [locations, setLocations] = useState([]);
58
+ const navigate = useNavigate();
59
+ const theme = useTheme();
60
+ const isDark = theme.palette.mode === 'dark';
61
+ const [columns, setColumns] = useState([{ field: 'index', label: '#', align: 'left' }]);
62
+ const [scrollToTop, setScrollToTop] = useState(false);
63
+ const [amountEarned, setAmountEarned] = useState(null);
64
+ const { user } = useSelector((state) => state.Authenticate);
65
+ const dispatch = useDispatch();
66
+ const implementation = GeneralUtil.getEnv();
67
+
68
+ const webtaskSaveActions = async (task) => {
69
+ await saveAction([task]);
70
+ await getWebTasksDetails(selectedWidgetData);
71
+ };
72
+
73
+ const loadInitialData = async () => {
74
+ try{
75
+ setIsLoading(true);
76
+ const { data: assignedFeatures } = await getAssignedFeatures('techo.dashboard.webtasks');
77
+ if (assignedFeatures) {
78
+ setRights(JSON.parse(assignedFeatures));
79
+ }
80
+ const { data: widgetData } = await getCount(implementation);
81
+ let currentBasketPreference = {};
82
+ if ((!GeneralUtil.isTecho || rights?.['view.manage.webtasks.retrievebasketpreference']) !== false) {
83
+ const { data: basketPreferenceData } = await retrieveBasketPreferenceByUserId({ userId: user?.id });
84
+ currentBasketPreference = basketPreferenceData || {};
85
+ }
86
+ if (currentBasketPreference) setBasketPreference(currentBasketPreference);
87
+ if (currentBasketPreference?.baskets?.length) {
88
+ setWidgetData(widgetData.filter((data) => !currentBasketPreference.baskets.includes(data.id)));
89
+ setHiddenWidgetData(
90
+ widgetData
91
+ .filter((data) => currentBasketPreference.baskets.includes(data.id))
92
+ .map((data) => ({
93
+ ...data,
94
+ colorCode: data.colorCode || defaultColors[Math.floor(Math.random() * defaultColors.length)],
95
+ }))
96
+ );
97
+ } else {
98
+ setWidgetData(widgetData);
99
+ }
100
+ setIsLoading(false);
101
+ } catch {
102
+ setIsLoading(false);
103
+ }
104
+ };
105
+ useEffect(() => {
106
+ loadInitialData();
107
+ }, []);
108
+
109
+ const handleHideWidget = async (item) => {
110
+ if (Object.keys(basketPreference).length === 0) {
111
+ basketPreference.baskets = [];
112
+ basketPreference.taskbar = 'show';
113
+ }
114
+ const updatedBasketPreference = { ...basketPreference, baskets: [...basketPreference.baskets, item.id] };
115
+ setBasketPreference(updatedBasketPreference);
116
+
117
+ await saveBasketPreferenceByUserId({ preference: JSON.stringify(updatedBasketPreference), userId: user?.id });
118
+ setHiddenWidgetData((prev) => [...prev, item]);
119
+ setWidgetData((prev) => {
120
+ // Filter out the item from widgetData by matching its id
121
+ return prev.filter((widgetItem) => widgetItem.id !== item.id);
122
+ });
123
+ };
124
+
125
+ const actions = (row) => {
126
+ return row.isActionRequired
127
+ ? [
128
+ (!GeneralUtil.isTecho || rights?.['view.manage.webtasks.getaction']) && {
129
+ label: '',
130
+ icon: <FontAwesomeIcon icon={faBars} size="lg" data-testid="webtaskslist-button-menu" />,
131
+ menuItems: [
132
+ (!GeneralUtil.isTecho || rights?.['create.manage.webtasks.saveaction']) && {
133
+ label: row?.url_name ? 'Fill the form' : row?.modal_name ? 'Perform Actions' : 'Actions',
134
+ onClick: () => {
135
+ if (row?.url_name) {
136
+ const formatToCamelCase = (str) => {
137
+ return str?.replace(/-([a-z])/g, (_, char) => char.toUpperCase());
138
+ };
139
+
140
+ const match = row.url_name.match(/^(.*?)\((\{.*\})\)$/);
141
+
142
+ if (!match) {
143
+ navigate('notfound');
144
+ }
145
+
146
+ let baseStructure = match[1].replace(/\./g, '/');
147
+ baseStructure = formatToCamelCase(baseStructure);
148
+
149
+ try {
150
+ const params = JSON.parse(match[2].replace(/'/g, '"'));
151
+
152
+ const { id, queryParams, ...restParams } = params;
153
+
154
+ const pathWithId = id ? `${baseStructure}/${id}` : baseStructure;
155
+
156
+ let queryString = '';
157
+ if (queryParams) {
158
+ queryString = `queryParams=${encodeURIComponent(JSON.stringify(queryParams))}`;
159
+ } else if (Object.keys(restParams).length > 0) {
160
+ queryString = new URLSearchParams(restParams).toString();
161
+ }
162
+
163
+ const finalUrl = queryString ? `/${pathWithId}?${queryString}` : `/${pathWithId}`;
164
+ const pathName = finalUrl.replace(/^\/?techo\//, 'medplat/');
165
+ navigate(`/ui/${pathName}`);
166
+ } catch (error) {
167
+ console.error('Navigation Error:', error);
168
+ navigate('notfound');
169
+ }
170
+ } else if (row?.modal_name) {
171
+ setModalName(row?.modal_name);
172
+ setOpen(true);
173
+ setTaskData({
174
+ ...basketData.find((data) => data.taskId === row.taskId),
175
+ title: selectedWidgetData.name,
176
+ });
177
+ } else {
178
+ setTaskData({
179
+ ...basketData.find((data) => data.taskId === row.taskId),
180
+ title: selectedWidgetData.name,
181
+ });
182
+ setShowActionModal(true);
183
+ }
184
+ },
185
+ },
186
+ ].filter(Boolean), // Filter out null/false items
187
+ },
188
+ ]
189
+ : [];
190
+ };
191
+
192
+ const handleOverlayState = () => setOverlayOpen(!overlayOpen);
193
+
194
+ const getWebTasksDetails = async (item) => {
195
+ dispatch(setHeaderTitle(item.name));
196
+ setSelectedWidgetData(item);
197
+ const { id, isLocationBasedFilterRequired } = item;
198
+ setShowFilter(isLocationBasedFilterRequired);
199
+
200
+ const { data: basketDetail } = await getWebTasksBasketDetails(
201
+ { limit: 100, offset: 0, taskTypeId: id },
202
+ implementation
203
+ ).catch((error) => {
204
+ console.error('🚀 ~ getWebTasksDetails ~ error:', error);
205
+ showToast({ message: 'Unable to retrieve task details', type: 'error' });
206
+ setWebTasksData([]);
207
+ return null;
208
+ });
209
+
210
+ setHasMore(() => basketDetail.length && basketDetail.length === 100);
211
+ setBasketData(basketDetail);
212
+ setWebTasksData(
213
+ basketDetail.map((data, index) => {
214
+ const { details, taskId, ...rest } = data;
215
+ return { index: index + 1, ...details, taskId, ...rest };
216
+ })
217
+ );
218
+
219
+ const excludedColumns = ['modal_name', 'url_name', 'id', 'widgetMessage'];
220
+ const columnNames = Object.keys(basketDetail[0].details).filter((column) => !excludedColumns.includes(column));
221
+
222
+ const columns = columnNames.map((column) => {
223
+ return {
224
+ field: column,
225
+ label: column,
226
+ align: 'left',
227
+ render: (row) => (
228
+ <div className="w-48 h-full flex items-center h-full">
229
+ <div dangerouslySetInnerHTML={{ __html: row?.[column] }} />
230
+ </div>
231
+ ),
232
+ };
233
+ });
234
+
235
+ const showActions = basketDetail.some((data) => data.isActionRequired);
236
+ const finalColumns = [{ field: 'index', label: '#', align: 'left' }, ...columns];
237
+
238
+ if (showActions) {
239
+ finalColumns.push({
240
+ field: 'Actions',
241
+ label: 'Actions',
242
+ align: 'left',
243
+ });
244
+ }
245
+
246
+ setColumns(finalColumns);
247
+ setScrollToTop(true);
248
+ };
249
+
250
+ const processAndDownloadExcel = async (data, locationId) => {
251
+ try {
252
+ const indexedData = data.map((item, index) => ({ '#': index + 1, ...item }));
253
+
254
+ const now = new Date();
255
+ const month = now.getMonth() + 1;
256
+ const fileName = `${selectedWidgetData.name}-${now.getDate()}/${month} ${now.getHours()}:${now.getMinutes()} ${now.getFullYear().toString().slice(-2)}`;
257
+
258
+ const worksheet = XLSX.utils.json_to_sheet(indexedData);
259
+
260
+ const headerStyle = {
261
+ font: { bold: true },
262
+ alignment: { horizontal: 'center' },
263
+ };
264
+
265
+ if (indexedData.length > 0) {
266
+ const range = XLSX.utils.decode_range(worksheet['!ref']);
267
+
268
+ for (let C = range.s.c; C <= range.e.c; ++C) {
269
+ const cell = worksheet[XLSX.utils.encode_cell({ r: 0, c: C })];
270
+ if (!cell) continue;
271
+ cell.s = headerStyle;
272
+ }
273
+ }
274
+
275
+ const workbook = XLSX.utils.book_new();
276
+ XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
277
+
278
+ const excelBuffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
279
+
280
+ const blob = new Blob([excelBuffer], {
281
+ type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
282
+ });
283
+ const blobSizeInMB = (blob.size / (1024 * 1024)).toFixed(2);
284
+
285
+ saveAs(blob, `${fileName}.xlsx`);
286
+
287
+ trackEvent('file_download', {
288
+ file_type: 'excel',
289
+ file_name: `${fileName}.xlsx`,
290
+ file_size: `${blobSizeInMB} MB`,
291
+ filter_parameters: {
292
+ location_id: locationId || null,
293
+ taskTypeId: selectedWidgetData.id,
294
+ },
295
+ download_status: 'success',
296
+ });
297
+ } catch (error) {
298
+ console.error('Error generating Excel file:', error);
299
+ showToast({ message: 'Error generating Excel file', type: 'error' });
300
+ }
301
+ };
302
+
303
+ const downloadExcel = async () => {
304
+ const selectedLocationId = selectedLocation?.finalSelected?.optionSelected?.id;
305
+ const downloadObject = {
306
+ limit: null,
307
+ offset: 0,
308
+ taskTypeId: selectedWidgetData.id,
309
+ };
310
+ if (selectedLocationId) downloadObject['locationId'] = selectedLocationId;
311
+
312
+ const { data: downloadWebtasksList } = await getWebTasksBasketDetails(downloadObject, implementation);
313
+
314
+ let taskDetails = [];
315
+ if (downloadWebtasksList && downloadWebtasksList.length > 0) {
316
+ taskDetails = downloadWebtasksList.map((task) => {
317
+ const details = { ...task.details };
318
+
319
+ // Convert `null` values to empty strings and boolean values to "Yes" or "No"
320
+ Object.keys(details).forEach((key) => {
321
+ if (details[key] === null) {
322
+ details[key] = '';
323
+ } else if (typeof details[key] === 'boolean') {
324
+ details[key] = details[key] ? 'Yes' : 'No';
325
+ }
326
+ });
327
+
328
+ return details;
329
+ });
330
+
331
+ // Call the function to process data and download the Excel file
332
+ }
333
+ processAndDownloadExcel(taskDetails, selectedLocationId);
334
+ };
335
+ const webTasksDataRef = useRef(null);
336
+ useEffect(() => {
337
+ webTasksDataRef.current = webTasksData;
338
+ }, [webTasksData]);
339
+ const loadMore = async (selectedWidgetData) => {
340
+ if (webTasksDataRef?.current?.length >= 100) {
341
+ const { data: basketDetail } = await getWebTasksBasketDetails(
342
+ {
343
+ limit: 100,
344
+ offset: webTasksDataRef?.current?.length,
345
+ taskTypeId: selectedWidgetData.id,
346
+ },
347
+ implementation
348
+ );
349
+ if (basketDetail) {
350
+ setHasMore(() => basketDetail.length && basketDetail.length === 100);
351
+ setWebTasksData([
352
+ ...webTasksDataRef.current,
353
+ ...basketDetail.map((data, index) => {
354
+ const { details, taskId, ...rest } = data;
355
+ return { index: webTasksDataRef?.current?.length + index + 1, ...details, taskId, ...rest };
356
+ // return data.details;
357
+ }),
358
+ ]);
359
+ }
360
+ }
361
+ };
362
+
363
+ const getUnhideWidgetPermission = () => {
364
+ return (!GeneralUtil.isTecho || rights?.['create.manage.webtasks.savebasketpreference']) ? true : false;
365
+ };
366
+
367
+ const getAmountEarned = async () => {
368
+ try {
369
+ const hasChesWidget = widgetData.some((widget) => widget.code === 'TOTAL_AMOUNT_EARNED_BY_CHES');
370
+
371
+ if (hasChesWidget) {
372
+ const res = await execute({
373
+ code: 'TOTAL_AMOUNT_EARNED_BY_CHES_QUERY',
374
+ paramerter: {
375
+ locationId: null,
376
+ },
377
+ });
378
+
379
+ if (res?.data) {
380
+ setAmountEarned(res.data?.result?.[0]['Grand Total Amount'] || null);
381
+ }
382
+ }
383
+ } catch (error) {
384
+ console.error('Error in getting total amount earned:', error);
385
+ // showToast({ message: 'Error generating Excel file', type: 'error' });
386
+ }
387
+ };
388
+ useEffect(() => {
389
+ getAmountEarned();
390
+ }, [widgetData]);
391
+
392
+ const handleUnhideWidget = async (item) => {
393
+ const updatedBaskets = basketPreference.baskets.filter((basketId) => basketId !== item.id);
394
+ const updatedBasketPreference = { ...basketPreference, baskets: updatedBaskets };
395
+
396
+ setBasketPreference(updatedBasketPreference);
397
+ await saveBasketPreferenceByUserId({ preference: JSON.stringify(updatedBasketPreference), userId: user?.id });
398
+
399
+ setHiddenWidgetData((prev) => {
400
+ return prev.filter((widgetItem) => widgetItem.id !== item.id);
401
+ });
402
+ setWidgetData((prev) => [...prev, item]);
403
+ };
404
+ const trackEvent = useTrackEvent();
405
+
406
+ const handleHideTaskbar = () => {
407
+ trackEvent('button_click', {
408
+ button_name: 'hide taskbar',
409
+ button_type: 'navigate',
410
+ button_id: 'taskbar-hide-button',
411
+ });
412
+
413
+ setShowTaskbar(null);
414
+ };
415
+
416
+ const closeActionBar = async (reload) => {
417
+ setShowActionModal(false);
418
+ if (reload) loadInitialData();
419
+ };
420
+
421
+ const hiddenWidgetsTotal = hiddenWidgetData.reduce((acc, item) => acc + (item.count || 0), 0);
422
+ const sortedWidgets = [...widgetData].sort((a, b) => {
423
+ if (a.orderNo === null) return 1;
424
+ if (b.orderNo === null) return -1;
425
+ return a.orderNo - b.orderNo;
426
+ });
427
+ const accentColor = selectedWidgetData?.colorCode || (isDark ? '#4da8da' : '#1c6fb7');
428
+ const shellBorder = theme.palette.custom?.shellBorder || alpha('#0f172a', 0.12);
429
+ const sectionSurface = {
430
+ borderRadius: '24px',
431
+ border: `1px solid ${shellBorder}`,
432
+ background: isDark ? theme.palette.background.paper : 'rgba(255,255,255,0.84)',
433
+ boxShadow: isDark ? '0 18px 36px rgba(0,0,0,0.3)' : '0 14px 30px rgba(148, 163, 184, 0.12)',
434
+ backdropFilter: 'blur(14px)',
435
+ };
436
+ const mutedTextColor = isDark ? alpha('#fff', 0.62) : '#6d8298';
437
+
438
+ return GeneralUtil.isTecho && !isLoading && !rights?.["view.manage.webtasks"] ? (
439
+ <Box className="flex justify-center items-center w-full h-[80vh]">
440
+ <Card
441
+ className="h-80 w-150 flex justify-center items-center"
442
+ >
443
+ <Typography variant="h5" className="text-customBlue">
444
+ You dont have permission to view Web Tasks
445
+ </Typography>
446
+ </Card>
447
+ </Box>
448
+ ) : (
449
+ <Grid
450
+ container
451
+ spacing={2}
452
+ className="w-full m-0"
453
+ sx={{
454
+ position: 'relative',
455
+ px: { xs: 0.25, md: 0.75 },
456
+ pb: 2.5,
457
+ }}
458
+ >
459
+ {modalName === 'health_workers_incorrect_details_modal' && (
460
+ <HealthWorkerIncorrectDetailsModal
461
+ open={open}
462
+ onClose={() => {
463
+ setOpen(false);
464
+ }}
465
+ task={taskData}
466
+ onSave={async (task) => await webtaskSaveActions(task)}
467
+ />
468
+ )}
469
+ {modalName === 'maternal_death_verification_modal_mo' && (
470
+ <MoMaternalDeathVerifcationModal
471
+ open={open}
472
+ onClose={() => {
473
+ setOpen(false);
474
+ }}
475
+ task={taskData}
476
+ onSave={async (task) => await webtaskSaveActions(task)}
477
+ />
478
+ )}
479
+ {modalName === 'cmtc_probable_confirmation_modal' && (
480
+ <MoVerficationForChildScreeningMoadal
481
+ open={open}
482
+ onClose={() => {
483
+ setOpen(false);
484
+ }}
485
+ task={taskData}
486
+ onSave={async (task) => await webtaskSaveActions(task)}
487
+ />
488
+ )}
489
+ {modalName === 'asha_data_quality_verification_modal' && (
490
+ <AshaScreenedMembersModal
491
+ open={open}
492
+ onClose={() => {
493
+ setOpen(false);
494
+ }}
495
+ task={taskData}
496
+ onSave={async () => await getWebTasksDetails(selectedWidgetData)}
497
+ />
498
+ )}
499
+ <Suspense>
500
+ {showActionModal && <ActionModal open={showActionModal} onClose={closeActionBar} selectedTask={taskData} />}
501
+ </Suspense>
502
+
503
+ <Grid size={12}>
504
+ <Box
505
+ sx={{
506
+ ...sectionSurface,
507
+ position: 'relative',
508
+ overflow: 'hidden',
509
+ mt: { xs: 0.5, md: 0.75 },
510
+ p: { xs: 1.75, md: 2.1 },
511
+ '&::before': {
512
+ content: '""',
513
+ position: 'absolute',
514
+ inset: 'auto auto -78px -62px',
515
+ width: 150,
516
+ height: 150,
517
+ borderRadius: '999px',
518
+ background: alpha(accentColor, isDark ? 0.18 : 0.12),
519
+ filter: 'blur(14px)',
520
+ },
521
+ '&::after': {
522
+ content: '""',
523
+ position: 'absolute',
524
+ top: -86,
525
+ right: -22,
526
+ width: 130,
527
+ height: 130,
528
+ borderRadius: '999px',
529
+ background: alpha('#7dd3fc', isDark ? 0.08 : 0.07),
530
+ filter: 'blur(16px)',
531
+ },
532
+ }}
533
+ >
534
+ <Box
535
+ sx={{
536
+ position: 'relative',
537
+ zIndex: 1,
538
+ display: 'flex',
539
+ alignItems: { xs: 'flex-start', md: 'center' },
540
+ justifyContent: 'space-between',
541
+ gap: 2,
542
+ flexWrap: 'wrap',
543
+ }}
544
+ >
545
+ <Box sx={{ minWidth: 0 }}>
546
+ <Typography
547
+ variant="h5"
548
+ sx={{ fontWeight: 800, letterSpacing: '-0.03em', color: theme.palette.text.primary }}
549
+ >
550
+ Dashboard
551
+ </Typography>
552
+ <Typography
553
+ sx={{
554
+ mt: 0.45,
555
+ maxWidth: 560,
556
+ color: mutedTextColor,
557
+ lineHeight: 1.5,
558
+ }}
559
+ >
560
+ Pick a basket and the related tasks appear here. The page stays intentionally light so the work is easy
561
+ to scan.
562
+ </Typography>
563
+ </Box>
564
+ <Box className="flex flex-wrap gap-2" sx={{ alignItems: 'center' }}>
565
+ <Box
566
+ sx={{
567
+ px: 1.25,
568
+ py: 0.65,
569
+ borderRadius: '999px',
570
+ background: isDark ? alpha('#fff', 0.08) : alpha('#0f172a', 0.05),
571
+ color: isDark ? alpha('#fff', 0.86) : '#38506c',
572
+ fontSize: '0.78rem',
573
+ fontWeight: 700,
574
+ }}
575
+ >
576
+ {widgetData.length} baskets
577
+ </Box>
578
+ {!GeneralUtil.isBahaar && (
579
+ <Box
580
+ sx={{
581
+ px: 1.25,
582
+ py: 0.65,
583
+ borderRadius: '999px',
584
+ background: alpha(accentColor, isDark ? 0.18 : 0.12),
585
+ color: isDark ? '#dbeafe' : accentColor,
586
+ fontSize: '0.78rem',
587
+ fontWeight: 700,
588
+ }}
589
+ >
590
+ {hiddenWidgetData.length} hidden
591
+ </Box>
592
+ )}
593
+ <Box
594
+ sx={{
595
+ px: 1.25,
596
+ py: 0.65,
597
+ borderRadius: '999px',
598
+ background: isDark ? alpha('#fff', 0.08) : alpha('#ffffff', 0.78),
599
+ color: isDark ? '#e2e8f0' : '#38506c',
600
+ fontSize: '0.78rem',
601
+ fontWeight: 700,
602
+ maxWidth: { xs: '100%', sm: 240 },
603
+ overflow: 'hidden',
604
+ textOverflow: 'ellipsis',
605
+ whiteSpace: 'nowrap',
606
+ }}
607
+ >
608
+ {selectedWidgetData?.name ? selectedWidgetData.name : 'No basket selected'}
609
+ </Box>
610
+ </Box>
611
+ </Box>
612
+ </Box>
613
+ </Grid>
614
+
615
+ <Grid size={{ xs: 12, lg: GeneralUtil.isBahaar ? 12 : 9 }}>
616
+ <Box
617
+ sx={{
618
+ ...sectionSurface,
619
+ p: { xs: 1.75, md: 2.25 },
620
+ }}
621
+ >
622
+ <Box className="flex items-start justify-between gap-4 flex-wrap">
623
+ <Box sx={{ display: 'flex', alignItems: 'center', gap: 3 }}>
624
+ <Box>
625
+ <Typography variant="h6" sx={{ fontWeight: 800, color: theme.palette.text.primary }}>
626
+ Workflow baskets
627
+ </Typography>
628
+ <Typography sx={{ mt: 0.4, color: mutedTextColor }}>Select a basket to load its task list.</Typography>
629
+ </Box>
630
+ {amountEarned && (
631
+ <Chip
632
+ label={
633
+ <span style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
634
+ <span style={{ fontWeight: 900 }}>Total Earnings:</span>
635
+ <span style={{ fontWeight: 600, letterSpacing: '0.5px' }}>₹ {amountEarned}</span>
636
+ </span>
637
+ }
638
+ sx={{
639
+ fontSize: '0.85rem',
640
+ px: 0.5,
641
+ py: 2,
642
+ borderRadius: '12px',
643
+ backgroundColor: isDark ? alpha('#10b981', 0.15) : alpha('#10b981', 0.1),
644
+ color: isDark ? '#34d399' : '#059669',
645
+ border: '1px solid',
646
+ borderColor: isDark ? alpha('#10b981', 0.3) : alpha('#10b981', 0.4),
647
+ boxShadow: '0 2px 8px rgba(16, 185, 129, 0.15)',
648
+ }}
649
+ />
650
+ )}
651
+ </Box>
652
+ <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
653
+ <Box
654
+ sx={{
655
+ px: 1.3,
656
+ py: 0.65,
657
+ borderRadius: '999px',
658
+ background: isDark ? alpha('#fff', 0.08) : alpha('#0f172a', 0.05),
659
+ color: isDark ? alpha('#fff', 0.82) : '#38506c',
660
+ fontSize: '0.78rem',
661
+ fontWeight: 700,
662
+ }}
663
+ >
664
+ {sortedWidgets.length} available
665
+ </Box>
666
+ {GeneralUtil.isBahaar && (
667
+ <IconButton
668
+ onClick={(e) => setShowTaskbar(e.currentTarget)}
669
+ sx={{
670
+ width: 34,
671
+ height: 34,
672
+ background: isDark ? alpha('#fff', 0.08) : alpha(accentColor, 0.1),
673
+ }}
674
+ data-testid="bahaar-manage-tray-button"
675
+ >
676
+ <FontAwesomeIcon icon={faEllipsisVertical} className={isDark ? 'text-white' : 'text-slate-700'} />
677
+ </IconButton>
678
+ )}
679
+ </Box>
680
+ </Box>
681
+
682
+ <Grid container spacing={1.5} className="mt-2">
683
+ {sortedWidgets.map((item) => {
684
+ item.colorCode = item.colorCode || defaultColors[Math.floor(Math.random() * defaultColors.length)];
685
+ return (
686
+ <Suspense key={item.id}>
687
+ <Grid item size={{ xs: 12, sm: 6, md: 4, xl: 3 }}>
688
+ <WidgetCard
689
+ widgetData={item}
690
+ hidden={false}
691
+ isSelected={item.id === selectedWidgetData?.id}
692
+ onClick={() => getWebTasksDetails(item)}
693
+ onArrowClick={() => (handleHideWidget(item))}
694
+ showIcon = {(!GeneralUtil.isTecho || rights?.['create.manage.webtasks.savebasketpreference'])? true: false}
695
+ dataTestId="Dashboard-Widget-Card"
696
+ />
697
+ </Grid>
698
+ </Suspense>
699
+ );
700
+ })}
701
+ </Grid>
702
+ </Box>
703
+ </Grid>
704
+
705
+ {!GeneralUtil.isBahaar && (
706
+ <Grid size={{ xs: 12, lg: 3 }}>
707
+ <Card
708
+ sx={{
709
+ ...sectionSurface,
710
+ borderRadius: '24px',
711
+ overflow: 'hidden',
712
+ background: isDark
713
+ ? theme.palette.background.paper
714
+ : 'linear-gradient(180deg, rgba(255,255,255,0.96) 0%, rgba(246,249,255,0.98) 100%)',
715
+ }}
716
+ data-testid="taskbar-widget-card"
717
+ onClick={(e) => setShowTaskbar(e.currentTarget)}
718
+ >
719
+ <Box sx={{ p: 2 }}>
720
+ <Box className="flex items-start justify-between gap-3">
721
+ <Box>
722
+ <Typography
723
+ sx={{ fontSize: '0.82rem', fontWeight: 800, color: isDark ? alpha('#fff', 0.7) : '#60768f' }}
724
+ >
725
+ Hidden basket tray
726
+ </Typography>
727
+ <Typography
728
+ data-testid="dashboard-hidden-count"
729
+ sx={{ mt: 0.8, fontSize: '1.75rem', fontWeight: 800, color: theme.palette.text.primary }}
730
+ >
731
+ {hiddenWidgetsTotal}
732
+ </Typography>
733
+ </Box>
734
+ <Box
735
+ sx={{
736
+ px: 1.1,
737
+ py: 0.55,
738
+ borderRadius: '999px',
739
+ background: isDark ? alpha('#fff', 0.08) : alpha(accentColor, 0.08),
740
+ color: isDark ? alpha('#fff', 0.84) : '#38506c',
741
+ fontSize: '0.72rem',
742
+ fontWeight: 700,
743
+ }}
744
+ >
745
+ {hiddenWidgetData.length} items
746
+ </Box>
747
+ </Box>
748
+ <Typography sx={{ mt: 0.5, color: mutedTextColor, lineHeight: 1.55 }}>
749
+ Hidden baskets stay here until you need them again.
750
+ </Typography>
751
+ <Box className="flex flex-wrap gap-2 mt-3">
752
+ {hiddenWidgetData.slice(0, 2).map((item) => (
753
+ <Box
754
+ key={item.id}
755
+ sx={{
756
+ px: 1.2,
757
+ py: 0.6,
758
+ borderRadius: '999px',
759
+ background: isDark ? alpha('#fff', 0.08) : alpha(accentColor, 0.08),
760
+ color: isDark ? alpha('#fff', 0.86) : '#38506c',
761
+ fontSize: '0.74rem',
762
+ maxWidth: '100%',
763
+ }}
764
+ >
765
+ {item.name}
766
+ </Box>
767
+ ))}
768
+ {hiddenWidgetData.length > 2 && (
769
+ <Box
770
+ sx={{
771
+ px: 1.2,
772
+ py: 0.6,
773
+ borderRadius: '999px',
774
+ background: isDark ? alpha('#fff', 0.08) : alpha(accentColor, 0.08),
775
+ color: isDark ? alpha('#fff', 0.86) : '#38506c',
776
+ fontSize: '0.74rem',
777
+ }}
778
+ >
779
+ +{hiddenWidgetData.length - 2} more
780
+ </Box>
781
+ )}
782
+ {hiddenWidgetData.length === 0 && (
783
+ <Box
784
+ sx={{
785
+ px: 1.2,
786
+ py: 0.6,
787
+ borderRadius: '999px',
788
+ background: isDark ? alpha('#fff', 0.06) : alpha('#0f172a', 0.05),
789
+ color: isDark ? alpha('#fff', 0.62) : '#72859c',
790
+ fontSize: '0.74rem',
791
+ }}
792
+ >
793
+ Nothing hidden right now
794
+ </Box>
795
+ )}
796
+ </Box>
797
+ </Box>
798
+ <Box
799
+ sx={{
800
+ px: 2,
801
+ py: 1.05,
802
+ display: 'flex',
803
+ alignItems: 'center',
804
+ justifyContent: 'space-between',
805
+ background: isDark ? alpha('#fff', 0.05) : alpha(accentColor, 0.06),
806
+ borderTop: `1px solid ${shellBorder}`,
807
+ }}
808
+ >
809
+ <Typography sx={{ fontWeight: 700, color: theme.palette.text.primary }}>Manage tray</Typography>
810
+ <IconButton
811
+ sx={{
812
+ width: 34,
813
+ height: 34,
814
+ background: isDark ? alpha('#fff', 0.08) : alpha(accentColor, 0.1),
815
+ }}
816
+ >
817
+ <FontAwesomeIcon icon={faEllipsisVertical} className={isDark ? 'text-white' : 'text-slate-700'} />
818
+ </IconButton>
819
+ </Box>
820
+ </Card>
821
+
822
+ <Popover
823
+ id={showTaskbar ? 'simple-popover' : undefined}
824
+ open={!!showTaskbar}
825
+ anchorEl={showTaskbar}
826
+ onClose={handleHideTaskbar}
827
+ anchorOrigin={{
828
+ vertical: 'bottom',
829
+ horizontal: 'right',
830
+ }}
831
+ transformOrigin={{
832
+ vertical: 'top',
833
+ horizontal: 'right',
834
+ }}
835
+ slotProps={{
836
+ paper: {
837
+ style: {
838
+ width: '450px',
839
+ borderRadius: '24px',
840
+ overflow: 'hidden',
841
+ },
842
+ },
843
+ }}
844
+ >
845
+ <Suspense>
846
+ <Taskbar
847
+ show={showTaskbar}
848
+ hiddenWidgets={hiddenWidgetData}
849
+ handleHideTaskbar={handleHideTaskbar}
850
+ handleUnhideWidget={getUnhideWidgetPermission()? handleUnhideWidget : null}
851
+ onWidgetClick={getWebTasksDetails}
852
+ />
853
+ </Suspense>
854
+ </Popover>
855
+ </Grid>
856
+ )}
857
+
858
+ {GeneralUtil.isBahaar && (
859
+ <Popover
860
+ id={showTaskbar ? 'bahaar-popover' : undefined}
861
+ open={!!showTaskbar}
862
+ anchorEl={showTaskbar}
863
+ onClose={handleHideTaskbar}
864
+ anchorOrigin={{
865
+ vertical: 'bottom',
866
+ horizontal: 'right',
867
+ }}
868
+ transformOrigin={{
869
+ vertical: 'top',
870
+ horizontal: 'right',
871
+ }}
872
+ slotProps={{
873
+ paper: {
874
+ style: {
875
+ width: '450px',
876
+ borderRadius: '24px',
877
+ overflow: 'hidden',
878
+ },
879
+ },
880
+ }}
881
+ >
882
+ <Suspense>
883
+ <Taskbar
884
+ show={showTaskbar}
885
+ hiddenWidgets={hiddenWidgetData}
886
+ handleHideTaskbar={handleHideTaskbar}
887
+ handleUnhideWidget={getUnhideWidgetPermission()? handleUnhideWidget : null}
888
+ onWidgetClick={getWebTasksDetails}
889
+ />
890
+ </Suspense>
891
+ </Popover>
892
+ )}
893
+
894
+ <Grid size={12}>
895
+ <Box
896
+ sx={{
897
+ ...sectionSurface,
898
+ p: { xs: 1.75, md: 2.25 },
899
+ }}
900
+ >
901
+ <Box className="flex items-start justify-between gap-4 flex-wrap">
902
+ <Box>
903
+ <Typography variant="h6" sx={{ fontWeight: 800, color: theme.palette.text.primary }}>
904
+ {selectedWidgetData?.name || 'Task workspace'}
905
+ </Typography>
906
+ <Typography sx={{ mt: 0.4, color: mutedTextColor }}>
907
+ Review tasks, act on pending work, and export when needed.
908
+ </Typography>
909
+ </Box>
910
+ <Box className="flex items-center gap-3 flex-wrap">
911
+ {showFilter && (
912
+ <button
913
+ onClick={handleOverlayState}
914
+ className="cursor-pointer px-4 py-2 rounded-xl transition-all text-sm font-bold"
915
+ style={{
916
+ background: isDark ? alpha('#fff', 0.08) : alpha(accentColor, 0.08),
917
+ color: isDark ? '#f8fafc' : accentColor,
918
+ border: `1px solid ${alpha(accentColor, 0.22)}`,
919
+ }}
920
+ >
921
+ Filters
922
+ </button>
923
+ )}
924
+ {webTasksData.length > 0 && (
925
+ <button
926
+ onClick={downloadExcel}
927
+ className="cursor-pointer px-4 py-2 rounded-xl transition-all flex items-center gap-2 text-sm font-black"
928
+ style={{
929
+ background: `linear-gradient(135deg, ${accentColor} 0%, ${isDark ? '#245c89' : '#0f4f8a'} 100%)`,
930
+ color: '#ffffff',
931
+ boxShadow: isDark ? '0 14px 28px rgba(2, 8, 23, 0.3)' : '0 14px 30px rgba(28, 111, 183, 0.22)',
932
+ }}
933
+ data-testid="dashboard-webtaskslist-icon-pdf"
934
+ >
935
+ <FontAwesomeIcon icon={faFileExcel} className="mr-1" />
936
+ Export Excel
937
+ </button>
938
+ )}
939
+ </Box>
940
+ </Box>
941
+
942
+ {webTasksData?.[0]?.widgetMessage && (
943
+ <Box
944
+ sx={{
945
+ mt: 2,
946
+ px: 1.35,
947
+ py: 1.1,
948
+ borderRadius: '16px',
949
+ background: isDark ? alpha('#fff', 0.06) : alpha(accentColor, 0.06),
950
+ color: theme.palette.text.primary,
951
+ }}
952
+ >
953
+ <div
954
+ dangerouslySetInnerHTML={{
955
+ __html: webTasksData?.[0]?.widgetMessage,
956
+ }}
957
+ />
958
+ </Box>
959
+ )}
960
+
961
+ {webTasksData.length > 0 ? (
962
+ <Box sx={{ mt: 2 }}>
963
+ <CustomizedTable
964
+ columns={columns}
965
+ tableData={webTasksData}
966
+ actions={actions}
967
+ paginationConfig={{
968
+ pagination: true,
969
+ paginationType: 'infinite-scroll',
970
+ hasMore,
971
+ loadMore: () => loadMore(selectedWidgetData),
972
+ }}
973
+ styleConfig={{ tableStyle: { maxHeight: 80 } }}
974
+ scrollToTop={scrollToTop}
975
+ setScrollToTop={setScrollToTop}
976
+ dataTestId="widgetlist-table-customized"
977
+ />
978
+ </Box>
979
+ ) : (
980
+ <Box
981
+ sx={{
982
+ mt: 2,
983
+ borderRadius: '20px',
984
+ p: { xs: 2.25, md: 3.25 },
985
+ textAlign: 'center',
986
+ border: `1px dashed ${alpha(accentColor, 0.28)}`,
987
+ background: isDark ? alpha('#fff', 0.03) : alpha(accentColor, 0.04),
988
+ }}
989
+ >
990
+ <Typography sx={{ fontSize: '1.05rem', fontWeight: 700, color: theme.palette.text.primary }}>
991
+ Select a basket to open the task table
992
+ </Typography>
993
+ <Typography sx={{ mt: 0.65, color: mutedTextColor }}>
994
+ Task rows, filters, actions, and export controls will appear here.
995
+ </Typography>
996
+ </Box>
997
+ )}
998
+ </Box>
999
+ </Grid>
1000
+
1001
+ {showFilter && (
1002
+ <SideOverlay
1003
+ title="Filter"
1004
+ showSideBarTitle={false}
1005
+ FormBody={WebtasksFilterForm}
1006
+ handleOverlayState={handleOverlayState}
1007
+ overlayOpen={overlayOpen}
1008
+ dataTestId="dashboard-webtasks-overlay-filter"
1009
+ formProps={{
1010
+ setWebTasksData,
1011
+ selectedWidgetData,
1012
+ locations,
1013
+ setLocations,
1014
+ selectedLocation,
1015
+ setSelectedLocation,
1016
+ }}
1017
+ />
1018
+ )}
1019
+
1020
+ <Grid size={12}>
1021
+ <Box
1022
+ sx={{
1023
+ ...sectionSurface,
1024
+ px: { xs: 1, md: 1.5 },
1025
+ py: { xs: 1.1, md: 1.35 },
1026
+ background: isDark ? theme.palette.background.paper : 'rgba(255,255,255,0.72)',
1027
+ boxShadow: 'none',
1028
+ }}
1029
+ >
1030
+ <Box className="flex items-center justify-between gap-3 flex-wrap px-3 pt-1">
1031
+ <Box>
1032
+ <Typography sx={{ fontWeight: 800, color: theme.palette.text.primary }}>Quick links</Typography>
1033
+ <Typography sx={{ mt: 0.35, color: mutedTextColor }}>Your frequent destinations, kept close.</Typography>
1034
+ </Box>
1035
+ </Box>
1036
+ <QuickLinks />
1037
+ </Box>
1038
+ </Grid>
1039
+ </Grid>
1040
+ );
1041
+ };
1042
+
1043
+ export default Dashboard;