@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,514 @@
1
+ import FullCalendar from '@fullcalendar/react';
2
+ import dayGridPlugin from '@fullcalendar/daygrid';
3
+ import listPlugin from '@fullcalendar/list';
4
+ import timeGridPlugin from '@fullcalendar/timegrid';
5
+ import interactionPlugin from '@fullcalendar/interaction';
6
+ import { Popover, Tooltip, Typography } from '@mui/material';
7
+ import PropTypes from 'prop-types';
8
+ import { useEffect, useRef, useState } from 'react';
9
+ import dayjs from 'dayjs';
10
+ import { useSelector } from 'react-redux';
11
+ import './calendar.scss';
12
+ import { useNavigate } from 'react-router';
13
+ const DATE_FORMAT = 'YYYY-MM-DD';
14
+ const MONTH_GRID_CALENDAR = 'dayGridMonth';
15
+ const TELE_CONSULTATION = 'TELE_CONSULTATION';
16
+ const CustomFullCalendar = ({
17
+ initialView,
18
+ handleMonthViewMore,
19
+ monthViewPopoverOpenRef,
20
+ isExtraLargeScreenForCalendarView,
21
+ setCalendarView,
22
+ calendarView,
23
+ viewInfo,
24
+ setViewInfo,
25
+ eventClick,
26
+ blockedDays,
27
+ slotDuration,
28
+ blockedEvents = [],
29
+ onFilteredAppointmentsChange,
30
+ appointmentResponse,
31
+ handleDateClick,
32
+ }) => {
33
+ const navigate = useNavigate();
34
+ const currentTime = useState(dayjs().subtract(60, 'minute').format('HH:mm:ss'));
35
+ const calendarRef = useRef(null);
36
+ const [anchorEl, setAnchorEl] = useState(null);
37
+ const [popoverOpen, setPopoverOpen] = useState(false);
38
+ const [selectedAppointmentMonth, setSelectedAppointmentMonth] = useState(null);
39
+ const selectedAppointment = null;
40
+ const allEvents = useSelector((state) => state.CalendarEvents.allEvents);
41
+ const eventsForViewsExceptMonthView = useSelector((state) => state.CalendarEvents.eventsForViewsExceptMonthView);
42
+ const monthViewEvents = useSelector((state) => state.CalendarEvents.monthViewEvents);
43
+ const listView = 'listWeek';
44
+ const largeScreenToolbar = {
45
+ end: 'today prev,next',
46
+ start: `timeGridDay,timeGridWeek,dayGridMonth,${listView}`,
47
+ center: 'title',
48
+ };
49
+ const smallScreenToolbar = {
50
+ start: `timeGridDay,timeGridWeek,dayGridMonth,${listView}`,
51
+ center: 'today prev,next',
52
+ end: 'title',
53
+ };
54
+
55
+ useEffect(() => {
56
+ return () => {
57
+ if (monthViewPopoverOpenRef) {
58
+ monthViewPopoverOpenRef.current = false;
59
+ }
60
+ };
61
+ }, []);
62
+
63
+ useEffect(() => {
64
+ const toolbar = document.querySelector('.fc-toolbar');
65
+ if (toolbar) {
66
+ if (isExtraLargeScreenForCalendarView) {
67
+ toolbar.classList.remove('small-screen-toolbar');
68
+ } else {
69
+ toolbar.classList.add('small-screen-toolbar');
70
+ }
71
+ }
72
+ }, [isExtraLargeScreenForCalendarView]);
73
+
74
+ const isDateBlocked = (info) => {
75
+ if (info.view.type === MONTH_GRID_CALENDAR) {
76
+ const formattedDate = dayjs(info.date).format(DATE_FORMAT);
77
+ return blockedDays.some(
78
+ (blockedDay) => blockedDay.startDate <= formattedDate && blockedDay.endDate >= formattedDate
79
+ );
80
+ }
81
+ return false;
82
+ };
83
+
84
+ const updateScrollTime = (info) => {
85
+ if (calendarRef.current) {
86
+ const now = dayjs();
87
+
88
+ let isTodayVisible = false;
89
+
90
+ if (info.view.type === 'timeGridWeek') {
91
+ const startOfWeek = dayjs(info.start);
92
+ const endOfWeek = dayjs(info.end);
93
+ isTodayVisible = now.isAfter(startOfWeek) && now.isBefore(endOfWeek);
94
+ } else {
95
+ // For timeGridDay or other views
96
+ const startDate = dayjs(info.start);
97
+ isTodayVisible = startDate.isSame(now, 'day');
98
+ }
99
+
100
+ // Decide scroll time
101
+ const scrollTime = isTodayVisible
102
+ ? now.hour() < 2
103
+ ? '00:00:00'
104
+ : now.subtract(2, 'hour').format('HH:mm:ss')
105
+ : '00:00:00';
106
+
107
+ calendarRef.current.getApi().scrollToTime(scrollTime);
108
+ }
109
+ };
110
+
111
+ const initialScrollRef = useRef(false);
112
+
113
+ const handleDateChange = (info) => {
114
+ updateScrollTime(info);
115
+ initialScrollRef.current = true;
116
+ setViewInfo(info);
117
+ setCalendarView(info.view.type);
118
+ onFilteredAppointmentsChange(allEvents.value, info, appointmentResponse);
119
+ };
120
+
121
+ useEffect(() => {
122
+ if (viewInfo) {
123
+ handleDateChange(viewInfo);
124
+ }
125
+ }, [allEvents, appointmentResponse]);
126
+ return (
127
+ <div className="h-full pb-2">
128
+ <FullCalendar
129
+ ref={calendarRef}
130
+ plugins={[dayGridPlugin, timeGridPlugin, interactionPlugin, listPlugin]}
131
+ headerToolbar={isExtraLargeScreenForCalendarView ? largeScreenToolbar : smallScreenToolbar}
132
+ initialView={initialView ?? 'timeGridDay'}
133
+ allDaySlot={false}
134
+ weekends={true}
135
+ slotDuration={{ minute: slotDuration }}
136
+ slotLabelInterval={{ minute: slotDuration }}
137
+ scrollTime={currentTime}
138
+ slotLabelFormat={{
139
+ hour: 'numeric',
140
+ minute: '2-digit',
141
+ omitZeroMinute: false,
142
+ meridiem: 'short',
143
+ }}
144
+ buttonText={{
145
+ today: 'Today',
146
+ month: 'Month',
147
+ week: 'Week',
148
+ day: 'Day',
149
+ list: 'All',
150
+ }}
151
+ slotMinTime={'00:00:00'}
152
+ slotMaxTime={'23:59:59'}
153
+ events={
154
+ calendarView === MONTH_GRID_CALENDAR
155
+ ? [...monthViewEvents] // When it's month grid view, show monthViewEvents
156
+ : [...eventsForViewsExceptMonthView.value, ...blockedEvents]
157
+ }
158
+ eventContent={(eventInfo) =>
159
+ renderEventContent(
160
+ eventInfo,
161
+ eventClick,
162
+ selectedAppointment,
163
+ anchorEl,
164
+ setAnchorEl,
165
+ popoverOpen,
166
+ setPopoverOpen,
167
+ monthViewPopoverOpenRef,
168
+ selectedAppointmentMonth,
169
+ setSelectedAppointmentMonth,
170
+ navigate
171
+ )
172
+ }
173
+ dayMaxEventRows={2}
174
+ fixedWeekCount={false}
175
+ views={{
176
+ day: {},
177
+ week: {
178
+ eventMaxStack: 1,
179
+ },
180
+ }}
181
+ height="100%"
182
+ noEventsText="There are no appointments to show !"
183
+ eventClick={calendarView === MONTH_GRID_CALENDAR ? handleMonthViewMore : eventClick}
184
+ dayCellClassNames={(cellInfo) => (isDateBlocked(cellInfo) ? ['blocked_day'] : [])}
185
+ datesSet={handleDateChange}
186
+ eventDidMount={(info) => {
187
+ if (info.view.type === listView) {
188
+ info.el.style.backgroundColor = info.event.extendedProps?.eventSelected ? '#E6EEf1' : 'default';
189
+ }
190
+ }}
191
+ eventOrder={(a, b) => (calendarView === listView ? 0 : a.extendedProps.priority - b.extendedProps.priority)}
192
+ dateClick={(info) => {
193
+ handleDateClick?.(info.date); // Call the passed handler
194
+ }}
195
+ />
196
+ </div>
197
+ );
198
+ };
199
+
200
+ const renderEventContent = (
201
+ eventInfo,
202
+ eventClick,
203
+ selectedAppointment,
204
+ anchorEl,
205
+ setAnchorEl,
206
+ popoverOpen,
207
+ setPopoverOpen,
208
+ monthViewPopoverOpenRef,
209
+ selectedAppointmentMonth,
210
+ setSelectedAppointmentMonth,
211
+ navigate
212
+ ) => {
213
+ const AppointmentItem = ({ item, isSelected }) => (
214
+ <div
215
+ style={{
216
+ display: 'flex',
217
+ backgroundColor: isSelected ? '#29bf91' : '#004C70',
218
+ padding: '2px 4px',
219
+ width: '100%',
220
+ borderRadius: '10px',
221
+
222
+ cursor: 'pointer',
223
+ overflow: 'hidden',
224
+ margin: '0px 0px 2px 0px',
225
+ }}
226
+ onClick={async () => {
227
+ eventClick({ event: { id: item.id } });
228
+ monthViewPopoverOpenRef.current = false;
229
+ setPopoverOpen(false);
230
+ }}
231
+ >
232
+ <p className="fc-patient-name" style={{ color: 'white', width: '150px' }}>
233
+ {item.title}
234
+ </p>
235
+ </div>
236
+ );
237
+ AppointmentItem.propTypes = { item: PropTypes.string, isSelected: PropTypes.string };
238
+ const statusStyles = {
239
+ SCHEDULED: 'bg-green-100 text-green-700',
240
+ CANCELLED: 'bg-red-100 text-red-700',
241
+ RESCHEDULED: 'bg-yellow-100 text-yellow-700',
242
+ COMPLETED: 'bg-blue-100 text-blue-700',
243
+ NO_SHOW: 'bg-gray-100 text-gray-700',
244
+ CHECKED_IN: 'bg-purple-100 text-purple-700',
245
+ MISSED_BY_PATIENT: 'bg-purple-100 text-purple-700',
246
+ MISSED_BY_DOCTOR: 'bg-purple-100 text-purple-700',
247
+ };
248
+ return (
249
+ <>
250
+ {eventInfo.view.type === MONTH_GRID_CALENDAR ? (
251
+ <>
252
+ {eventInfo.event.extendedProps.count > 0 && (
253
+ <div
254
+ className="flex items-center bg-transparent cursor-pointer z-[100] overflow-hidden"
255
+ onClick={async (event) => {
256
+ if (eventInfo.event.extendedProps.count > 1) {
257
+ setSelectedAppointmentMonth({
258
+ ...eventInfo.event.extendedProps,
259
+ start: dayjs(eventInfo.event.start).format('MMMM DD, YYYY'),
260
+ });
261
+ if (monthViewPopoverOpenRef) {
262
+ monthViewPopoverOpenRef.current = true;
263
+ }
264
+ setPopoverOpen(true);
265
+ setAnchorEl(event.currentTarget);
266
+ } else {
267
+ eventClick({ event: { id: eventInfo.event.extendedProps.teleAppointment[0]?.id } });
268
+ }
269
+ }}
270
+ >
271
+ <div
272
+ className="appointment-count flex-shrink-0"
273
+ style={{
274
+ backgroundColor: '#004c70',
275
+ }}
276
+ >
277
+ {eventInfo.event.extendedProps.count}{' '}
278
+ </div>
279
+ </div>
280
+ )}
281
+ <Popover
282
+ open={popoverOpen}
283
+ anchorEl={anchorEl}
284
+ onClose={() => {
285
+ setAnchorEl(null);
286
+ if (monthViewPopoverOpenRef) {
287
+ monthViewPopoverOpenRef.current = false;
288
+ }
289
+ setPopoverOpen(false);
290
+ }}
291
+ anchorOrigin={{
292
+ vertical: 'bottom',
293
+ horizontal: 'right',
294
+ }}
295
+ transformOrigin={{
296
+ vertical: 'center',
297
+ horizontal: 'left',
298
+ }}
299
+ elevation={0}
300
+ sx={{ left: '-25px' }}
301
+ >
302
+ {selectedAppointmentMonth && (
303
+ <div style={{ border: '1px solid #ddd', maxHeight: '300px' }}>
304
+ <div
305
+ style={{
306
+ backgroundColor: '#d1d1d14c',
307
+ padding: '3px 4px',
308
+ color: '#616161',
309
+ display: 'flex',
310
+ justifyContent: 'space-between',
311
+ }}
312
+ >
313
+ <span>{selectedAppointmentMonth?.start}</span>
314
+ <i
315
+ className="ri-close-line"
316
+ style={{ cursor: 'pointer' }}
317
+ onClick={() => {
318
+ setAnchorEl(null);
319
+ if (monthViewPopoverOpenRef) {
320
+ monthViewPopoverOpenRef.current = false;
321
+ }
322
+ setPopoverOpen(false);
323
+ }}
324
+ />
325
+ </div>
326
+ <div style={{ padding: '10px', overflowY: 'auto', height: '6rem' }} className="common-scrollbar">
327
+ {selectedAppointmentMonth.appointmentType === TELE_CONSULTATION &&
328
+ selectedAppointmentMonth.teleAppointment && (
329
+ <div>
330
+ {selectedAppointmentMonth.teleAppointment.map((item) => (
331
+ <AppointmentItem key={item.id} item={item} isSelected={item.id === selectedAppointment?.id} />
332
+ ))}
333
+ </div>
334
+ )}
335
+ </div>
336
+ </div>
337
+ )}
338
+ </Popover>
339
+ </>
340
+ ) : ['listWeek', 'listMonth'].includes(eventInfo.view.type) ? (
341
+ <div
342
+ className="flex !p-1 w-full justify-between !ml-2.5"
343
+ onClick={(e) => {
344
+ const parent = e.currentTarget.parentElement;
345
+ if (parent instanceof HTMLElement) {
346
+ parent.click();
347
+ }
348
+ }}
349
+ >
350
+ <Tooltip title={`Dr. ${eventInfo.event.extendedProps.doctorName}`} arrow>
351
+ <Typography
352
+ variant="h6"
353
+ className="list-patient-name calendar-list-doctor-name text-customBlue"
354
+ sx={{
355
+ fontWeight: '500',
356
+ fontSize: { md: '12px', lg: '12px', xl: '12px' },
357
+ // flex: '1.5',
358
+ mt: '7px',
359
+ }}
360
+ >
361
+ {eventInfo.event.extendedProps.doctorName}
362
+ </Typography>
363
+ </Tooltip>
364
+ <Tooltip title={eventInfo.event.title} arrow>
365
+ <Typography
366
+ variant="h6"
367
+ className="list-patient-name calendar-list-patient-name text-customBlue"
368
+ sx={{
369
+ fontWeight: '500',
370
+ fontSize: { md: '12px', lg: '12px', xl: '12px' },
371
+ ml: '10px',
372
+ mr: '10px',
373
+ mt: '7px',
374
+ }}
375
+ >
376
+ {eventInfo.event.title}
377
+ </Typography>
378
+ </Tooltip>
379
+ <Tooltip title={eventInfo.event.extendedProps.sadhikaName} arrow>
380
+ <Typography
381
+ variant="h6"
382
+ className="list-patient-name calendar-list-patient-name text-customBlue"
383
+ sx={{
384
+ fontWeight: '500',
385
+ fontSize: { md: '12px', lg: '12px', xl: '12px' },
386
+ ml: '10px',
387
+ mr: '10px',
388
+ mt: '7px',
389
+ }}
390
+ >
391
+ {eventInfo.event.extendedProps.sadhikaName} (Sadhika)
392
+ </Typography>
393
+ </Tooltip>
394
+ <Tooltip title={'Join appointment'} arrow>
395
+ {eventInfo.event?.extendedProps?.appointmentStatus !== 'COMPLETED' &&
396
+ eventInfo.event?.extendedProps?.appointmentStatus !== 'CANCELLED' &&
397
+ !dayjs().isAfter(eventInfo.event?.end) ? (
398
+ <div
399
+ className={`px-6 py-2 text-sm rounded-full text-center bg-green-600 text-white`}
400
+ onClick={() => {
401
+ navigate(`/ui/teleCommunication/${eventInfo.event?.id}`);
402
+ }}
403
+ >
404
+ JOIN
405
+ </div>
406
+ ) : (
407
+ // <Button
408
+ // variant="contained"
409
+ // color="primary"
410
+ // size="small"
411
+ // sx={{
412
+ // fontWeight: '500',
413
+ // fontSize: { md: '12px', lg: '12px', xl: '12px' },
414
+ // }}
415
+ // // disabled={!showJoinButton}
416
+ // onClick={() => {
417
+ // navigate(`/ui/teleCommunication/${eventInfo.event?.id}`);
418
+ // }}
419
+ // >
420
+ // Join
421
+ // </Button>
422
+ <div>
423
+ {(eventInfo.event?.extendedProps?.appointmentStatus === 'SCHEDULED' ||
424
+ eventInfo.event?.extendedProps?.appointmentStatus === 'RESCHEDULED') &&
425
+ dayjs().isAfter(eventInfo.event?.end) ? (
426
+ <div
427
+ className={`py-1 px-3 text-sm font-medium rounded-full text-center w-full ${statusStyles['MISSED_BY_PATIENT']}`}
428
+ >
429
+ MISSED
430
+ </div>
431
+ ) : (
432
+ <div
433
+ className={`px-3 py-1 text-sm rounded-full text-center ${statusStyles[`${eventInfo.event?.extendedProps?.appointmentStatus}`]}`}
434
+ >
435
+ {eventInfo.event?.extendedProps?.appointmentStatus?.replace(/_/g, ' ')}
436
+ </div>
437
+ )}
438
+ </div>
439
+ )}
440
+ </Tooltip>
441
+ </div>
442
+ ) : (
443
+ <div
444
+ onClick={(e) => {
445
+ const parent = e.currentTarget.parentElement;
446
+ if (parent instanceof HTMLElement) {
447
+ parent.click();
448
+ }
449
+ }}
450
+ style={{
451
+ maxWidth: '100%',
452
+ }}
453
+ >
454
+ {eventInfo.event.extendedProps.appointmentType === 'Blocked' ? (
455
+ <div
456
+ style={{
457
+ backgroundColor: '#b2c9d4',
458
+ width: 'auto',
459
+ height: '100%',
460
+ }}
461
+ />
462
+ ) : (
463
+ <div
464
+ style={{
465
+ display: 'flex',
466
+ backgroundColor:
467
+ eventInfo.event.extendedProps?.appointmentId === selectedAppointment?.id ? '#29bf91' : '#004C70',
468
+ padding: '2px 4px',
469
+ width: '100%',
470
+ borderRadius: '10px',
471
+ border: '1px solid white',
472
+ cursor: 'pointer',
473
+ overflow: 'hidden',
474
+ }}
475
+ >
476
+ <p
477
+ className="fc-patient-name"
478
+ style={{
479
+ color: 'white',
480
+ width: '150px',
481
+ }}
482
+ >
483
+ {eventInfo.event.title}
484
+ </p>
485
+ </div>
486
+ )}
487
+ </div>
488
+ )}
489
+ </>
490
+ );
491
+ };
492
+
493
+ CustomFullCalendar.propTypes = {
494
+ initialView: PropTypes.string,
495
+ handleMonthViewMore: PropTypes.func,
496
+ monthViewEventsData: PropTypes.array,
497
+ monthViewPopoverOpenRef: PropTypes.object,
498
+ isExtraLargeScreenForCalendarView: PropTypes.bool,
499
+ setCalendarView: PropTypes.func,
500
+ calendarView: PropTypes.string,
501
+ viewInfo: PropTypes.object,
502
+ setViewInfo: PropTypes.func,
503
+ eventClick: PropTypes.func,
504
+ blockedDays: PropTypes.array,
505
+ slotDuration: PropTypes.number,
506
+ blockedEvents: PropTypes.array,
507
+ onFilteredAppointmentsChange: PropTypes.func,
508
+ appointmentResponse: PropTypes.array,
509
+ handleDateClick: PropTypes.func,
510
+ setIsFilterDrawerOpen: PropTypes.func,
511
+ handleDateRangeChange: PropTypes.func,
512
+ };
513
+
514
+ export default CustomFullCalendar;
@@ -0,0 +1,126 @@
1
+ import React, { useEffect, useRef } from 'react';
2
+ import { styled } from '@mui/material/styles';
3
+ import TableContainer from '@mui/material/TableContainer';
4
+ import { Paper, Box, CircularProgress } from '@mui/material';
5
+ import PropTypes from 'prop-types';
6
+ import { throttle } from 'lodash';
7
+
8
+ const StyledTableContainer = styled(TableContainer)(() => ({
9
+ borderRadius: '3px 3px 0 0',
10
+ '&::-webkit-scrollbar': {
11
+ width: '50px',
12
+ },
13
+ scrollbarWidth: 'thin',
14
+ }));
15
+
16
+ const CustomInfiniteScroll = ({
17
+ renderTableBody,
18
+ loadMore,
19
+ hasMore,
20
+ customHeight = null,
21
+ scrollToTop = false,
22
+ setScrollToTop = () => { },
23
+ }) => {
24
+ const scrollParentRef = useRef(null); // Ref for scroll container
25
+
26
+ useEffect(() => {
27
+ if (scrollToTop && scrollParentRef.current) {
28
+ scrollParentRef.current.scrollTop = 0;
29
+ setScrollToTop(false);
30
+ }
31
+ }, [scrollToTop, scrollParentRef]);
32
+
33
+ const [loading, setLoading] = React.useState(false);
34
+
35
+ const triggerLoadMore = async () => {
36
+ try {
37
+ setLoading(true);
38
+ // Ensure loader is visible by scrolling to bottom
39
+ setTimeout(() => {
40
+ if (scrollParentRef.current) {
41
+ scrollParentRef.current.scrollTop = scrollParentRef.current.scrollHeight;
42
+ }
43
+ }, 50);
44
+ await new Promise((resolve) => setTimeout(resolve, 500));
45
+ await loadMore();
46
+ setLoading(false);
47
+ } catch (error) {
48
+ console.error(error);
49
+ setLoading(false);
50
+ }
51
+ }
52
+
53
+ const checkAndLoadIfNotScrollable = async () => {
54
+ const container = scrollParentRef.current;
55
+ if (container && container.scrollHeight <= container.clientHeight && hasMore && !loading) {
56
+ triggerLoadMore();
57
+ }
58
+ };
59
+
60
+ const handleScroll = throttle(async () => {
61
+ if (!hasMore || loading) return;
62
+ const container = scrollParentRef.current;
63
+ if (container) {
64
+ const { scrollTop, scrollHeight, clientHeight } = container;
65
+ if (scrollTop + clientHeight >= scrollHeight - 10) {
66
+ // Trigger loadMore if the user scrolls near the bottom
67
+ triggerLoadMore();
68
+ }
69
+ }
70
+ }, 200);
71
+
72
+ useEffect(() => {
73
+ const container = scrollParentRef.current;
74
+ if (container) {
75
+ setTimeout(() => {
76
+ container.addEventListener('scroll', handleScroll);
77
+ checkAndLoadIfNotScrollable();
78
+ }, 500);
79
+ }
80
+ return () => {
81
+ if (container) {
82
+ container.removeEventListener('scroll', handleScroll);
83
+ hasMore = null;
84
+ // setLoading(false);
85
+ }
86
+ };
87
+ }, [loading, hasMore]); // Re-run if `loading` or `hasMore` changes
88
+
89
+ return (
90
+ <StyledTableContainer
91
+ component={Paper}
92
+ style={{ position: 'relative', overflow: 'auto' }}
93
+ sx={{ maxHeight: customHeight ? `calc(100vh - ${150 + customHeight}px)` : `calc(100vh - 150px)` }}
94
+ ref={scrollParentRef} // Attach the scroll ref
95
+ >
96
+ {renderTableBody()}
97
+ {loading && (
98
+ <Box
99
+ sx={{
100
+ display: 'flex',
101
+ justifyContent: 'center',
102
+ alignItems: 'center',
103
+ py: 2,
104
+ width: '100%',
105
+ backgroundColor: (theme) => (theme.palette.mode === 'dark' ? 'rgba(0,0,0,0.05)' : 'rgba(255,255,255,0.8)'),
106
+ borderTop: '1px solid',
107
+ borderColor: 'divider',
108
+ }}
109
+ >
110
+ <CircularProgress size={24} thickness={4} />
111
+ </Box>
112
+ )}
113
+ </StyledTableContainer>
114
+ );
115
+ };
116
+
117
+ CustomInfiniteScroll.propTypes = {
118
+ renderTableBody: PropTypes.any,
119
+ loadMore: PropTypes.any,
120
+ hasMore: PropTypes.any,
121
+ customHeight: PropTypes.any,
122
+ scrollToTop: PropTypes.any,
123
+ setScrollToTop: PropTypes.any,
124
+ };
125
+
126
+ export default CustomInfiniteScroll;
@@ -0,0 +1,65 @@
1
+ import React from 'react';
2
+ import { FormControl, RadioGroup, FormControlLabel, Radio } from '@mui/material';
3
+ import { Controller, get } from 'react-hook-form';
4
+ import PropTypes from 'prop-types';
5
+ import { useTranslateProvider } from '@/common/languageTranslator/TranslationContext';
6
+
7
+ const CustomRadioGroup = ({ name, control, options, errors, direction = 'column', dataTestId, ...props }) => {
8
+ const error = get(errors, name);
9
+ const { translate } = useTranslateProvider();
10
+
11
+ return (
12
+ <FormControl component="fieldset" className='w-full'>
13
+ <Controller
14
+ name={name}
15
+ control={control}
16
+ {...props}
17
+ render={({ field }) => {
18
+ return (
19
+ <RadioGroup
20
+ {...field}
21
+ {...props}
22
+ data-testid={dataTestId}
23
+ value={field.value !== undefined ? String(field.value) : ''}
24
+ onChange={(e) => {
25
+ const value =
26
+ e.target.value === 'true' ? true : (() => (e.target.value === 'false' ? false : e.target.value))();
27
+ field.onChange(value);
28
+ }}
29
+ sx={{ flexDirection: direction }}
30
+ >
31
+ {options.map((option) => (
32
+ <FormControlLabel
33
+ {...field}
34
+ {...props}
35
+ key={option.value}
36
+ value={String(option.value)} // Ensure the value is a string
37
+ control={<Radio />}
38
+ label={translate(option.label)}
39
+ sx={{
40
+ '& .MuiFormControlLabel-label': {
41
+ fontSize: '14px',
42
+ },
43
+ }}
44
+ data-testid={`${dataTestId}-${String(option.label)}`}
45
+ />
46
+ ))}
47
+ </RadioGroup>
48
+ );
49
+ }}
50
+ />
51
+ {error && <p className="error-helper-text">{error?.message}</p>}
52
+ </FormControl>
53
+ );
54
+ };
55
+
56
+ CustomRadioGroup.propTypes = {
57
+ name: PropTypes.any,
58
+ control: PropTypes.any,
59
+ options: PropTypes.any,
60
+ errors: PropTypes.any,
61
+ direction: PropTypes.any,
62
+ dataTestId: PropTypes.any,
63
+ };
64
+
65
+ export default CustomRadioGroup;