ui-soxo-bootstrap-core 2.6.40-dev.1 → 2.6.40-dev.12
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/PUBLISHING.md +333 -0
- 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 +635 -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,1068 +1,1068 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
* A Single Dashboard that should be able to manage any process in a business
|
|
4
|
-
* according to configred by system .
|
|
5
|
-
*
|
|
6
|
-
* A process of different steps , each step linked to different roles of users and has a form/page to complete
|
|
7
|
-
* that particular step is part of this module .
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* @description Component for updating each process
|
|
12
|
-
* @author Ashique
|
|
13
|
-
*
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
import React, { useState, useEffect, useContext, useRef } from 'react';
|
|
18
|
-
|
|
19
|
-
import { Timeline, Card, Skeleton, Button, Modal, Typography, Form, Select, message, Tag } from 'antd';
|
|
20
|
-
|
|
21
|
-
import { Process, ProcessTransactions, Steps } from '../../../';
|
|
22
|
-
|
|
23
|
-
import TaskForm from './../task-form/task-form';
|
|
24
|
-
|
|
25
|
-
import './process-dashboard.scss';
|
|
26
|
-
|
|
27
|
-
import TaskStatus from './../task-status/task-status';
|
|
28
|
-
|
|
29
|
-
import DateUtils from '../../../../utils/date/date.utils';
|
|
30
|
-
|
|
31
|
-
import { ClockCircleOutlined, CopyOutlined, CheckCircleOutlined, LoadingOutlined, EditOutlined, ReloadOutlined, SoundOutlined, PauseCircleOutlined } from '@ant-design/icons';
|
|
32
|
-
|
|
33
|
-
import { CopyToClipBoard } from '../../../..';
|
|
34
|
-
|
|
35
|
-
import { GlobalContext } from './../../../../Store';
|
|
36
|
-
|
|
37
|
-
const { Title } = Typography;
|
|
38
|
-
|
|
39
|
-
const { Option } = Select;
|
|
40
|
-
|
|
41
|
-
let stepMaster = {
|
|
42
|
-
ongoing: {
|
|
43
|
-
icon: LoadingOutlined,
|
|
44
|
-
color: 'blue'
|
|
45
|
-
},
|
|
46
|
-
pending: {
|
|
47
|
-
icon: ClockCircleOutlined,
|
|
48
|
-
color: 'orange'
|
|
49
|
-
},
|
|
50
|
-
completed: {
|
|
51
|
-
icon: CheckCircleOutlined,
|
|
52
|
-
color: 'green'
|
|
53
|
-
},
|
|
54
|
-
|
|
55
|
-
waiting: {
|
|
56
|
-
icon: ClockCircleOutlined,
|
|
57
|
-
color: 'red'
|
|
58
|
-
},
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const GEMINI_TTS_MODEL =
|
|
63
|
-
process.env.GEMINI_TTS_MODEL || process.env.REACT_APP_GEMINI_TTS_MODEL || 'gemini-2.5-flash-preview-tts';
|
|
64
|
-
const GEMINI_TTS_VOICE = process.env.GEMINI_TTS_VOICE || process.env.REACT_APP_GEMINI_TTS_VOICE || 'Kore';
|
|
65
|
-
const GEMINI_TTS_API_BASE_URL =
|
|
66
|
-
process.env.GEMINI_API_BASE_URL || process.env.REACT_APP_GEMINI_API_BASE_URL || 'https://generativelanguage.googleapis.com/v1beta';
|
|
67
|
-
const ELEVENLABS_TTS_API_BASE_URL =
|
|
68
|
-
process.env.ELEVENLABS_TTS_API_BASE_URL ||
|
|
69
|
-
process.env.REACT_APP_ELEVENLABS_TTS_API_BASE_URL ||
|
|
70
|
-
'https://api.elevenlabs.io/v1/text-to-speech';
|
|
71
|
-
const ELEVENLABS_MODEL_ID =
|
|
72
|
-
process.env.ELEVENLABS_MODEL_ID || process.env.REACT_APP_ELEVENLABS_MODEL_ID || 'eleven_multilingual_v2';
|
|
73
|
-
const ELEVENLABS_OUTPUT_FORMAT =
|
|
74
|
-
process.env.ELEVENLABS_OUTPUT_FORMAT || process.env.REACT_APP_ELEVENLABS_OUTPUT_FORMAT || 'mp3_44100_128';
|
|
75
|
-
const DEFAULT_ELEVENLABS_VOICE_ID =
|
|
76
|
-
process.env.ELEVENLABS_VOICE_ID ||
|
|
77
|
-
process.env.ELEVEN_LABS_VOICE_ID ||
|
|
78
|
-
process.env.REACT_APP_ELEVENLABS_VOICE_ID ||
|
|
79
|
-
'21m00Tcm4TlvDq8ikWAM';
|
|
80
|
-
|
|
81
|
-
function getFromStorage(storageKey) {
|
|
82
|
-
|
|
83
|
-
if (typeof window === 'undefined' || !window.localStorage) {
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
try {
|
|
88
|
-
return window.localStorage.getItem(storageKey);
|
|
89
|
-
} catch (error) {
|
|
90
|
-
return null;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function getGeminiApiKey() {
|
|
95
|
-
|
|
96
|
-
if (process.env.GEMINI_API_KEY) {
|
|
97
|
-
return process.env.GEMINI_API_KEY;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (process.env.REACT_APP_GEMINI_API_KEY) {
|
|
101
|
-
return process.env.REACT_APP_GEMINI_API_KEY;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (typeof window !== 'undefined') {
|
|
105
|
-
try {
|
|
106
|
-
if (window.localStorage) {
|
|
107
|
-
return window.localStorage.getItem('gemini_api_key');
|
|
108
|
-
}
|
|
109
|
-
} catch (error) {
|
|
110
|
-
return null;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return null;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function getElevenLabsApiKey() {
|
|
118
|
-
return (
|
|
119
|
-
process.env.ELEVEN_LABS_KEY ||
|
|
120
|
-
process.env.ELEVENLABS_API_KEY ||
|
|
121
|
-
process.env.REACT_APP_ELEVEN_LABS_KEY ||
|
|
122
|
-
process.env.REACT_APP_ELEVENLABS_API_KEY ||
|
|
123
|
-
getFromStorage('eleven_labs_key') ||
|
|
124
|
-
getFromStorage('elevenlabs_api_key') ||
|
|
125
|
-
getFromStorage('ELEVEN_LABS_KEY') ||
|
|
126
|
-
getFromStorage('REACT_APP_ELEVEN_LABS_KEY') ||
|
|
127
|
-
getFromStorage('REACT_APP_ELEVENLABS_API_KEY')
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function getStepNarration({ step, step_transactions }) {
|
|
132
|
-
|
|
133
|
-
if (!step) {
|
|
134
|
-
return 'Step details are not available.';
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const chunks = [];
|
|
138
|
-
|
|
139
|
-
chunks.push(`Step ${step.name || 'Unnamed step'}.`);
|
|
140
|
-
|
|
141
|
-
if (step.description) {
|
|
142
|
-
chunks.push(step.description);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const currentState = step.current_state || 'pending';
|
|
146
|
-
|
|
147
|
-
chunks.push(`Current status is ${currentState}.`);
|
|
148
|
-
|
|
149
|
-
if (step.roles && step.roles.length) {
|
|
150
|
-
const roleNames = step.roles.map((role) => role && role.name).filter(Boolean);
|
|
151
|
-
|
|
152
|
-
if (roleNames.length) {
|
|
153
|
-
chunks.push(`Pending with ${roleNames.join(', ')}.`);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
if (step_transactions && step_transactions.start_time) {
|
|
158
|
-
const startTime = DateUtils.displayFirestoreTime(step_transactions.start_time);
|
|
159
|
-
|
|
160
|
-
if (startTime) {
|
|
161
|
-
chunks.push(`Started at ${startTime}.`);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
if (step_transactions && step_transactions.completed && step_transactions.end_time) {
|
|
166
|
-
const endTime = DateUtils.displayFirestoreTime(step_transactions.end_time);
|
|
167
|
-
|
|
168
|
-
if (endTime) {
|
|
169
|
-
chunks.push(`Completed at ${endTime}.`);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
return chunks.join(' ');
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
function extractGeminiAudio(payload) {
|
|
177
|
-
const candidates = payload && payload.candidates ? payload.candidates : [];
|
|
178
|
-
|
|
179
|
-
for (const candidate of candidates) {
|
|
180
|
-
const parts = candidate && candidate.content && candidate.content.parts ? candidate.content.parts : [];
|
|
181
|
-
|
|
182
|
-
for (const part of parts) {
|
|
183
|
-
const inlineData = part.inlineData || part.inline_data || part.audio;
|
|
184
|
-
|
|
185
|
-
if (inlineData && inlineData.data) {
|
|
186
|
-
return {
|
|
187
|
-
mimeType: inlineData.mimeType || inlineData.mime_type || 'audio/wav',
|
|
188
|
-
data: inlineData.data
|
|
189
|
-
};
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
return null;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
async function synthesizeGeminiAudio(text) {
|
|
198
|
-
|
|
199
|
-
const apiKey = getGeminiApiKey();
|
|
200
|
-
|
|
201
|
-
if (!apiKey) {
|
|
202
|
-
throw new Error('Gemini API key is missing');
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
const endpoint = `${GEMINI_TTS_API_BASE_URL}/models/${GEMINI_TTS_MODEL}:generateContent?key=${apiKey}`;
|
|
206
|
-
|
|
207
|
-
const response = await fetch(endpoint, {
|
|
208
|
-
method: 'POST',
|
|
209
|
-
headers: {
|
|
210
|
-
'Content-Type': 'application/json'
|
|
211
|
-
},
|
|
212
|
-
body: JSON.stringify({
|
|
213
|
-
contents: [{
|
|
214
|
-
role: 'user',
|
|
215
|
-
parts: [{ text }]
|
|
216
|
-
}],
|
|
217
|
-
generationConfig: {
|
|
218
|
-
responseModalities: ['AUDIO'],
|
|
219
|
-
speechConfig: {
|
|
220
|
-
voiceConfig: {
|
|
221
|
-
prebuiltVoiceConfig: {
|
|
222
|
-
voiceName: GEMINI_TTS_VOICE
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
})
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
if (!response.ok) {
|
|
231
|
-
throw new Error(`Gemini TTS request failed with status ${response.status}`);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
const payload = await response.json();
|
|
235
|
-
|
|
236
|
-
const audio = extractGeminiAudio(payload);
|
|
237
|
-
|
|
238
|
-
if (!audio || !audio.data) {
|
|
239
|
-
throw new Error('Gemini did not return audio data');
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
return `data:${audio.mimeType};base64,${audio.data}`;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
async function synthesizeElevenLabsAudio(text) {
|
|
246
|
-
|
|
247
|
-
const apiKey = getElevenLabsApiKey();
|
|
248
|
-
|
|
249
|
-
if (!apiKey) {
|
|
250
|
-
throw new Error('ElevenLabs API key is missing');
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
const endpoint = `${ELEVENLABS_TTS_API_BASE_URL}/${encodeURIComponent(DEFAULT_ELEVENLABS_VOICE_ID)}/stream?output_format=${encodeURIComponent(
|
|
254
|
-
ELEVENLABS_OUTPUT_FORMAT
|
|
255
|
-
)}`;
|
|
256
|
-
|
|
257
|
-
const response = await fetch(endpoint, {
|
|
258
|
-
method: 'POST',
|
|
259
|
-
headers: {
|
|
260
|
-
'Content-Type': 'application/json',
|
|
261
|
-
Accept: 'audio/mpeg',
|
|
262
|
-
'xi-api-key': apiKey
|
|
263
|
-
},
|
|
264
|
-
body: JSON.stringify({
|
|
265
|
-
text,
|
|
266
|
-
model_id: ELEVENLABS_MODEL_ID
|
|
267
|
-
})
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
if (!response.ok) {
|
|
271
|
-
throw new Error(`ElevenLabs TTS request failed with status ${response.status}`);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
return response.blob();
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
function playAudioDataUri(dataUri, audioReference) {
|
|
278
|
-
return new Promise((resolve, reject) => {
|
|
279
|
-
const audio = new Audio(dataUri);
|
|
280
|
-
|
|
281
|
-
audioReference.current = audio;
|
|
282
|
-
|
|
283
|
-
const clean = () => {
|
|
284
|
-
if (audioReference.current === audio) {
|
|
285
|
-
audioReference.current = null;
|
|
286
|
-
}
|
|
287
|
-
};
|
|
288
|
-
|
|
289
|
-
audio.onended = () => {
|
|
290
|
-
clean();
|
|
291
|
-
resolve();
|
|
292
|
-
};
|
|
293
|
-
|
|
294
|
-
audio.onpause = () => {
|
|
295
|
-
clean();
|
|
296
|
-
resolve();
|
|
297
|
-
};
|
|
298
|
-
|
|
299
|
-
audio.onerror = () => {
|
|
300
|
-
clean();
|
|
301
|
-
reject(new Error('Audio playback failed'));
|
|
302
|
-
};
|
|
303
|
-
|
|
304
|
-
audio.play().catch((error) => {
|
|
305
|
-
clean();
|
|
306
|
-
reject(error);
|
|
307
|
-
});
|
|
308
|
-
});
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
function playAudioBlob(audioBlob, audioReference, audioUrlReference) {
|
|
312
|
-
return new Promise((resolve, reject) => {
|
|
313
|
-
if (typeof window === 'undefined' || !window.Audio || !window.URL) {
|
|
314
|
-
reject(new Error('Audio playback is not available'));
|
|
315
|
-
return;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
if (audioUrlReference.current) {
|
|
319
|
-
window.URL.revokeObjectURL(audioUrlReference.current);
|
|
320
|
-
audioUrlReference.current = null;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
const audioUrl = window.URL.createObjectURL(audioBlob);
|
|
324
|
-
const audio = new Audio(audioUrl);
|
|
325
|
-
|
|
326
|
-
audioReference.current = audio;
|
|
327
|
-
audioUrlReference.current = audioUrl;
|
|
328
|
-
|
|
329
|
-
const clean = () => {
|
|
330
|
-
if (audioReference.current === audio) {
|
|
331
|
-
audioReference.current = null;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
if (audioUrlReference.current === audioUrl) {
|
|
335
|
-
window.URL.revokeObjectURL(audioUrl);
|
|
336
|
-
audioUrlReference.current = null;
|
|
337
|
-
}
|
|
338
|
-
};
|
|
339
|
-
|
|
340
|
-
audio.onended = () => {
|
|
341
|
-
clean();
|
|
342
|
-
resolve();
|
|
343
|
-
};
|
|
344
|
-
|
|
345
|
-
audio.onpause = () => {
|
|
346
|
-
clean();
|
|
347
|
-
resolve();
|
|
348
|
-
};
|
|
349
|
-
|
|
350
|
-
audio.onerror = () => {
|
|
351
|
-
clean();
|
|
352
|
-
reject(new Error('Audio playback failed'));
|
|
353
|
-
};
|
|
354
|
-
|
|
355
|
-
audio.play().catch((error) => {
|
|
356
|
-
clean();
|
|
357
|
-
reject(error);
|
|
358
|
-
});
|
|
359
|
-
});
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
function speakWithBrowser(text, speechReference) {
|
|
363
|
-
return new Promise((resolve, reject) => {
|
|
364
|
-
if (typeof window === 'undefined' || !window.speechSynthesis || !window.SpeechSynthesisUtterance) {
|
|
365
|
-
reject(new Error('Speech synthesis is not available'));
|
|
366
|
-
return;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
const utterance = new window.SpeechSynthesisUtterance(text);
|
|
370
|
-
|
|
371
|
-
utterance.lang = process.env.REACT_APP_TTS_LANG || 'en-US';
|
|
372
|
-
|
|
373
|
-
speechReference.current = utterance;
|
|
374
|
-
|
|
375
|
-
utterance.onend = () => {
|
|
376
|
-
if (speechReference.current === utterance) {
|
|
377
|
-
speechReference.current = null;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
resolve();
|
|
381
|
-
};
|
|
382
|
-
|
|
383
|
-
utterance.onerror = () => {
|
|
384
|
-
if (speechReference.current === utterance) {
|
|
385
|
-
speechReference.current = null;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
reject(new Error('Browser narration failed'));
|
|
389
|
-
};
|
|
390
|
-
|
|
391
|
-
window.speechSynthesis.cancel();
|
|
392
|
-
window.speechSynthesis.speak(utterance);
|
|
393
|
-
});
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
/**
|
|
397
|
-
*
|
|
398
|
-
*/
|
|
399
|
-
export default function ProcessDashboard({ id, identifier, callback = () => { } }) {
|
|
400
|
-
|
|
401
|
-
const { user = { locations: [] } } = useContext(GlobalContext);
|
|
402
|
-
|
|
403
|
-
const [loading, setLoading] = useState(false);
|
|
404
|
-
|
|
405
|
-
const [process, setProcess] = useState([]);
|
|
406
|
-
|
|
407
|
-
const [transactionmodal, setTransactionmodal] = useState(false);
|
|
408
|
-
|
|
409
|
-
useEffect(() => {
|
|
410
|
-
|
|
411
|
-
// We have to load the process for the identified received as a property
|
|
412
|
-
|
|
413
|
-
// The process / steps are recorded specific to a an id which can be of any model .
|
|
414
|
-
getProcess();
|
|
415
|
-
|
|
416
|
-
return () => {
|
|
417
|
-
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
}, [])
|
|
421
|
-
|
|
422
|
-
/**
|
|
423
|
-
* Get the process of an identifier
|
|
424
|
-
*
|
|
425
|
-
* @returns
|
|
426
|
-
*/
|
|
427
|
-
function getProcess() {
|
|
428
|
-
|
|
429
|
-
setLoading(true);
|
|
430
|
-
|
|
431
|
-
var queries = [{
|
|
432
|
-
field: 'modelIdentifier',
|
|
433
|
-
value: identifier
|
|
434
|
-
}]
|
|
435
|
-
|
|
436
|
-
// Get the process with the current status of an id passed .
|
|
437
|
-
return Process.getProcessTimeline({ identifier, id }).then((result) => {
|
|
438
|
-
|
|
439
|
-
setProcess(result);
|
|
440
|
-
|
|
441
|
-
console.log(result);
|
|
442
|
-
|
|
443
|
-
setLoading(false);
|
|
444
|
-
|
|
445
|
-
});
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
/**
|
|
450
|
-
* Revert the modal
|
|
451
|
-
*/
|
|
452
|
-
function openRevertModal() {
|
|
453
|
-
|
|
454
|
-
setTransactionmodal(true);
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
/**
|
|
459
|
-
* Close the revert modal
|
|
460
|
-
*/
|
|
461
|
-
function closeRevertModal() {
|
|
462
|
-
setTransactionmodal(false);
|
|
463
|
-
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
return (<div className="process-dashboard card">
|
|
467
|
-
|
|
468
|
-
{/*
|
|
469
|
-
<div className="page-header">
|
|
470
|
-
|
|
471
|
-
<Title level={5}>
|
|
472
|
-
Process Dashboard
|
|
473
|
-
</Title>
|
|
474
|
-
|
|
475
|
-
<div className="actions">
|
|
476
|
-
|
|
477
|
-
{
|
|
478
|
-
user.isAdmin
|
|
479
|
-
&&
|
|
480
|
-
<Button size={'small'} onClick={() => { openRevertModal() }}>
|
|
481
|
-
<ReloadOutlined />
|
|
482
|
-
Revert
|
|
483
|
-
</Button>
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
</div>
|
|
487
|
-
</div> */}
|
|
488
|
-
|
|
489
|
-
{
|
|
490
|
-
loading
|
|
491
|
-
?
|
|
492
|
-
<>
|
|
493
|
-
|
|
494
|
-
<strong className="process-title">
|
|
495
|
-
Loading content ,
|
|
496
|
-
</strong>
|
|
497
|
-
|
|
498
|
-
<Skeleton />
|
|
499
|
-
</>
|
|
500
|
-
|
|
501
|
-
:
|
|
502
|
-
<>
|
|
503
|
-
|
|
504
|
-
{
|
|
505
|
-
process.map((records) => {
|
|
506
|
-
|
|
507
|
-
// If there is a process transaction record this process has started
|
|
508
|
-
let { process_transactions = [] } = records;
|
|
509
|
-
|
|
510
|
-
return (<>
|
|
511
|
-
|
|
512
|
-
<div className='page-header'>
|
|
513
|
-
<div>
|
|
514
|
-
|
|
515
|
-
<strong className="process-title">
|
|
516
|
-
{records.name}
|
|
517
|
-
</strong>
|
|
518
|
-
|
|
519
|
-
<p className="process-description">
|
|
520
|
-
<small>
|
|
521
|
-
{records.description}
|
|
522
|
-
</small>
|
|
523
|
-
</p>
|
|
524
|
-
</div>
|
|
525
|
-
|
|
526
|
-
<div className='actions'>
|
|
527
|
-
|
|
528
|
-
<CopyToClipBoard id={records.id} record={records} />
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
{
|
|
532
|
-
user.isAdmin
|
|
533
|
-
&&
|
|
534
|
-
<Button size={'small'} onClick={() => { openRevertModal() }}>
|
|
535
|
-
<ReloadOutlined />
|
|
536
|
-
Revert
|
|
537
|
-
</Button>
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
</div>
|
|
541
|
-
|
|
542
|
-
</div>
|
|
543
|
-
|
|
544
|
-
{
|
|
545
|
-
process_transactions.length
|
|
546
|
-
?
|
|
547
|
-
<small className='timeline'>
|
|
548
|
-
{/* {DateUtils.displayFirestoreTime(process_transactions[0].start_time)} - {process_transactions[0].completed ? DateUtils.displayFirestoreTime(process_transactions[0].end_time) : 'Pending'} */}
|
|
549
|
-
</small>
|
|
550
|
-
:
|
|
551
|
-
null
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
<Timeline className="process-timeline">
|
|
555
|
-
|
|
556
|
-
{/* Steps List */}
|
|
557
|
-
<StepsList id={id} steps={records.steps} callback={getProcess} />
|
|
558
|
-
{/* Steps List Ends */}
|
|
559
|
-
|
|
560
|
-
</Timeline>
|
|
561
|
-
</>)
|
|
562
|
-
})
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
{/* Add Modal */}
|
|
566
|
-
<Modal destroyOnClose confirmLoading={loading} title="Revert" visible={transactionmodal} onCancel={() => { closeRevertModal() }} footer={null}>
|
|
567
|
-
|
|
568
|
-
<RevertProcessTransaction id={id} process={process} callback={() => {
|
|
569
|
-
|
|
570
|
-
closeRevertModal()
|
|
571
|
-
}} />
|
|
572
|
-
|
|
573
|
-
</Modal>
|
|
574
|
-
{/* Add Modal Ends */}
|
|
575
|
-
|
|
576
|
-
</>
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
</div >)
|
|
580
|
-
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
/**
|
|
584
|
-
* The Timeline item that displays a step
|
|
585
|
-
*/
|
|
586
|
-
function StepTimelineItem({ id, color, Icon, step, step_transactions, callback }) {
|
|
587
|
-
|
|
588
|
-
const [body, setBody] = useState({});
|
|
589
|
-
|
|
590
|
-
const [visible, setVisible] = useState(false);
|
|
591
|
-
|
|
592
|
-
const [loading, setLoading] = useState(false);
|
|
593
|
-
|
|
594
|
-
const [narrating, setNarrating] = useState(false);
|
|
595
|
-
|
|
596
|
-
const { user = { locations: [] } } = useContext(GlobalContext);
|
|
597
|
-
|
|
598
|
-
const audioReference = useRef(null);
|
|
599
|
-
|
|
600
|
-
const audioUrlReference = useRef(null);
|
|
601
|
-
|
|
602
|
-
const speechReference = useRef(null);
|
|
603
|
-
|
|
604
|
-
const narrationSessionReference = useRef(0);
|
|
605
|
-
|
|
606
|
-
const fallbackNoticeShownReference = useRef(false);
|
|
607
|
-
|
|
608
|
-
useEffect(() => {
|
|
609
|
-
return () => {
|
|
610
|
-
stopNarration();
|
|
611
|
-
}
|
|
612
|
-
}, [])
|
|
613
|
-
|
|
614
|
-
/**
|
|
615
|
-
* Stop active narration audio
|
|
616
|
-
*/
|
|
617
|
-
function stopNarration() {
|
|
618
|
-
narrationSessionReference.current += 1;
|
|
619
|
-
|
|
620
|
-
if (audioReference.current) {
|
|
621
|
-
audioReference.current.pause();
|
|
622
|
-
audioReference.current.src = '';
|
|
623
|
-
audioReference.current = null;
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
if (audioUrlReference.current && typeof window !== 'undefined' && window.URL) {
|
|
627
|
-
window.URL.revokeObjectURL(audioUrlReference.current);
|
|
628
|
-
audioUrlReference.current = null;
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
if (typeof window !== 'undefined' && window.speechSynthesis) {
|
|
632
|
-
window.speechSynthesis.cancel();
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
speechReference.current = null;
|
|
636
|
-
setNarrating(false);
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
/**
|
|
640
|
-
* Narrate the current step with ElevenLabs/Gemini TTS only (no browser fallback).
|
|
641
|
-
*/
|
|
642
|
-
async function narrateStep() {
|
|
643
|
-
const narration = getStepNarration({ step, step_transactions });
|
|
644
|
-
|
|
645
|
-
if (!narration) {
|
|
646
|
-
message.warning('Narration text is not available for this step.');
|
|
647
|
-
return;
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
stopNarration();
|
|
651
|
-
|
|
652
|
-
const sessionId = narrationSessionReference.current;
|
|
653
|
-
const hasElevenLabsKey = Boolean(getElevenLabsApiKey());
|
|
654
|
-
|
|
655
|
-
setNarrating(true);
|
|
656
|
-
|
|
657
|
-
try {
|
|
658
|
-
let aiNarrationComplete = false;
|
|
659
|
-
let aiNarrationError = null;
|
|
660
|
-
|
|
661
|
-
if (hasElevenLabsKey) {
|
|
662
|
-
try {
|
|
663
|
-
const audioBlob = await synthesizeElevenLabsAudio(narration);
|
|
664
|
-
|
|
665
|
-
if (sessionId !== narrationSessionReference.current) {
|
|
666
|
-
return;
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
await playAudioBlob(audioBlob, audioReference, audioUrlReference);
|
|
670
|
-
aiNarrationComplete = true;
|
|
671
|
-
} catch (elevenLabsError) {
|
|
672
|
-
aiNarrationError = elevenLabsError;
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
if (!aiNarrationComplete) {
|
|
677
|
-
try {
|
|
678
|
-
const dataUri = await synthesizeGeminiAudio(narration);
|
|
679
|
-
|
|
680
|
-
if (sessionId !== narrationSessionReference.current) {
|
|
681
|
-
return;
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
await playAudioDataUri(dataUri, audioReference);
|
|
685
|
-
aiNarrationComplete = true;
|
|
686
|
-
} catch (geminiError) {
|
|
687
|
-
aiNarrationError = geminiError;
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
if (!aiNarrationComplete) {
|
|
692
|
-
throw aiNarrationError || new Error('AI narration unavailable');
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
} catch (error) {
|
|
696
|
-
if (sessionId !== narrationSessionReference.current) {
|
|
697
|
-
return;
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
if (!fallbackNoticeShownReference.current) {
|
|
701
|
-
message.warning(`${hasElevenLabsKey ? 'ElevenLabs/Gemini' : 'Gemini'} narration unavailable.`);
|
|
702
|
-
fallbackNoticeShownReference.current = true;
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
message.error(error?.message || 'Unable to play narration for this step.');
|
|
706
|
-
} finally {
|
|
707
|
-
if (sessionId === narrationSessionReference.current) {
|
|
708
|
-
setNarrating(false);
|
|
709
|
-
}
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
/**
|
|
714
|
-
* Function to open editModal for Step
|
|
715
|
-
*
|
|
716
|
-
* @param {*} step
|
|
717
|
-
*/
|
|
718
|
-
function openEditModal(step) {
|
|
719
|
-
|
|
720
|
-
setVisible(true);
|
|
721
|
-
|
|
722
|
-
setBody(step)
|
|
723
|
-
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
/**
|
|
727
|
-
*
|
|
728
|
-
* @param {*} step
|
|
729
|
-
*/
|
|
730
|
-
async function startStep(step) {
|
|
731
|
-
|
|
732
|
-
// Batch
|
|
733
|
-
let app = Process.getFireStoreApp();
|
|
734
|
-
|
|
735
|
-
// Starting a batched write
|
|
736
|
-
let batch = app.batch();
|
|
737
|
-
|
|
738
|
-
let body = {
|
|
739
|
-
record_id: id,
|
|
740
|
-
model_identifer: 'Candidates'
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
await Process.startStepBatch({ batch, step, body });
|
|
744
|
-
|
|
745
|
-
await batch.commit();
|
|
746
|
-
|
|
747
|
-
message.success("Step Started");
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
/**
|
|
751
|
-
*
|
|
752
|
-
* @param {*} step
|
|
753
|
-
*/
|
|
754
|
-
async function completeStep(step) {
|
|
755
|
-
|
|
756
|
-
// Batch
|
|
757
|
-
let app = Process.getFireStoreApp();
|
|
758
|
-
|
|
759
|
-
// Starting a batched write
|
|
760
|
-
let batch = app.batch();
|
|
761
|
-
|
|
762
|
-
let body = {
|
|
763
|
-
record_id: id,
|
|
764
|
-
model_identifer: 'Candidates'
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
await Process.stopStepBatch({ batch, step, body });
|
|
768
|
-
|
|
769
|
-
message.success("Step Ended");
|
|
770
|
-
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
/**
|
|
774
|
-
*
|
|
775
|
-
* @param {*} step
|
|
776
|
-
*/
|
|
777
|
-
function closeModal() {
|
|
778
|
-
|
|
779
|
-
setVisible(false);
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
return (<Timeline.Item color={color} dot={<Icon />} >
|
|
784
|
-
|
|
785
|
-
{/* Timeline Step Template */}
|
|
786
|
-
<div className="timeline-content">
|
|
787
|
-
|
|
788
|
-
<p className={'timeline-title'}>
|
|
789
|
-
{step.name}
|
|
790
|
-
|
|
791
|
-
<p className={'timeline-description'}>
|
|
792
|
-
<small>
|
|
793
|
-
{step.description}
|
|
794
|
-
</small>
|
|
795
|
-
</p>
|
|
796
|
-
</p>
|
|
797
|
-
|
|
798
|
-
{/* Actions for a step */}
|
|
799
|
-
<div className="actions">
|
|
800
|
-
|
|
801
|
-
<Button size={'small'} onClick={() => {
|
|
802
|
-
if (narrating) {
|
|
803
|
-
stopNarration();
|
|
804
|
-
return;
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
narrateStep();
|
|
808
|
-
}}>
|
|
809
|
-
|
|
810
|
-
{narrating ? <PauseCircleOutlined /> : <SoundOutlined />}
|
|
811
|
-
|
|
812
|
-
{narrating ? 'Stop Narration' : 'Narrate'}
|
|
813
|
-
|
|
814
|
-
</Button>
|
|
815
|
-
|
|
816
|
-
{user.isAdmin && <>
|
|
817
|
-
|
|
818
|
-
<CopyToClipBoard record={step} id={step.id} />
|
|
819
|
-
|
|
820
|
-
<Button size={'small'} onClick={() => { openEditModal(step) }}>
|
|
821
|
-
|
|
822
|
-
<EditOutlined />
|
|
823
|
-
|
|
824
|
-
Edit
|
|
825
|
-
|
|
826
|
-
</Button>
|
|
827
|
-
|
|
828
|
-
<Button size={'small'} onClick={() => { startStep(step) }}>
|
|
829
|
-
|
|
830
|
-
Start
|
|
831
|
-
|
|
832
|
-
</Button>
|
|
833
|
-
|
|
834
|
-
<Button size={'small'} onClick={() => { completeStep(step) }}>
|
|
835
|
-
|
|
836
|
-
Complete
|
|
837
|
-
|
|
838
|
-
</Button>
|
|
839
|
-
|
|
840
|
-
</>}
|
|
841
|
-
|
|
842
|
-
</div>
|
|
843
|
-
{/* Actions for a step Ends */}
|
|
844
|
-
|
|
845
|
-
</div>
|
|
846
|
-
{/* Timeline Step Template Ends */}
|
|
847
|
-
|
|
848
|
-
{/* Summary of Step Activity */}
|
|
849
|
-
<TaskStatus id={id} color={color} step={step} step_transactions={step_transactions} />
|
|
850
|
-
{/* Summary of Step Activity Ends */}
|
|
851
|
-
|
|
852
|
-
{/* Form for the Step */}
|
|
853
|
-
{step.formEnabled && <Card className="task-form-card">
|
|
854
|
-
|
|
855
|
-
<h1>
|
|
856
|
-
Form Enabled Value {step.formEnabled} - {step.name}
|
|
857
|
-
|
|
858
|
-
</h1>
|
|
859
|
-
|
|
860
|
-
<TaskForm
|
|
861
|
-
record_id={id}
|
|
862
|
-
step={step}
|
|
863
|
-
|
|
864
|
-
callback={callback}
|
|
865
|
-
|
|
866
|
-
/>
|
|
867
|
-
|
|
868
|
-
</Card>}
|
|
869
|
-
{/* Form for the Step Ends */}
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
{
|
|
873
|
-
step.sub_steps.length ?
|
|
874
|
-
<>
|
|
875
|
-
<Timeline className="process-timeline">
|
|
876
|
-
|
|
877
|
-
<StepsList id={id} steps={step.sub_steps} />
|
|
878
|
-
|
|
879
|
-
</Timeline>
|
|
880
|
-
</>
|
|
881
|
-
:
|
|
882
|
-
null
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
{/* Add Modal */}
|
|
887
|
-
<Modal destroyOnClose confirmLoading={loading} title="Edit Step" visible={visible} onCancel={() => { closeModal() }} footer={null}>
|
|
888
|
-
<Steps.ModalAddComponent
|
|
889
|
-
// match={match}
|
|
890
|
-
model={Steps}
|
|
891
|
-
additional_queries={[]}
|
|
892
|
-
formContent={body}
|
|
893
|
-
|
|
894
|
-
callback={() => {
|
|
895
|
-
closeModal(true);
|
|
896
|
-
}}
|
|
897
|
-
/>
|
|
898
|
-
</Modal>
|
|
899
|
-
{/* Add Modal Ends */}
|
|
900
|
-
|
|
901
|
-
{/* </>
|
|
902
|
-
} */}
|
|
903
|
-
|
|
904
|
-
</Timeline.Item>)
|
|
905
|
-
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
/**
|
|
910
|
-
* List of Steps inside a Timline
|
|
911
|
-
*/
|
|
912
|
-
function StepsList({ id, steps = [], callback }) {
|
|
913
|
-
|
|
914
|
-
return (<>
|
|
915
|
-
|
|
916
|
-
{
|
|
917
|
-
steps.map((step) => {
|
|
918
|
-
|
|
919
|
-
let color = stepMaster[step.current_state].color;
|
|
920
|
-
|
|
921
|
-
let Icon = stepMaster[step.current_state].icon;
|
|
922
|
-
|
|
923
|
-
let step_transactions = false;
|
|
924
|
-
|
|
925
|
-
if (step.step_transactions && step.step_transactions.length) {
|
|
926
|
-
|
|
927
|
-
step_transactions = step.step_transactions[0];
|
|
928
|
-
|
|
929
|
-
}
|
|
930
|
-
|
|
931
|
-
return (<>
|
|
932
|
-
|
|
933
|
-
{/* Details of the step */}
|
|
934
|
-
<StepTimelineItem
|
|
935
|
-
id={id}
|
|
936
|
-
color={color}
|
|
937
|
-
Icon={Icon}
|
|
938
|
-
step={step}
|
|
939
|
-
step_transactions={step_transactions}
|
|
940
|
-
|
|
941
|
-
callback={callback}
|
|
942
|
-
/>
|
|
943
|
-
{/* Details of the step Ends */}
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
{/* Form for the Step */}
|
|
947
|
-
{/* {step.formEnabled && <Card className="task-form-card">
|
|
948
|
-
|
|
949
|
-
<h1>
|
|
950
|
-
Form Enabled Value {step.formEnabled} - {step.name}
|
|
951
|
-
|
|
952
|
-
</h1>
|
|
953
|
-
|
|
954
|
-
<TaskForm
|
|
955
|
-
record_id={id}
|
|
956
|
-
step={step}
|
|
957
|
-
|
|
958
|
-
// callback={callback}
|
|
959
|
-
|
|
960
|
-
/>
|
|
961
|
-
|
|
962
|
-
</Card>} */}
|
|
963
|
-
{/* Form for the Step Ends */}
|
|
964
|
-
|
|
965
|
-
</>)
|
|
966
|
-
})
|
|
967
|
-
}
|
|
968
|
-
|
|
969
|
-
</>)
|
|
970
|
-
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
/**
|
|
977
|
-
*
|
|
978
|
-
*
|
|
979
|
-
* @returns
|
|
980
|
-
*/
|
|
981
|
-
function RevertProcessTransaction({ id, process = [], callback }) {
|
|
982
|
-
|
|
983
|
-
// const form = useRef(null)
|
|
984
|
-
|
|
985
|
-
const [loading, setLoading] = useState(false);
|
|
986
|
-
|
|
987
|
-
const [processtransactions, setProcesstransactions] = useState([])
|
|
988
|
-
|
|
989
|
-
useEffect(() => {
|
|
990
|
-
|
|
991
|
-
getProcessTransaction();
|
|
992
|
-
|
|
993
|
-
return () => {
|
|
994
|
-
}
|
|
995
|
-
}, [])
|
|
996
|
-
|
|
997
|
-
/**
|
|
998
|
-
*
|
|
999
|
-
* @returns
|
|
1000
|
-
*/
|
|
1001
|
-
function getProcessTransaction() {
|
|
1002
|
-
|
|
1003
|
-
var queries = [{ field: 'record_id', value: id }];
|
|
1004
|
-
|
|
1005
|
-
return ProcessTransactions.get(queries).then(({ process_transactions }) => {
|
|
1006
|
-
|
|
1007
|
-
setProcesstransactions(process_transactions);
|
|
1008
|
-
|
|
1009
|
-
console.log(process_transactions);
|
|
1010
|
-
|
|
1011
|
-
})
|
|
1012
|
-
}
|
|
1013
|
-
|
|
1014
|
-
/**
|
|
1015
|
-
* On Submit of form , Change the process transaction to specific step
|
|
1016
|
-
*/
|
|
1017
|
-
function onSubmit(values) {
|
|
1018
|
-
|
|
1019
|
-
// Batch
|
|
1020
|
-
let app = Process.getFireStoreApp();
|
|
1021
|
-
|
|
1022
|
-
// Starting a batched write
|
|
1023
|
-
let batch = app.batch();
|
|
1024
|
-
|
|
1025
|
-
setLoading(true);
|
|
1026
|
-
|
|
1027
|
-
console.log(values);
|
|
1028
|
-
|
|
1029
|
-
Process.triggerProcessBatch(batch, values.process_id, {}, processtransactions[0].id).then(() => {
|
|
1030
|
-
|
|
1031
|
-
message.success("Reverted case to ", values.process_id);
|
|
1032
|
-
|
|
1033
|
-
setLoading(false);
|
|
1034
|
-
|
|
1035
|
-
callback();
|
|
1036
|
-
|
|
1037
|
-
})
|
|
1038
|
-
}
|
|
1039
|
-
|
|
1040
|
-
return (<>
|
|
1041
|
-
|
|
1042
|
-
<Title level={4}>
|
|
1043
|
-
Revert Step
|
|
1044
|
-
</Title>
|
|
1045
|
-
|
|
1046
|
-
<Form
|
|
1047
|
-
// form={form}
|
|
1048
|
-
layout="vertical"
|
|
1049
|
-
onFinish={onSubmit}>
|
|
1050
|
-
|
|
1051
|
-
<Form.Item label="Process" name="process_id" required>
|
|
1052
|
-
<Select style={{ width: '100%' }}>
|
|
1053
|
-
|
|
1054
|
-
{process.map((staff) => <Option value={staff.id}>{staff.name}</Option>)}
|
|
1055
|
-
|
|
1056
|
-
</Select>
|
|
1057
|
-
</Form.Item>
|
|
1058
|
-
|
|
1059
|
-
<Form.Item >
|
|
1060
|
-
<Button loading={loading} type="primary" htmlType="submit">
|
|
1061
|
-
Submit
|
|
1062
|
-
</Button>
|
|
1063
|
-
</Form.Item>
|
|
1064
|
-
|
|
1065
|
-
</Form>
|
|
1066
|
-
</>)
|
|
1067
|
-
|
|
1068
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* A Single Dashboard that should be able to manage any process in a business
|
|
4
|
+
* according to configred by system .
|
|
5
|
+
*
|
|
6
|
+
* A process of different steps , each step linked to different roles of users and has a form/page to complete
|
|
7
|
+
* that particular step is part of this module .
|
|
8
|
+
*
|
|
9
|
+
*
|
|
10
|
+
*
|
|
11
|
+
* @description Component for updating each process
|
|
12
|
+
* @author Ashique
|
|
13
|
+
*
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
import React, { useState, useEffect, useContext, useRef } from 'react';
|
|
18
|
+
|
|
19
|
+
import { Timeline, Card, Skeleton, Button, Modal, Typography, Form, Select, message, Tag } from 'antd';
|
|
20
|
+
|
|
21
|
+
import { Process, ProcessTransactions, Steps } from '../../../';
|
|
22
|
+
|
|
23
|
+
import TaskForm from './../task-form/task-form';
|
|
24
|
+
|
|
25
|
+
import './process-dashboard.scss';
|
|
26
|
+
|
|
27
|
+
import TaskStatus from './../task-status/task-status';
|
|
28
|
+
|
|
29
|
+
import DateUtils from '../../../../utils/date/date.utils';
|
|
30
|
+
|
|
31
|
+
import { ClockCircleOutlined, CopyOutlined, CheckCircleOutlined, LoadingOutlined, EditOutlined, ReloadOutlined, SoundOutlined, PauseCircleOutlined } from '@ant-design/icons';
|
|
32
|
+
|
|
33
|
+
import { CopyToClipBoard } from '../../../..';
|
|
34
|
+
|
|
35
|
+
import { GlobalContext } from './../../../../Store';
|
|
36
|
+
|
|
37
|
+
const { Title } = Typography;
|
|
38
|
+
|
|
39
|
+
const { Option } = Select;
|
|
40
|
+
|
|
41
|
+
let stepMaster = {
|
|
42
|
+
ongoing: {
|
|
43
|
+
icon: LoadingOutlined,
|
|
44
|
+
color: 'blue'
|
|
45
|
+
},
|
|
46
|
+
pending: {
|
|
47
|
+
icon: ClockCircleOutlined,
|
|
48
|
+
color: 'orange'
|
|
49
|
+
},
|
|
50
|
+
completed: {
|
|
51
|
+
icon: CheckCircleOutlined,
|
|
52
|
+
color: 'green'
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
waiting: {
|
|
56
|
+
icon: ClockCircleOutlined,
|
|
57
|
+
color: 'red'
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const GEMINI_TTS_MODEL =
|
|
63
|
+
process.env.GEMINI_TTS_MODEL || process.env.REACT_APP_GEMINI_TTS_MODEL || 'gemini-2.5-flash-preview-tts';
|
|
64
|
+
const GEMINI_TTS_VOICE = process.env.GEMINI_TTS_VOICE || process.env.REACT_APP_GEMINI_TTS_VOICE || 'Kore';
|
|
65
|
+
const GEMINI_TTS_API_BASE_URL =
|
|
66
|
+
process.env.GEMINI_API_BASE_URL || process.env.REACT_APP_GEMINI_API_BASE_URL || 'https://generativelanguage.googleapis.com/v1beta';
|
|
67
|
+
const ELEVENLABS_TTS_API_BASE_URL =
|
|
68
|
+
process.env.ELEVENLABS_TTS_API_BASE_URL ||
|
|
69
|
+
process.env.REACT_APP_ELEVENLABS_TTS_API_BASE_URL ||
|
|
70
|
+
'https://api.elevenlabs.io/v1/text-to-speech';
|
|
71
|
+
const ELEVENLABS_MODEL_ID =
|
|
72
|
+
process.env.ELEVENLABS_MODEL_ID || process.env.REACT_APP_ELEVENLABS_MODEL_ID || 'eleven_multilingual_v2';
|
|
73
|
+
const ELEVENLABS_OUTPUT_FORMAT =
|
|
74
|
+
process.env.ELEVENLABS_OUTPUT_FORMAT || process.env.REACT_APP_ELEVENLABS_OUTPUT_FORMAT || 'mp3_44100_128';
|
|
75
|
+
const DEFAULT_ELEVENLABS_VOICE_ID =
|
|
76
|
+
process.env.ELEVENLABS_VOICE_ID ||
|
|
77
|
+
process.env.ELEVEN_LABS_VOICE_ID ||
|
|
78
|
+
process.env.REACT_APP_ELEVENLABS_VOICE_ID ||
|
|
79
|
+
'21m00Tcm4TlvDq8ikWAM';
|
|
80
|
+
|
|
81
|
+
function getFromStorage(storageKey) {
|
|
82
|
+
|
|
83
|
+
if (typeof window === 'undefined' || !window.localStorage) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
return window.localStorage.getItem(storageKey);
|
|
89
|
+
} catch (error) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function getGeminiApiKey() {
|
|
95
|
+
|
|
96
|
+
if (process.env.GEMINI_API_KEY) {
|
|
97
|
+
return process.env.GEMINI_API_KEY;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (process.env.REACT_APP_GEMINI_API_KEY) {
|
|
101
|
+
return process.env.REACT_APP_GEMINI_API_KEY;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (typeof window !== 'undefined') {
|
|
105
|
+
try {
|
|
106
|
+
if (window.localStorage) {
|
|
107
|
+
return window.localStorage.getItem('gemini_api_key');
|
|
108
|
+
}
|
|
109
|
+
} catch (error) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function getElevenLabsApiKey() {
|
|
118
|
+
return (
|
|
119
|
+
process.env.ELEVEN_LABS_KEY ||
|
|
120
|
+
process.env.ELEVENLABS_API_KEY ||
|
|
121
|
+
process.env.REACT_APP_ELEVEN_LABS_KEY ||
|
|
122
|
+
process.env.REACT_APP_ELEVENLABS_API_KEY ||
|
|
123
|
+
getFromStorage('eleven_labs_key') ||
|
|
124
|
+
getFromStorage('elevenlabs_api_key') ||
|
|
125
|
+
getFromStorage('ELEVEN_LABS_KEY') ||
|
|
126
|
+
getFromStorage('REACT_APP_ELEVEN_LABS_KEY') ||
|
|
127
|
+
getFromStorage('REACT_APP_ELEVENLABS_API_KEY')
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function getStepNarration({ step, step_transactions }) {
|
|
132
|
+
|
|
133
|
+
if (!step) {
|
|
134
|
+
return 'Step details are not available.';
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const chunks = [];
|
|
138
|
+
|
|
139
|
+
chunks.push(`Step ${step.name || 'Unnamed step'}.`);
|
|
140
|
+
|
|
141
|
+
if (step.description) {
|
|
142
|
+
chunks.push(step.description);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const currentState = step.current_state || 'pending';
|
|
146
|
+
|
|
147
|
+
chunks.push(`Current status is ${currentState}.`);
|
|
148
|
+
|
|
149
|
+
if (step.roles && step.roles.length) {
|
|
150
|
+
const roleNames = step.roles.map((role) => role && role.name).filter(Boolean);
|
|
151
|
+
|
|
152
|
+
if (roleNames.length) {
|
|
153
|
+
chunks.push(`Pending with ${roleNames.join(', ')}.`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (step_transactions && step_transactions.start_time) {
|
|
158
|
+
const startTime = DateUtils.displayFirestoreTime(step_transactions.start_time);
|
|
159
|
+
|
|
160
|
+
if (startTime) {
|
|
161
|
+
chunks.push(`Started at ${startTime}.`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (step_transactions && step_transactions.completed && step_transactions.end_time) {
|
|
166
|
+
const endTime = DateUtils.displayFirestoreTime(step_transactions.end_time);
|
|
167
|
+
|
|
168
|
+
if (endTime) {
|
|
169
|
+
chunks.push(`Completed at ${endTime}.`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return chunks.join(' ');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function extractGeminiAudio(payload) {
|
|
177
|
+
const candidates = payload && payload.candidates ? payload.candidates : [];
|
|
178
|
+
|
|
179
|
+
for (const candidate of candidates) {
|
|
180
|
+
const parts = candidate && candidate.content && candidate.content.parts ? candidate.content.parts : [];
|
|
181
|
+
|
|
182
|
+
for (const part of parts) {
|
|
183
|
+
const inlineData = part.inlineData || part.inline_data || part.audio;
|
|
184
|
+
|
|
185
|
+
if (inlineData && inlineData.data) {
|
|
186
|
+
return {
|
|
187
|
+
mimeType: inlineData.mimeType || inlineData.mime_type || 'audio/wav',
|
|
188
|
+
data: inlineData.data
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async function synthesizeGeminiAudio(text) {
|
|
198
|
+
|
|
199
|
+
const apiKey = getGeminiApiKey();
|
|
200
|
+
|
|
201
|
+
if (!apiKey) {
|
|
202
|
+
throw new Error('Gemini API key is missing');
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const endpoint = `${GEMINI_TTS_API_BASE_URL}/models/${GEMINI_TTS_MODEL}:generateContent?key=${apiKey}`;
|
|
206
|
+
|
|
207
|
+
const response = await fetch(endpoint, {
|
|
208
|
+
method: 'POST',
|
|
209
|
+
headers: {
|
|
210
|
+
'Content-Type': 'application/json'
|
|
211
|
+
},
|
|
212
|
+
body: JSON.stringify({
|
|
213
|
+
contents: [{
|
|
214
|
+
role: 'user',
|
|
215
|
+
parts: [{ text }]
|
|
216
|
+
}],
|
|
217
|
+
generationConfig: {
|
|
218
|
+
responseModalities: ['AUDIO'],
|
|
219
|
+
speechConfig: {
|
|
220
|
+
voiceConfig: {
|
|
221
|
+
prebuiltVoiceConfig: {
|
|
222
|
+
voiceName: GEMINI_TTS_VOICE
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
})
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
if (!response.ok) {
|
|
231
|
+
throw new Error(`Gemini TTS request failed with status ${response.status}`);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const payload = await response.json();
|
|
235
|
+
|
|
236
|
+
const audio = extractGeminiAudio(payload);
|
|
237
|
+
|
|
238
|
+
if (!audio || !audio.data) {
|
|
239
|
+
throw new Error('Gemini did not return audio data');
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return `data:${audio.mimeType};base64,${audio.data}`;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
async function synthesizeElevenLabsAudio(text) {
|
|
246
|
+
|
|
247
|
+
const apiKey = getElevenLabsApiKey();
|
|
248
|
+
|
|
249
|
+
if (!apiKey) {
|
|
250
|
+
throw new Error('ElevenLabs API key is missing');
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const endpoint = `${ELEVENLABS_TTS_API_BASE_URL}/${encodeURIComponent(DEFAULT_ELEVENLABS_VOICE_ID)}/stream?output_format=${encodeURIComponent(
|
|
254
|
+
ELEVENLABS_OUTPUT_FORMAT
|
|
255
|
+
)}`;
|
|
256
|
+
|
|
257
|
+
const response = await fetch(endpoint, {
|
|
258
|
+
method: 'POST',
|
|
259
|
+
headers: {
|
|
260
|
+
'Content-Type': 'application/json',
|
|
261
|
+
Accept: 'audio/mpeg',
|
|
262
|
+
'xi-api-key': apiKey
|
|
263
|
+
},
|
|
264
|
+
body: JSON.stringify({
|
|
265
|
+
text,
|
|
266
|
+
model_id: ELEVENLABS_MODEL_ID
|
|
267
|
+
})
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
if (!response.ok) {
|
|
271
|
+
throw new Error(`ElevenLabs TTS request failed with status ${response.status}`);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return response.blob();
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function playAudioDataUri(dataUri, audioReference) {
|
|
278
|
+
return new Promise((resolve, reject) => {
|
|
279
|
+
const audio = new Audio(dataUri);
|
|
280
|
+
|
|
281
|
+
audioReference.current = audio;
|
|
282
|
+
|
|
283
|
+
const clean = () => {
|
|
284
|
+
if (audioReference.current === audio) {
|
|
285
|
+
audioReference.current = null;
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
audio.onended = () => {
|
|
290
|
+
clean();
|
|
291
|
+
resolve();
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
audio.onpause = () => {
|
|
295
|
+
clean();
|
|
296
|
+
resolve();
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
audio.onerror = () => {
|
|
300
|
+
clean();
|
|
301
|
+
reject(new Error('Audio playback failed'));
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
audio.play().catch((error) => {
|
|
305
|
+
clean();
|
|
306
|
+
reject(error);
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function playAudioBlob(audioBlob, audioReference, audioUrlReference) {
|
|
312
|
+
return new Promise((resolve, reject) => {
|
|
313
|
+
if (typeof window === 'undefined' || !window.Audio || !window.URL) {
|
|
314
|
+
reject(new Error('Audio playback is not available'));
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (audioUrlReference.current) {
|
|
319
|
+
window.URL.revokeObjectURL(audioUrlReference.current);
|
|
320
|
+
audioUrlReference.current = null;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const audioUrl = window.URL.createObjectURL(audioBlob);
|
|
324
|
+
const audio = new Audio(audioUrl);
|
|
325
|
+
|
|
326
|
+
audioReference.current = audio;
|
|
327
|
+
audioUrlReference.current = audioUrl;
|
|
328
|
+
|
|
329
|
+
const clean = () => {
|
|
330
|
+
if (audioReference.current === audio) {
|
|
331
|
+
audioReference.current = null;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if (audioUrlReference.current === audioUrl) {
|
|
335
|
+
window.URL.revokeObjectURL(audioUrl);
|
|
336
|
+
audioUrlReference.current = null;
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
audio.onended = () => {
|
|
341
|
+
clean();
|
|
342
|
+
resolve();
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
audio.onpause = () => {
|
|
346
|
+
clean();
|
|
347
|
+
resolve();
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
audio.onerror = () => {
|
|
351
|
+
clean();
|
|
352
|
+
reject(new Error('Audio playback failed'));
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
audio.play().catch((error) => {
|
|
356
|
+
clean();
|
|
357
|
+
reject(error);
|
|
358
|
+
});
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function speakWithBrowser(text, speechReference) {
|
|
363
|
+
return new Promise((resolve, reject) => {
|
|
364
|
+
if (typeof window === 'undefined' || !window.speechSynthesis || !window.SpeechSynthesisUtterance) {
|
|
365
|
+
reject(new Error('Speech synthesis is not available'));
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
const utterance = new window.SpeechSynthesisUtterance(text);
|
|
370
|
+
|
|
371
|
+
utterance.lang = process.env.REACT_APP_TTS_LANG || 'en-US';
|
|
372
|
+
|
|
373
|
+
speechReference.current = utterance;
|
|
374
|
+
|
|
375
|
+
utterance.onend = () => {
|
|
376
|
+
if (speechReference.current === utterance) {
|
|
377
|
+
speechReference.current = null;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
resolve();
|
|
381
|
+
};
|
|
382
|
+
|
|
383
|
+
utterance.onerror = () => {
|
|
384
|
+
if (speechReference.current === utterance) {
|
|
385
|
+
speechReference.current = null;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
reject(new Error('Browser narration failed'));
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
window.speechSynthesis.cancel();
|
|
392
|
+
window.speechSynthesis.speak(utterance);
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
*
|
|
398
|
+
*/
|
|
399
|
+
export default function ProcessDashboard({ id, identifier, callback = () => { } }) {
|
|
400
|
+
|
|
401
|
+
const { user = { locations: [] } } = useContext(GlobalContext);
|
|
402
|
+
|
|
403
|
+
const [loading, setLoading] = useState(false);
|
|
404
|
+
|
|
405
|
+
const [process, setProcess] = useState([]);
|
|
406
|
+
|
|
407
|
+
const [transactionmodal, setTransactionmodal] = useState(false);
|
|
408
|
+
|
|
409
|
+
useEffect(() => {
|
|
410
|
+
|
|
411
|
+
// We have to load the process for the identified received as a property
|
|
412
|
+
|
|
413
|
+
// The process / steps are recorded specific to a an id which can be of any model .
|
|
414
|
+
getProcess();
|
|
415
|
+
|
|
416
|
+
return () => {
|
|
417
|
+
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
}, [])
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Get the process of an identifier
|
|
424
|
+
*
|
|
425
|
+
* @returns
|
|
426
|
+
*/
|
|
427
|
+
function getProcess() {
|
|
428
|
+
|
|
429
|
+
setLoading(true);
|
|
430
|
+
|
|
431
|
+
var queries = [{
|
|
432
|
+
field: 'modelIdentifier',
|
|
433
|
+
value: identifier
|
|
434
|
+
}]
|
|
435
|
+
|
|
436
|
+
// Get the process with the current status of an id passed .
|
|
437
|
+
return Process.getProcessTimeline({ identifier, id }).then((result) => {
|
|
438
|
+
|
|
439
|
+
setProcess(result);
|
|
440
|
+
|
|
441
|
+
console.log(result);
|
|
442
|
+
|
|
443
|
+
setLoading(false);
|
|
444
|
+
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Revert the modal
|
|
451
|
+
*/
|
|
452
|
+
function openRevertModal() {
|
|
453
|
+
|
|
454
|
+
setTransactionmodal(true);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Close the revert modal
|
|
460
|
+
*/
|
|
461
|
+
function closeRevertModal() {
|
|
462
|
+
setTransactionmodal(false);
|
|
463
|
+
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
return (<div className="process-dashboard card">
|
|
467
|
+
|
|
468
|
+
{/*
|
|
469
|
+
<div className="page-header">
|
|
470
|
+
|
|
471
|
+
<Title level={5}>
|
|
472
|
+
Process Dashboard
|
|
473
|
+
</Title>
|
|
474
|
+
|
|
475
|
+
<div className="actions">
|
|
476
|
+
|
|
477
|
+
{
|
|
478
|
+
user.isAdmin
|
|
479
|
+
&&
|
|
480
|
+
<Button size={'small'} onClick={() => { openRevertModal() }}>
|
|
481
|
+
<ReloadOutlined />
|
|
482
|
+
Revert
|
|
483
|
+
</Button>
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
</div>
|
|
487
|
+
</div> */}
|
|
488
|
+
|
|
489
|
+
{
|
|
490
|
+
loading
|
|
491
|
+
?
|
|
492
|
+
<>
|
|
493
|
+
|
|
494
|
+
<strong className="process-title">
|
|
495
|
+
Loading content ,
|
|
496
|
+
</strong>
|
|
497
|
+
|
|
498
|
+
<Skeleton />
|
|
499
|
+
</>
|
|
500
|
+
|
|
501
|
+
:
|
|
502
|
+
<>
|
|
503
|
+
|
|
504
|
+
{
|
|
505
|
+
process.map((records) => {
|
|
506
|
+
|
|
507
|
+
// If there is a process transaction record this process has started
|
|
508
|
+
let { process_transactions = [] } = records;
|
|
509
|
+
|
|
510
|
+
return (<>
|
|
511
|
+
|
|
512
|
+
<div className='page-header'>
|
|
513
|
+
<div>
|
|
514
|
+
|
|
515
|
+
<strong className="process-title">
|
|
516
|
+
{records.name}
|
|
517
|
+
</strong>
|
|
518
|
+
|
|
519
|
+
<p className="process-description">
|
|
520
|
+
<small>
|
|
521
|
+
{records.description}
|
|
522
|
+
</small>
|
|
523
|
+
</p>
|
|
524
|
+
</div>
|
|
525
|
+
|
|
526
|
+
<div className='actions'>
|
|
527
|
+
|
|
528
|
+
<CopyToClipBoard id={records.id} record={records} />
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
{
|
|
532
|
+
user.isAdmin
|
|
533
|
+
&&
|
|
534
|
+
<Button size={'small'} onClick={() => { openRevertModal() }}>
|
|
535
|
+
<ReloadOutlined />
|
|
536
|
+
Revert
|
|
537
|
+
</Button>
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
</div>
|
|
541
|
+
|
|
542
|
+
</div>
|
|
543
|
+
|
|
544
|
+
{
|
|
545
|
+
process_transactions.length
|
|
546
|
+
?
|
|
547
|
+
<small className='timeline'>
|
|
548
|
+
{/* {DateUtils.displayFirestoreTime(process_transactions[0].start_time)} - {process_transactions[0].completed ? DateUtils.displayFirestoreTime(process_transactions[0].end_time) : 'Pending'} */}
|
|
549
|
+
</small>
|
|
550
|
+
:
|
|
551
|
+
null
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
<Timeline className="process-timeline">
|
|
555
|
+
|
|
556
|
+
{/* Steps List */}
|
|
557
|
+
<StepsList id={id} steps={records.steps} callback={getProcess} />
|
|
558
|
+
{/* Steps List Ends */}
|
|
559
|
+
|
|
560
|
+
</Timeline>
|
|
561
|
+
</>)
|
|
562
|
+
})
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
{/* Add Modal */}
|
|
566
|
+
<Modal destroyOnClose confirmLoading={loading} title="Revert" visible={transactionmodal} onCancel={() => { closeRevertModal() }} footer={null}>
|
|
567
|
+
|
|
568
|
+
<RevertProcessTransaction id={id} process={process} callback={() => {
|
|
569
|
+
|
|
570
|
+
closeRevertModal()
|
|
571
|
+
}} />
|
|
572
|
+
|
|
573
|
+
</Modal>
|
|
574
|
+
{/* Add Modal Ends */}
|
|
575
|
+
|
|
576
|
+
</>
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
</div >)
|
|
580
|
+
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* The Timeline item that displays a step
|
|
585
|
+
*/
|
|
586
|
+
function StepTimelineItem({ id, color, Icon, step, step_transactions, callback }) {
|
|
587
|
+
|
|
588
|
+
const [body, setBody] = useState({});
|
|
589
|
+
|
|
590
|
+
const [visible, setVisible] = useState(false);
|
|
591
|
+
|
|
592
|
+
const [loading, setLoading] = useState(false);
|
|
593
|
+
|
|
594
|
+
const [narrating, setNarrating] = useState(false);
|
|
595
|
+
|
|
596
|
+
const { user = { locations: [] } } = useContext(GlobalContext);
|
|
597
|
+
|
|
598
|
+
const audioReference = useRef(null);
|
|
599
|
+
|
|
600
|
+
const audioUrlReference = useRef(null);
|
|
601
|
+
|
|
602
|
+
const speechReference = useRef(null);
|
|
603
|
+
|
|
604
|
+
const narrationSessionReference = useRef(0);
|
|
605
|
+
|
|
606
|
+
const fallbackNoticeShownReference = useRef(false);
|
|
607
|
+
|
|
608
|
+
useEffect(() => {
|
|
609
|
+
return () => {
|
|
610
|
+
stopNarration();
|
|
611
|
+
}
|
|
612
|
+
}, [])
|
|
613
|
+
|
|
614
|
+
/**
|
|
615
|
+
* Stop active narration audio
|
|
616
|
+
*/
|
|
617
|
+
function stopNarration() {
|
|
618
|
+
narrationSessionReference.current += 1;
|
|
619
|
+
|
|
620
|
+
if (audioReference.current) {
|
|
621
|
+
audioReference.current.pause();
|
|
622
|
+
audioReference.current.src = '';
|
|
623
|
+
audioReference.current = null;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
if (audioUrlReference.current && typeof window !== 'undefined' && window.URL) {
|
|
627
|
+
window.URL.revokeObjectURL(audioUrlReference.current);
|
|
628
|
+
audioUrlReference.current = null;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
if (typeof window !== 'undefined' && window.speechSynthesis) {
|
|
632
|
+
window.speechSynthesis.cancel();
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
speechReference.current = null;
|
|
636
|
+
setNarrating(false);
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
* Narrate the current step with ElevenLabs/Gemini TTS only (no browser fallback).
|
|
641
|
+
*/
|
|
642
|
+
async function narrateStep() {
|
|
643
|
+
const narration = getStepNarration({ step, step_transactions });
|
|
644
|
+
|
|
645
|
+
if (!narration) {
|
|
646
|
+
message.warning('Narration text is not available for this step.');
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
stopNarration();
|
|
651
|
+
|
|
652
|
+
const sessionId = narrationSessionReference.current;
|
|
653
|
+
const hasElevenLabsKey = Boolean(getElevenLabsApiKey());
|
|
654
|
+
|
|
655
|
+
setNarrating(true);
|
|
656
|
+
|
|
657
|
+
try {
|
|
658
|
+
let aiNarrationComplete = false;
|
|
659
|
+
let aiNarrationError = null;
|
|
660
|
+
|
|
661
|
+
if (hasElevenLabsKey) {
|
|
662
|
+
try {
|
|
663
|
+
const audioBlob = await synthesizeElevenLabsAudio(narration);
|
|
664
|
+
|
|
665
|
+
if (sessionId !== narrationSessionReference.current) {
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
await playAudioBlob(audioBlob, audioReference, audioUrlReference);
|
|
670
|
+
aiNarrationComplete = true;
|
|
671
|
+
} catch (elevenLabsError) {
|
|
672
|
+
aiNarrationError = elevenLabsError;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
if (!aiNarrationComplete) {
|
|
677
|
+
try {
|
|
678
|
+
const dataUri = await synthesizeGeminiAudio(narration);
|
|
679
|
+
|
|
680
|
+
if (sessionId !== narrationSessionReference.current) {
|
|
681
|
+
return;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
await playAudioDataUri(dataUri, audioReference);
|
|
685
|
+
aiNarrationComplete = true;
|
|
686
|
+
} catch (geminiError) {
|
|
687
|
+
aiNarrationError = geminiError;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
if (!aiNarrationComplete) {
|
|
692
|
+
throw aiNarrationError || new Error('AI narration unavailable');
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
} catch (error) {
|
|
696
|
+
if (sessionId !== narrationSessionReference.current) {
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
if (!fallbackNoticeShownReference.current) {
|
|
701
|
+
message.warning(`${hasElevenLabsKey ? 'ElevenLabs/Gemini' : 'Gemini'} narration unavailable.`);
|
|
702
|
+
fallbackNoticeShownReference.current = true;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
message.error(error?.message || 'Unable to play narration for this step.');
|
|
706
|
+
} finally {
|
|
707
|
+
if (sessionId === narrationSessionReference.current) {
|
|
708
|
+
setNarrating(false);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
/**
|
|
714
|
+
* Function to open editModal for Step
|
|
715
|
+
*
|
|
716
|
+
* @param {*} step
|
|
717
|
+
*/
|
|
718
|
+
function openEditModal(step) {
|
|
719
|
+
|
|
720
|
+
setVisible(true);
|
|
721
|
+
|
|
722
|
+
setBody(step)
|
|
723
|
+
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
/**
|
|
727
|
+
*
|
|
728
|
+
* @param {*} step
|
|
729
|
+
*/
|
|
730
|
+
async function startStep(step) {
|
|
731
|
+
|
|
732
|
+
// Batch
|
|
733
|
+
let app = Process.getFireStoreApp();
|
|
734
|
+
|
|
735
|
+
// Starting a batched write
|
|
736
|
+
let batch = app.batch();
|
|
737
|
+
|
|
738
|
+
let body = {
|
|
739
|
+
record_id: id,
|
|
740
|
+
model_identifer: 'Candidates'
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
await Process.startStepBatch({ batch, step, body });
|
|
744
|
+
|
|
745
|
+
await batch.commit();
|
|
746
|
+
|
|
747
|
+
message.success("Step Started");
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
/**
|
|
751
|
+
*
|
|
752
|
+
* @param {*} step
|
|
753
|
+
*/
|
|
754
|
+
async function completeStep(step) {
|
|
755
|
+
|
|
756
|
+
// Batch
|
|
757
|
+
let app = Process.getFireStoreApp();
|
|
758
|
+
|
|
759
|
+
// Starting a batched write
|
|
760
|
+
let batch = app.batch();
|
|
761
|
+
|
|
762
|
+
let body = {
|
|
763
|
+
record_id: id,
|
|
764
|
+
model_identifer: 'Candidates'
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
await Process.stopStepBatch({ batch, step, body });
|
|
768
|
+
|
|
769
|
+
message.success("Step Ended");
|
|
770
|
+
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
/**
|
|
774
|
+
*
|
|
775
|
+
* @param {*} step
|
|
776
|
+
*/
|
|
777
|
+
function closeModal() {
|
|
778
|
+
|
|
779
|
+
setVisible(false);
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
|
|
783
|
+
return (<Timeline.Item color={color} dot={<Icon />} >
|
|
784
|
+
|
|
785
|
+
{/* Timeline Step Template */}
|
|
786
|
+
<div className="timeline-content">
|
|
787
|
+
|
|
788
|
+
<p className={'timeline-title'}>
|
|
789
|
+
{step.name}
|
|
790
|
+
|
|
791
|
+
<p className={'timeline-description'}>
|
|
792
|
+
<small>
|
|
793
|
+
{step.description}
|
|
794
|
+
</small>
|
|
795
|
+
</p>
|
|
796
|
+
</p>
|
|
797
|
+
|
|
798
|
+
{/* Actions for a step */}
|
|
799
|
+
<div className="actions">
|
|
800
|
+
|
|
801
|
+
<Button size={'small'} onClick={() => {
|
|
802
|
+
if (narrating) {
|
|
803
|
+
stopNarration();
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
narrateStep();
|
|
808
|
+
}}>
|
|
809
|
+
|
|
810
|
+
{narrating ? <PauseCircleOutlined /> : <SoundOutlined />}
|
|
811
|
+
|
|
812
|
+
{narrating ? 'Stop Narration' : 'Narrate'}
|
|
813
|
+
|
|
814
|
+
</Button>
|
|
815
|
+
|
|
816
|
+
{user.isAdmin && <>
|
|
817
|
+
|
|
818
|
+
<CopyToClipBoard record={step} id={step.id} />
|
|
819
|
+
|
|
820
|
+
<Button size={'small'} onClick={() => { openEditModal(step) }}>
|
|
821
|
+
|
|
822
|
+
<EditOutlined />
|
|
823
|
+
|
|
824
|
+
Edit
|
|
825
|
+
|
|
826
|
+
</Button>
|
|
827
|
+
|
|
828
|
+
<Button size={'small'} onClick={() => { startStep(step) }}>
|
|
829
|
+
|
|
830
|
+
Start
|
|
831
|
+
|
|
832
|
+
</Button>
|
|
833
|
+
|
|
834
|
+
<Button size={'small'} onClick={() => { completeStep(step) }}>
|
|
835
|
+
|
|
836
|
+
Complete
|
|
837
|
+
|
|
838
|
+
</Button>
|
|
839
|
+
|
|
840
|
+
</>}
|
|
841
|
+
|
|
842
|
+
</div>
|
|
843
|
+
{/* Actions for a step Ends */}
|
|
844
|
+
|
|
845
|
+
</div>
|
|
846
|
+
{/* Timeline Step Template Ends */}
|
|
847
|
+
|
|
848
|
+
{/* Summary of Step Activity */}
|
|
849
|
+
<TaskStatus id={id} color={color} step={step} step_transactions={step_transactions} />
|
|
850
|
+
{/* Summary of Step Activity Ends */}
|
|
851
|
+
|
|
852
|
+
{/* Form for the Step */}
|
|
853
|
+
{step.formEnabled && <Card className="task-form-card">
|
|
854
|
+
|
|
855
|
+
<h1>
|
|
856
|
+
Form Enabled Value {step.formEnabled} - {step.name}
|
|
857
|
+
|
|
858
|
+
</h1>
|
|
859
|
+
|
|
860
|
+
<TaskForm
|
|
861
|
+
record_id={id}
|
|
862
|
+
step={step}
|
|
863
|
+
|
|
864
|
+
callback={callback}
|
|
865
|
+
|
|
866
|
+
/>
|
|
867
|
+
|
|
868
|
+
</Card>}
|
|
869
|
+
{/* Form for the Step Ends */}
|
|
870
|
+
|
|
871
|
+
|
|
872
|
+
{
|
|
873
|
+
step.sub_steps.length ?
|
|
874
|
+
<>
|
|
875
|
+
<Timeline className="process-timeline">
|
|
876
|
+
|
|
877
|
+
<StepsList id={id} steps={step.sub_steps} />
|
|
878
|
+
|
|
879
|
+
</Timeline>
|
|
880
|
+
</>
|
|
881
|
+
:
|
|
882
|
+
null
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
|
|
886
|
+
{/* Add Modal */}
|
|
887
|
+
<Modal destroyOnClose confirmLoading={loading} title="Edit Step" visible={visible} onCancel={() => { closeModal() }} footer={null}>
|
|
888
|
+
<Steps.ModalAddComponent
|
|
889
|
+
// match={match}
|
|
890
|
+
model={Steps}
|
|
891
|
+
additional_queries={[]}
|
|
892
|
+
formContent={body}
|
|
893
|
+
|
|
894
|
+
callback={() => {
|
|
895
|
+
closeModal(true);
|
|
896
|
+
}}
|
|
897
|
+
/>
|
|
898
|
+
</Modal>
|
|
899
|
+
{/* Add Modal Ends */}
|
|
900
|
+
|
|
901
|
+
{/* </>
|
|
902
|
+
} */}
|
|
903
|
+
|
|
904
|
+
</Timeline.Item>)
|
|
905
|
+
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
|
|
909
|
+
/**
|
|
910
|
+
* List of Steps inside a Timline
|
|
911
|
+
*/
|
|
912
|
+
function StepsList({ id, steps = [], callback }) {
|
|
913
|
+
|
|
914
|
+
return (<>
|
|
915
|
+
|
|
916
|
+
{
|
|
917
|
+
steps.map((step) => {
|
|
918
|
+
|
|
919
|
+
let color = stepMaster[step.current_state].color;
|
|
920
|
+
|
|
921
|
+
let Icon = stepMaster[step.current_state].icon;
|
|
922
|
+
|
|
923
|
+
let step_transactions = false;
|
|
924
|
+
|
|
925
|
+
if (step.step_transactions && step.step_transactions.length) {
|
|
926
|
+
|
|
927
|
+
step_transactions = step.step_transactions[0];
|
|
928
|
+
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
return (<>
|
|
932
|
+
|
|
933
|
+
{/* Details of the step */}
|
|
934
|
+
<StepTimelineItem
|
|
935
|
+
id={id}
|
|
936
|
+
color={color}
|
|
937
|
+
Icon={Icon}
|
|
938
|
+
step={step}
|
|
939
|
+
step_transactions={step_transactions}
|
|
940
|
+
|
|
941
|
+
callback={callback}
|
|
942
|
+
/>
|
|
943
|
+
{/* Details of the step Ends */}
|
|
944
|
+
|
|
945
|
+
|
|
946
|
+
{/* Form for the Step */}
|
|
947
|
+
{/* {step.formEnabled && <Card className="task-form-card">
|
|
948
|
+
|
|
949
|
+
<h1>
|
|
950
|
+
Form Enabled Value {step.formEnabled} - {step.name}
|
|
951
|
+
|
|
952
|
+
</h1>
|
|
953
|
+
|
|
954
|
+
<TaskForm
|
|
955
|
+
record_id={id}
|
|
956
|
+
step={step}
|
|
957
|
+
|
|
958
|
+
// callback={callback}
|
|
959
|
+
|
|
960
|
+
/>
|
|
961
|
+
|
|
962
|
+
</Card>} */}
|
|
963
|
+
{/* Form for the Step Ends */}
|
|
964
|
+
|
|
965
|
+
</>)
|
|
966
|
+
})
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
</>)
|
|
970
|
+
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
|
|
974
|
+
|
|
975
|
+
|
|
976
|
+
/**
|
|
977
|
+
*
|
|
978
|
+
*
|
|
979
|
+
* @returns
|
|
980
|
+
*/
|
|
981
|
+
function RevertProcessTransaction({ id, process = [], callback }) {
|
|
982
|
+
|
|
983
|
+
// const form = useRef(null)
|
|
984
|
+
|
|
985
|
+
const [loading, setLoading] = useState(false);
|
|
986
|
+
|
|
987
|
+
const [processtransactions, setProcesstransactions] = useState([])
|
|
988
|
+
|
|
989
|
+
useEffect(() => {
|
|
990
|
+
|
|
991
|
+
getProcessTransaction();
|
|
992
|
+
|
|
993
|
+
return () => {
|
|
994
|
+
}
|
|
995
|
+
}, [])
|
|
996
|
+
|
|
997
|
+
/**
|
|
998
|
+
*
|
|
999
|
+
* @returns
|
|
1000
|
+
*/
|
|
1001
|
+
function getProcessTransaction() {
|
|
1002
|
+
|
|
1003
|
+
var queries = [{ field: 'record_id', value: id }];
|
|
1004
|
+
|
|
1005
|
+
return ProcessTransactions.get(queries).then(({ process_transactions }) => {
|
|
1006
|
+
|
|
1007
|
+
setProcesstransactions(process_transactions);
|
|
1008
|
+
|
|
1009
|
+
console.log(process_transactions);
|
|
1010
|
+
|
|
1011
|
+
})
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
/**
|
|
1015
|
+
* On Submit of form , Change the process transaction to specific step
|
|
1016
|
+
*/
|
|
1017
|
+
function onSubmit(values) {
|
|
1018
|
+
|
|
1019
|
+
// Batch
|
|
1020
|
+
let app = Process.getFireStoreApp();
|
|
1021
|
+
|
|
1022
|
+
// Starting a batched write
|
|
1023
|
+
let batch = app.batch();
|
|
1024
|
+
|
|
1025
|
+
setLoading(true);
|
|
1026
|
+
|
|
1027
|
+
console.log(values);
|
|
1028
|
+
|
|
1029
|
+
Process.triggerProcessBatch(batch, values.process_id, {}, processtransactions[0].id).then(() => {
|
|
1030
|
+
|
|
1031
|
+
message.success("Reverted case to ", values.process_id);
|
|
1032
|
+
|
|
1033
|
+
setLoading(false);
|
|
1034
|
+
|
|
1035
|
+
callback();
|
|
1036
|
+
|
|
1037
|
+
})
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
return (<>
|
|
1041
|
+
|
|
1042
|
+
<Title level={4}>
|
|
1043
|
+
Revert Step
|
|
1044
|
+
</Title>
|
|
1045
|
+
|
|
1046
|
+
<Form
|
|
1047
|
+
// form={form}
|
|
1048
|
+
layout="vertical"
|
|
1049
|
+
onFinish={onSubmit}>
|
|
1050
|
+
|
|
1051
|
+
<Form.Item label="Process" name="process_id" required>
|
|
1052
|
+
<Select style={{ width: '100%' }}>
|
|
1053
|
+
|
|
1054
|
+
{process.map((staff) => <Option value={staff.id}>{staff.name}</Option>)}
|
|
1055
|
+
|
|
1056
|
+
</Select>
|
|
1057
|
+
</Form.Item>
|
|
1058
|
+
|
|
1059
|
+
<Form.Item >
|
|
1060
|
+
<Button loading={loading} type="primary" htmlType="submit">
|
|
1061
|
+
Submit
|
|
1062
|
+
</Button>
|
|
1063
|
+
</Form.Item>
|
|
1064
|
+
|
|
1065
|
+
</Form>
|
|
1066
|
+
</>)
|
|
1067
|
+
|
|
1068
|
+
}
|