@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,909 @@
1
+ import React, { useEffect } from 'react';
2
+ import { Box, FormControl, InputLabel, Select, MenuItem, Typography, CircularProgress } from '@mui/material';
3
+ import Grid from '@mui/material/Grid2';
4
+ import { useTranslateProvider } from '@/common/languageTranslator/TranslationContext';
5
+ import { getParent, retrieveNextLevel } from '@/common/services/LocationService';
6
+ import { retriveLocationType } from '@/common/services/LocationType';
7
+ import GeneralUtil from '@/common/services/util/GeneralUtil';
8
+ import { showToast } from '@/common/toaster/toaster';
9
+ import PropTypes from 'prop-types';
10
+ import { useState, useRef } from 'react';
11
+ import { useForm, useFormContext } from 'react-hook-form';
12
+ import cloneDeep from 'lodash/cloneDeep';
13
+ import { useSelector } from 'react-redux';
14
+ import CustomDropdown from '@/views/custom-components/CustomDropdown';
15
+
16
+ export const LocationSelectionComponent = ({
17
+ locations,
18
+ setLocations,
19
+ selectedLocation = {},
20
+ setSelectedLocation,
21
+ templateType = 'inline',
22
+ fetchAccordingToUserAoi = false,
23
+ demographicFilterRequired = false,
24
+ requiredUptoLevel = 1,
25
+ fetchUptoLevel,
26
+ multipleOnLevel,
27
+ onChange,
28
+ setSelectedDemographic = () => { },
29
+ allDistrictReq,
30
+ setAllDistrictReq = () => { },
31
+ setPassedLocationLevel,
32
+ allBlockReq,
33
+ setAllBlockReq = () => { },
34
+ allPhcReq,
35
+ setAllPhcReq = () => { },
36
+ reloadFunction = () => { },
37
+ childForm = false,
38
+ uiLocationId = null,
39
+ changedUsingUi = null,
40
+ setFetchUptoLevelLimit = () => { },
41
+ setUiSelectedLocation = () => { },
42
+ setUiLocations = () => { },
43
+ clearPreviousLocation = false,
44
+ triggerFirstRun = 0,
45
+ locationBreadCrumbSelected = null,
46
+ }) => {
47
+ const { translate } = useTranslateProvider();
48
+ const [noLocationInHierarchyMessage, setNoLocationInHierarchyMessage] = useState(null);
49
+ const [onFirstRunTemp, setOnFirstRunTemp] = useState(false);
50
+ const [minLevel, setMinLevel] = useState(1);
51
+ const [requiredLocationLevel, setRequiredLocationLevel] = useState(requiredUptoLevel);
52
+ const [demoGraphicFilterNeeded, setDemoGraphicFilterNeeded] = useState(demographicFilterRequired);
53
+ const [loading, setLoading] = useState(false);
54
+ const { user: loggedInUser } = useSelector((state) => state.Authenticate);
55
+ const fetchingLevels = useRef(new Set());
56
+
57
+ const allRegion = { id: -1, locType: 'Region', name: 'All District', type: 'R' };
58
+ const allBlocks = { id: -2, locType: 'District', name: 'All Block', type: 'D' };
59
+ const allPHC = { id: -3, locType: 'Block', name: 'All PHC', type: 'B' };
60
+ const [locationTypes, setLocationTypes] = useState([]);
61
+
62
+ const getSelectedOptionIds = (optionSelected) => {
63
+ if (Array.isArray(optionSelected)) {
64
+ return optionSelected
65
+ .map((option) => option?.id)
66
+ .filter((optionId) => optionId !== null && optionId !== undefined);
67
+ }
68
+
69
+ return optionSelected?.id !== null && optionSelected?.id !== undefined
70
+ ? [optionSelected.id]
71
+ : [];
72
+ };
73
+
74
+ const hasSelectedOption = (optionSelected) =>
75
+ getSelectedOptionIds(optionSelected).length > 0;
76
+
77
+ const getFirstSelectedOption = (optionSelected) => {
78
+ return Array.isArray(optionSelected) ? optionSelected[0] : optionSelected;
79
+ };
80
+
81
+ const getFormValueForLevel = (optionSelected, isMultiple) => {
82
+ const selectedIds = getSelectedOptionIds(optionSelected);
83
+
84
+ return isMultiple ? selectedIds : selectedIds[0] || '';
85
+ };
86
+
87
+ // Initialize onFirstRun when locations change
88
+ useEffect(() => {
89
+ if (onFirstRunTemp && locations.length > 0) {
90
+ locations.forEach((location) => {
91
+ if (location.locationDetails.length === 1) {
92
+ onFirstRun(location);
93
+ }
94
+ });
95
+ }
96
+ }, [locations, onFirstRunTemp]);
97
+
98
+ const getLastSelectedLevel = (selection = {}) => {
99
+ return Object.keys(selection)
100
+ .filter((key) => key.startsWith('level'))
101
+ .map((key) => Number(key.replace('level', '')))
102
+ .filter((level) => {
103
+ const value = selection[`level${level}`];
104
+ return Array.isArray(value) ? value.length > 0 : value != null;
105
+ })
106
+ .sort((a, b) => b - a)[0];
107
+ };
108
+
109
+ const clearLastSelectedLevel = () => {
110
+ const lastSelectedLevel = getLastSelectedLevel(selectedLocation);
111
+
112
+ if (!lastSelectedLevel) {
113
+ return;
114
+ }
115
+
116
+ // 2. CHECK IF CLEARED
117
+ // Check for empty array (multiple) or empty string/null (single)
118
+
119
+ if (lastSelectedLevel > locations[0].level) {
120
+ const cleanedSelectedLocation = clearLowerLevelLocation(lastSelectedLevel - 1, selectedLocation);
121
+
122
+ const newSelectedLocation = {
123
+ ...cleanedSelectedLocation,
124
+ };
125
+
126
+ setValue(`level${lastSelectedLevel - 1}`, newSelectedLocation[`level${lastSelectedLevel - 1}`], {
127
+ shouldValidate: true,
128
+ shouldDirty: true,
129
+ });
130
+ onLocationChange(
131
+ locations.find((loc) => loc?.level === lastSelectedLevel - 1),
132
+ false,
133
+ newSelectedLocation
134
+ );
135
+ }
136
+ };
137
+
138
+ useEffect(() => {
139
+ if (clearPreviousLocation) {
140
+ clearLastSelectedLevel();
141
+ }
142
+ }, [clearPreviousLocation]);
143
+ useEffect(() => {
144
+ if (
145
+ uiLocationId &&
146
+ changedUsingUi &&
147
+ changedUsingUi?.clicked &&
148
+ uiLocationId.locationId &&
149
+ (fetchUptoLevel >= uiLocationId.level || fetchUptoLevel == '' || fetchUptoLevel == null) &&
150
+ locationTypes != null
151
+ ) {
152
+ let maxlevel = Math.max(...locationTypes.map((item) => item.level));
153
+ let currentLevel = selectedLocation?.finalSelected?.level;
154
+ setOnFirstRunTemp(false);
155
+ if (maxlevel == currentLevel && selectedLocation[`level${maxlevel}`] != null) {
156
+ showToast({
157
+ message: 'Reached maximum allowed level of location. No data available below this level.',
158
+ type: 'warn',
159
+ });
160
+ return;
161
+ }
162
+
163
+ const selectedValue = uiLocationId.locationId;
164
+ const level = uiLocationId.level;
165
+ let updatedSelection;
166
+ const isMultiple = multipleOnLevel && level >= multipleOnLevel;
167
+ const location = locations.find((loc) => loc?.level === level);
168
+ const selectedIds = Array.isArray(selectedValue)
169
+ ? selectedValue
170
+ : [selectedValue];
171
+ if (isMultiple) {
172
+ updatedSelection = location?.locationDetails?.filter((opt) => selectedIds.includes(opt.id));
173
+ } else {
174
+ updatedSelection = location?.locationDetails?.find((opt) => selectedIds.includes(opt.id));
175
+ }
176
+
177
+ // Clean selectedLocation of all lower levels
178
+ const cleanedSelectedLocation = clearLowerLevelLocation(level, selectedLocation);
179
+
180
+ // Set new value for this level only on the cleaned object
181
+ const newSelectedLocation = {
182
+ ...cleanedSelectedLocation,
183
+ [`level${level}`]: updatedSelection,
184
+ };
185
+ setSelectedLocation(newSelectedLocation);
186
+ setValue(
187
+ `level${level}`,
188
+ getFormValueForLevel(updatedSelection, isMultiple),
189
+ {
190
+ shouldValidate: true,
191
+ shouldDirty: true,
192
+ }
193
+ );
194
+ onLocationChange(location, false, newSelectedLocation);
195
+ } else if (!(fetchUptoLevel >= uiLocationId?.level) && changedUsingUi?.clicked && !uiLocationId?.linkActive) {
196
+ showToast({ message: 'Maximum location selected', type: 'info' });
197
+ setFetchUptoLevelLimit(true);
198
+ }
199
+ }, [uiLocationId, changedUsingUi]);
200
+
201
+ const onFirstRun = (location) => {
202
+ let latestSelectedLocation = {
203
+ ...location,
204
+ [`level${location.level}`]: location.locationDetails[0],
205
+ level: location.level,
206
+ optionsLists: selectedLocation?.optionsLists || {},
207
+ };
208
+ setSelectedLocation(() => latestSelectedLocation);
209
+ onLocationChange(latestSelectedLocation, false, latestSelectedLocation);
210
+ setOnFirstRunTemp(false);
211
+ };
212
+
213
+ // Use parent form context if used as a child, otherwise create local form
214
+ let methods;
215
+ if (childForm) {
216
+ methods = useFormContext();
217
+ } else {
218
+ methods = useForm({
219
+ mode: 'all',
220
+ });
221
+ }
222
+
223
+ const {
224
+ control,
225
+ setValue,
226
+ formState: { errors },
227
+ reset: resetForm,
228
+ } = methods;
229
+
230
+ // Returns a new selectedLocation object with all lower levels removed
231
+ const clearLowerLevelLocation = (selectedLocationLevel, selectedLocation) => {
232
+ const cleaned = { ...selectedLocation };
233
+ // Remove lower level selections
234
+ Object.keys(cleaned).forEach((key) => {
235
+ if (key.startsWith('level')) {
236
+ const level = parseInt(key.replace('level', ''));
237
+ if (level > selectedLocationLevel) {
238
+ delete cleaned[key];
239
+ methods.resetField(`level${level}`, { defaultValue: '' });
240
+ }
241
+ }
242
+ });
243
+ // Remove lower level optionsLists
244
+ if (cleaned.optionsLists) {
245
+ const newOptionsLists = { ...cleaned.optionsLists };
246
+ Object.keys(newOptionsLists).forEach((key) => {
247
+ const level = parseInt(key.replace('level', ''));
248
+ if (level > selectedLocationLevel) {
249
+ delete newOptionsLists[key];
250
+ }
251
+ });
252
+ cleaned.optionsLists = newOptionsLists;
253
+ }
254
+ setLocations((prev) => prev.filter((location) => location.level <= selectedLocationLevel));
255
+ return cleaned;
256
+ };
257
+
258
+ const onDemographicChange = (e) => {
259
+ const value = e.target.value;
260
+ setSelectedLocation((prev) => ({ ...prev, selectedDemographic: value }));
261
+ setSelectedDemographic(value);
262
+ };
263
+
264
+ const retrieveLocationTypes = async () => {
265
+ try {
266
+ const response = await retriveLocationType({}, { showLoader: false });
267
+ return response.data.filter((r) => r.isActive);
268
+ } catch (error) {
269
+ console.error(error);
270
+ showToast({ message: 'Error in loading Location Types', type: 'error' });
271
+ }
272
+ };
273
+
274
+ // Initialization logic
275
+ useEffect(() => {
276
+ const initialize = async () => {
277
+ setLoading(true);
278
+ try {
279
+ const types = await retrieveLocationTypes();
280
+ if (types) setLocationTypes(types.filter((loc) => loc.isActive));
281
+
282
+ if (!demographicFilterRequired || !fetchAccordingToUserAoi) {
283
+ setDemoGraphicFilterNeeded(false);
284
+ }
285
+
286
+ if (!allDistrictReq || allDistrictReq === 'false') {
287
+ setAllDistrictReq(false);
288
+ } else if (demographicFilterRequired === 'true') {
289
+ setAllDistrictReq(true);
290
+ }
291
+
292
+ if (!allBlockReq || allBlockReq === 'false') {
293
+ setAllBlockReq(false);
294
+ } else if (demographicFilterRequired === 'true') {
295
+ setAllBlockReq(true);
296
+ }
297
+
298
+ if (!allPhcReq || allPhcReq === 'false') {
299
+ setAllPhcReq(false);
300
+ } else if (demographicFilterRequired === 'true') {
301
+ setAllPhcReq(true);
302
+ }
303
+
304
+ if (selectedLocation && selectedLocation.optionsLists && Object.keys(selectedLocation.optionsLists).length > 0) {
305
+ const reconstructedLocations = Object.keys(selectedLocation.optionsLists)
306
+ .map((key) => {
307
+ const level = parseInt(key.replace('level', ''));
308
+ const type = types.find((t) => t.level === level);
309
+ return {
310
+ level,
311
+ locationLabel: type ? type.name : '',
312
+ locationDetails: selectedLocation.optionsLists[key],
313
+ };
314
+ })
315
+ .sort((a, b) => a.level - b.level);
316
+ setLocations(reconstructedLocations);
317
+ } else {
318
+ setOnFirstRunTemp(true);
319
+ await onLocationChange(null, true, selectedLocation);
320
+ }
321
+ } catch (error) {
322
+ console.error('Initialization error:', error);
323
+ } finally {
324
+ setLoading(false);
325
+ }
326
+ };
327
+ if (!locations || locations.length === 0) {
328
+ initialize();
329
+ }
330
+ }, []);
331
+
332
+ useEffect(() => {
333
+ setNoLocationInHierarchyMessage(null);
334
+ reloadFunction?.();
335
+
336
+ if (locations.length > 0 && selectedLocation && Object.keys(selectedLocation).length === 0) {
337
+ clearLowerLevelLocation(minLevel, selectedLocation);
338
+ resetForm();
339
+ }
340
+ }, [selectedLocation]);
341
+
342
+ useEffect(() => {
343
+ if (triggerFirstRun > 0) {
344
+ resetForm();
345
+ setNoLocationInHierarchyMessage(null);
346
+ setUiLocations(null);
347
+ setUiSelectedLocation(null);
348
+
349
+ const performReset = async () => {
350
+ setLoading(true);
351
+ try {
352
+ setLocations([]);
353
+ const emptySelection = {};
354
+ setSelectedLocation(emptySelection);
355
+ setOnFirstRunTemp(true);
356
+ await onLocationChange(null, true, emptySelection);
357
+ } catch (error) {
358
+ console.error('Reset error:', error);
359
+ } finally {
360
+ setLoading(false);
361
+ }
362
+ };
363
+ performReset();
364
+ }
365
+ }, [triggerFirstRun]);
366
+ useEffect(() => {
367
+ if (locationBreadCrumbSelected) {
368
+ setOnFirstRunTemp(false);
369
+ if (locations.length > 0) {
370
+ const selectedState =
371
+ locationBreadCrumbSelected.fullState || selectedLocation;
372
+ const cleanedSelectedLocation = clearLowerLevelLocation(
373
+ locationBreadCrumbSelected.level,
374
+ selectedState
375
+ );
376
+ const selectedLevelValue =
377
+ selectedState?.[`level${locationBreadCrumbSelected.level}`] ||
378
+ locationBreadCrumbSelected.fullState?.finalSelected?.optionSelected;
379
+
380
+ const newSelectedLocation = {
381
+ ...cleanedSelectedLocation,
382
+ [`level${locationBreadCrumbSelected.level}`]: selectedLevelValue,
383
+ };
384
+ const isMultiple =
385
+ multipleOnLevel && locationBreadCrumbSelected.level >= multipleOnLevel;
386
+
387
+ setValue(
388
+ `level${locationBreadCrumbSelected.level}`,
389
+ getFormValueForLevel(
390
+ newSelectedLocation[`level${locationBreadCrumbSelected.level}`],
391
+ isMultiple
392
+ ),
393
+ {
394
+ shouldValidate: true,
395
+ shouldDirty: true,
396
+ }
397
+ );
398
+ 1;
399
+ onLocationChange(
400
+ locations.find((loc) => loc?.level === locationBreadCrumbSelected.level),
401
+ false,
402
+ newSelectedLocation
403
+ );
404
+ }
405
+ }
406
+ }, [locationBreadCrumbSelected]);
407
+
408
+ useEffect(() => {
409
+ if (locations.length > 0 && selectedLocation) {
410
+ locations.forEach((location) => {
411
+ const level = location.level;
412
+ const isMultiple = multipleOnLevel && level >= multipleOnLevel;
413
+ if (selectedLocation[`level${level}`]) {
414
+ setValue(
415
+ `level${level}`,
416
+ isMultiple
417
+ ? Array.isArray(selectedLocation[`level${level}`])
418
+ ? selectedLocation[`level${level}`].map((v) => v?.id)
419
+ : selectedLocation[`level${level}`]?.id ? [selectedLocation[`level${level}`].id] : []
420
+ : selectedLocation[`level${level}`]?.id || ''
421
+ );
422
+ }
423
+ });
424
+ }
425
+ }, [locations, selectedLocation, multipleOnLevel, setValue]);
426
+
427
+ const addLocationHierarchy = async (locationIds, level, loadInit) => {
428
+ if (fetchingLevels.current.has(level)) {
429
+ return;
430
+ }
431
+ fetchingLevels.current.add(level);
432
+ try {
433
+ const response = await retrieveNextLevel(
434
+ locationIds,
435
+ level,
436
+ fetchAccordingToUserAoi,
437
+ loggedInUser.languagePreference
438
+ );
439
+
440
+ let locationData = null;
441
+ if (response && response.length > 0) {
442
+ locationData = response[0];
443
+ const isDistrictReq = allDistrictReq && allDistrictReq !== 'false';
444
+ const isBlockReq = allBlockReq && allBlockReq !== 'false';
445
+ const isPhcReq = allPhcReq && allPhcReq !== 'false';
446
+
447
+ if (isDistrictReq && level === 2 && (GeneralUtil.isMedplat || GeneralUtil.isTecho)) {
448
+ locationData.locationDetails = [allRegion, ...locationData.locationDetails];
449
+ } else if (isBlockReq && level === 3 && (GeneralUtil.isMedplat || GeneralUtil.isTecho)) {
450
+ locationData.locationDetails = [allBlocks, ...locationData.locationDetails];
451
+ } else if (isPhcReq && level === 4 && (GeneralUtil.isMedplat || GeneralUtil.isTecho)) {
452
+ locationData.locationDetails = [allPHC, ...locationData.locationDetails];
453
+ }
454
+ if (loadInit) {
455
+ setMinLevel(locationData.level);
456
+ if (requiredLocationLevel === 1) {
457
+ setRequiredLocationLevel(locationData.level);
458
+ }
459
+ }
460
+ } else if (requiredLocationLevel >= level) {
461
+ const nextLevelNames = locationTypes?.filter((type) => type.level === level)?.map((type) => type.name) || [];
462
+
463
+ setNoLocationInHierarchyMessage(nextLevelNames.length ? nextLevelNames.join('/') : null);
464
+ showToast({
465
+ message: 'Could not find any location under the selected hierarchy',
466
+ type: 'error',
467
+ });
468
+ }
469
+ // Update locations and optionsLists together using functional updates
470
+ setLocations((prevLocations) => {
471
+ const newLocations = [...prevLocations];
472
+ if (locationData) {
473
+ const exists = newLocations.some((loc) => loc.level === locationData.level);
474
+ if (!exists) {
475
+ newLocations.push(locationData);
476
+ }
477
+ }
478
+
479
+ // Build optionsLists from the updated locations array
480
+ const optionsLists = {};
481
+ newLocations.forEach((location) => {
482
+ if (location) {
483
+ optionsLists[`level${location.level}`] = location.locationDetails;
484
+ }
485
+ });
486
+
487
+ // Update selectedLocation with the new optionsLists
488
+ setSelectedLocation((prev) => ({
489
+ ...prev,
490
+ optionsLists,
491
+ }));
492
+
493
+ return newLocations;
494
+ });
495
+ } catch (error) {
496
+ console.error(error);
497
+ showToast({
498
+ message: 'Error in loading location hierarchy',
499
+ type: 'error',
500
+ });
501
+ } finally {
502
+ fetchingLevels.current.delete(level);
503
+ }
504
+ };
505
+ const onLocationChange = async (location, loadInit, selectedLocation) => {
506
+ try {
507
+ let locationIds = [],
508
+ level;
509
+ // clear lower levels
510
+ if (
511
+ location ||
512
+ (selectedLocation.finalSelected &&
513
+ !hasSelectedOption(selectedLocation.finalSelected.optionSelected))
514
+ ) {
515
+ clearLowerLevelLocation(location.level, selectedLocation);
516
+ level = location.level + 1;
517
+ }
518
+
519
+ if (selectedLocation && location && selectedLocation['level' + location.level]) {
520
+ if (multipleOnLevel && location.level >= multipleOnLevel) {
521
+ locationIds = getSelectedOptionIds(selectedLocation['level' + location.level]);
522
+ } else {
523
+ locationIds = getSelectedOptionIds(selectedLocation['level' + location.level]);
524
+ }
525
+ }
526
+ let locationSelected = cloneDeep(location);
527
+ if (location) {
528
+ locationSelected.optionSelected = selectedLocation['level' + location.level];
529
+ locationSelected['level' + location.level + 'options'] = locations[locations.length - 1].locationDetails;
530
+ }
531
+ let latestSelectedLocation = { ...cloneDeep(selectedLocation), finalSelected: locationSelected };
532
+ setSelectedLocation(() => latestSelectedLocation);
533
+ if (
534
+ (((fetchUptoLevel && location && location.level + 1 <= fetchUptoLevel) || loadInit || !fetchUptoLevel) &&
535
+ latestSelectedLocation.finalSelected &&
536
+ (((!multipleOnLevel || location.level < multipleOnLevel) && latestSelectedLocation.finalSelected.optionSelected) ||
537
+ (multipleOnLevel &&
538
+ location.level >= multipleOnLevel &&
539
+ getSelectedOptionIds(latestSelectedLocation.finalSelected.optionSelected).length === 1))) ||
540
+ loadInit
541
+ ) {
542
+ // when selected location is not all blocks set relative parent
543
+ let level3Id;
544
+ if (level === 4 && multipleOnLevel && location.level >= multipleOnLevel) {
545
+ const level3Selection = latestSelectedLocation.level3;
546
+ level3Id =
547
+ Array.isArray(level3Selection) && level3Selection.length > 0
548
+ ? level3Selection[0].id
549
+ : !Array.isArray(level3Selection) && level3Selection?.id
550
+ ? level3Selection.id
551
+ : -2;
552
+ } else if (level === 4) {
553
+ level3Id = getFirstSelectedOption(latestSelectedLocation.level3)?.id;
554
+ }
555
+ if (level === 4 && level3Id !== -2) {
556
+ const res = await getParent(level3Id, loggedInUser.languagePreference);
557
+ if (res) {
558
+ setSelectedLocation((prevSelectedLocation) => ({
559
+ ...prevSelectedLocation,
560
+ level2: res,
561
+ }));
562
+ setValue('level2', res?.id || '', { shouldValidate: true, shouldDirty: true });
563
+ setLocations((prevLocations) => prevLocations.slice(0, -1));
564
+
565
+ await addLocationHierarchy([res?.id], 3, loadInit);
566
+ await addLocationHierarchy(locationIds, level, loadInit);
567
+ }
568
+ }
569
+ // added -2 for all blocks when selected location is all blocks set parent all districts
570
+ else if (level === 4 && level3Id === -2 && (GeneralUtil.isMedplat || GeneralUtil.isTecho)) {
571
+ setSelectedLocation((prevSelectedLocation) => ({
572
+ ...prevSelectedLocation,
573
+ level2: allRegion,
574
+ }));
575
+ setValue('level2', allRegion?.id || '', { shouldValidate: true, shouldDirty: true });
576
+ setLocations((prevLocations) => prevLocations.slice(0, -1));
577
+
578
+ await addLocationHierarchy([-1], 3, loadInit);
579
+ await addLocationHierarchy(locationIds, level, loadInit);
580
+ } else if (
581
+ level === 5 &&
582
+ getFirstSelectedOption(latestSelectedLocation?.level4)?.id === -3 &&
583
+ (GeneralUtil.isMedplat || GeneralUtil.isTecho)
584
+ ) {
585
+ setSelectedLocation((prevSelectedLocation) => ({
586
+ ...prevSelectedLocation,
587
+ level2: allRegion,
588
+ level3: allBlocks,
589
+ }));
590
+ setValue('level2', allRegion?.id || '', { shouldValidate: true, shouldDirty: true });
591
+ setValue('level3', allBlocks?.id || '', { shouldValidate: true, shouldDirty: true });
592
+ setLocations((prevLocations) => prevLocations.slice(0, -1));
593
+
594
+ await addLocationHierarchy([-2], 4, loadInit);
595
+ await addLocationHierarchy(locationIds, level, loadInit);
596
+ } else if (level === 2 && fetchUptoLevel != level) {
597
+ await addLocationHierarchy(locationIds, level, loadInit);
598
+ await addLocationHierarchy(locationIds, level + 1, loadInit);
599
+ } else {
600
+ await addLocationHierarchy(locationIds, level, loadInit);
601
+ }
602
+ }
603
+ // to get selected parent (Region) automatically on selection of child (District) when (
604
+ else if (
605
+ latestSelectedLocation.finalSelected &&
606
+ latestSelectedLocation.finalSelected.optionSelected &&
607
+ fetchUptoLevel &&
608
+ location &&
609
+ location.level === 3 &&
610
+ location.level == fetchUptoLevel
611
+ ) {
612
+ let level3Id;
613
+ if (multipleOnLevel && latestSelectedLocation.level3 && Array.isArray(latestSelectedLocation.level3)) {
614
+ level3Id =
615
+ latestSelectedLocation.level3 && latestSelectedLocation.level3.length > 0
616
+ ? latestSelectedLocation.level3[0].id
617
+ : -2;
618
+ } else {
619
+ level3Id = getFirstSelectedOption(latestSelectedLocation.level3)?.id;
620
+ }
621
+ const res = await getParent(level3Id, loggedInUser.languagePreference);
622
+ if (res) {
623
+ setSelectedLocation((prevSelectedLocation) => ({
624
+ ...prevSelectedLocation,
625
+ level2: res,
626
+ }));
627
+ setValue('level2', res?.id || '', { shouldValidate: true, shouldDirty: true });
628
+ setLocations((prevLocations) => prevLocations.slice(0, -1));
629
+
630
+ await addLocationHierarchy([res?.id], 3, loadInit);
631
+ }
632
+ }
633
+ // to get previous level details when option is unselected;
634
+ else if (
635
+ ((!multipleOnLevel || location?.level < multipleOnLevel) && !latestSelectedLocation?.finalSelected?.optionSelected) ||
636
+ (multipleOnLevel &&
637
+ location?.level >= multipleOnLevel &&
638
+ getSelectedOptionIds(latestSelectedLocation?.finalSelected?.optionSelected).length == 0)
639
+ ) {
640
+ level = location.level - 1;
641
+ if (level === 1) {
642
+ await addLocationHierarchy([2], 3, loadInit);
643
+ }
644
+ const previousLevel = locations.find((loc) => loc.level === level);
645
+ if (previousLevel) {
646
+ setSelectedLocation((prevSelectedLocation) => ({
647
+ ...prevSelectedLocation,
648
+ finalSelected: {
649
+ ...prevSelectedLocation.finalSelected,
650
+ previousLevelLabel: previousLevel.locationLabel,
651
+ previousLevelOptions: previousLevel.locationDetails,
652
+ },
653
+ }));
654
+ }
655
+ if (latestSelectedLocation['level' + level]) {
656
+ const updatedSelectedLocation = {
657
+ ...latestSelectedLocation,
658
+ };
659
+ if (multipleOnLevel && level >= multipleOnLevel) {
660
+ updatedSelectedLocation.finalSelected.optionSelected = latestSelectedLocation['level' + level];
661
+ } else {
662
+ updatedSelectedLocation.finalSelected.optionSelected = latestSelectedLocation['level' + level];
663
+ }
664
+ if (setPassedLocationLevel) {
665
+ setPassedLocationLevel(level - 1);
666
+ }
667
+ setSelectedLocation(() => updatedSelectedLocation);
668
+ } else {
669
+ // setField(() => null);
670
+ if (setPassedLocationLevel) {
671
+ setPassedLocationLevel(null);
672
+ }
673
+ }
674
+ }
675
+ if (
676
+ !loadInit &&
677
+ latestSelectedLocation &&
678
+ (((!multipleOnLevel || location.level < multipleOnLevel) && latestSelectedLocation.finalSelected.optionSelected) ||
679
+ (multipleOnLevel &&
680
+ location.level >= multipleOnLevel &&
681
+ getSelectedOptionIds(latestSelectedLocation.finalSelected.optionSelected).length > 0))
682
+ ) {
683
+ if (!(multipleOnLevel && location.level >= multipleOnLevel)) {
684
+ // setField(() => null);
685
+ if (setPassedLocationLevel) {
686
+ setPassedLocationLevel(null);
687
+ }
688
+ }
689
+ if (setPassedLocationLevel) {
690
+ setPassedLocationLevel(level - 1);
691
+ }
692
+ }
693
+ // setValue(`level${level}`, latestSelectedLocation[`level${level}`] || null);
694
+ if (onChange && typeof onChange === 'function') {
695
+ onChange();
696
+ }
697
+ } catch (error) {
698
+ console.error(error);
699
+ }
700
+ };
701
+
702
+ const renderLocationSelect = (location, selectedLocation) => {
703
+ const level = location.level;
704
+ const isMultiple = multipleOnLevel && level >= multipleOnLevel;
705
+ let required = false;
706
+ if (requiredUptoLevel && requiredUptoLevel > 0) {
707
+ required = level <= requiredUptoLevel;
708
+ }
709
+ // setValue(`level${level}`, selectedLocation[`level${level}`] || null);
710
+ return (
711
+ <>
712
+ <Typography>
713
+ {translate('Select')} {location.locationLabel}
714
+ {required && <span className="text-red-500 ml-1">*</span>}
715
+ </Typography>
716
+ <CustomDropdown
717
+ required={required}
718
+ multiple={isMultiple}
719
+ id={'level' + level}
720
+ control={control}
721
+ name={`level${level}`}
722
+ isNullSelectDisabled={false}
723
+ errors={errors}
724
+ options={selectedLocation?.optionsLists?.[`level${level}`]}
725
+ getOptionDisabled={(option) => {
726
+ return option.id === '';
727
+ }}
728
+ value={
729
+ isMultiple
730
+ ? Array.isArray(selectedLocation?.[`level${level}`])
731
+ ? selectedLocation[`level${level}`].map((v) => v?.id)
732
+ : selectedLocation?.[`level${level}`]?.id
733
+ ? [selectedLocation[`level${level}`].id]
734
+ : []
735
+ : Array.isArray(selectedLocation?.[`level${level}`])
736
+ ? selectedLocation[`level${level}`][0]?.id || ''
737
+ : selectedLocation?.[`level${level}`]?.id || ''
738
+ }
739
+ placeholder={`${translate('Select')} ${location.locationLabel}`}
740
+ onChange={(event) => {
741
+ setOnFirstRunTemp(false);
742
+ const selectedValue = event.target.value;
743
+ let updatedSelection;
744
+
745
+ // 2. CHECK IF CLEARED
746
+ // Check for empty array (multiple) or empty string/null (single)
747
+ const isCleared = !selectedValue || (Array.isArray(selectedValue) && selectedValue.length === 0);
748
+
749
+ if (isCleared) {
750
+ setUiLocations(locations);
751
+ setUiSelectedLocation(selectedLocation);
752
+ if (level > locations[0].level) {
753
+ updatedSelection = isMultiple ? [] : null;
754
+ const cleanedSelectedLocation = clearLowerLevelLocation(level - 1, selectedLocation);
755
+
756
+ const newSelectedLocation = {
757
+ ...cleanedSelectedLocation,
758
+ };
759
+
760
+ setValue(`level${level - 1}`, newSelectedLocation[`level${level - 1}`], {
761
+ shouldValidate: true,
762
+ shouldDirty: true,
763
+ });
764
+ onLocationChange(
765
+ locations.find((loc) => loc?.level === level - 1),
766
+ false,
767
+ newSelectedLocation
768
+ );
769
+ }
770
+ if (level === locations[0].level) {
771
+ // setOnFirstRunTemp(true);
772
+ updatedSelection = isMultiple ? [] : null;
773
+ const cleanedSelectedLocation = clearLowerLevelLocation(level, selectedLocation);
774
+
775
+ const newSelectedLocation = {
776
+ ...cleanedSelectedLocation,
777
+ };
778
+
779
+ onLocationChange(
780
+ locations.find((loc) => loc?.level === level),
781
+ false,
782
+ newSelectedLocation
783
+ );
784
+ }
785
+ } else {
786
+ // 3. Calculate Selection if not cleared
787
+ if (isMultiple) {
788
+ // Ensure rawValue is treated as an array for filtering
789
+ const valueArray = Array.isArray(selectedValue) ? selectedValue : [selectedValue];
790
+ updatedSelection = location.locationDetails.filter((opt) => valueArray.includes(opt.id));
791
+ } else {
792
+ updatedSelection = location.locationDetails.find((opt) => opt.id === selectedValue);
793
+ }
794
+ const cleanedSelectedLocation = clearLowerLevelLocation(level, selectedLocation);
795
+
796
+ // Set new value for this level only on the cleaned object
797
+ const newSelectedLocation = {
798
+ ...cleanedSelectedLocation,
799
+ [`level${level}`]: updatedSelection,
800
+ };
801
+ setSelectedLocation(newSelectedLocation);
802
+ setValue(
803
+ `level${level}`,
804
+ getFormValueForLevel(updatedSelection, isMultiple),
805
+ {
806
+ shouldValidate: true,
807
+ shouldDirty: true,
808
+ }
809
+ );
810
+ onLocationChange(location, false, newSelectedLocation);
811
+ }
812
+
813
+ // Clean selectedLocation of all lower levels
814
+ }}
815
+ displayName="name"
816
+ optionValue="id"
817
+ rules={required ? { required: `${location.locationLabel} ${translate('is required')}` } : {}}
818
+ />
819
+ </>
820
+ );
821
+ };
822
+
823
+ const renderDemographicFilter = () => (
824
+ <FormControl fullWidth sx={{ mb: 2 }}>
825
+ <InputLabel>{translate('Demographic')}</InputLabel>
826
+ <Select
827
+ value={selectedLocation.selectedDemographic || ''}
828
+ label={translate('Demographic')}
829
+ onChange={onDemographicChange}
830
+ >
831
+ <MenuItem value="">{translate('Both')}</MenuItem>
832
+ <MenuItem value="U">{translate('Urban')}</MenuItem>
833
+ <MenuItem value="R">{translate('Rural')}</MenuItem>
834
+ </Select>
835
+ </FormControl>
836
+ );
837
+
838
+ const renderInlineTemplate = () => (
839
+ <>
840
+ {locations.map((location) => (
841
+ <React.Fragment key={location.level}>{renderLocationSelect(location, selectedLocation)}</React.Fragment>
842
+ ))}
843
+ {demoGraphicFilterNeeded && renderDemographicFilter()}
844
+ </>
845
+ );
846
+
847
+ const renderTwoPartTemplate = () => (
848
+ <Grid container spacing={2}>
849
+ {locations.map((location) => (
850
+ <Grid size={{ xs: 6 }} key={location.level}>
851
+ {renderLocationSelect(location, selectedLocation)}
852
+ </Grid>
853
+ ))}
854
+ </Grid>
855
+ );
856
+
857
+ if (loading) {
858
+ return (
859
+ <Box display="flex" justifyContent="center" py={4}>
860
+ <CircularProgress />
861
+ </Box>
862
+ );
863
+ }
864
+
865
+ return (
866
+ <Box>
867
+ {noLocationInHierarchyMessage && (
868
+ <Typography color="error" sx={{ mb: 2 }}>
869
+ {translate('Could not retrieve')} {noLocationInHierarchyMessage}. {translate('Please add it first')}
870
+ </Typography>
871
+ )}
872
+ {templateType === 'inline' ? renderInlineTemplate() : renderTwoPartTemplate()}
873
+ </Box>
874
+ );
875
+ };
876
+
877
+ LocationSelectionComponent.propTypes = {
878
+ selectedLocation: PropTypes.object,
879
+ setSelectedLocation: PropTypes.func.isRequired,
880
+ templateType: PropTypes.any,
881
+ fetchAccordingToUserAoi: PropTypes.bool,
882
+ demographicFilterRequired: PropTypes.bool,
883
+ requiredUptoLevel: PropTypes.number,
884
+ fetchUptoLevel: PropTypes.number,
885
+ multipleOnLevel: PropTypes.number,
886
+ onChange: PropTypes.func,
887
+ setSelectedDemographic: PropTypes.func,
888
+ allDistrictReq: PropTypes.bool,
889
+ setPassedLocationLevel: PropTypes.func,
890
+ allBlockReq: PropTypes.bool,
891
+ allPhcReq: PropTypes.bool,
892
+ reloadFunction: PropTypes.func,
893
+ childForm: PropTypes.bool,
894
+ locations: PropTypes.any,
895
+ setLocations: PropTypes.any,
896
+ uiLocationId: PropTypes.any,
897
+ changedUsingUi: PropTypes.any,
898
+ setFetchUptoLevelLimit: PropTypes.any,
899
+ setAllDistrictReq: PropTypes.any,
900
+ setAllBlockReq: PropTypes.any,
901
+ setAllPhcReq: PropTypes.any,
902
+ setUiLocations: PropTypes.any,
903
+ setUiSelectedLocation: PropTypes.any,
904
+ clearPreviousLocation: PropTypes.any,
905
+ triggerFirstRun: PropTypes.number,
906
+ locationBreadCrumbSelected: PropTypes.any,
907
+ };
908
+
909
+ export default LocationSelectionComponent;