ui-soxo-bootstrap-core 2.6.5 → 2.6.6

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 (405) hide show
  1. package/.babelrc +8 -8
  2. package/.github/workflows/npm-publish.yml +33 -33
  3. package/.husky/pre-commit +11 -11
  4. package/.prettierrc.json +10 -10
  5. package/babel.config.js +2 -2
  6. package/core/components/component-loader/component-loader.js +125 -125
  7. package/core/components/component-wrapper/component-wrapper.js +121 -121
  8. package/core/components/external-window/DEVELOPER_GUIDE.md +705 -705
  9. package/core/components/external-window/external-window.js +236 -236
  10. package/core/components/external-window/external-window.test.js +80 -80
  11. package/core/components/extra-info/extra-info-details.js +155 -155
  12. package/core/components/extra-info/extra-info-details.scss +26 -26
  13. package/core/components/extra-info/extra-info.js +134 -134
  14. package/core/components/index.js +20 -20
  15. package/core/components/landing-api/landing-api.js +492 -492
  16. package/core/components/landing-api/landing-api.scss +19 -19
  17. package/core/components/menu-template-api/menu-template-api.js +321 -321
  18. package/core/components/root-application-api/root-application-api.js +174 -174
  19. package/core/index.js +13 -13
  20. package/core/lib/Store.js +365 -365
  21. package/core/lib/components/application-bootstrap/application-bootstrap.js +115 -115
  22. package/core/lib/components/approval-form/approval-form.js +280 -280
  23. package/core/lib/components/approval-form/approval-form.scss +183 -183
  24. package/core/lib/components/approval-list/approval-list.js +143 -143
  25. package/core/lib/components/approval-list/approval-list.scss +2 -2
  26. package/core/lib/components/approval-list/components/request-card/request-card.js +42 -42
  27. package/core/lib/components/approval-list/components/request-card/request-card.scss +30 -30
  28. package/core/lib/components/camera/camera.js +230 -230
  29. package/core/lib/components/camera/camera.scss +86 -86
  30. package/core/lib/components/comment-block/comment-block.js +138 -138
  31. package/core/lib/components/comment-block/comment-block.scss +3 -3
  32. package/core/lib/components/confirm-modal/confirm-modal.js +82 -82
  33. package/core/lib/components/confirm-modal/confirm-modal.scss +2 -2
  34. package/core/lib/components/consent/consent.js +67 -67
  35. package/core/lib/components/consent/pdf-signature.js +299 -299
  36. package/core/lib/components/consent/signature-pad.js +90 -90
  37. package/core/lib/components/consent/signature-pad.scss +14 -14
  38. package/core/lib/components/file-upload/file-upload.js +133 -133
  39. package/core/lib/components/finger-print-reader/finger-print-reader.js +295 -295
  40. package/core/lib/components/finger-print-reader/finger-print-reader.scss +47 -47
  41. package/core/lib/components/finger-print-search/finger-print-search.js +200 -200
  42. package/core/lib/components/finger-print-search/finger-print-search.scss +47 -47
  43. package/core/lib/components/global-header/animations.js +18 -18
  44. package/core/lib/components/global-header/global-header.js +413 -413
  45. package/core/lib/components/global-header/global-header.scss +369 -369
  46. package/core/lib/components/header/generic-header.js +76 -76
  47. package/core/lib/components/header/generic-header.scss +99 -99
  48. package/core/lib/components/image-preview/image-preview.js +33 -33
  49. package/core/lib/components/image-wrapper/image-wrapper.js +108 -108
  50. package/core/lib/components/image-wrapper/image-wrapper.scss +12 -12
  51. package/core/lib/components/index.js +206 -206
  52. package/core/lib/components/landing/landing.js +403 -403
  53. package/core/lib/components/language-switcher/language-switcher.js +49 -49
  54. package/core/lib/components/menu-context/menu-context.js +69 -69
  55. package/core/lib/components/menu-template/menu-template.js +249 -249
  56. package/core/lib/components/menu-template/menu-template.scss +9 -9
  57. package/core/lib/components/modal-search/modal-search.js +153 -153
  58. package/core/lib/components/modal-search/modal-search.scss +78 -78
  59. package/core/lib/components/modal-wrapper/modal-manager.js +15 -15
  60. package/core/lib/components/modal-wrapper/modal-wrapper.js +108 -108
  61. package/core/lib/components/modal-wrapper/modal-wrapper.scss +13 -13
  62. package/core/lib/components/notice-board/notice-board.js +132 -132
  63. package/core/lib/components/notice-board/notice-board.scss +65 -65
  64. package/core/lib/components/page-container/page-container.js +55 -55
  65. package/core/lib/components/page-container/page-container.scss +8 -8
  66. package/core/lib/components/page-header/page-header.js +23 -23
  67. package/core/lib/components/page-header/page-header.scss +17 -17
  68. package/core/lib/components/pdf-viewer/pdf-viewer.js +56 -56
  69. package/core/lib/components/portlet-table/components/table-actions/table-actions.js +58 -58
  70. package/core/lib/components/portlet-table/components/table-actions/table-actions.scss +1 -1
  71. package/core/lib/components/portlet-table/components/table-data/table-data.js +106 -106
  72. package/core/lib/components/portlet-table/portlet-table.js +63 -63
  73. package/core/lib/components/portlet-table/portlet-table.scss +90 -90
  74. package/core/lib/components/progress-bar/progress-bar.js +58 -58
  75. package/core/lib/components/progress-bar/progress-bar.scss +15 -15
  76. package/core/lib/components/request-form/request-form.js +110 -110
  77. package/core/lib/components/root-application/root-application.js +70 -70
  78. package/core/lib/components/rupee/rupee.js +14 -14
  79. package/core/lib/components/script-input/script-input.js +169 -169
  80. package/core/lib/components/script-input/script-input.scss +8 -8
  81. package/core/lib/components/sidemenu/animations.js +51 -51
  82. package/core/lib/components/sidemenu/sidemenu.js +578 -578
  83. package/core/lib/components/sidemenu/sidemenu.scss +277 -277
  84. package/core/lib/components/spotlight-search/spotlight-search.component.js +635 -635
  85. package/core/lib/components/spotlight-search/spotlight-search.component.scss +78 -78
  86. package/core/lib/components/table-wrapper/table-wrapper.js +135 -135
  87. package/core/lib/components/table-wrapper/table-wrapper.scss +72 -72
  88. package/core/lib/components/ui_elements/Loader.js +12 -12
  89. package/core/lib/components/ui_elements/Notify.js +12 -12
  90. package/core/lib/components/ui_elements/PlaceHolder.js +33 -33
  91. package/core/lib/components/web-camera/web-camera.js +161 -161
  92. package/core/lib/components/web-camera/web-camera.scss +28 -28
  93. package/core/lib/core.md +9 -9
  94. package/core/lib/elements/Elements.md +2 -2
  95. package/core/lib/elements/basic/LoggedUserRedirect.js +21 -21
  96. package/core/lib/elements/basic/PrivateRoute.js +16 -16
  97. package/core/lib/elements/basic/button/Button.md +43 -43
  98. package/core/lib/elements/basic/button/button.js +170 -170
  99. package/core/lib/elements/basic/card/Card.md +15 -15
  100. package/core/lib/elements/basic/card/card.js +40 -40
  101. package/core/lib/elements/basic/card/card.scss +13 -13
  102. package/core/lib/elements/basic/checkbox/checkbox.js +23 -23
  103. package/core/lib/elements/basic/col/col.js +15 -15
  104. package/core/lib/elements/basic/copy-to-clipboard/Readme.md +40 -40
  105. package/core/lib/elements/basic/copy-to-clipboard/copy-to-clipboard.js +61 -61
  106. package/core/lib/elements/basic/country-phone-input/Readme.md +98 -98
  107. package/core/lib/elements/basic/country-phone-input/country-phone-input.js +106 -106
  108. package/core/lib/elements/basic/country-phone-input/phone-input.scss +61 -61
  109. package/core/lib/elements/basic/datepicker/datepicker.js +33 -33
  110. package/core/lib/elements/basic/dragabble-wrapper/draggable-wrapper.js +136 -136
  111. package/core/lib/elements/basic/empty/empty.js +14 -14
  112. package/core/lib/elements/basic/fingerprint-protrected/fingerprint-protected.js +118 -118
  113. package/core/lib/elements/basic/fingerprint-protrected/fingerprint-protected.scss +10 -10
  114. package/core/lib/elements/basic/form/form.js +70 -70
  115. package/core/lib/elements/basic/form/form.scss +3 -3
  116. package/core/lib/elements/basic/image/image.js +45 -45
  117. package/core/lib/elements/basic/image/image.scss +17 -17
  118. package/core/lib/elements/basic/image/readme.md +26 -26
  119. package/core/lib/elements/basic/image-viewer/image-viewer.js +108 -108
  120. package/core/lib/elements/basic/image-viewer/image-viewer.scss +7 -7
  121. package/core/lib/elements/basic/input/input.js +81 -81
  122. package/core/lib/elements/basic/input/readme.md +77 -77
  123. package/core/lib/elements/basic/json-input/json-input.js +51 -51
  124. package/core/lib/elements/basic/menu-dashboard/menu-dashboard.js +216 -216
  125. package/core/lib/elements/basic/menu-dashboard/menu-dashboard.scss +28 -28
  126. package/core/lib/elements/basic/menu-tree/menu-tree.js +114 -114
  127. package/core/lib/elements/basic/modal/modal.js +64 -64
  128. package/core/lib/elements/basic/modal/readme.md +62 -62
  129. package/core/lib/elements/basic/popconfirm/popconfirm.js +17 -17
  130. package/core/lib/elements/basic/popover/popover.js +12 -12
  131. package/core/lib/elements/basic/radio/radio.js +18 -18
  132. package/core/lib/elements/basic/rangepicker/rangepicker.js +141 -141
  133. package/core/lib/elements/basic/rangepicker/rangepicker.scss +24 -24
  134. package/core/lib/elements/basic/rangepicker/readme.md +81 -81
  135. package/core/lib/elements/basic/reference-select/readme.md +18 -18
  136. package/core/lib/elements/basic/reference-select/reference-select.js +337 -337
  137. package/core/lib/elements/basic/row/row.js +15 -15
  138. package/core/lib/elements/basic/select/select.js +46 -46
  139. package/core/lib/elements/basic/select-box/readme.md +52 -52
  140. package/core/lib/elements/basic/select-box/select-box.js +63 -63
  141. package/core/lib/elements/basic/skeleton/readme.md +35 -35
  142. package/core/lib/elements/basic/skeleton/skeleton.js +35 -35
  143. package/core/lib/elements/basic/skeleton/skeleton.scss +53 -53
  144. package/core/lib/elements/basic/space/space.js +12 -12
  145. package/core/lib/elements/basic/switch/readme.md +29 -29
  146. package/core/lib/elements/basic/switch/switch.js +67 -67
  147. package/core/lib/elements/basic/tab/tab.js +14 -14
  148. package/core/lib/elements/basic/table/readme.md +8 -8
  149. package/core/lib/elements/basic/table/table.js +100 -100
  150. package/core/lib/elements/basic/tag/tag.js +63 -63
  151. package/core/lib/elements/basic/tag/tag.scss +2 -2
  152. package/core/lib/elements/basic/timeline/timeline.js +13 -13
  153. package/core/lib/elements/basic/title/readme.md +20 -20
  154. package/core/lib/elements/basic/title/title.js +37 -37
  155. package/core/lib/elements/basic/user-search/user-search.js +192 -192
  156. package/core/lib/elements/complex/barcode/barcode.js +27 -27
  157. package/core/lib/elements/complex/bargraph/bar-graph.js +262 -262
  158. package/core/lib/elements/complex/basic-table/basic-table.js +110 -110
  159. package/core/lib/elements/complex/basic-table/basic-table.scss +4 -4
  160. package/core/lib/elements/complex/date-display/date-display.js +37 -37
  161. package/core/lib/elements/complex/error-boundary/error-boundary.js +29 -29
  162. package/core/lib/elements/complex/google-location-input/map-container-library-load.js +92 -92
  163. package/core/lib/elements/complex/google-map/google-map.js +230 -230
  164. package/core/lib/elements/complex/google-map/google-map.scss +13 -13
  165. package/core/lib/elements/complex/line-graph/line-graph.js +108 -108
  166. package/core/lib/elements/complex/location-search-input/location-search-input.js +100 -100
  167. package/core/lib/elements/complex/pie-chart/pie-chart.js +202 -202
  168. package/core/lib/elements/complex/qr-code/qr-code.js +27 -27
  169. package/core/lib/elements/complex/qrscanner/qrscanner.js +57 -57
  170. package/core/lib/elements/complex/search-debounce/search-debounce.js +37 -37
  171. package/core/lib/elements/complex/statistic-card/dashboard-statistic-card.js +75 -75
  172. package/core/lib/elements/complex/statistic-card/statistic-card.js +28 -28
  173. package/core/lib/elements/index.js +226 -226
  174. package/core/lib/hooks/device-detect.js +25 -25
  175. package/core/lib/hooks/index.js +9 -9
  176. package/core/lib/hooks/use-location.js +33 -33
  177. package/core/lib/hooks/use-otp-timer.js +80 -80
  178. package/core/lib/hooks/use-window-size.js +34 -34
  179. package/core/lib/i18n.js +69 -69
  180. package/core/lib/index.js +106 -106
  181. package/core/lib/introduction.md +73 -73
  182. package/core/lib/js-styleguide.md +4112 -4112
  183. package/core/lib/models/actions/actions.js +127 -127
  184. package/core/lib/models/actions/components/action-detail/action-detail.js +190 -190
  185. package/core/lib/models/actions/components/custom-actions/custom-actions.js +185 -185
  186. package/core/lib/models/attachments/attachments.js +231 -231
  187. package/core/lib/models/base-loader.js +99 -99
  188. package/core/lib/models/base.js +716 -716
  189. package/core/lib/models/branches/branches.js +125 -125
  190. package/core/lib/models/checklists/checklists.js +114 -114
  191. package/core/lib/models/columns/columns.js +169 -169
  192. package/core/lib/models/columns/components/columns-add/columns-add.js +171 -171
  193. package/core/lib/models/comments/comments.js +213 -213
  194. package/core/lib/models/departments/departments.js +107 -107
  195. package/core/lib/models/financial-years/financial_years.js +127 -127
  196. package/core/lib/models/forms/components/form-creator/form-creator.js +624 -624
  197. package/core/lib/models/forms/components/form-creator/form-creator.scss +30 -29
  198. package/core/lib/models/forms/components/form-detail/form-detail.js +224 -224
  199. package/core/lib/models/forms/forms.js +121 -121
  200. package/core/lib/models/index.js +203 -203
  201. package/core/lib/models/invoice-numbers/invoice_numbers.js +204 -204
  202. package/core/lib/models/lookup-types/components/lookup-detail/lookup-detail.js +145 -145
  203. package/core/lib/models/lookup-types/lookup-types.js +113 -113
  204. package/core/lib/models/lookup-values/components/lookup-values-add/lookup-values-add.js +126 -126
  205. package/core/lib/models/lookup-values/lookup-values.js +107 -107
  206. package/core/lib/models/menu-roles/menu-roles.js +127 -127
  207. package/core/lib/models/menus/components/menu-add/menu-add.js +228 -228
  208. package/core/lib/models/menus/components/menu-detail/menu-detail.js +170 -170
  209. package/core/lib/models/menus/components/menu-list/menu-list.js +593 -593
  210. package/core/lib/models/menus/components/menu-list/menu-list.scss +5 -5
  211. package/core/lib/models/menus/components/menu-roles-add/menu-roles-add.js +183 -183
  212. package/core/lib/models/menus/menus.js +499 -499
  213. package/core/lib/models/models/components/model-detail/model-detail.js +137 -137
  214. package/core/lib/models/models/components/models.js +128 -128
  215. package/core/lib/models/modules/modules.js +204 -204
  216. package/core/lib/models/outbox/outbox.js +73 -73
  217. package/core/lib/models/pages/pages.js +107 -107
  218. package/core/lib/models/permissions/permissions.js +71 -71
  219. package/core/lib/models/process/components/process-add/process-add.js +181 -181
  220. package/core/lib/models/process/components/process-dashboard/process-dashboard.js +601 -601
  221. package/core/lib/models/process/components/process-dashboard/process-dashboard.scss +62 -62
  222. package/core/lib/models/process/components/process-detail/process-detail.js +140 -140
  223. package/core/lib/models/process/components/process-timeline/process-timeline.js +139 -139
  224. package/core/lib/models/process/components/task-detail/task-detail.js +240 -240
  225. package/core/lib/models/process/components/task-detail/task-detail.scss +27 -27
  226. package/core/lib/models/process/components/task-form/task-form.js +528 -528
  227. package/core/lib/models/process/components/task-form/task-form.scss +7 -7
  228. package/core/lib/models/process/components/task-list/task-list.js +221 -221
  229. package/core/lib/models/process/components/task-list/task-list.scss +14 -14
  230. package/core/lib/models/process/components/task-overview/task-overview.js +299 -299
  231. package/core/lib/models/process/components/task-overview-legacy/task-overview-legacy.js +192 -192
  232. package/core/lib/models/process/components/task-routes/task-routes.js +45 -45
  233. package/core/lib/models/process/components/task-status/task-status.js +175 -175
  234. package/core/lib/models/process/components/task-status/task-status.scss +11 -11
  235. package/core/lib/models/process/process.js +780 -780
  236. package/core/lib/models/process-transactions/process-transactions.js +123 -123
  237. package/core/lib/models/roles/roles.js +106 -106
  238. package/core/lib/models/scripts/scripts.js +111 -111
  239. package/core/lib/models/step-transactions/step-transcations.js +147 -147
  240. package/core/lib/models/steps/components/step-add/step-add.js +261 -261
  241. package/core/lib/models/steps/components/step-detail/step-detail.js +157 -157
  242. package/core/lib/models/steps/steps.js +356 -356
  243. package/core/lib/models/user-preferences/user-preferences.js +83 -83
  244. package/core/lib/models/users/components/user-add/user-add.js +226 -226
  245. package/core/lib/models/users/users.js +119 -119
  246. package/core/lib/modules/business/launch-page/launch-page.js +29 -29
  247. package/core/lib/modules/business/launch-page/launch-page.scss +5 -5
  248. package/core/lib/modules/business/slots/slots.js +231 -231
  249. package/core/lib/modules/business/slots/slots.scss +108 -108
  250. package/core/lib/modules/forms/components/field-customizer/field-customizer.js +138 -138
  251. package/core/lib/modules/forms/components/field-selector/field-selector.js +157 -157
  252. package/core/lib/modules/forms/components/field-selector/field-selector.scss +25 -25
  253. package/core/lib/modules/forms/components/form-display/form-display.js +203 -203
  254. package/core/lib/modules/forms/components/form-display/form-display.scss +9 -9
  255. package/core/lib/modules/forms/components/tab-customizer/tab-customizer.js +124 -124
  256. package/core/lib/modules/generic/generic-add/generic-add.js +213 -213
  257. package/core/lib/modules/generic/generic-detail/generic-detail.js +199 -199
  258. package/core/lib/modules/generic/generic-edit/generic-edit.js +120 -120
  259. package/core/lib/modules/generic/generic-list/ExportReactCSV.js +62 -62
  260. package/core/lib/modules/generic/generic-list/generic-list.js +705 -705
  261. package/core/lib/modules/generic/generic-list/generic-list.scss +34 -34
  262. package/core/lib/modules/generic/generic-upload/generic-upload.js +483 -483
  263. package/core/lib/modules/generic/table-settings/table-settings.js +226 -226
  264. package/core/lib/modules/generic/table-settings/table-settings.scss +37 -37
  265. package/core/lib/modules/index.js +52 -52
  266. package/core/lib/modules/modules-routes/module-routes.js +35 -35
  267. package/core/lib/pages/change-password/change-password.js +201 -201
  268. package/core/lib/pages/change-password/change-password.scss +73 -73
  269. package/core/lib/pages/homepage/homepage.js +53 -53
  270. package/core/lib/pages/index.js +19 -19
  271. package/core/lib/pages/login/commnication-mode-selection.js +46 -46
  272. package/core/lib/pages/login/communication-mode-selection.scss +60 -60
  273. package/core/lib/pages/login/login.js +864 -864
  274. package/core/lib/pages/login/login.scss +344 -344
  275. package/core/lib/pages/login/reset-password.js +125 -125
  276. package/core/lib/pages/login/reset-password.scss +22 -22
  277. package/core/lib/pages/manage-users/manage-users.js +429 -429
  278. package/core/lib/pages/manage-users/manage-users.scss +25 -25
  279. package/core/lib/pages/profile/profile.js +247 -247
  280. package/core/lib/pages/profile/profile.scss +107 -107
  281. package/core/lib/pages/profile/theme-config.js +18 -18
  282. package/core/lib/pages/profile/themes-backup.json +310 -310
  283. package/core/lib/pages/profile/themes.json +254 -254
  284. package/core/lib/pages/register/register.js +176 -176
  285. package/core/lib/pages/register/register.scss +128 -128
  286. package/core/lib/react-styleguide.md +756 -756
  287. package/core/lib/utils/api/api.utils.js +211 -211
  288. package/core/lib/utils/api/readme.md +426 -426
  289. package/core/lib/utils/async.js +35 -35
  290. package/core/lib/utils/common/common.utils.js +223 -223
  291. package/core/lib/utils/common/readme.md +30 -30
  292. package/core/lib/utils/date/date.utils.js +295 -295
  293. package/core/lib/utils/date/readme.md +2 -2
  294. package/core/lib/utils/firebase.support.utils.js +98 -98
  295. package/core/lib/utils/firebase.utils.js +808 -808
  296. package/core/lib/utils/form/form.utils.js +255 -255
  297. package/core/lib/utils/generic/generic.utils.js +69 -69
  298. package/core/lib/utils/http/auth.helper.js +95 -95
  299. package/core/lib/utils/http/http.utils.js +158 -158
  300. package/core/lib/utils/http/readme.md +14 -14
  301. package/core/lib/utils/index.js +40 -40
  302. package/core/lib/utils/location/location.utils.js +137 -137
  303. package/core/lib/utils/location/readme.md +18 -18
  304. package/core/lib/utils/modal.utils.js +15 -15
  305. package/core/lib/utils/notification.utils.js +34 -34
  306. package/core/lib/utils/pwa/pwa.utils.js +88 -88
  307. package/core/lib/utils/script.utils.js +235 -235
  308. package/core/lib/utils/setting.utils.js +68 -68
  309. package/core/lib/utils/upload.utils.js +29 -29
  310. package/core/models/Preference/Preferences.js +46 -46
  311. package/core/models/base/base.js +403 -403
  312. package/core/models/base-clone-loader.js +107 -107
  313. package/core/models/base-clone.js +187 -187
  314. package/core/models/base-loader.js +97 -97
  315. package/core/models/core-scripts/core-scripts.js +150 -150
  316. package/core/models/dashboard/dashboard.js +201 -201
  317. package/core/models/detail-loader.js +88 -88
  318. package/core/models/doctor/components/doctor-add/doctor-add.js +427 -427
  319. package/core/models/doctor/components/doctor-add/doctor-add.scss +32 -32
  320. package/core/models/groups.js +82 -82
  321. package/core/models/index.js +100 -100
  322. package/core/models/lookup-types/components/lookup-detail/lookup-detail.js +129 -129
  323. package/core/models/lookup-types/lookup-types.js +96 -96
  324. package/core/models/lookup-values/components/lookup-values-modal/lookup-values-modal.js +95 -95
  325. package/core/models/lookup-values/lookup-values.js +92 -92
  326. package/core/models/menu-roles/components/menu-roles-add/menu-roles-add.js +153 -153
  327. package/core/models/menu-roles/menu-roles.js +158 -158
  328. package/core/models/menus/components/menu-add/menu-add.js +288 -288
  329. package/core/models/menus/components/menu-add/menu-add.scss +31 -31
  330. package/core/models/menus/components/menu-detail/menu-detail.js +263 -263
  331. package/core/models/menus/components/menu-list/menu-list.js +392 -392
  332. package/core/models/menus/components/menu-lists/menu-lists.js +585 -585
  333. package/core/models/menus/components/menu-lists/menu-lists.scss +46 -46
  334. package/core/models/menus/menus.js +310 -310
  335. package/core/models/model-columns.js +121 -121
  336. package/core/models/models/components/model-detail/model-add.js +120 -120
  337. package/core/models/models/components/model-detail/model-detail.js +133 -133
  338. package/core/models/models/models.js +154 -154
  339. package/core/models/pages/components/page-add/page-add.js +163 -163
  340. package/core/models/pages/components/page-add/page-add.scss +30 -30
  341. package/core/models/pages/components/page-details/page-details.js +209 -209
  342. package/core/models/pages/components/page-list/page-list.js +248 -248
  343. package/core/models/pages/pages.js +142 -142
  344. package/core/models/pages.js +142 -142
  345. package/core/models/roles/components/role-add/role-add.js +312 -312
  346. package/core/models/roles/components/role-add/role-add.scss +4 -4
  347. package/core/models/roles/components/role-list/role-list.js +386 -386
  348. package/core/models/roles/roles.js +196 -196
  349. package/core/models/staff/components/staff-add/staff-add.js +467 -467
  350. package/core/models/user-roles/components/user-roles-add/user-roles-add.js +149 -149
  351. package/core/models/user-roles/user-roles.js +113 -113
  352. package/core/models/users/components/assign-role/assign-role.js +406 -406
  353. package/core/models/users/components/assign-role/assign-role.scss +281 -281
  354. package/core/models/users/components/assign-role/avatar-props.js +45 -45
  355. package/core/models/users/components/user-add/user-add.js +856 -856
  356. package/core/models/users/components/user-add/user-edit.js +106 -106
  357. package/core/models/users/components/user-detail/user-detail.js +236 -236
  358. package/core/models/users/components/user-list/user-list.js +397 -397
  359. package/core/models/users/users.js +379 -379
  360. package/core/modules/Informations/change-info/change-info.js +618 -618
  361. package/core/modules/Informations/change-info/change-info.scss +134 -134
  362. package/core/modules/dashboard/components/dashboard-card/animations.js +64 -64
  363. package/core/modules/dashboard/components/dashboard-card/dashboard-card.js +197 -197
  364. package/core/modules/dashboard/components/dashboard-card/menu-dashboard-card.js +430 -430
  365. package/core/modules/dashboard/components/dashboard-card/menu-dashboard-card.scss +59 -59
  366. package/core/modules/dashboard/components/pop-query-dashboard/pop-query-dashboard.js +66 -66
  367. package/core/modules/generic/components/generic-add/generic-add.js +121 -121
  368. package/core/modules/generic/components/generic-add/generic-add.scss +13 -13
  369. package/core/modules/generic/components/generic-add-modal/generic-add-modal.js +125 -125
  370. package/core/modules/generic/components/generic-add-modal/generic-add-modal.scss +13 -13
  371. package/core/modules/generic/components/generic-detail/generic-detail.js +184 -184
  372. package/core/modules/generic/components/generic-detail/generic-detail.scss +25 -25
  373. package/core/modules/generic/components/generic-edit/generic-edit.js +123 -123
  374. package/core/modules/generic/components/generic-list/generic-list.js +335 -335
  375. package/core/modules/generic/components/generic-list/generic-list.scss +35 -35
  376. package/core/modules/index.js +42 -42
  377. package/core/modules/module-routes/module-routes.js +37 -37
  378. package/core/modules/reporting/components/index.js +6 -6
  379. package/core/modules/reporting/components/reporting-dashboard/README.md +316 -0
  380. package/core/modules/reporting/components/reporting-dashboard/display-columns/build-display-columns.js +74 -0
  381. package/core/modules/reporting/components/reporting-dashboard/display-columns/build-display-columns.test.js +74 -0
  382. package/core/modules/reporting/components/reporting-dashboard/display-columns/display-cell-renderer.js +252 -0
  383. package/core/modules/reporting/components/reporting-dashboard/display-columns/display-cell-renderer.test.js +126 -0
  384. package/core/modules/reporting/components/reporting-dashboard/reporting-dashboard.js +880 -1206
  385. package/core/modules/reporting/components/reporting-dashboard/reporting-dashboard.scss +171 -171
  386. package/core/modules/steps/action-buttons.js +74 -76
  387. package/core/modules/steps/action-buttons.scss +44 -15
  388. package/core/modules/steps/steps.js +348 -346
  389. package/core/modules/steps/steps.scss +357 -159
  390. package/core/modules/steps/timeline.js +56 -54
  391. package/core/pages/homepage-api/homepage-api.js +106 -106
  392. package/core/pages/homepage-api/homepage-api.scss +233 -233
  393. package/core/pages/homepage-api/menu-dashboard.js +169 -169
  394. package/core/pages/homepage-api/menu-dashboard.scss +11 -11
  395. package/core/translation.json +53 -53
  396. package/core/translations.json +19 -19
  397. package/core/utils/script.utils.js +129 -129
  398. package/core/utils/settings.utils.js +25 -25
  399. package/eslint.config.mjs +79 -79
  400. package/index.js +35 -35
  401. package/jest.config.js +7 -7
  402. package/jest.setup.js +1 -1
  403. package/package.json +123 -123
  404. package/tsconfig.json +26 -26
  405. package/webpack.config.js +173 -173
@@ -1,864 +1,864 @@
1
- import React, { useState, useContext, useEffect } from 'react';
2
-
3
- import { Form, Input, message, Result, Radio, Divider, Typography } from 'antd';
4
-
5
- import { withRouter, Link } from 'react-router-dom';
6
-
7
- import backgroundImage from './../../../assets/images/vector.png';
8
-
9
- import OTPInput from 'otp-input-react';
10
-
11
- import { useOtpTimer } from '../../hooks/use-otp-timer';
12
-
13
- import { motion } from 'framer-motion';
14
-
15
- import { Button } from '../../elements';
16
-
17
- import './login.scss';
18
-
19
- // import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
20
-
21
- // import { faCheck } from "@fortawesome/free-solid-svg-icons";
22
-
23
- import FirebaseUtils from '../../../lib/utils/firebase.utils';
24
-
25
- import ApiUtils from '../../utils/api/api.utils';
26
-
27
- import { GlobalContext } from './../../Store';
28
-
29
- import { getAccessToken, getRefreshToken } from '../../utils/http/auth.helper';
30
-
31
- import { Location } from '../../utils';
32
-
33
- import { checkLicenseStatus, formatMobile, checkExpiryStatus, safeJSON } from '../../utils/common/common.utils';
34
-
35
- import { MailOutlined, MessageOutlined, WhatsAppOutlined } from '@ant-design/icons';
36
-
37
- import ResetPassword from './reset-password';
38
-
39
- const { Text, Title } = Typography;
40
-
41
- const layout = {
42
- labelCol: { span: 24 },
43
-
44
- wrapperCol: { span: 24 },
45
- };
46
-
47
- const tailLayout = {
48
- wrapperCol: { span: 8 },
49
- };
50
-
51
- const LICENSE_EXPIRY = '2026-12-12';
52
-
53
- //password valdity expire
54
- const PASSWORD_VALIDITY_DAYS = 90;
55
-
56
- const headers = {
57
- db_ptr: 'nuraho',
58
- };
59
-
60
- /**
61
- *
62
- * @param {*} param0
63
- * @returns
64
- */
65
- function LoginPhone({ history, appSettings }) {
66
- const { brandLogo, heroImage, footerLogo } = appSettings;
67
-
68
- // Hook for OTP Timer
69
- const { expired: otpExpired, formatted, startFromExpiry } = useOtpTimer();
70
-
71
- const { dispatch, state, isMobile } = useContext(GlobalContext);
72
- // variabel used for btnloading
73
-
74
- const [loading, setLoading] = useState(false);
75
-
76
- const [ldaploading, setLdapLoading] = useState(false);
77
-
78
- // variable used to show otp generating
79
-
80
- const [otpVisible, setOtpVisible] = useState(false);
81
- // variabale used to show otp entering screen
82
-
83
- const [otpVerification, setotpVerification] = useState(false);
84
- // otp sucess
85
- const [otpSuccess, setOtpSuccess] = useState(false);
86
- // otp fail err
87
- const [otpError, setOtpError] = useState(false);
88
-
89
- const [otpValue, setOtpValue] = useState('');
90
- // setting user credentials
91
- const [user, setUser] = useState([]);
92
-
93
- // for communication mode [mobile,sms,email]
94
- const [communicationMode, setCommunicationMode] = useState(null); // default selected email
95
- const [modeError, setModeError] = useState(false);
96
-
97
- //for forgot password show
98
- const [showResetpassword, setShowResetpassword] = useState(false);
99
-
100
- //for expired password show
101
- const [expiredPassword, setExpiredPassword] = useState(false);
102
-
103
- //for default name select when expire case
104
- const [defaultUsername, setDefaultUsername] = useState('');
105
-
106
- const isAuthenticated = Boolean(getAccessToken());
107
- const isRefreshTokenExist = Boolean(getRefreshToken());
108
-
109
- const path = window.location.pathname;
110
-
111
- /**
112
- * handlePasswordExpiryCheck
113
- * --------------------------
114
- * Validates whether a user's password is expired or nearing expiry.
115
- *
116
- * - Parses `last_password_change` from user.other_details.
117
- * - Calculates expiry using PASSWORD_VALIDITY_DAYS.
118
- * - Uses `checkExpiryStatus()` to determine status.
119
- * - Shows Ant Design warning message if expired or within warning period.
120
- * - Warning message includes navigation to `/change-password`.
121
- *
122
- * Requires:
123
- * - PASSWORD_VALIDITY_DAYS constant
124
- * - checkExpiryStatus utility
125
- * - React Router history
126
- * - antd message component
127
- */
128
- const handlePasswordExpiryCheck = (user) => {
129
- const otherDetails = user?.other_details ? JSON.parse(user.other_details) : null;
130
-
131
- const lastPasswordChange = otherDetails?.last_password_change;
132
-
133
- if (lastPasswordChange) {
134
- const onlyDate = new Date(lastPasswordChange).toISOString().split('T')[0];
135
- const passwordExpiryDate = new Date(onlyDate);
136
- passwordExpiryDate.setDate(passwordExpiryDate.getDate() + PASSWORD_VALIDITY_DAYS);
137
-
138
- const passwordStatus = checkExpiryStatus({
139
- expiryDate: passwordExpiryDate,
140
- warningDays: 2,
141
- expiredMessage: 'Your password has expired. Please reset it.',
142
- warningMessage: (d) => (
143
- <span>
144
- Your password will expire in {d} day(s).{' '}
145
- <a
146
- onClick={() => {
147
- history.push('/change-password');
148
- }}
149
- >
150
- Click here to update.
151
- </a>
152
- </span>
153
- ),
154
- });
155
-
156
- if (passwordStatus.message) {
157
- message.warning(passwordStatus.message);
158
- }
159
- }
160
- };
161
-
162
- const onFinish = (values) => {
163
- setLoading(true);
164
-
165
- const status = checkLicenseStatus(LICENSE_EXPIRY);
166
-
167
- if (!status.valid) {
168
- message.error(status.message);
169
- setLoading(false);
170
- return;
171
- }
172
-
173
- if (status.message) {
174
- if (status.level === 'error') {
175
- message.error(status.message);
176
- } else if (status.level === 'warning') {
177
- message.warning(status.message);
178
- }
179
- }
180
-
181
- if (process.env.REACT_APP_PRIMARY_BACKEND === 'SQL') {
182
- let formBody = {
183
- username: values.email,
184
-
185
- password: values.password,
186
- };
187
-
188
- return ApiUtils.post({ url: 'auth/login', formBody, headers })
189
-
190
- .then((result) => {
191
- setLoading(false);
192
-
193
- const { user, access_token, refresh_token, insider_token } = result;
194
- if (access_token) localStorage.access_token = access_token;
195
-
196
- if (insider_token) localStorage.insider_token = insider_token;
197
-
198
- if (result.success) {
199
- handlePasswordExpiryCheck(user);
200
-
201
- //two_factor_authentication variable is present then proceed Two factor authentication
202
- if (result.data && result.data.two_factor_authentication) {
203
- let data;
204
-
205
- // set variable used for otp send screen
206
- setOtpVisible(true);
207
-
208
- // set user credentials
209
- data = {
210
- username: result.data.email,
211
- password: values.password,
212
- mode: result.data.mode ? result.data.mode : null,
213
- mobile: result.data.mobile ? result.data.mobile : null,
214
- };
215
-
216
- // set user values
217
- setUser(data);
218
- // Set default communication mode automatically
219
- if (result.data.mode) {
220
- setCommunicationMode(result.data.mode);
221
- }
222
- } else {
223
- let d = user;
224
-
225
- let userInfo = {
226
- id: user.id,
227
- locations: [],
228
- ...d,
229
- ...{
230
- loggedCheckDone: true,
231
- },
232
- };
233
-
234
- dispatch({ type: 'user', payload: userInfo });
235
-
236
- localStorage.setItem('userInfo', JSON.stringify(userInfo));
237
- if (refresh_token) localStorage.setItem('refresh_token', refresh_token);
238
-
239
- // Setting DBPTR
240
- if (user?.organization_details) {
241
- const data = safeJSON(user?.organization_details);
242
-
243
- const defaultBranch = data.branch.find((b) => b.defaultBranch === true);
244
-
245
- const defaultDbptr = defaultBranch?.dbPtr;
246
-
247
- localStorage.setItem('db_ptr', defaultDbptr);
248
- }
249
-
250
- history.push('/');
251
- }
252
- } else {
253
- if (result.passwordChange) {
254
- message.warning(result.message);
255
-
256
- //time for redirect when expire
257
- setTimeout(() => {
258
- setExpiredPassword(true);
259
- setDefaultUsername(values.email);
260
-
261
- setShowResetpassword(true);
262
- }, 1500);
263
- } else {
264
- message.warning(result.message);
265
- }
266
- }
267
- })
268
- .catch((error) => {
269
- console.log(error);
270
-
271
- message.error('This operation has failed.');
272
-
273
- setLoading(false);
274
- });
275
- } else {
276
- FirebaseUtils.loginWithEmail(values)
277
-
278
- .then((result) => {
279
- setLoading(false);
280
-
281
- if (result.id) {
282
- if (result.active) {
283
- let d = result;
284
-
285
- let userInfo = {
286
- id: result.id,
287
- locations: [],
288
- ...d,
289
- ...{
290
- loggedCheckDone: true,
291
- },
292
- };
293
-
294
- if (result.role && result.role.name === 'admin') {
295
- userInfo.isAdmin = true;
296
- }
297
-
298
- dispatch({ type: 'user', payload: userInfo });
299
-
300
- localStorage.setItem('userInfo', JSON.stringify(userInfo));
301
-
302
- history.push('/');
303
- } else {
304
- message.error('Your account is inactive, Please contact support.');
305
- }
306
- } else {
307
- message.error('No accounts found.');
308
- }
309
- })
310
- .catch((result) => {
311
- console.log(result);
312
-
313
- setLoading(false);
314
-
315
- message.error('Login Failed');
316
- });
317
- }
318
- };
319
-
320
- /**
321
- *
322
- * Function to implement 2 factor authentication on login
323
- *
324
- */
325
- const sendAuthenticationOtp = () => {
326
- // Reset previous error
327
- setModeError(false);
328
-
329
- // Validate communication mode
330
- if (!communicationMode) {
331
- setModeError(true); // Show error
332
- return; // Stop OTP send
333
- }
334
-
335
- setLoading(true);
336
-
337
- // set formbody
338
- let formBody;
339
- formBody = {
340
- email: user.username,
341
- mode: communicationMode,
342
- };
343
-
344
- // api used to send otp corresponding mail address
345
- return ApiUtils.post({
346
- url: 'auth/send-authentication-otp',
347
- formBody,
348
- headers,
349
- }).then((result) => {
350
- // if the api is sucess then go for otpverification step
351
- if (result.success) {
352
- // for expiry_time
353
- startFromExpiry(result?.expiry_time);
354
- // set button loading false
355
- setLoading(false);
356
- // if the api is sucess then go for otpverification step
357
- setotpVerification(true);
358
- } else {
359
- setLoading(false);
360
- message.error(result.message);
361
- }
362
- });
363
- };
364
-
365
- /**
366
- * Function to implement 2 factor authentication verification
367
- * @returns
368
- */
369
-
370
- const verifyOtp = () => {
371
- // If OTP expired, block verification
372
- if (otpExpired) {
373
- return;
374
- }
375
-
376
- setLoading(true);
377
-
378
- const formBody = {
379
- username: user.username,
380
- password: user.password,
381
- mode: communicationMode,
382
- mobile: user.mobile,
383
- otp: otpValue,
384
- };
385
- // verifying is otp is correct or not
386
- return ApiUtils.post({
387
- url: 'auth/verify-authentication-otp',
388
- formBody,
389
- headers,
390
- hideError: true, // removing unwanted error msg
391
- })
392
- .then((result) => {
393
- if (result.success) {
394
- // OTP success
395
- setOtpSuccess(true);
396
- setOtpError(false);
397
- setLoading(false);
398
-
399
- const userInfo = {
400
- id: result.user.id,
401
- locations: [],
402
- ...result.user,
403
- loggedCheckDone: true,
404
- };
405
- // Setting access_token
406
- if (result?.access_token) localStorage.access_token = result.access_token;
407
- // Setting refresh_token
408
- if (result.refresh_token) localStorage.setItem('refresh_token', result.refresh_token);
409
-
410
- // Setting DBPTR
411
- if (result?.user?.organization_details) {
412
- const data = safeJSON(result?.user?.organization_details);
413
-
414
- const defaultBranch = data.branch.find((b) => b.defaultBranch === true);
415
- const defaultDbptr = defaultBranch?.dbPtr;
416
-
417
- localStorage.setItem('db_ptr', defaultDbptr);
418
- }
419
-
420
- dispatch({ type: 'user', payload: userInfo });
421
- // set user info into local storage
422
- localStorage.setItem('userInfo', JSON.stringify(userInfo));
423
-
424
- handlePasswordExpiryCheck(result.user);
425
-
426
- setTimeout(() => history.push('/'), 500);
427
- } else {
428
- // OTP FAILED (wrong OTP)
429
- setOtpSuccess(false);
430
- setOtpError(true);
431
- setOtpValue(''); // Clear OTP
432
- setLoading(false);
433
- }
434
- })
435
- .catch((error) => {
436
- // Server error, timeout, network fail → treat as failed OTP
437
- setOtpSuccess(false);
438
- setOtpError(true);
439
-
440
- setLoading(false);
441
- });
442
- };
443
-
444
- const onFinishFailed = () => {
445
- setLoading(false);
446
-
447
- setOtpVisible(false);
448
- };
449
-
450
- /**
451
- * otp onange
452
- * @param {*} value
453
- */
454
- const handleOtpChange = (value) => {
455
- setOtpValue(value);
456
- // Reset states so correct OTP will work after wrong OTP
457
- setOtpError(false);
458
- setOtpSuccess(false);
459
- };
460
-
461
- /**
462
- * Otp resend Logic
463
- */
464
- const handleResendOTP = () => {
465
- setOtpValue('');
466
- setModeError(false);
467
- setOtpError(false);
468
- setOtpSuccess(false);
469
- // resend the OTP automatically
470
- sendAuthenticationOtp();
471
- };
472
-
473
- /**
474
- * Cancel otp send process
475
- */
476
- const handlecancel = () => {
477
- setOtpVisible(false);
478
- setotpVerification(false);
479
- setOtpValue('');
480
- setModeError(false);
481
- setOtpError(false);
482
- };
483
-
484
- // Redirect Home Page, When token is exist
485
- useEffect(() => {
486
- // Do NOT redirect when OTP is visible or verification is happening
487
- if (otpVerification) return;
488
- if (isAuthenticated && isRefreshTokenExist && path === '/login') {
489
- Location.navigate({ url: '/' });
490
- } else {
491
- Location.navigate({ url: '/login' });
492
- }
493
- }, [isAuthenticated, isRefreshTokenExist, path]);
494
-
495
- useEffect(() => {
496
- // Dynamically set the CSS variables based on the current theme
497
- // document.documentElement.style.setProperty('--custom-text-color', state.theme.colors.colorText);
498
- // document.documentElement.style.setProperty('--custom-bg-color', state.theme.colors.primaryButtonBg);
499
- // document.documentElement.style.setProperty('--custom-btn-text-color', state.theme.colors.primaryButtonText);
500
- // document.documentElement.style.setProperty('--custom-input-bg-color', state.theme.colors.inputBgColor);
501
- // document.documentElement.style.setProperty('--custom-input-color', state.theme.colors.inputColor);
502
- }, [state.theme]);
503
-
504
- // when otp is expired
505
- useEffect(() => {
506
- if (otpExpired) {
507
- setOtpValue(''); // Clear OTP box
508
- setOtpError(false);
509
- }
510
- }, [otpExpired]);
511
- /**
512
- * Function to get Ldap users
513
- * @returns
514
- */
515
-
516
- const loggedUser = () => {
517
- return fetch('http://localhost:3800/users/logged-user', {
518
- method: 'GET',
519
- headers: {
520
- 'Content-Type': 'application/json',
521
- },
522
- })
523
- .then((response) => {
524
- if (!response.ok) {
525
- throw message.warning('Client application not running');
526
- }
527
- return response.json();
528
- })
529
- .then((data) => {
530
- if (data && data.success) {
531
- return data.username;
532
- } else {
533
- message.warning('Client application not running');
534
- }
535
- })
536
- .catch((error) => {
537
- console.log(error);
538
- message.warning('Client application not running');
539
- setLdapLoading(false);
540
- return null;
541
- });
542
- };
543
-
544
- /**
545
- *
546
- * @returns Function to login with ldap
547
- *
548
- */
549
- const loginWithLdap = async () => {
550
- //call function to get the current logged username
551
- const username = await loggedUser();
552
-
553
- //formbody consist of username from loggeduser
554
- let formBody = {
555
- username: username,
556
- };
557
- //calling ldap-login API
558
- return ApiUtils.post({
559
- // url: "users/logged-user",
560
- url: 'auth/ldap-login',
561
- formBody,
562
- headers,
563
- })
564
- .then((result) => {
565
- setLdapLoading(false);
566
-
567
- const { user, access_token } = result;
568
-
569
- localStorage.access_token = access_token;
570
-
571
- if (result.success) {
572
- //two_factor_authentication variable is present then proceed Two factor authentication
573
- if (result.data && result.data.two_factor_authentication) {
574
- let data;
575
-
576
- // set variable used for otp send screen
577
- setOtpVisible(true);
578
-
579
- // set user credentials
580
- data = {
581
- username: result.data.email,
582
- password: values.password,
583
- mode: result.data.mode ? result.data.mode : null,
584
- mobile: result.data.mobile ? result.data.mobile : null,
585
- };
586
-
587
- // set user values
588
- setUser(data);
589
- } else {
590
- let d = user;
591
-
592
- let userInfo = {
593
- id: user.id,
594
- locations: [],
595
- ...d,
596
- ...{
597
- loggedCheckDone: true,
598
- },
599
- };
600
-
601
- dispatch({ type: 'user', payload: userInfo });
602
-
603
- localStorage.setItem('userInfo', JSON.stringify(userInfo));
604
-
605
- history.push('/');
606
- }
607
- } else {
608
- message.error(result.message);
609
- }
610
- })
611
- .catch((error) => {
612
- console.log(error);
613
-
614
- message.error('This operation has failed.');
615
-
616
- setLdapLoading(false);
617
- });
618
- };
619
-
620
- // helper to show contact in OTP verification screen
621
- const getOtpDestinationText = () => {
622
- if (communicationMode === 'mobile') return formatMobile(user.mobile);
623
- // if (communicationMode === 'whatsapp') return user.mobile;
624
- return user.username;
625
- };
626
-
627
- const { globalCustomerHeader = () => {} } = appSettings;
628
-
629
- const themeName = process.env.REACT_APP_THEME; // e.g., 'purple'
630
- const isPurple = themeName === 'purple';
631
-
632
- const sectionStyle = isPurple
633
- ? {
634
- width: '100%',
635
- height: '100vh',
636
- backgroundImage: `${state.theme.colors.loginPageBackground}`,
637
- backgroundPosition: 'center bottom, center',
638
- backgroundRepeat: 'no-repeat, no-repeat',
639
- backgroundSize: 'cover, cover',
640
- }
641
- : {
642
- width: '100%',
643
- height: '100vh',
644
- background: 'linear-gradient(to bottom, #F7F6E3 0%, #EEF1DE 20%, #D5E4DA 45%, #9DBFC8 75%, #4F89A6 100%)',
645
- backgroundPosition: 'center bottom, center',
646
- backgroundRepeat: 'no-repeat, no-repeat',
647
- backgroundSize: 'cover, cover',
648
- };
649
-
650
- return (
651
- <section className="full-page" style={sectionStyle}>
652
- <section className="user-authentication-section">
653
- {/* Background Section */}
654
- <motion.div
655
- className="page-background"
656
- initial={{ y: -50, opacity: 0 }}
657
- animate={{ y: 0, opacity: 1 }}
658
- transition={{ duration: 1, ease: 'anticipate' }}
659
- exit={{ opacity: 0 }}
660
- />
661
- {/* Background Section Ends */}
662
-
663
- <motion.div
664
- className="auth-form-wrapper"
665
- initial={{ y: 20 }}
666
- animate={{ y: 0 }}
667
- transition={{ duration: 1, ease: 'anticipate' }}
668
- exit={{ opacity: 0 }}
669
- >
670
- <div
671
- className=" login-form-container"
672
- style={{
673
- background: state.theme.colors.tableBg,
674
- borderStyle: state.theme.colors.tableBorderStyle,
675
- }}
676
- >
677
- <div className="brand-logo">
678
- <img className="logo-welcome" src={brandLogo} alt="Logo" />
679
- </div>
680
-
681
- <div className="otp-form">
682
- {/* OTP Verification Section */}
683
-
684
- {/* OTP Method Selection Section */}
685
- {otpVisible && (
686
- <div className="otp-input-container">
687
- <div className="form-title">
688
- {otpVerification ? (
689
- <>
690
- {/* <h3>OTP Verification</h3> */}
691
- {/* <p>
692
- Enter the verification code we sent to{' '}
693
- <span className="otp-mode-text">
694
- <strong>{getOtpDestinationText()}</strong>
695
- </span>
696
- </p> */}
697
- </>
698
- ) : (
699
- <>
700
- <Text type="primary">Two Factor Authentication</Text>
701
- <p>
702
- Two-Factor Authentication is enabled for your account. Please verify your account before logging in to enhance security.
703
- </p>
704
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
705
- </>
706
- )}
707
- </div>
708
-
709
- {/* Show Communication Method ONLY IF:
710
- - OTP not sent OR
711
- - OTP expired
712
- */}
713
-
714
- {(!otpVerification || otpExpired) && (
715
- <>
716
- <Divider />
717
- <div className="otp-method-section">
718
- <Text type="primary">Select Preferred OTP Verification Method</Text>
719
- <div className="otp-method-group">
720
- <Radio checked={communicationMode === 'email'} onChange={() => setCommunicationMode('email')}>
721
- Email <MailOutlined className="otp-icon" style={{ marginLeft: 6 }} />
722
- </Radio>
723
- <Radio checked={communicationMode === 'mobile'} onChange={() => setCommunicationMode('mobile')}>
724
- SMS <MessageOutlined className="otp-icon" style={{ marginLeft: 6 }} />
725
- </Radio>
726
- </div>
727
- {modeError && <p className="otp-mode-error">Please select a communication mode.</p>}
728
- </div>
729
- </>
730
- )}
731
-
732
- {!otpVerification ? (
733
- <div className="otp-container">
734
- <Button type="primary" onClick={sendAuthenticationOtp} style={{ marginTop: '6px' }}>
735
- Send OTP
736
- </Button>
737
- </div>
738
- ) : (
739
- <>
740
- {/* <Divider /> */}
741
- <div className="otp-container">
742
- <p>
743
- Enter the verification code we sent to{' '}
744
- <span className="otp-mode-text">
745
- <strong>{getOtpDestinationText()}</strong>
746
- </span>
747
- </p>
748
- <OTPInput
749
- value={otpValue}
750
- onChange={handleOtpChange}
751
- autoFocus
752
- OTPLength={6}
753
- disabled={loading || otpExpired}
754
- inputStyles={{
755
- border: otpSuccess
756
- ? '2px solid #52c41a' // green
757
- : otpError
758
- ? '2px solid #FF5C5C' // red
759
- : '1px solid #d9d9d9', // default
760
- borderRadius: 4,
761
- width: isMobile ? 28 : 45, // MOBILE FIX
762
- height: isMobile ? 36 : 40, // MOBILE FIX
763
- margin: isMobile ? '2px' : '0 4px',
764
- fontSize: isMobile ? 16 : 18,
765
- textAlign: 'center',
766
- }}
767
- />
768
- {/* Timer below OTP */}
769
- <div className="otp-timer">
770
- {/* {!otpExpired ? */}
771
- {otpSuccess ? null : <span>{formatted}</span>}
772
- {/* {otpError && (
773
- <p style={{ color: 'red', marginTop: 8 }}>Invalid OTP, please try again</p>
774
- )} */}
775
-
776
- {otpSuccess && <p style={{ color: 'green', marginTop: 8 }}>Your OTP has been verified successfully.</p>}
777
- </div>
778
- </div>
779
- {!otpSuccess && (
780
- <Button type="primary" disabled={otpExpired} onClick={verifyOtp} style={{ marginTop: 16 }}>
781
- Verify OTP
782
- </Button>
783
- )}
784
- </>
785
- )}
786
- </div>
787
- )}
788
-
789
- {/* Login Form Section */}
790
- {!otpVerification && !otpVisible && !showResetpassword && (
791
- <Form {...layout} layout="vertical" name="basic" onFinish={onFinish} onFinishFailed={onFinishFailed}>
792
- <div className="form-title">
793
- <h4></h4>
794
- </div>
795
-
796
- {/* {!process.env.REACT_APP_SHOW_BRANCH_SWITCHER && <div className="branch-switcher">{globalCustomerHeader()}</div>} */}
797
-
798
- {process.env.REACT_APP_ENABLE_LDAP === 'true' && (
799
- <Button loading={ldaploading} type="secondary" className="SubmitBtn" onClick={loginWithLdap}>
800
- Sign in using AD
801
- </Button>
802
- )}
803
-
804
- <Form.Item label="Email" name="email" rules={[{ required: true, message: 'Please input your email!' }]}>
805
- <Input autoComplete="off" autoFocus />
806
- </Form.Item>
807
-
808
- <Form.Item label="Password" name="password" rules={[{ required: true, message: 'Please input your password!' }]}>
809
- <Input.Password autoComplete="off" />
810
- </Form.Item>
811
-
812
- <Form.Item {...tailLayout} style={{ marginBottom: '0px' }}>
813
- <Button loading={loading} type="primary" htmlType="submit" className="SubmitBtn">
814
- &nbsp;&nbsp; Submit
815
- </Button>
816
- <div className="forgot-password" style={{ marginTop: '8px', textAlign: 'center' }}>
817
- <Link onClick={() => setShowResetpassword(true)}>Forgot Password?</Link>
818
- </div>
819
- </Form.Item>
820
- </Form>
821
- )}
822
-
823
- {/* Forgot Password Section */}
824
- {showResetpassword && (
825
- <ResetPassword
826
- defaultUsername={expiredPassword ? defaultUsername : undefined}
827
- disabledUserName={expiredPassword}
828
- onBack={() => {
829
- setShowResetpassword(false);
830
- setExpiredPassword(false);
831
- }}
832
- title={expiredPassword ? 'Password Expired!' : 'Forgot Password?'}
833
- // subtitle={
834
- // expiredPassword
835
- // ? 'Your password has expired. Select a preferred communication method to receive the One-Time Password (OTP) to continue.'
836
- // : 'Enter your username and Select a preferred communication method to receive the One-Time Password (OTP) to continue..'
837
- // }
838
- buttonText={expiredPassword ? 'Send Reset Link' : 'Reset Password'}
839
- />
840
- )}
841
- </div>
842
- </div>
843
- {!otpSuccess && otpVerification && (
844
- <div className="otp-actions">
845
- <div className="resend-action">
846
- <Text disabled>Didn't receive OTP?</Text>
847
-
848
- <Link className="resend-otp-link" disabled={!otpExpired} onClick={handleResendOTP}>
849
- Resend OTP
850
- </Link>
851
- </div>
852
-
853
- <Button size="small" type="default" onClick={handlecancel}>
854
- Cancel
855
- </Button>
856
- </div>
857
- )}
858
- </motion.div>
859
- </section>
860
- </section>
861
- );
862
- }
863
-
864
- export default withRouter(LoginPhone);
1
+ import React, { useState, useContext, useEffect } from 'react';
2
+
3
+ import { Form, Input, message, Result, Radio, Divider, Typography } from 'antd';
4
+
5
+ import { withRouter, Link } from 'react-router-dom';
6
+
7
+ import backgroundImage from './../../../assets/images/vector.png';
8
+
9
+ import OTPInput from 'otp-input-react';
10
+
11
+ import { useOtpTimer } from '../../hooks/use-otp-timer';
12
+
13
+ import { motion } from 'framer-motion';
14
+
15
+ import { Button } from '../../elements';
16
+
17
+ import './login.scss';
18
+
19
+ // import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
20
+
21
+ // import { faCheck } from "@fortawesome/free-solid-svg-icons";
22
+
23
+ import FirebaseUtils from '../../../lib/utils/firebase.utils';
24
+
25
+ import ApiUtils from '../../utils/api/api.utils';
26
+
27
+ import { GlobalContext } from './../../Store';
28
+
29
+ import { getAccessToken, getRefreshToken } from '../../utils/http/auth.helper';
30
+
31
+ import { Location } from '../../utils';
32
+
33
+ import { checkLicenseStatus, formatMobile, checkExpiryStatus, safeJSON } from '../../utils/common/common.utils';
34
+
35
+ import { MailOutlined, MessageOutlined, WhatsAppOutlined } from '@ant-design/icons';
36
+
37
+ import ResetPassword from './reset-password';
38
+
39
+ const { Text, Title } = Typography;
40
+
41
+ const layout = {
42
+ labelCol: { span: 24 },
43
+
44
+ wrapperCol: { span: 24 },
45
+ };
46
+
47
+ const tailLayout = {
48
+ wrapperCol: { span: 8 },
49
+ };
50
+
51
+ const LICENSE_EXPIRY = '2026-12-12';
52
+
53
+ //password valdity expire
54
+ const PASSWORD_VALIDITY_DAYS = 90;
55
+
56
+ const headers = {
57
+ db_ptr: 'nuraho',
58
+ };
59
+
60
+ /**
61
+ *
62
+ * @param {*} param0
63
+ * @returns
64
+ */
65
+ function LoginPhone({ history, appSettings }) {
66
+ const { brandLogo, heroImage, footerLogo } = appSettings;
67
+
68
+ // Hook for OTP Timer
69
+ const { expired: otpExpired, formatted, startFromExpiry } = useOtpTimer();
70
+
71
+ const { dispatch, state, isMobile } = useContext(GlobalContext);
72
+ // variabel used for btnloading
73
+
74
+ const [loading, setLoading] = useState(false);
75
+
76
+ const [ldaploading, setLdapLoading] = useState(false);
77
+
78
+ // variable used to show otp generating
79
+
80
+ const [otpVisible, setOtpVisible] = useState(false);
81
+ // variabale used to show otp entering screen
82
+
83
+ const [otpVerification, setotpVerification] = useState(false);
84
+ // otp sucess
85
+ const [otpSuccess, setOtpSuccess] = useState(false);
86
+ // otp fail err
87
+ const [otpError, setOtpError] = useState(false);
88
+
89
+ const [otpValue, setOtpValue] = useState('');
90
+ // setting user credentials
91
+ const [user, setUser] = useState([]);
92
+
93
+ // for communication mode [mobile,sms,email]
94
+ const [communicationMode, setCommunicationMode] = useState(null); // default selected email
95
+ const [modeError, setModeError] = useState(false);
96
+
97
+ //for forgot password show
98
+ const [showResetpassword, setShowResetpassword] = useState(false);
99
+
100
+ //for expired password show
101
+ const [expiredPassword, setExpiredPassword] = useState(false);
102
+
103
+ //for default name select when expire case
104
+ const [defaultUsername, setDefaultUsername] = useState('');
105
+
106
+ const isAuthenticated = Boolean(getAccessToken());
107
+ const isRefreshTokenExist = Boolean(getRefreshToken());
108
+
109
+ const path = window.location.pathname;
110
+
111
+ /**
112
+ * handlePasswordExpiryCheck
113
+ * --------------------------
114
+ * Validates whether a user's password is expired or nearing expiry.
115
+ *
116
+ * - Parses `last_password_change` from user.other_details.
117
+ * - Calculates expiry using PASSWORD_VALIDITY_DAYS.
118
+ * - Uses `checkExpiryStatus()` to determine status.
119
+ * - Shows Ant Design warning message if expired or within warning period.
120
+ * - Warning message includes navigation to `/change-password`.
121
+ *
122
+ * Requires:
123
+ * - PASSWORD_VALIDITY_DAYS constant
124
+ * - checkExpiryStatus utility
125
+ * - React Router history
126
+ * - antd message component
127
+ */
128
+ const handlePasswordExpiryCheck = (user) => {
129
+ const otherDetails = user?.other_details ? JSON.parse(user.other_details) : null;
130
+
131
+ const lastPasswordChange = otherDetails?.last_password_change;
132
+
133
+ if (lastPasswordChange) {
134
+ const onlyDate = new Date(lastPasswordChange).toISOString().split('T')[0];
135
+ const passwordExpiryDate = new Date(onlyDate);
136
+ passwordExpiryDate.setDate(passwordExpiryDate.getDate() + PASSWORD_VALIDITY_DAYS);
137
+
138
+ const passwordStatus = checkExpiryStatus({
139
+ expiryDate: passwordExpiryDate,
140
+ warningDays: 2,
141
+ expiredMessage: 'Your password has expired. Please reset it.',
142
+ warningMessage: (d) => (
143
+ <span>
144
+ Your password will expire in {d} day(s).{' '}
145
+ <a
146
+ onClick={() => {
147
+ history.push('/change-password');
148
+ }}
149
+ >
150
+ Click here to update.
151
+ </a>
152
+ </span>
153
+ ),
154
+ });
155
+
156
+ if (passwordStatus.message) {
157
+ message.warning(passwordStatus.message);
158
+ }
159
+ }
160
+ };
161
+
162
+ const onFinish = (values) => {
163
+ setLoading(true);
164
+
165
+ const status = checkLicenseStatus(LICENSE_EXPIRY);
166
+
167
+ if (!status.valid) {
168
+ message.error(status.message);
169
+ setLoading(false);
170
+ return;
171
+ }
172
+
173
+ if (status.message) {
174
+ if (status.level === 'error') {
175
+ message.error(status.message);
176
+ } else if (status.level === 'warning') {
177
+ message.warning(status.message);
178
+ }
179
+ }
180
+
181
+ if (process.env.REACT_APP_PRIMARY_BACKEND === 'SQL') {
182
+ let formBody = {
183
+ username: values.email,
184
+
185
+ password: values.password,
186
+ };
187
+
188
+ return ApiUtils.post({ url: 'auth/login', formBody, headers })
189
+
190
+ .then((result) => {
191
+ setLoading(false);
192
+
193
+ const { user, access_token, refresh_token, insider_token } = result;
194
+ if (access_token) localStorage.access_token = access_token;
195
+
196
+ if (insider_token) localStorage.insider_token = insider_token;
197
+
198
+ if (result.success) {
199
+ handlePasswordExpiryCheck(user);
200
+
201
+ //two_factor_authentication variable is present then proceed Two factor authentication
202
+ if (result.data && result.data.two_factor_authentication) {
203
+ let data;
204
+
205
+ // set variable used for otp send screen
206
+ setOtpVisible(true);
207
+
208
+ // set user credentials
209
+ data = {
210
+ username: result.data.email,
211
+ password: values.password,
212
+ mode: result.data.mode ? result.data.mode : null,
213
+ mobile: result.data.mobile ? result.data.mobile : null,
214
+ };
215
+
216
+ // set user values
217
+ setUser(data);
218
+ // Set default communication mode automatically
219
+ if (result.data.mode) {
220
+ setCommunicationMode(result.data.mode);
221
+ }
222
+ } else {
223
+ let d = user;
224
+
225
+ let userInfo = {
226
+ id: user.id,
227
+ locations: [],
228
+ ...d,
229
+ ...{
230
+ loggedCheckDone: true,
231
+ },
232
+ };
233
+
234
+ dispatch({ type: 'user', payload: userInfo });
235
+
236
+ localStorage.setItem('userInfo', JSON.stringify(userInfo));
237
+ if (refresh_token) localStorage.setItem('refresh_token', refresh_token);
238
+
239
+ // Setting DBPTR
240
+ if (user?.organization_details) {
241
+ const data = safeJSON(user?.organization_details);
242
+
243
+ const defaultBranch = data.branch.find((b) => b.defaultBranch === true);
244
+
245
+ const defaultDbptr = defaultBranch?.dbPtr;
246
+
247
+ localStorage.setItem('db_ptr', defaultDbptr);
248
+ }
249
+
250
+ history.push('/');
251
+ }
252
+ } else {
253
+ if (result.passwordChange) {
254
+ message.warning(result.message);
255
+
256
+ //time for redirect when expire
257
+ setTimeout(() => {
258
+ setExpiredPassword(true);
259
+ setDefaultUsername(values.email);
260
+
261
+ setShowResetpassword(true);
262
+ }, 1500);
263
+ } else {
264
+ message.warning(result.message);
265
+ }
266
+ }
267
+ })
268
+ .catch((error) => {
269
+ console.log(error);
270
+
271
+ message.error('This operation has failed.');
272
+
273
+ setLoading(false);
274
+ });
275
+ } else {
276
+ FirebaseUtils.loginWithEmail(values)
277
+
278
+ .then((result) => {
279
+ setLoading(false);
280
+
281
+ if (result.id) {
282
+ if (result.active) {
283
+ let d = result;
284
+
285
+ let userInfo = {
286
+ id: result.id,
287
+ locations: [],
288
+ ...d,
289
+ ...{
290
+ loggedCheckDone: true,
291
+ },
292
+ };
293
+
294
+ if (result.role && result.role.name === 'admin') {
295
+ userInfo.isAdmin = true;
296
+ }
297
+
298
+ dispatch({ type: 'user', payload: userInfo });
299
+
300
+ localStorage.setItem('userInfo', JSON.stringify(userInfo));
301
+
302
+ history.push('/');
303
+ } else {
304
+ message.error('Your account is inactive, Please contact support.');
305
+ }
306
+ } else {
307
+ message.error('No accounts found.');
308
+ }
309
+ })
310
+ .catch((result) => {
311
+ console.log(result);
312
+
313
+ setLoading(false);
314
+
315
+ message.error('Login Failed');
316
+ });
317
+ }
318
+ };
319
+
320
+ /**
321
+ *
322
+ * Function to implement 2 factor authentication on login
323
+ *
324
+ */
325
+ const sendAuthenticationOtp = () => {
326
+ // Reset previous error
327
+ setModeError(false);
328
+
329
+ // Validate communication mode
330
+ if (!communicationMode) {
331
+ setModeError(true); // Show error
332
+ return; // Stop OTP send
333
+ }
334
+
335
+ setLoading(true);
336
+
337
+ // set formbody
338
+ let formBody;
339
+ formBody = {
340
+ email: user.username,
341
+ mode: communicationMode,
342
+ };
343
+
344
+ // api used to send otp corresponding mail address
345
+ return ApiUtils.post({
346
+ url: 'auth/send-authentication-otp',
347
+ formBody,
348
+ headers,
349
+ }).then((result) => {
350
+ // if the api is sucess then go for otpverification step
351
+ if (result.success) {
352
+ // for expiry_time
353
+ startFromExpiry(result?.expiry_time);
354
+ // set button loading false
355
+ setLoading(false);
356
+ // if the api is sucess then go for otpverification step
357
+ setotpVerification(true);
358
+ } else {
359
+ setLoading(false);
360
+ message.error(result.message);
361
+ }
362
+ });
363
+ };
364
+
365
+ /**
366
+ * Function to implement 2 factor authentication verification
367
+ * @returns
368
+ */
369
+
370
+ const verifyOtp = () => {
371
+ // If OTP expired, block verification
372
+ if (otpExpired) {
373
+ return;
374
+ }
375
+
376
+ setLoading(true);
377
+
378
+ const formBody = {
379
+ username: user.username,
380
+ password: user.password,
381
+ mode: communicationMode,
382
+ mobile: user.mobile,
383
+ otp: otpValue,
384
+ };
385
+ // verifying is otp is correct or not
386
+ return ApiUtils.post({
387
+ url: 'auth/verify-authentication-otp',
388
+ formBody,
389
+ headers,
390
+ hideError: true, // removing unwanted error msg
391
+ })
392
+ .then((result) => {
393
+ if (result.success) {
394
+ // OTP success
395
+ setOtpSuccess(true);
396
+ setOtpError(false);
397
+ setLoading(false);
398
+
399
+ const userInfo = {
400
+ id: result.user.id,
401
+ locations: [],
402
+ ...result.user,
403
+ loggedCheckDone: true,
404
+ };
405
+ // Setting access_token
406
+ if (result?.access_token) localStorage.access_token = result.access_token;
407
+ // Setting refresh_token
408
+ if (result.refresh_token) localStorage.setItem('refresh_token', result.refresh_token);
409
+
410
+ // Setting DBPTR
411
+ if (result?.user?.organization_details) {
412
+ const data = safeJSON(result?.user?.organization_details);
413
+
414
+ const defaultBranch = data.branch.find((b) => b.defaultBranch === true);
415
+ const defaultDbptr = defaultBranch?.dbPtr;
416
+
417
+ localStorage.setItem('db_ptr', defaultDbptr);
418
+ }
419
+
420
+ dispatch({ type: 'user', payload: userInfo });
421
+ // set user info into local storage
422
+ localStorage.setItem('userInfo', JSON.stringify(userInfo));
423
+
424
+ handlePasswordExpiryCheck(result.user);
425
+
426
+ setTimeout(() => history.push('/'), 500);
427
+ } else {
428
+ // OTP FAILED (wrong OTP)
429
+ setOtpSuccess(false);
430
+ setOtpError(true);
431
+ setOtpValue(''); // Clear OTP
432
+ setLoading(false);
433
+ }
434
+ })
435
+ .catch((error) => {
436
+ // Server error, timeout, network fail → treat as failed OTP
437
+ setOtpSuccess(false);
438
+ setOtpError(true);
439
+
440
+ setLoading(false);
441
+ });
442
+ };
443
+
444
+ const onFinishFailed = () => {
445
+ setLoading(false);
446
+
447
+ setOtpVisible(false);
448
+ };
449
+
450
+ /**
451
+ * otp onange
452
+ * @param {*} value
453
+ */
454
+ const handleOtpChange = (value) => {
455
+ setOtpValue(value);
456
+ // Reset states so correct OTP will work after wrong OTP
457
+ setOtpError(false);
458
+ setOtpSuccess(false);
459
+ };
460
+
461
+ /**
462
+ * Otp resend Logic
463
+ */
464
+ const handleResendOTP = () => {
465
+ setOtpValue('');
466
+ setModeError(false);
467
+ setOtpError(false);
468
+ setOtpSuccess(false);
469
+ // resend the OTP automatically
470
+ sendAuthenticationOtp();
471
+ };
472
+
473
+ /**
474
+ * Cancel otp send process
475
+ */
476
+ const handlecancel = () => {
477
+ setOtpVisible(false);
478
+ setotpVerification(false);
479
+ setOtpValue('');
480
+ setModeError(false);
481
+ setOtpError(false);
482
+ };
483
+
484
+ // Redirect Home Page, When token is exist
485
+ useEffect(() => {
486
+ // Do NOT redirect when OTP is visible or verification is happening
487
+ if (otpVerification) return;
488
+ if (isAuthenticated && isRefreshTokenExist && path === '/login') {
489
+ Location.navigate({ url: '/' });
490
+ } else {
491
+ Location.navigate({ url: '/login' });
492
+ }
493
+ }, [isAuthenticated, isRefreshTokenExist, path]);
494
+
495
+ useEffect(() => {
496
+ // Dynamically set the CSS variables based on the current theme
497
+ // document.documentElement.style.setProperty('--custom-text-color', state.theme.colors.colorText);
498
+ // document.documentElement.style.setProperty('--custom-bg-color', state.theme.colors.primaryButtonBg);
499
+ // document.documentElement.style.setProperty('--custom-btn-text-color', state.theme.colors.primaryButtonText);
500
+ // document.documentElement.style.setProperty('--custom-input-bg-color', state.theme.colors.inputBgColor);
501
+ // document.documentElement.style.setProperty('--custom-input-color', state.theme.colors.inputColor);
502
+ }, [state.theme]);
503
+
504
+ // when otp is expired
505
+ useEffect(() => {
506
+ if (otpExpired) {
507
+ setOtpValue(''); // Clear OTP box
508
+ setOtpError(false);
509
+ }
510
+ }, [otpExpired]);
511
+ /**
512
+ * Function to get Ldap users
513
+ * @returns
514
+ */
515
+
516
+ const loggedUser = () => {
517
+ return fetch('http://localhost:3800/users/logged-user', {
518
+ method: 'GET',
519
+ headers: {
520
+ 'Content-Type': 'application/json',
521
+ },
522
+ })
523
+ .then((response) => {
524
+ if (!response.ok) {
525
+ throw message.warning('Client application not running');
526
+ }
527
+ return response.json();
528
+ })
529
+ .then((data) => {
530
+ if (data && data.success) {
531
+ return data.username;
532
+ } else {
533
+ message.warning('Client application not running');
534
+ }
535
+ })
536
+ .catch((error) => {
537
+ console.log(error);
538
+ message.warning('Client application not running');
539
+ setLdapLoading(false);
540
+ return null;
541
+ });
542
+ };
543
+
544
+ /**
545
+ *
546
+ * @returns Function to login with ldap
547
+ *
548
+ */
549
+ const loginWithLdap = async () => {
550
+ //call function to get the current logged username
551
+ const username = await loggedUser();
552
+
553
+ //formbody consist of username from loggeduser
554
+ let formBody = {
555
+ username: username,
556
+ };
557
+ //calling ldap-login API
558
+ return ApiUtils.post({
559
+ // url: "users/logged-user",
560
+ url: 'auth/ldap-login',
561
+ formBody,
562
+ headers,
563
+ })
564
+ .then((result) => {
565
+ setLdapLoading(false);
566
+
567
+ const { user, access_token } = result;
568
+
569
+ localStorage.access_token = access_token;
570
+
571
+ if (result.success) {
572
+ //two_factor_authentication variable is present then proceed Two factor authentication
573
+ if (result.data && result.data.two_factor_authentication) {
574
+ let data;
575
+
576
+ // set variable used for otp send screen
577
+ setOtpVisible(true);
578
+
579
+ // set user credentials
580
+ data = {
581
+ username: result.data.email,
582
+ password: values.password,
583
+ mode: result.data.mode ? result.data.mode : null,
584
+ mobile: result.data.mobile ? result.data.mobile : null,
585
+ };
586
+
587
+ // set user values
588
+ setUser(data);
589
+ } else {
590
+ let d = user;
591
+
592
+ let userInfo = {
593
+ id: user.id,
594
+ locations: [],
595
+ ...d,
596
+ ...{
597
+ loggedCheckDone: true,
598
+ },
599
+ };
600
+
601
+ dispatch({ type: 'user', payload: userInfo });
602
+
603
+ localStorage.setItem('userInfo', JSON.stringify(userInfo));
604
+
605
+ history.push('/');
606
+ }
607
+ } else {
608
+ message.error(result.message);
609
+ }
610
+ })
611
+ .catch((error) => {
612
+ console.log(error);
613
+
614
+ message.error('This operation has failed.');
615
+
616
+ setLdapLoading(false);
617
+ });
618
+ };
619
+
620
+ // helper to show contact in OTP verification screen
621
+ const getOtpDestinationText = () => {
622
+ if (communicationMode === 'mobile') return formatMobile(user.mobile);
623
+ // if (communicationMode === 'whatsapp') return user.mobile;
624
+ return user.username;
625
+ };
626
+
627
+ const { globalCustomerHeader = () => {} } = appSettings;
628
+
629
+ const themeName = process.env.REACT_APP_THEME; // e.g., 'purple'
630
+ const isPurple = themeName === 'purple';
631
+
632
+ const sectionStyle = isPurple
633
+ ? {
634
+ width: '100%',
635
+ height: '100vh',
636
+ backgroundImage: `${state.theme.colors.loginPageBackground}`,
637
+ backgroundPosition: 'center bottom, center',
638
+ backgroundRepeat: 'no-repeat, no-repeat',
639
+ backgroundSize: 'cover, cover',
640
+ }
641
+ : {
642
+ width: '100%',
643
+ height: '100vh',
644
+ background: 'linear-gradient(to bottom, #F7F6E3 0%, #EEF1DE 20%, #D5E4DA 45%, #9DBFC8 75%, #4F89A6 100%)',
645
+ backgroundPosition: 'center bottom, center',
646
+ backgroundRepeat: 'no-repeat, no-repeat',
647
+ backgroundSize: 'cover, cover',
648
+ };
649
+
650
+ return (
651
+ <section className="full-page" style={sectionStyle}>
652
+ <section className="user-authentication-section">
653
+ {/* Background Section */}
654
+ <motion.div
655
+ className="page-background"
656
+ initial={{ y: -50, opacity: 0 }}
657
+ animate={{ y: 0, opacity: 1 }}
658
+ transition={{ duration: 1, ease: 'anticipate' }}
659
+ exit={{ opacity: 0 }}
660
+ />
661
+ {/* Background Section Ends */}
662
+
663
+ <motion.div
664
+ className="auth-form-wrapper"
665
+ initial={{ y: 20 }}
666
+ animate={{ y: 0 }}
667
+ transition={{ duration: 1, ease: 'anticipate' }}
668
+ exit={{ opacity: 0 }}
669
+ >
670
+ <div
671
+ className=" login-form-container"
672
+ style={{
673
+ background: state.theme.colors.tableBg,
674
+ borderStyle: state.theme.colors.tableBorderStyle,
675
+ }}
676
+ >
677
+ <div className="brand-logo">
678
+ <img className="logo-welcome" src={brandLogo} alt="Logo" />
679
+ </div>
680
+
681
+ <div className="otp-form">
682
+ {/* OTP Verification Section */}
683
+
684
+ {/* OTP Method Selection Section */}
685
+ {otpVisible && (
686
+ <div className="otp-input-container">
687
+ <div className="form-title">
688
+ {otpVerification ? (
689
+ <>
690
+ {/* <h3>OTP Verification</h3> */}
691
+ {/* <p>
692
+ Enter the verification code we sent to{' '}
693
+ <span className="otp-mode-text">
694
+ <strong>{getOtpDestinationText()}</strong>
695
+ </span>
696
+ </p> */}
697
+ </>
698
+ ) : (
699
+ <>
700
+ <Text type="primary">Two Factor Authentication</Text>
701
+ <p>
702
+ Two-Factor Authentication is enabled for your account. Please verify your account before logging in to enhance security.
703
+ </p>
704
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
705
+ </>
706
+ )}
707
+ </div>
708
+
709
+ {/* Show Communication Method ONLY IF:
710
+ - OTP not sent OR
711
+ - OTP expired
712
+ */}
713
+
714
+ {(!otpVerification || otpExpired) && (
715
+ <>
716
+ <Divider />
717
+ <div className="otp-method-section">
718
+ <Text type="primary">Select Preferred OTP Verification Method</Text>
719
+ <div className="otp-method-group">
720
+ <Radio checked={communicationMode === 'email'} onChange={() => setCommunicationMode('email')}>
721
+ Email <MailOutlined className="otp-icon" style={{ marginLeft: 6 }} />
722
+ </Radio>
723
+ <Radio checked={communicationMode === 'mobile'} onChange={() => setCommunicationMode('mobile')}>
724
+ SMS <MessageOutlined className="otp-icon" style={{ marginLeft: 6 }} />
725
+ </Radio>
726
+ </div>
727
+ {modeError && <p className="otp-mode-error">Please select a communication mode.</p>}
728
+ </div>
729
+ </>
730
+ )}
731
+
732
+ {!otpVerification ? (
733
+ <div className="otp-container">
734
+ <Button type="primary" onClick={sendAuthenticationOtp} style={{ marginTop: '6px' }}>
735
+ Send OTP
736
+ </Button>
737
+ </div>
738
+ ) : (
739
+ <>
740
+ {/* <Divider /> */}
741
+ <div className="otp-container">
742
+ <p>
743
+ Enter the verification code we sent to{' '}
744
+ <span className="otp-mode-text">
745
+ <strong>{getOtpDestinationText()}</strong>
746
+ </span>
747
+ </p>
748
+ <OTPInput
749
+ value={otpValue}
750
+ onChange={handleOtpChange}
751
+ autoFocus
752
+ OTPLength={6}
753
+ disabled={loading || otpExpired}
754
+ inputStyles={{
755
+ border: otpSuccess
756
+ ? '2px solid #52c41a' // green
757
+ : otpError
758
+ ? '2px solid #FF5C5C' // red
759
+ : '1px solid #d9d9d9', // default
760
+ borderRadius: 4,
761
+ width: isMobile ? 28 : 45, // MOBILE FIX
762
+ height: isMobile ? 36 : 40, // MOBILE FIX
763
+ margin: isMobile ? '2px' : '0 4px',
764
+ fontSize: isMobile ? 16 : 18,
765
+ textAlign: 'center',
766
+ }}
767
+ />
768
+ {/* Timer below OTP */}
769
+ <div className="otp-timer">
770
+ {/* {!otpExpired ? */}
771
+ {otpSuccess ? null : <span>{formatted}</span>}
772
+ {/* {otpError && (
773
+ <p style={{ color: 'red', marginTop: 8 }}>Invalid OTP, please try again</p>
774
+ )} */}
775
+
776
+ {otpSuccess && <p style={{ color: 'green', marginTop: 8 }}>Your OTP has been verified successfully.</p>}
777
+ </div>
778
+ </div>
779
+ {!otpSuccess && (
780
+ <Button type="primary" disabled={otpExpired} onClick={verifyOtp} style={{ marginTop: 16 }}>
781
+ Verify OTP
782
+ </Button>
783
+ )}
784
+ </>
785
+ )}
786
+ </div>
787
+ )}
788
+
789
+ {/* Login Form Section */}
790
+ {!otpVerification && !otpVisible && !showResetpassword && (
791
+ <Form {...layout} layout="vertical" name="basic" onFinish={onFinish} onFinishFailed={onFinishFailed}>
792
+ <div className="form-title">
793
+ <h4></h4>
794
+ </div>
795
+
796
+ {/* {!process.env.REACT_APP_SHOW_BRANCH_SWITCHER && <div className="branch-switcher">{globalCustomerHeader()}</div>} */}
797
+
798
+ {process.env.REACT_APP_ENABLE_LDAP === 'true' && (
799
+ <Button loading={ldaploading} type="secondary" className="SubmitBtn" onClick={loginWithLdap}>
800
+ Sign in using AD
801
+ </Button>
802
+ )}
803
+
804
+ <Form.Item label="Email" name="email" rules={[{ required: true, message: 'Please input your email!' }]}>
805
+ <Input autoComplete="off" autoFocus />
806
+ </Form.Item>
807
+
808
+ <Form.Item label="Password" name="password" rules={[{ required: true, message: 'Please input your password!' }]}>
809
+ <Input.Password autoComplete="off" />
810
+ </Form.Item>
811
+
812
+ <Form.Item {...tailLayout} style={{ marginBottom: '0px' }}>
813
+ <Button loading={loading} type="primary" htmlType="submit" className="SubmitBtn">
814
+ &nbsp;&nbsp; Submit
815
+ </Button>
816
+ <div className="forgot-password" style={{ marginTop: '8px', textAlign: 'center' }}>
817
+ <Link onClick={() => setShowResetpassword(true)}>Forgot Password?</Link>
818
+ </div>
819
+ </Form.Item>
820
+ </Form>
821
+ )}
822
+
823
+ {/* Forgot Password Section */}
824
+ {showResetpassword && (
825
+ <ResetPassword
826
+ defaultUsername={expiredPassword ? defaultUsername : undefined}
827
+ disabledUserName={expiredPassword}
828
+ onBack={() => {
829
+ setShowResetpassword(false);
830
+ setExpiredPassword(false);
831
+ }}
832
+ title={expiredPassword ? 'Password Expired!' : 'Forgot Password?'}
833
+ // subtitle={
834
+ // expiredPassword
835
+ // ? 'Your password has expired. Select a preferred communication method to receive the One-Time Password (OTP) to continue.'
836
+ // : 'Enter your username and Select a preferred communication method to receive the One-Time Password (OTP) to continue..'
837
+ // }
838
+ buttonText={expiredPassword ? 'Send Reset Link' : 'Reset Password'}
839
+ />
840
+ )}
841
+ </div>
842
+ </div>
843
+ {!otpSuccess && otpVerification && (
844
+ <div className="otp-actions">
845
+ <div className="resend-action">
846
+ <Text disabled>Didn't receive OTP?</Text>
847
+
848
+ <Link className="resend-otp-link" disabled={!otpExpired} onClick={handleResendOTP}>
849
+ Resend OTP
850
+ </Link>
851
+ </div>
852
+
853
+ <Button size="small" type="default" onClick={handlecancel}>
854
+ Cancel
855
+ </Button>
856
+ </div>
857
+ )}
858
+ </motion.div>
859
+ </section>
860
+ </section>
861
+ );
862
+ }
863
+
864
+ export default withRouter(LoginPhone);