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