@acorex/modules 20.0.6 → 20.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/common/index.d.ts +22 -2
- package/contact-management/README.md +568 -0
- package/contact-management/index.d.ts +263 -0
- package/conversation/index.d.ts +222 -189
- package/document-management/index.d.ts +5 -1
- package/fesm2022/{acorex-modules-application-management-module-designer.component-oGgCaUDu.mjs → acorex-modules-application-management-module-designer.component-BErRgx0w.mjs} +7 -7
- package/fesm2022/{acorex-modules-application-management-module-designer.component-oGgCaUDu.mjs.map → acorex-modules-application-management-module-designer.component-BErRgx0w.mjs.map} +1 -1
- package/fesm2022/acorex-modules-application-management.mjs +41 -42
- package/fesm2022/acorex-modules-application-management.mjs.map +1 -1
- package/fesm2022/{acorex-modules-auth-acorex-modules-auth-Cj4td3eM.mjs → acorex-modules-auth-acorex-modules-auth-X866H4oy.mjs} +44 -44
- package/fesm2022/acorex-modules-auth-acorex-modules-auth-X866H4oy.mjs.map +1 -0
- package/fesm2022/{acorex-modules-auth-app-chooser.component-C60idNYx.mjs → acorex-modules-auth-app-chooser.component-DqKTfLA2.mjs} +5 -5
- package/fesm2022/{acorex-modules-auth-app-chooser.component-C60idNYx.mjs.map → acorex-modules-auth-app-chooser.component-DqKTfLA2.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-auth-blank.layout-C5d42pO1.mjs → acorex-modules-auth-blank.layout-D2qSgxTy.mjs} +4 -4
- package/fesm2022/{acorex-modules-auth-blank.layout-C5d42pO1.mjs.map → acorex-modules-auth-blank.layout-D2qSgxTy.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-auth-login.module-siRdi16m.mjs → acorex-modules-auth-login.module-CWOYzn0L.mjs} +8 -8
- package/fesm2022/{acorex-modules-auth-login.module-siRdi16m.mjs.map → acorex-modules-auth-login.module-CWOYzn0L.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-auth-master.layout-BJCAe5Ai.mjs → acorex-modules-auth-master.layout-384T0lIg.mjs} +5 -5
- package/fesm2022/{acorex-modules-auth-master.layout-BJCAe5Ai.mjs.map → acorex-modules-auth-master.layout-384T0lIg.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-auth-password.component-VhDUmkMc.mjs → acorex-modules-auth-password.component-BW_ooTQG.mjs} +5 -5
- package/fesm2022/{acorex-modules-auth-password.component-VhDUmkMc.mjs.map → acorex-modules-auth-password.component-BW_ooTQG.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-auth-password.component-6-EEsfc2.mjs → acorex-modules-auth-password.component-JG95JpLz.mjs} +5 -5
- package/fesm2022/{acorex-modules-auth-password.component-6-EEsfc2.mjs.map → acorex-modules-auth-password.component-JG95JpLz.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-auth-routes-BwBn4o81.mjs → acorex-modules-auth-routes-DqKtHu-i.mjs} +2 -2
- package/fesm2022/{acorex-modules-auth-routes-BwBn4o81.mjs.map → acorex-modules-auth-routes-DqKtHu-i.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-auth-tenant-chooser.component-fmuXNByb.mjs → acorex-modules-auth-tenant-chooser.component-C0jxaqqg.mjs} +4 -4
- package/fesm2022/{acorex-modules-auth-tenant-chooser.component-fmuXNByb.mjs.map → acorex-modules-auth-tenant-chooser.component-C0jxaqqg.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-auth-two-factor-code.component-JYtAQ3qF.mjs → acorex-modules-auth-two-factor-code.component-D7KOomHD.mjs} +4 -4
- package/fesm2022/{acorex-modules-auth-two-factor-code.component-JYtAQ3qF.mjs.map → acorex-modules-auth-two-factor-code.component-D7KOomHD.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-auth-two-factor.module-D7NgZHmC.mjs → acorex-modules-auth-two-factor.module-C88pXqao.mjs} +7 -7
- package/fesm2022/{acorex-modules-auth-two-factor.module-D7NgZHmC.mjs.map → acorex-modules-auth-two-factor.module-C88pXqao.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-auth-user-sessions.component-DhlBCxly.mjs → acorex-modules-auth-user-sessions.component-loloVwv0.mjs} +5 -5
- package/fesm2022/{acorex-modules-auth-user-sessions.component-DhlBCxly.mjs.map → acorex-modules-auth-user-sessions.component-loloVwv0.mjs.map} +1 -1
- package/fesm2022/acorex-modules-auth.mjs +1 -1
- package/fesm2022/{acorex-modules-common-search-popup.component-B5JU9uH9.mjs → acorex-modules-common-search-popup.component-CCKiQx0U.mjs} +8 -8
- package/fesm2022/{acorex-modules-common-search-popup.component-B5JU9uH9.mjs.map → acorex-modules-common-search-popup.component-CCKiQx0U.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-common-timeline-version-history-popup.component-DzvUTy5z.mjs → acorex-modules-common-timeline-version-history-popup.component-DJOcjquG.mjs} +8 -8
- package/fesm2022/{acorex-modules-common-timeline-version-history-popup.component-DzvUTy5z.mjs.map → acorex-modules-common-timeline-version-history-popup.component-DJOcjquG.mjs.map} +1 -1
- package/fesm2022/acorex-modules-common.mjs +215 -86
- package/fesm2022/acorex-modules-common.mjs.map +1 -1
- package/fesm2022/acorex-modules-contact-management-address-type.entity-QMEODkhx.mjs +489 -0
- package/fesm2022/acorex-modules-contact-management-address-type.entity-QMEODkhx.mjs.map +1 -0
- package/fesm2022/acorex-modules-contact-management-contact-address.entity-0f4Vaw_k.mjs +827 -0
- package/fesm2022/acorex-modules-contact-management-contact-address.entity-0f4Vaw_k.mjs.map +1 -0
- package/fesm2022/acorex-modules-contact-management-contact-method.entity-ChEz1jW0.mjs +509 -0
- package/fesm2022/acorex-modules-contact-management-contact-method.entity-ChEz1jW0.mjs.map +1 -0
- package/fesm2022/acorex-modules-contact-management-contact-relationship.entity-DLfiEEfk.mjs +469 -0
- package/fesm2022/acorex-modules-contact-management-contact-relationship.entity-DLfiEEfk.mjs.map +1 -0
- package/fesm2022/acorex-modules-contact-management-contact-source.entity-hopVxiIT.mjs +489 -0
- package/fesm2022/acorex-modules-contact-management-contact-source.entity-hopVxiIT.mjs.map +1 -0
- package/fesm2022/acorex-modules-contact-management.mjs +2332 -0
- package/fesm2022/acorex-modules-contact-management.mjs.map +1 -0
- package/fesm2022/acorex-modules-content-management.mjs +119 -55
- package/fesm2022/acorex-modules-content-management.mjs.map +1 -1
- package/fesm2022/acorex-modules-conversation.mjs +1174 -1216
- package/fesm2022/acorex-modules-conversation.mjs.map +1 -1
- package/fesm2022/acorex-modules-dashboard-management.mjs +76 -76
- package/fesm2022/acorex-modules-dashboard-management.mjs.map +1 -1
- package/fesm2022/{acorex-modules-document-management-acorex-modules-document-management-ClH75xx1.mjs → acorex-modules-document-management-acorex-modules-document-management-C4cvhxSV.mjs} +310 -235
- package/fesm2022/acorex-modules-document-management-acorex-modules-document-management-C4cvhxSV.mjs.map +1 -0
- package/fesm2022/{acorex-modules-document-management-attachment-widget.component-B_tjfzIn.mjs → acorex-modules-document-management-attachment-widget.component-B5txg8z0.mjs} +5 -5
- package/fesm2022/{acorex-modules-document-management-attachment-widget.component-B_tjfzIn.mjs.map → acorex-modules-document-management-attachment-widget.component-B5txg8z0.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-document-management-create-folder-dialog.component-DNdRcCAs.mjs → acorex-modules-document-management-create-folder-dialog.component-LfnTz49a.mjs} +5 -5
- package/fesm2022/{acorex-modules-document-management-create-folder-dialog.component-DNdRcCAs.mjs.map → acorex-modules-document-management-create-folder-dialog.component-LfnTz49a.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-document-management-details-view.component-JsK1UgZh.mjs → acorex-modules-document-management-details-view.component-Co5F8eWp.mjs} +5 -5
- package/fesm2022/{acorex-modules-document-management-details-view.component-JsK1UgZh.mjs.map → acorex-modules-document-management-details-view.component-Co5F8eWp.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-document-management-drive-choose.component-DJT9oLek.mjs → acorex-modules-document-management-drive-choose.component-DFRdS7s1.mjs} +5 -5
- package/fesm2022/{acorex-modules-document-management-drive-choose.component-DJT9oLek.mjs.map → acorex-modules-document-management-drive-choose.component-DFRdS7s1.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-document-management-drive.component-DYxpvUWX.mjs → acorex-modules-document-management-drive.component-jGs09Jrd.mjs} +8 -8
- package/fesm2022/{acorex-modules-document-management-drive.component-DYxpvUWX.mjs.map → acorex-modules-document-management-drive.component-jGs09Jrd.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-document-management-large-icons-view.component-B324V2hL.mjs → acorex-modules-document-management-large-icons-view.component-DD9_xgL4.mjs} +5 -5
- package/fesm2022/{acorex-modules-document-management-large-icons-view.component-B324V2hL.mjs.map → acorex-modules-document-management-large-icons-view.component-DD9_xgL4.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-document-management-large-tiles-view.component-V5gHyu9X.mjs → acorex-modules-document-management-large-tiles-view.component-CNBUzaUz.mjs} +5 -5
- package/fesm2022/{acorex-modules-document-management-large-tiles-view.component-V5gHyu9X.mjs.map → acorex-modules-document-management-large-tiles-view.component-CNBUzaUz.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-document-management-link-dialog.component-B-BzU_4Y.mjs → acorex-modules-document-management-link-dialog.component-CXzR7mUW.mjs} +4 -4
- package/fesm2022/{acorex-modules-document-management-link-dialog.component-B-BzU_4Y.mjs.map → acorex-modules-document-management-link-dialog.component-CXzR7mUW.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-document-management-list-view.component-Bm2EH2aT.mjs → acorex-modules-document-management-list-view.component-D4DbyB6W.mjs} +5 -5
- package/fesm2022/{acorex-modules-document-management-list-view.component-Bm2EH2aT.mjs.map → acorex-modules-document-management-list-view.component-D4DbyB6W.mjs.map} +1 -1
- package/fesm2022/acorex-modules-document-management-meta-choose-popup.component-CmMvrfKW.mjs +315 -0
- package/fesm2022/acorex-modules-document-management-meta-choose-popup.component-CmMvrfKW.mjs.map +1 -0
- package/fesm2022/{acorex-modules-document-management-meta-selector-widget-column.component-BDhqsc2j.mjs → acorex-modules-document-management-meta-selector-widget-column.component-DHQjyq8s.mjs} +4 -4
- package/fesm2022/{acorex-modules-document-management-meta-selector-widget-column.component-BDhqsc2j.mjs.map → acorex-modules-document-management-meta-selector-widget-column.component-DHQjyq8s.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-document-management-meta-selector-widget-designer.component-C4GC0GbF.mjs → acorex-modules-document-management-meta-selector-widget-designer.component-Cc6n71wn.mjs} +4 -4
- package/fesm2022/{acorex-modules-document-management-meta-selector-widget-designer.component-C4GC0GbF.mjs.map → acorex-modules-document-management-meta-selector-widget-designer.component-Cc6n71wn.mjs.map} +1 -1
- package/fesm2022/acorex-modules-document-management-meta-selector-widget-view.component-D88h9eR6.mjs +31 -0
- package/fesm2022/acorex-modules-document-management-meta-selector-widget-view.component-D88h9eR6.mjs.map +1 -0
- package/fesm2022/{acorex-modules-document-management-permission-definition.provider-DGqVDVLJ.mjs → acorex-modules-document-management-permission-definition.provider-DoOyhnwQ.mjs} +2 -2
- package/fesm2022/{acorex-modules-document-management-permission-definition.provider-DGqVDVLJ.mjs.map → acorex-modules-document-management-permission-definition.provider-DoOyhnwQ.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-document-management-rename-node-dialog.component-LgpvDguk.mjs → acorex-modules-document-management-rename-node-dialog.component-JDZWsFXL.mjs} +5 -5
- package/fesm2022/{acorex-modules-document-management-rename-node-dialog.component-LgpvDguk.mjs.map → acorex-modules-document-management-rename-node-dialog.component-JDZWsFXL.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-document-management-share-dialog.component-DzuYhAD4.mjs → acorex-modules-document-management-share-dialog.component-DTzXwqHw.mjs} +4 -4
- package/fesm2022/{acorex-modules-document-management-share-dialog.component-DzuYhAD4.mjs.map → acorex-modules-document-management-share-dialog.component-DTzXwqHw.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-document-management-share-email-dialog.component-DNN_3JF2.mjs → acorex-modules-document-management-share-email-dialog.component-BaNzKKG4.mjs} +4 -4
- package/fesm2022/{acorex-modules-document-management-share-email-dialog.component-DNN_3JF2.mjs.map → acorex-modules-document-management-share-email-dialog.component-BaNzKKG4.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-document-management-small-icons-view.component-BwFoe1vd.mjs → acorex-modules-document-management-small-icons-view.component-BNTmgtYr.mjs} +5 -5
- package/fesm2022/{acorex-modules-document-management-small-icons-view.component-BwFoe1vd.mjs.map → acorex-modules-document-management-small-icons-view.component-BNTmgtYr.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-document-management-small-tiles-view.component-B5gp0wus.mjs → acorex-modules-document-management-small-tiles-view.component-CbCBAKyR.mjs} +5 -5
- package/fesm2022/{acorex-modules-document-management-small-tiles-view.component-B5gp0wus.mjs.map → acorex-modules-document-management-small-tiles-view.component-CbCBAKyR.mjs.map} +1 -1
- package/fesm2022/acorex-modules-document-management.mjs +1 -1
- package/fesm2022/{acorex-modules-form-template-management-acorex-modules-form-template-management-B3o427If.mjs → acorex-modules-form-template-management-acorex-modules-form-template-management-BsAsK1EG.mjs} +58 -57
- package/fesm2022/{acorex-modules-form-template-management-acorex-modules-form-template-management-B3o427If.mjs.map → acorex-modules-form-template-management-acorex-modules-form-template-management-BsAsK1EG.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-form-template-management-category.entity-B7dGrmoa.mjs → acorex-modules-form-template-management-category.entity-B3iAtREq.mjs} +2 -2
- package/fesm2022/{acorex-modules-form-template-management-category.entity-B7dGrmoa.mjs.map → acorex-modules-form-template-management-category.entity-B3iAtREq.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-form-template-management-designer.page-DaTGU3w_.mjs → acorex-modules-form-template-management-designer.page-B-TIUKl7.mjs} +4 -4
- package/fesm2022/{acorex-modules-form-template-management-designer.page-DaTGU3w_.mjs.map → acorex-modules-form-template-management-designer.page-B-TIUKl7.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-form-template-management-permission-definition.provider-CjjlgO0w.mjs → acorex-modules-form-template-management-permission-definition.provider-CTG95UDp.mjs} +2 -2
- package/fesm2022/{acorex-modules-form-template-management-permission-definition.provider-CjjlgO0w.mjs.map → acorex-modules-form-template-management-permission-definition.provider-CTG95UDp.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-form-template-management-settings.provider-CiSjuHGI.mjs → acorex-modules-form-template-management-settings.provider-BmFufTUd.mjs} +2 -2
- package/fesm2022/{acorex-modules-form-template-management-settings.provider-CiSjuHGI.mjs.map → acorex-modules-form-template-management-settings.provider-BmFufTUd.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-form-template-management-template-picker.component-CQZ37yC2.mjs → acorex-modules-form-template-management-template-picker.component-CNwhdnGC.mjs} +4 -4
- package/fesm2022/{acorex-modules-form-template-management-template-picker.component-CQZ37yC2.mjs.map → acorex-modules-form-template-management-template-picker.component-CNwhdnGC.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-form-template-management-template-widget-edit.component-DUeV0yO8.mjs → acorex-modules-form-template-management-template-widget-edit.component-BNIx16WW.mjs} +5 -5
- package/fesm2022/{acorex-modules-form-template-management-template-widget-edit.component-DUeV0yO8.mjs.map → acorex-modules-form-template-management-template-widget-edit.component-BNIx16WW.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-form-template-management-template.entity-Cps77n3G.mjs → acorex-modules-form-template-management-template.entity-BGsixiEI.mjs} +2 -2
- package/fesm2022/{acorex-modules-form-template-management-template.entity-Cps77n3G.mjs.map → acorex-modules-form-template-management-template.entity-BGsixiEI.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-form-template-management-viewer-popup.component-K2ZznaDw.mjs → acorex-modules-form-template-management-viewer-popup.component-CzjuUz4o.mjs} +9 -6
- package/fesm2022/acorex-modules-form-template-management-viewer-popup.component-CzjuUz4o.mjs.map +1 -0
- package/fesm2022/acorex-modules-form-template-management.mjs +1 -1
- package/fesm2022/{acorex-modules-issue-management-acorex-modules-issue-management-Blyh8QVB.mjs → acorex-modules-issue-management-acorex-modules-issue-management-C2JoHgaa.mjs} +24 -24
- package/fesm2022/{acorex-modules-issue-management-acorex-modules-issue-management-Blyh8QVB.mjs.map → acorex-modules-issue-management-acorex-modules-issue-management-C2JoHgaa.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-issue-management-capture-screen.component-BzUN6Cty.mjs → acorex-modules-issue-management-capture-screen.component-DTtUkL78.mjs} +5 -5
- package/fesm2022/{acorex-modules-issue-management-capture-screen.component-BzUN6Cty.mjs.map → acorex-modules-issue-management-capture-screen.component-DTtUkL78.mjs.map} +1 -1
- package/fesm2022/acorex-modules-issue-management.mjs +1 -1
- package/fesm2022/acorex-modules-log-management.mjs +10 -10
- package/fesm2022/acorex-modules-log-management.mjs.map +1 -1
- package/fesm2022/acorex-modules-notification-management.mjs +35 -35
- package/fesm2022/acorex-modules-notification-management.mjs.map +1 -1
- package/fesm2022/{acorex-modules-organization-management-add-item.component-COUAmxM8.mjs → acorex-modules-organization-management-add-item.component-D99TugmE.mjs} +4 -4
- package/fesm2022/{acorex-modules-organization-management-add-item.component-COUAmxM8.mjs.map → acorex-modules-organization-management-add-item.component-D99TugmE.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-organization-management-org-chart-configuration.page-DjGUUbel.mjs → acorex-modules-organization-management-org-chart-configuration.page-DTNqHbxt.mjs} +5 -5
- package/fesm2022/{acorex-modules-organization-management-org-chart-configuration.page-DjGUUbel.mjs.map → acorex-modules-organization-management-org-chart-configuration.page-DTNqHbxt.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-organization-management-org-chart-configuration.service-DeoDX_ir.mjs → acorex-modules-organization-management-org-chart-configuration.service-BSO0GrAW.mjs} +4 -4
- package/fesm2022/{acorex-modules-organization-management-org-chart-configuration.service-DeoDX_ir.mjs.map → acorex-modules-organization-management-org-chart-configuration.service-BSO0GrAW.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-organization-management-org-chart.page-xlNWhN4W.mjs → acorex-modules-organization-management-org-chart.page-ioMhEPnQ.mjs} +12 -12
- package/fesm2022/{acorex-modules-organization-management-org-chart.page-xlNWhN4W.mjs.map → acorex-modules-organization-management-org-chart.page-ioMhEPnQ.mjs.map} +1 -1
- package/fesm2022/acorex-modules-organization-management.mjs +122 -122
- package/fesm2022/acorex-modules-organization-management.mjs.map +1 -1
- package/fesm2022/{acorex-modules-platform-management-acorex-modules-platform-management-Dfux0tkB.mjs → acorex-modules-platform-management-acorex-modules-platform-management-CFoPmixl.mjs} +933 -315
- package/fesm2022/acorex-modules-platform-management-acorex-modules-platform-management-CFoPmixl.mjs.map +1 -0
- package/fesm2022/{acorex-modules-platform-management-list-version.component-CSNKxghv.mjs → acorex-modules-platform-management-list-version.component-D0-Ya-Yx.mjs} +7 -7
- package/fesm2022/{acorex-modules-platform-management-list-version.component-CSNKxghv.mjs.map → acorex-modules-platform-management-list-version.component-D0-Ya-Yx.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-platform-management-settings.provider-C4RaOgkr.mjs → acorex-modules-platform-management-settings.provider--ARXqBUY.mjs} +2 -2
- package/fesm2022/{acorex-modules-platform-management-settings.provider-C4RaOgkr.mjs.map → acorex-modules-platform-management-settings.provider--ARXqBUY.mjs.map} +1 -1
- package/fesm2022/acorex-modules-platform-management.mjs +1 -1
- package/fesm2022/acorex-modules-project-management.mjs +43 -43
- package/fesm2022/acorex-modules-project-management.mjs.map +1 -1
- package/fesm2022/acorex-modules-report-management-report-create-root.component-LrE6TkIp.mjs +302 -0
- package/fesm2022/acorex-modules-report-management-report-create-root.component-LrE6TkIp.mjs.map +1 -0
- package/fesm2022/{acorex-modules-report-management-report-runner-root-page.component-CtEDcg_B.mjs → acorex-modules-report-management-report-runner-root-page.component-BntIoMfN.mjs} +49 -21
- package/fesm2022/acorex-modules-report-management-report-runner-root-page.component-BntIoMfN.mjs.map +1 -0
- package/fesm2022/acorex-modules-report-management-run.command-CoXvPC15.mjs +20 -0
- package/fesm2022/acorex-modules-report-management-run.command-CoXvPC15.mjs.map +1 -0
- package/fesm2022/acorex-modules-report-management.mjs +797 -29
- package/fesm2022/acorex-modules-report-management.mjs.map +1 -1
- package/fesm2022/acorex-modules-scheduler-job-management.mjs +14 -14
- package/fesm2022/acorex-modules-scheduler-job-management.mjs.map +1 -1
- package/fesm2022/acorex-modules-security-management.mjs +63 -69
- package/fesm2022/acorex-modules-security-management.mjs.map +1 -1
- package/fesm2022/{acorex-modules-settings-management-setting-page.component-B2CEFpES.mjs → acorex-modules-settings-management-setting-page.component-BKwKLUpD.mjs} +4 -4
- package/fesm2022/{acorex-modules-settings-management-setting-page.component-B2CEFpES.mjs.map → acorex-modules-settings-management-setting-page.component-BKwKLUpD.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-settings-management-setting-view.component-DnD83gFz.mjs → acorex-modules-settings-management-setting-view.component-Dco7MvZr.mjs} +4 -4
- package/fesm2022/{acorex-modules-settings-management-setting-view.component-DnD83gFz.mjs.map → acorex-modules-settings-management-setting-view.component-Dco7MvZr.mjs.map} +1 -1
- package/fesm2022/acorex-modules-settings-management.mjs +6 -6
- package/fesm2022/acorex-modules-settings-management.mjs.map +1 -1
- package/fesm2022/acorex-modules-text-template-management.mjs +24 -24
- package/fesm2022/acorex-modules-text-template-management.mjs.map +1 -1
- package/fesm2022/acorex-modules-training-management.mjs +43 -44
- package/fesm2022/acorex-modules-training-management.mjs.map +1 -1
- package/fesm2022/acorex-modules-workflow-management-task-board.page-ChW_Hwf2.mjs +762 -0
- package/fesm2022/acorex-modules-workflow-management-task-board.page-ChW_Hwf2.mjs.map +1 -0
- package/fesm2022/acorex-modules-workflow-management.mjs +12 -12
- package/fesm2022/acorex-modules-workflow-management.mjs.map +1 -1
- package/package.json +9 -5
- package/platform-management/index.d.ts +235 -8
- package/report-management/index.d.ts +11 -4
- package/fesm2022/acorex-modules-auth-acorex-modules-auth-Cj4td3eM.mjs.map +0 -1
- package/fesm2022/acorex-modules-document-management-acorex-modules-document-management-ClH75xx1.mjs.map +0 -1
- package/fesm2022/acorex-modules-document-management-lock-dialog.component-DvZ-vrUE.mjs +0 -51
- package/fesm2022/acorex-modules-document-management-lock-dialog.component-DvZ-vrUE.mjs.map +0 -1
- package/fesm2022/acorex-modules-document-management-meta-choose-popup.component-q6mDKrFi.mjs +0 -190
- package/fesm2022/acorex-modules-document-management-meta-choose-popup.component-q6mDKrFi.mjs.map +0 -1
- package/fesm2022/acorex-modules-document-management-meta-selector-widget-view.component-rlSWRGGl.mjs +0 -32
- package/fesm2022/acorex-modules-document-management-meta-selector-widget-view.component-rlSWRGGl.mjs.map +0 -1
- package/fesm2022/acorex-modules-document-management-unlock-dialog.component-B_TMgAl1.mjs +0 -36
- package/fesm2022/acorex-modules-document-management-unlock-dialog.component-B_TMgAl1.mjs.map +0 -1
- package/fesm2022/acorex-modules-form-template-management-viewer-popup.component-K2ZznaDw.mjs.map +0 -1
- package/fesm2022/acorex-modules-platform-management-acorex-modules-platform-management-Dfux0tkB.mjs.map +0 -1
- package/fesm2022/acorex-modules-report-management-report-runner-root-page.component-CtEDcg_B.mjs.map +0 -1
- package/fesm2022/acorex-modules-workflow-management-task-board.page-Bugxqd0W.mjs +0 -494
- package/fesm2022/acorex-modules-workflow-management-task-board.page-Bugxqd0W.mjs.map +0 -1
@@ -1,75 +1,76 @@
|
|
1
1
|
import * as i2$4 from '@acorex/components/conversation';
|
2
|
-
import { AXConversationModule } from '@acorex/components/conversation';
|
2
|
+
import { AXConversationModule, AXConversationInputComponent } from '@acorex/components/conversation';
|
3
3
|
import { AXPSessionService, AXPAuthGuard } from '@acorex/platform/auth';
|
4
|
-
import { AXMEntityCrudServiceImpl, AXP_ENTITY_DEFINITION_LOADER } from '@acorex/platform/layout/entity';
|
4
|
+
import { AXMEntityCrudServiceImpl, AXPEntityService, AXP_ENTITY_DEFINITION_LOADER } from '@acorex/platform/layout/entity';
|
5
5
|
import { AXPRootLayoutComponent } from '@acorex/platform/themes/default';
|
6
|
-
import * as i1$
|
7
|
-
import { AsyncPipe,
|
6
|
+
import * as i1$2 from '@angular/common';
|
7
|
+
import { AsyncPipe, CommonModule, DatePipe } from '@angular/common';
|
8
8
|
import * as i0 from '@angular/core';
|
9
|
-
import { Injectable, inject,
|
9
|
+
import { Injectable, inject, input, signal, viewChild, DestroyRef, ChangeDetectionStrategy, Component, ViewEncapsulation, computed, output, effect, afterNextRender, HostListener, importProvidersFrom, NgModule } from '@angular/core';
|
10
10
|
import * as i2$3 from '@angular/router';
|
11
11
|
import { ActivatedRoute, Router, NavigationEnd, RouterModule, ROUTES } from '@angular/router';
|
12
|
-
import { createAllQueryView, AXPEntityCommandScope, AXPEntityQueryType } from '@acorex/platform/common';
|
13
|
-
import * as i2 from '@acorex/platform/layout/builder';
|
14
|
-
import { AXPWidgetsCatalog, AXPLayoutBuilderModule,
|
15
|
-
import
|
16
|
-
import
|
12
|
+
import { createAllQueryView, AXPEntityCommandScope, AXPEntityQueryType, AXPFilterOperatorMiddlewareService, AXP_MENU_PROVIDER } from '@acorex/platform/common';
|
13
|
+
import * as i2$1 from '@acorex/platform/layout/builder';
|
14
|
+
import { AXPWidgetsCatalog, AXPLayoutBuilderModule, AXPValueWidgetComponent, AXPWidgetGroupEnum } from '@acorex/platform/layout/builder';
|
15
|
+
import * as i2$5 from '@acorex/platform/workflow';
|
16
|
+
import { AXPWorkflowAction, AXPWorkflowModule } from '@acorex/platform/workflow';
|
17
|
+
import * as i3 from '@acorex/components/avatar';
|
17
18
|
import { AXAvatarModule } from '@acorex/components/avatar';
|
18
19
|
import * as i2$2 from '@acorex/components/badge';
|
19
20
|
import { AXBadgeModule } from '@acorex/components/badge';
|
20
|
-
import * as i5
|
21
|
+
import * as i5 from '@acorex/components/button';
|
21
22
|
import { AXButtonModule } from '@acorex/components/button';
|
22
23
|
import * as i4 from '@acorex/components/comment';
|
23
24
|
import { AXCommentModule } from '@acorex/components/comment';
|
24
|
-
import * as
|
25
|
+
import * as i1$1 from '@acorex/components/decorators';
|
25
26
|
import { AXDecoratorModule } from '@acorex/components/decorators';
|
26
|
-
import
|
27
|
+
import { AXDialogService } from '@acorex/components/dialog';
|
28
|
+
import * as i7 from '@acorex/components/dropdown';
|
27
29
|
import { AXDropdownModule } from '@acorex/components/dropdown';
|
28
|
-
import * as
|
30
|
+
import * as i12 from '@acorex/components/dropdown-button';
|
29
31
|
import { AXDropdownButtonModule } from '@acorex/components/dropdown-button';
|
30
|
-
import * as
|
32
|
+
import * as i9 from '@acorex/components/form';
|
31
33
|
import { AXFormModule } from '@acorex/components/form';
|
32
|
-
import * as i7 from '@acorex/components/image';
|
33
34
|
import { AXImageModule } from '@acorex/components/image';
|
34
35
|
import { AXLabelModule } from '@acorex/components/label';
|
35
|
-
import * as
|
36
|
+
import * as i6 from '@acorex/components/loading';
|
36
37
|
import { AXLoadingModule } from '@acorex/components/loading';
|
37
38
|
import { AXPopupService } from '@acorex/components/popup';
|
38
39
|
import * as i6$1 from '@acorex/components/search-box';
|
39
40
|
import { AXSearchBoxModule } from '@acorex/components/search-box';
|
40
41
|
import { AXSelectBoxModule } from '@acorex/components/select-box';
|
41
|
-
import * as i2
|
42
|
+
import * as i2 from '@acorex/components/skeleton';
|
42
43
|
import { AXSkeletonModule } from '@acorex/components/skeleton';
|
43
44
|
import * as i7$1 from '@acorex/components/tabs';
|
44
45
|
import { AXTabsModule } from '@acorex/components/tabs';
|
45
46
|
import { AXTextBoxModule } from '@acorex/components/text-box';
|
46
|
-
import * as
|
47
|
+
import * as i10 from '@acorex/components/toolbar';
|
47
48
|
import { AXToolBarModule } from '@acorex/components/toolbar';
|
48
49
|
import * as i1 from '@acorex/components/wysiwyg';
|
49
|
-
import { AXWysiwygModule
|
50
|
-
import * as
|
50
|
+
import { AXWysiwygModule } from '@acorex/components/wysiwyg';
|
51
|
+
import * as i8 from '@acorex/core/format';
|
51
52
|
import { AXFormatModule } from '@acorex/core/format';
|
52
|
-
import * as
|
53
|
-
import { AXTranslationModule } from '@acorex/core/translation';
|
53
|
+
import * as i4$1 from '@acorex/core/translation';
|
54
|
+
import { AXTranslationModule, AXTranslationService } from '@acorex/core/translation';
|
54
55
|
import { AXUnsubscriber } from '@acorex/core/utils';
|
55
|
-
import { AXMUsersEntityService } from '@acorex/modules/security-management';
|
56
56
|
import { AXPUserAvatarComponent, AXPThemeLayoutBlockComponent, AXPThemeLayoutStartSideComponent, AXPThemeLayoutHeaderComponent, AXPThemeLayoutToolbarComponent } from '@acorex/platform/layout/components';
|
57
57
|
import { AXPPageLayoutBaseComponent, AXPPageLayoutComponent, AXPPageLayoutBase } from '@acorex/platform/layout/views';
|
58
|
-
import
|
58
|
+
import { trigger, transition, style, animate } from '@angular/animations';
|
59
|
+
import * as i11 from '@angular/forms';
|
59
60
|
import { FormsModule } from '@angular/forms';
|
60
61
|
import { Subject, filter, startWith } from 'rxjs';
|
61
|
-
import { AXDialogService } from '@acorex/components/dialog';
|
62
62
|
import { AXToastService } from '@acorex/components/toast';
|
63
|
-
import { AXPlatform } from '@acorex/core/platform';
|
64
63
|
import { DomSanitizer } from '@angular/platform-browser';
|
64
|
+
import { AXMUsersEntityService } from '@acorex/modules/security-management';
|
65
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
65
66
|
import { AXBasePageComponent } from '@acorex/components/page';
|
66
67
|
import { AXDomChangeDirective } from '@acorex/cdk/dom';
|
67
68
|
import { AXFileService } from '@acorex/core/file';
|
68
|
-
import { AXValidationModule } from '@acorex/core/validation';
|
69
69
|
|
70
70
|
const config = {
|
71
71
|
i18n: 'conversation',
|
72
72
|
module: 'Conversation',
|
73
|
+
route: 'chat',
|
73
74
|
};
|
74
75
|
const RootConfig = {
|
75
76
|
config,
|
@@ -101,10 +102,10 @@ class AXMMessageServiceImpl extends AXMMessageService {
|
|
101
102
|
constructor() {
|
102
103
|
super(`${RootConfig.module.name}.${RootConfig.entities.message.name}`);
|
103
104
|
}
|
104
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.
|
105
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.
|
105
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMMessageServiceImpl, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
106
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMMessageServiceImpl }); }
|
106
107
|
}
|
107
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.
|
108
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMMessageServiceImpl, decorators: [{
|
108
109
|
type: Injectable
|
109
110
|
}], ctorParameters: () => [] });
|
110
111
|
|
@@ -379,10 +380,10 @@ class AXMRoomServiceImpl extends AXMRoomService {
|
|
379
380
|
constructor() {
|
380
381
|
super(`${RootConfig.module.name}.${RootConfig.entities.room.name}`);
|
381
382
|
}
|
382
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.
|
383
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.
|
383
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMRoomServiceImpl, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
384
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMRoomServiceImpl }); }
|
384
385
|
}
|
385
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.
|
386
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMRoomServiceImpl, decorators: [{
|
386
387
|
type: Injectable
|
387
388
|
}], ctorParameters: () => [] });
|
388
389
|
|
@@ -670,395 +671,331 @@ class AXMConversationModuleEntityProvider {
|
|
670
671
|
return null;
|
671
672
|
}
|
672
673
|
}
|
673
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.
|
674
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.
|
674
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMConversationModuleEntityProvider, deps: [{ token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
675
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMConversationModuleEntityProvider }); }
|
675
676
|
}
|
676
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.
|
677
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMConversationModuleEntityProvider, decorators: [{
|
677
678
|
type: Injectable
|
678
679
|
}], ctorParameters: () => [{ type: i0.Injector }] });
|
679
680
|
|
680
|
-
|
681
|
-
|
682
|
-
|
681
|
+
class AXMMenuProvider {
|
682
|
+
constructor() {
|
683
|
+
this.sessionService = inject(AXPSessionService);
|
684
|
+
this.entityService = inject(AXPEntityService);
|
685
|
+
}
|
686
|
+
async provide(context) {
|
687
|
+
const module = RootConfig;
|
688
|
+
const scope = RootConfig.config.i18n;
|
689
|
+
context.addItems([
|
690
|
+
{
|
691
|
+
text: `t('plural-title', {scope:"${scope}"})`,
|
692
|
+
path: `${this.sessionService.application?.name}/${module.config.route}`,
|
693
|
+
priority: 2,
|
694
|
+
icon: RootConfig.entities.room.icon,
|
695
|
+
},
|
696
|
+
]);
|
697
|
+
}
|
698
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMMenuProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
699
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMMenuProvider }); }
|
700
|
+
}
|
701
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMMenuProvider, decorators: [{
|
702
|
+
type: Injectable
|
703
|
+
}] });
|
704
|
+
|
705
|
+
//#region ---- Abstract Comment Service ----
|
683
706
|
class AXMCommentService {
|
684
707
|
}
|
708
|
+
//#endregion
|
685
709
|
class AXMCommentServiceImpl {
|
686
710
|
constructor() {
|
711
|
+
//#region ---- Dependencies ----
|
687
712
|
this.roomService = inject(AXMRoomService);
|
688
713
|
this.messageService = inject(AXMMessageService);
|
689
714
|
this.sessionService = inject(AXPSessionService);
|
690
715
|
this.usersService = inject(AXMUsersEntityService);
|
716
|
+
this.filterService = inject(AXPFilterOperatorMiddlewareService);
|
717
|
+
//#endregion
|
718
|
+
//#region ---- Observables ----
|
719
|
+
this._commentAdded$ = new Subject();
|
720
|
+
this.commentAdded$ = this._commentAdded$.asObservable();
|
721
|
+
this._commentRemoved$ = new Subject();
|
722
|
+
this.commentRemoved$ = this._commentRemoved$.asObservable();
|
723
|
+
this._commentUpdated$ = new Subject();
|
724
|
+
this.commentUpdated$ = this._commentUpdated$.asObservable();
|
725
|
+
this._threadAdded$ = new Subject();
|
726
|
+
this.threadAdded$ = this._threadAdded$.asObservable();
|
727
|
+
this._threadRemoved$ = new Subject();
|
728
|
+
this.threadRemoved$ = this._threadRemoved$.asObservable();
|
691
729
|
}
|
692
|
-
|
730
|
+
//#endregion
|
731
|
+
//#region ---- Helper Methods ----
|
693
732
|
getCurrentUser() {
|
694
733
|
const user = this.sessionService.user;
|
734
|
+
if (!user) {
|
735
|
+
throw new Error('No authenticated user found.');
|
736
|
+
}
|
695
737
|
return {
|
696
|
-
id: user
|
738
|
+
id: user.id,
|
697
739
|
type: 'user',
|
698
740
|
};
|
699
741
|
}
|
700
742
|
async getUserInfo(userId) {
|
701
743
|
try {
|
702
|
-
|
703
|
-
return {
|
704
|
-
id: user.id,
|
705
|
-
userName: user.username || user.id,
|
706
|
-
firstName: user.firstName || '',
|
707
|
-
lastName: user.lastName || '',
|
708
|
-
fullName: `${user.firstName || ''} ${user.lastName || ''}`.trim() || 'Unknown User',
|
709
|
-
avatar: '',
|
710
|
-
};
|
744
|
+
await this.usersService.getOne(userId); // check if user exists
|
745
|
+
return { id: userId, type: 'user' };
|
711
746
|
}
|
712
|
-
catch
|
713
|
-
|
714
|
-
return {
|
715
|
-
id: userId,
|
716
|
-
userName: userId,
|
717
|
-
firstName: 'Unknown',
|
718
|
-
lastName: 'User',
|
719
|
-
fullName: 'Unknown User',
|
720
|
-
avatar: '',
|
721
|
-
};
|
747
|
+
catch {
|
748
|
+
throw new Error(`User with ID ${userId} not found`);
|
722
749
|
}
|
723
750
|
}
|
724
|
-
|
725
|
-
return `${roomType}:${entityId}:${instanceId}`;
|
726
|
-
}
|
727
|
-
async formatComment(message) {
|
728
|
-
const currentUserId = this.getCurrentUser().id;
|
729
|
-
// Check if the current user has liked this message
|
730
|
-
const isLiked = (message.reactions || []).some((reaction) => reaction.author.id === currentUserId && reaction.type === 'like');
|
731
|
-
// Count total reactions
|
732
|
-
const reactionsCount = (message.reactions || []).filter((r) => r.type === 'like').length;
|
733
|
-
// Get the full user info for the author
|
734
|
-
const userInfo = await this.getUserInfo(message.author.id);
|
751
|
+
formatComment(message, depth = 0) {
|
735
752
|
return {
|
736
753
|
...message,
|
737
|
-
|
738
|
-
...message.author,
|
739
|
-
...userInfo,
|
740
|
-
},
|
741
|
-
isFromCurrentUser: message.author.id === currentUserId,
|
742
|
-
formattedDate: new Date(message.createdAt || new Date()).toLocaleString(),
|
743
|
-
isLiked,
|
744
|
-
reactionsCount,
|
754
|
+
depth,
|
745
755
|
replies: [],
|
756
|
+
replyCount: 0,
|
746
757
|
};
|
747
758
|
}
|
748
|
-
|
749
|
-
|
750
|
-
const
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
if (!comment.replies) {
|
757
|
-
comment.replies = [];
|
758
|
-
}
|
759
|
-
// If this is a root comment (no replyId), add it to the root comments array
|
760
|
-
if (!comment.replyId) {
|
761
|
-
rootComments.push(comment);
|
762
|
-
}
|
763
|
-
}
|
764
|
-
// Second pass: build the hierarchy by adding replies to their parent comments
|
765
|
-
for (const comment of comments) {
|
766
|
-
if (comment.replyId) {
|
767
|
-
const parentComment = commentMap.get(comment.replyId);
|
768
|
-
if (parentComment && parentComment.replies) {
|
769
|
-
parentComment.replies.push(comment);
|
770
|
-
}
|
771
|
-
else {
|
772
|
-
// If parent not found (might be deleted), treat as a root comment
|
773
|
-
rootComments.push(comment);
|
774
|
-
}
|
759
|
+
buildCommentTree(comments) {
|
760
|
+
const commentMap = new Map(comments.map((c) => [c.id, c]));
|
761
|
+
const tree = [];
|
762
|
+
comments.forEach((comment) => {
|
763
|
+
if (comment.replyId && commentMap.has(comment.replyId)) {
|
764
|
+
const parent = commentMap.get(comment.replyId);
|
765
|
+
parent.replies.push(comment);
|
766
|
+
comment.depth = parent.depth + 1;
|
775
767
|
}
|
776
|
-
|
777
|
-
|
778
|
-
const sortByDate = (a, b) => {
|
779
|
-
const dateA = a.createdAt ? new Date(a.createdAt).getTime() : 0;
|
780
|
-
const dateB = b.createdAt ? new Date(b.createdAt).getTime() : 0;
|
781
|
-
return dateB - dateA;
|
782
|
-
};
|
783
|
-
rootComments.sort(sortByDate);
|
784
|
-
// Sort the replies within each comment
|
785
|
-
for (const comment of rootComments) {
|
786
|
-
if (comment.replies && comment.replies.length > 0) {
|
787
|
-
comment.replies.sort(sortByDate);
|
768
|
+
else {
|
769
|
+
tree.push(comment);
|
788
770
|
}
|
789
|
-
}
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
return this.roomService.query({ skip, take });
|
795
|
-
}
|
796
|
-
async getRoomDetails(roomId) {
|
797
|
-
return this.roomService.getOne(roomId);
|
798
|
-
}
|
799
|
-
async createRoom(roomData) {
|
800
|
-
return this.roomService.insertOne(roomData);
|
771
|
+
});
|
772
|
+
commentMap.forEach((comment) => {
|
773
|
+
comment.replyCount = comment.replies.length;
|
774
|
+
});
|
775
|
+
return tree;
|
801
776
|
}
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
return typeof result === 'string' ? result : roomId;
|
820
|
-
}
|
821
|
-
catch (e) {
|
822
|
-
// If we get a duplicate error, the room was created by another request
|
823
|
-
return roomId;
|
824
|
-
}
|
777
|
+
//#endregion
|
778
|
+
//#region ---- Comment Thread Service Implementation ----
|
779
|
+
async createThread(entityRef, topic, title) {
|
780
|
+
const currentUser = this.getCurrentUser();
|
781
|
+
const room = {
|
782
|
+
type: 'comment',
|
783
|
+
topic: topic,
|
784
|
+
title: title || `Comments for ${entityRef.type}#${entityRef.id}`,
|
785
|
+
members: [currentUser],
|
786
|
+
entityRef: entityRef,
|
787
|
+
createdBy: currentUser.id,
|
788
|
+
createdAt: new Date(),
|
789
|
+
};
|
790
|
+
await this.roomService.insertOne(room);
|
791
|
+
const newThread = await this.getThread(entityRef, topic);
|
792
|
+
if (!newThread) {
|
793
|
+
throw new Error('Failed to create or retrieve thread after creation.');
|
825
794
|
}
|
795
|
+
this._threadAdded$.next(newThread);
|
796
|
+
return newThread;
|
826
797
|
}
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
if (!entityId || !instanceId) {
|
832
|
-
throw new Error('EntityId and InstanceId are required for querying comments');
|
833
|
-
}
|
834
|
-
const roomId = this.formatRoomId(entityId, instanceId, roomType);
|
835
|
-
// Fetch messages for this room
|
836
|
-
const result = await this.messageService.query({
|
837
|
-
skip,
|
838
|
-
take,
|
798
|
+
async getThread(entityRef, topic) {
|
799
|
+
const { items } = await this.roomService.query({
|
800
|
+
skip: 0,
|
801
|
+
take: 1,
|
839
802
|
filter: {
|
840
|
-
|
841
|
-
|
842
|
-
|
803
|
+
logic: 'and',
|
804
|
+
filters: [
|
805
|
+
{
|
806
|
+
field: 'entityRef.id',
|
807
|
+
value: entityRef.id,
|
808
|
+
operator: this.filterService.getOperator('equal'),
|
809
|
+
},
|
810
|
+
{
|
811
|
+
field: 'entityRef.type',
|
812
|
+
value: entityRef.type,
|
813
|
+
operator: this.filterService.getOperator('equal'),
|
814
|
+
},
|
815
|
+
{
|
816
|
+
field: 'topic',
|
817
|
+
value: topic,
|
818
|
+
operator: this.filterService.getOperator('equal'),
|
819
|
+
},
|
820
|
+
],
|
843
821
|
},
|
844
822
|
});
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
823
|
+
const room = items[0];
|
824
|
+
if (!room) {
|
825
|
+
return null;
|
826
|
+
}
|
827
|
+
const comments = await this.getComments(room.id, true);
|
849
828
|
return {
|
850
|
-
|
851
|
-
|
829
|
+
...room,
|
830
|
+
comments,
|
831
|
+
commentCount: comments.length,
|
852
832
|
};
|
853
833
|
}
|
854
|
-
async
|
855
|
-
const
|
856
|
-
|
834
|
+
async listThreads(entityRef, topic) {
|
835
|
+
const { items } = await this.roomService.query({
|
836
|
+
skip: 0,
|
837
|
+
take: 100,
|
838
|
+
filter: {
|
839
|
+
logic: 'and',
|
840
|
+
filters: [
|
841
|
+
{
|
842
|
+
field: 'entityRef.id',
|
843
|
+
value: entityRef.id,
|
844
|
+
operator: this.filterService.getOperator('equal'),
|
845
|
+
},
|
846
|
+
{
|
847
|
+
field: 'entityRef.type',
|
848
|
+
value: entityRef.type,
|
849
|
+
operator: this.filterService.getOperator('equal'),
|
850
|
+
},
|
851
|
+
{
|
852
|
+
field: 'topic',
|
853
|
+
value: topic,
|
854
|
+
operator: this.filterService.getOperator('equal'),
|
855
|
+
},
|
856
|
+
],
|
857
|
+
},
|
858
|
+
});
|
859
|
+
const threads = await Promise.all(items.map((room) => this.getThread(room.entityRef, room.topic)));
|
860
|
+
return threads.filter((t) => t !== null);
|
857
861
|
}
|
858
|
-
async
|
859
|
-
const
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
862
|
+
async updateThread(entityRef, topic, data) {
|
863
|
+
const thread = await this.getThread(entityRef, topic);
|
864
|
+
if (!thread) {
|
865
|
+
throw new Error(`Thread for entity ${entityRef.type}#${entityRef.id} not found.`);
|
866
|
+
}
|
867
|
+
await this.roomService.updateOne(thread.id, data);
|
868
|
+
const updatedThread = await this.getThread(entityRef, topic);
|
869
|
+
if (!updatedThread) {
|
870
|
+
throw new Error('Failed to retrieve thread after update.');
|
871
|
+
}
|
872
|
+
return updatedThread;
|
873
|
+
}
|
874
|
+
async deleteThread(entityRef, topic) {
|
875
|
+
const thread = await this.getThread(entityRef, topic);
|
876
|
+
if (thread) {
|
877
|
+
await this.roomService.deleteOne(thread.id);
|
878
|
+
this._threadRemoved$.next(thread.id);
|
879
|
+
}
|
880
|
+
return true;
|
881
|
+
}
|
882
|
+
//#endregion
|
883
|
+
//#region ---- Comment Service Implementation ----
|
884
|
+
async addComment(threadId, content, parentCommentId, contentType = 'text', userId) {
|
885
|
+
const author = userId ? await this.getUserInfo(userId) : this.getCurrentUser();
|
886
|
+
const messageContent = { content, contentType };
|
868
887
|
const message = {
|
869
|
-
roomId,
|
888
|
+
roomId: threadId,
|
870
889
|
message: messageContent,
|
871
|
-
author
|
872
|
-
replyId:
|
890
|
+
author,
|
891
|
+
replyId: parentCommentId,
|
873
892
|
reactions: [],
|
874
893
|
seen: [],
|
894
|
+
createdBy: author.id,
|
895
|
+
createdAt: new Date(),
|
875
896
|
};
|
876
|
-
// Insert the message
|
877
897
|
const messageId = await this.messageService.insertOne(message);
|
878
|
-
|
879
|
-
|
880
|
-
return
|
881
|
-
}
|
882
|
-
async updateOne(id, update) {
|
883
|
-
// If content is being updated, format it correctly
|
884
|
-
let messageUpdate = {};
|
885
|
-
if (update.message?.content) {
|
886
|
-
messageUpdate.message = {
|
887
|
-
content: update.message.content,
|
888
|
-
contentType: update.message.contentType || 'text',
|
889
|
-
};
|
890
|
-
}
|
891
|
-
// Apply the update
|
892
|
-
const result = await this.messageService.updateOne(id, messageUpdate);
|
893
|
-
// Return as a comment entity
|
894
|
-
return this.formatComment(result);
|
898
|
+
const newComment = await this.getComment(messageId);
|
899
|
+
this._commentAdded$.next(newComment);
|
900
|
+
return newComment;
|
895
901
|
}
|
896
|
-
async
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
902
|
+
async getComments(threadId, nested = true) {
|
903
|
+
const { items } = await this.messageService.query({
|
904
|
+
skip: 0,
|
905
|
+
filter: { field: 'roomId', value: threadId, operator: this.filterService.getOperator('equal') },
|
906
|
+
sort: [{ field: 'createdAt', dir: 'asc' }],
|
907
|
+
take: 500, // Assuming a reasonable limit for comments per thread
|
908
|
+
});
|
909
|
+
const formattedComments = items.map((c) => this.formatComment(c));
|
910
|
+
if (nested) {
|
911
|
+
return this.buildCommentTree(formattedComments);
|
904
912
|
}
|
913
|
+
return formattedComments;
|
914
|
+
}
|
915
|
+
async getComment(commentId) {
|
916
|
+
const message = await this.messageService.getOne(commentId);
|
917
|
+
return this.formatComment(message);
|
905
918
|
}
|
906
|
-
|
907
|
-
|
919
|
+
async editComment(commentId, content, contentType = 'text') {
|
920
|
+
const messageContent = { content, contentType };
|
921
|
+
await this.messageService.updateOne(commentId, {
|
922
|
+
message: messageContent,
|
923
|
+
updatedAt: new Date(),
|
924
|
+
updatedBy: this.getCurrentUser().id,
|
925
|
+
});
|
926
|
+
const updatedComment = await this.getComment(commentId);
|
927
|
+
this._commentUpdated$.next(updatedComment);
|
928
|
+
return updatedComment;
|
929
|
+
}
|
930
|
+
async deleteComment(commentId) {
|
931
|
+
// Note: This is a hard delete. Soft delete might be preferable.
|
932
|
+
await this.messageService.deleteOne(commentId);
|
933
|
+
this._commentRemoved$.next(commentId);
|
934
|
+
return true;
|
935
|
+
}
|
936
|
+
//#endregion
|
937
|
+
//#region ---- Comment Reaction Service Implementation ----
|
938
|
+
async addReaction(commentId, type) {
|
908
939
|
const author = this.getCurrentUser();
|
909
|
-
const
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
let updatedReactions;
|
914
|
-
if (existingReaction) {
|
915
|
-
// If the reaction exists, remove it (unlike)
|
916
|
-
updatedReactions = reactions.filter((r) => !(r.author.id === author.id && r.type === 'like'));
|
917
|
-
}
|
918
|
-
else {
|
919
|
-
// If the reaction doesn't exist, add it (like)
|
920
|
-
updatedReactions = [...reactions, { author, type: 'like' }];
|
940
|
+
const comment = await this.messageService.getOne(commentId);
|
941
|
+
const reactions = comment.reactions || [];
|
942
|
+
if (reactions.some((r) => r.author.id === author.id && r.type === type)) {
|
943
|
+
return this.formatComment(comment);
|
921
944
|
}
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
945
|
+
const updatedReactions = [...reactions, { author, type }];
|
946
|
+
await this.messageService.updateOne(commentId, { reactions: updatedReactions });
|
947
|
+
const updatedComment = await this.getComment(commentId);
|
948
|
+
this._commentUpdated$.next(updatedComment);
|
949
|
+
return updatedComment;
|
926
950
|
}
|
927
|
-
async
|
928
|
-
const
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
value: roomId,
|
936
|
-
operator: { type: 'equal' },
|
937
|
-
},
|
938
|
-
});
|
939
|
-
return result.total;
|
940
|
-
}
|
941
|
-
catch (error) {
|
942
|
-
console.error('Failed to get comment count:', error);
|
943
|
-
return 0;
|
944
|
-
}
|
951
|
+
async removeReaction(commentId, type) {
|
952
|
+
const author = this.getCurrentUser();
|
953
|
+
const comment = await this.messageService.getOne(commentId);
|
954
|
+
const updatedReactions = (comment.reactions || []).filter((r) => !(r.author.id === author.id && r.type === type));
|
955
|
+
await this.messageService.updateOne(commentId, { reactions: updatedReactions });
|
956
|
+
const updatedComment = await this.getComment(commentId);
|
957
|
+
this._commentUpdated$.next(updatedComment);
|
958
|
+
return updatedComment;
|
945
959
|
}
|
946
|
-
async
|
947
|
-
const
|
948
|
-
|
949
|
-
skip,
|
950
|
-
take,
|
951
|
-
};
|
952
|
-
return this.query(queryRequest);
|
960
|
+
async getReactions(commentId) {
|
961
|
+
const comment = await this.messageService.getOne(commentId);
|
962
|
+
return comment.reactions || [];
|
953
963
|
}
|
954
|
-
|
955
|
-
|
956
|
-
}
|
957
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXMCommentServiceImpl, decorators: [{
|
958
|
-
type: Injectable,
|
959
|
-
args: [{
|
960
|
-
providedIn: 'root',
|
961
|
-
}]
|
962
|
-
}] });
|
963
|
-
|
964
|
-
class AXMCommentLookupPopup extends AXBasePageComponent {
|
965
|
-
constructor() {
|
966
|
-
super(...arguments);
|
967
|
-
this.lookupNode = {
|
968
|
-
name: 'form-field',
|
969
|
-
path: 'form-field',
|
970
|
-
type: 'form-field',
|
971
|
-
children: [
|
972
|
-
{
|
973
|
-
name: 'lookup',
|
974
|
-
path: 'lookup',
|
975
|
-
type: 'lookup-editor',
|
976
|
-
options: {
|
977
|
-
entity: 'SecurityManagement.users',
|
978
|
-
multiple: true,
|
979
|
-
},
|
980
|
-
},
|
981
|
-
],
|
982
|
-
options: {
|
983
|
-
label: 'Select users:',
|
984
|
-
},
|
985
|
-
};
|
986
|
-
this.titleNode = {
|
987
|
-
name: 'form-field',
|
988
|
-
path: 'form-field',
|
989
|
-
type: 'form-field',
|
990
|
-
children: [
|
991
|
-
{
|
992
|
-
name: 'title',
|
993
|
-
path: 'title',
|
994
|
-
type: 'text-editor',
|
995
|
-
options: {
|
996
|
-
placeholder: 'Enter title',
|
997
|
-
required: true,
|
998
|
-
},
|
999
|
-
},
|
1000
|
-
],
|
1001
|
-
options: {
|
1002
|
-
label: 'Title:',
|
1003
|
-
},
|
1004
|
-
};
|
1005
|
-
this.context = signal({});
|
964
|
+
async likeComment(commentId) {
|
965
|
+
return this.addReaction(commentId, 'like');
|
1006
966
|
}
|
1007
|
-
|
1008
|
-
this.
|
1009
|
-
lookup: this.context()?.lookup,
|
1010
|
-
title: this.context()?.title,
|
1011
|
-
});
|
967
|
+
async unlikeComment(commentId) {
|
968
|
+
return this.removeReaction(commentId, 'like');
|
1012
969
|
}
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1029
|
-
(onClick)="handleClose()"
|
1030
|
-
></ax-button>
|
1031
|
-
</ax-suffix>
|
1032
|
-
</ax-footer>`, isInline: true, dependencies: [{ kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i5.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXPLayoutBuilderModule }, { kind: "component", type: i2.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i2.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i5$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }] }); }
|
970
|
+
//#endregion
|
971
|
+
//#region ---- Comment Pin Service Implementation ----
|
972
|
+
async pinComment(commentId) {
|
973
|
+
await this.messageService.updateOne(commentId, { isPinned: true });
|
974
|
+
const updatedComment = await this.getComment(commentId);
|
975
|
+
this._commentUpdated$.next(updatedComment);
|
976
|
+
return updatedComment;
|
977
|
+
}
|
978
|
+
async unpinComment(commentId) {
|
979
|
+
await this.messageService.updateOne(commentId, { isPinned: false });
|
980
|
+
const updatedComment = await this.getComment(commentId);
|
981
|
+
this._commentUpdated$.next(updatedComment);
|
982
|
+
return updatedComment;
|
983
|
+
}
|
984
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMCommentServiceImpl, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
985
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMCommentServiceImpl, providedIn: 'root' }); }
|
1033
986
|
}
|
1034
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.
|
1035
|
-
type:
|
987
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMCommentServiceImpl, decorators: [{
|
988
|
+
type: Injectable,
|
1036
989
|
args: [{
|
1037
|
-
|
1038
|
-
<div class="ax-p-4 ax-flex ax-flex-col ax-gap-4">
|
1039
|
-
<ng-container axp-widget-renderer [node]="lookupNode" [mode]="'edit'"> </ng-container>
|
1040
|
-
@if (context()?.lookup?.length > 1) {
|
1041
|
-
<ng-container axp-widget-renderer [node]="titleNode" [mode]="'edit'"> </ng-container>
|
1042
|
-
}
|
1043
|
-
</div>
|
1044
|
-
</axp-widgets-container>
|
1045
|
-
|
1046
|
-
<ax-footer>
|
1047
|
-
<ax-suffix>
|
1048
|
-
<ax-button
|
1049
|
-
text="Accept & Send"
|
1050
|
-
color="primary"
|
1051
|
-
[disabled]="context()?.lookup?.length > 1 && !context()?.title"
|
1052
|
-
(onClick)="handleClose()"
|
1053
|
-
></ax-button>
|
1054
|
-
</ax-suffix>
|
1055
|
-
</ax-footer>`,
|
1056
|
-
imports: [AXDecoratorModule, AXPLayoutBuilderModule, AXButtonModule],
|
990
|
+
providedIn: 'root',
|
1057
991
|
}]
|
1058
992
|
}] });
|
1059
993
|
|
1060
|
-
class
|
994
|
+
class AXMCommentComponent {
|
1061
995
|
constructor() {
|
996
|
+
this.refrenceType = input.required();
|
997
|
+
this.refrenceId = input.required();
|
998
|
+
this.subject = input.required();
|
1062
999
|
this.hasCooldown = signal(false);
|
1063
1000
|
this.commentContent = signal('');
|
1064
1001
|
this.isSubmitting = signal(false);
|
@@ -1068,34 +1005,23 @@ class AXMCommentListViewComponent {
|
|
1068
1005
|
this.failedImageIds = signal([]);
|
1069
1006
|
this.activeReplyComment = signal(undefined);
|
1070
1007
|
this.activeEditComment = signal(undefined);
|
1008
|
+
this.highlightedCommentId = signal(null);
|
1071
1009
|
this.wysiwygEditor = viewChild.required('w');
|
1072
1010
|
this.commentService = inject(AXMCommentService);
|
1073
|
-
this.
|
1074
|
-
this.route = inject(ActivatedRoute);
|
1075
|
-
this.popupService = inject(AXPopupService);
|
1011
|
+
this.sessionService = inject(AXPSessionService);
|
1076
1012
|
this.toastService = inject(AXToastService);
|
1077
1013
|
this.dialogService = inject(AXDialogService);
|
1078
1014
|
this.sanitize = inject(DomSanitizer);
|
1079
|
-
this.
|
1080
|
-
this.getPayload = computed(() => ({
|
1081
|
-
params: this.payload(),
|
1082
|
-
skip: 0,
|
1083
|
-
take: 10,
|
1084
|
-
}));
|
1085
|
-
this.payload = computed(() => ({
|
1086
|
-
roomType: 'default',
|
1087
|
-
entityId: this.routeParams.params?.['module'] + '.' + this.routeParams.params?.['entity'],
|
1088
|
-
instanceId: this.routeParams.params?.['id'],
|
1089
|
-
}));
|
1015
|
+
this.destroyRef = inject(DestroyRef);
|
1090
1016
|
this.comments = signal([]);
|
1091
|
-
this.
|
1017
|
+
this.thread = signal(undefined);
|
1092
1018
|
this.wysiwygOptions = signal({
|
1093
1019
|
look: 'solid',
|
1094
1020
|
});
|
1095
1021
|
this.avatarConfig = signal({
|
1096
1022
|
color: 'primary',
|
1097
1023
|
look: 'rounded',
|
1098
|
-
type: 'solid',
|
1024
|
+
type: 'solid',
|
1099
1025
|
});
|
1100
1026
|
this.validateContent = (content) => {
|
1101
1027
|
let isValid = true;
|
@@ -1111,39 +1037,84 @@ class AXMCommentListViewComponent {
|
|
1111
1037
|
};
|
1112
1038
|
}
|
1113
1039
|
ngOnInit() {
|
1114
|
-
this.loadComments();
|
1115
|
-
}
|
1116
|
-
sanitizeHtml(htmlContent) {
|
1117
|
-
if (!htmlContent)
|
1118
|
-
return this.sanitize.bypassSecurityTrustHtml('');
|
1119
|
-
return this.sanitize.bypassSecurityTrustHtml(htmlContent);
|
1120
|
-
}
|
1121
|
-
handleImageError(imageId) {
|
1122
|
-
this.failedImageIds.update((ids) => [...ids, imageId]);
|
1123
|
-
}
|
1124
|
-
checkImageExists(imageId) {
|
1125
|
-
return !this.failedImageIds().includes(imageId);
|
1126
|
-
}
|
1127
|
-
extractInitials(name) {
|
1128
|
-
if (!name)
|
1129
|
-
return '?';
|
1130
|
-
// Handle the case where name is an object with fullName property
|
1131
|
-
const nameStr = typeof name === 'object' && name.fullName ? name.fullName : String(name);
|
1132
|
-
const words = nameStr.split(' ');
|
1133
|
-
const initials = words.map((word) => word.charAt(0).toUpperCase());
|
1134
|
-
return initials.join('');
|
1135
|
-
}
|
1136
|
-
async loadComments() {
|
1137
1040
|
this.isLoading.set(true);
|
1138
|
-
|
1139
|
-
|
1140
|
-
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1144
|
-
|
1145
|
-
|
1146
|
-
|
1041
|
+
this.loadComments().finally(() => {
|
1042
|
+
setTimeout(() => {
|
1043
|
+
this.isLoading.set(false);
|
1044
|
+
}, 250);
|
1045
|
+
});
|
1046
|
+
this.commentService.commentAdded$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((comment) => {
|
1047
|
+
if (comment.replyId) {
|
1048
|
+
this.comments.update((comments) => {
|
1049
|
+
return comments.map((c) => {
|
1050
|
+
if (c.id === comment.replyId) {
|
1051
|
+
const newReplies = c.replies ? [...c.replies, comment] : [comment];
|
1052
|
+
return { ...c, replies: newReplies, replyCount: newReplies.length };
|
1053
|
+
}
|
1054
|
+
return c;
|
1055
|
+
});
|
1056
|
+
});
|
1057
|
+
}
|
1058
|
+
else {
|
1059
|
+
this.comments.update((comments) => [...comments, comment]);
|
1060
|
+
}
|
1061
|
+
});
|
1062
|
+
this.commentService.commentUpdated$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((updatedComment) => {
|
1063
|
+
const update = (list) => {
|
1064
|
+
return list.map((c) => {
|
1065
|
+
if (c.id === updatedComment.id) {
|
1066
|
+
return { ...c, ...updatedComment, replies: updatedComment.replies || c.replies };
|
1067
|
+
}
|
1068
|
+
if (c.replies && c.replies.length > 0) {
|
1069
|
+
return { ...c, replies: update(c.replies) };
|
1070
|
+
}
|
1071
|
+
return c;
|
1072
|
+
});
|
1073
|
+
};
|
1074
|
+
this.comments.update((comments) => update(comments));
|
1075
|
+
});
|
1076
|
+
}
|
1077
|
+
getCurrentUser() {
|
1078
|
+
const user = this.sessionService.user;
|
1079
|
+
return user ? { id: user.id, type: 'user' } : null;
|
1080
|
+
}
|
1081
|
+
isLikedByUser(comment) {
|
1082
|
+
const user = this.getCurrentUser();
|
1083
|
+
if (!user)
|
1084
|
+
return false;
|
1085
|
+
return (comment.reactions || []).some((r) => r.author.id === user.id && r.type === 'like');
|
1086
|
+
}
|
1087
|
+
getReactionsCount(comment) {
|
1088
|
+
return (comment.reactions || []).filter((r) => r.type === 'like').length;
|
1089
|
+
}
|
1090
|
+
sanitizeHtml(htmlContent) {
|
1091
|
+
if (!htmlContent)
|
1092
|
+
return this.sanitize.bypassSecurityTrustHtml('');
|
1093
|
+
return this.sanitize.bypassSecurityTrustHtml(htmlContent);
|
1094
|
+
}
|
1095
|
+
handleImageError(imageId) {
|
1096
|
+
this.failedImageIds.update((ids) => [...ids, imageId]);
|
1097
|
+
}
|
1098
|
+
checkImageExists(imageId) {
|
1099
|
+
return !this.failedImageIds().includes(imageId);
|
1100
|
+
}
|
1101
|
+
async loadComments() {
|
1102
|
+
try {
|
1103
|
+
const thread = await this.commentService.getThread({ type: this.refrenceType(), id: this.refrenceId() }, this.subject());
|
1104
|
+
if (thread) {
|
1105
|
+
this.thread.set(thread);
|
1106
|
+
this.comments.set(thread.comments);
|
1107
|
+
}
|
1108
|
+
else {
|
1109
|
+
this.comments.set([]);
|
1110
|
+
this.thread.set(undefined);
|
1111
|
+
}
|
1112
|
+
}
|
1113
|
+
catch (error) {
|
1114
|
+
console.error('Failed to load comments:', error);
|
1115
|
+
this.toastService.show({
|
1116
|
+
content: 'Failed to load comments. Please try again.',
|
1117
|
+
color: 'danger',
|
1147
1118
|
location: 'bottom-center',
|
1148
1119
|
closeButton: true,
|
1149
1120
|
timeOut: 3000,
|
@@ -1151,36 +1122,31 @@ class AXMCommentListViewComponent {
|
|
1151
1122
|
});
|
1152
1123
|
this.comments.set([]);
|
1153
1124
|
}
|
1154
|
-
finally {
|
1155
|
-
setTimeout(() => {
|
1156
|
-
this.isLoading.set(false);
|
1157
|
-
}, 250);
|
1158
|
-
}
|
1159
1125
|
}
|
1160
|
-
editMessage(comment, reply) {
|
1126
|
+
editMessage(comment, reply, userName) {
|
1161
1127
|
this.isReplyingMode.set(false);
|
1162
1128
|
this.activeReplyComment.set(undefined);
|
1163
1129
|
this.isEditingMode.set(true);
|
1164
|
-
this.activeEditComment.set(comment);
|
1130
|
+
this.activeEditComment.set({ ...comment, userName: userName || '' });
|
1165
1131
|
const contentToEdit = reply ? reply.message?.content : comment.message?.content;
|
1166
1132
|
this.commentContent.set(contentToEdit || '');
|
1167
1133
|
this.wysiwygEditor().getHostElement().scrollIntoView({ behavior: 'smooth', block: 'start' });
|
1168
1134
|
}
|
1169
|
-
replyMessage(comment, reply) {
|
1135
|
+
replyMessage(comment, reply, userName) {
|
1170
1136
|
this.isEditingMode.set(false);
|
1171
1137
|
this.activeEditComment.set(undefined);
|
1172
1138
|
this.isReplyingMode.set(true);
|
1173
|
-
this.activeReplyComment.set(comment);
|
1139
|
+
this.activeReplyComment.set({ ...comment, userName: userName || '' });
|
1174
1140
|
if (reply) {
|
1175
1141
|
const author = reply.author.fullName || reply.author.id;
|
1176
1142
|
const mention = `<a data-id="${reply.id}">@${author}</a> `;
|
1177
1143
|
this.commentContent.set(mention);
|
1178
|
-
this.wysiwyg()?.focus();
|
1179
1144
|
document.getElementsByClassName('ql-editor')[0].innerHTML = mention;
|
1145
|
+
this.wysiwygEditor()?.focus();
|
1180
1146
|
}
|
1181
1147
|
this.wysiwygEditor().getHostElement().scrollIntoView({ behavior: 'smooth', block: 'start' });
|
1182
1148
|
}
|
1183
|
-
async deleteComment(
|
1149
|
+
async deleteComment(commentId) {
|
1184
1150
|
const dialog = this.dialogService.open({
|
1185
1151
|
icon: 'fa-regular fa-warning',
|
1186
1152
|
content: 'Are you sure you want to delete this comment?',
|
@@ -1197,77 +1163,20 @@ class AXMCommentListViewComponent {
|
|
1197
1163
|
e.source.disabled = true;
|
1198
1164
|
e.source.loading = true;
|
1199
1165
|
try {
|
1200
|
-
|
1201
|
-
|
1202
|
-
this.removeMessageById(comment.id);
|
1203
|
-
this.toastService.show({
|
1204
|
-
content: 'Comment deleted successfully.',
|
1205
|
-
color: 'success',
|
1206
|
-
location: 'bottom-center',
|
1207
|
-
closeButton: true,
|
1208
|
-
timeOut: 3000,
|
1209
|
-
timeOutProgress: true,
|
1210
|
-
});
|
1211
|
-
if (this.isEditingMode() && this.activeEditComment()?.id === comment.id) {
|
1212
|
-
this.resetReplyEditState();
|
1213
|
-
}
|
1214
|
-
dialog.close();
|
1215
|
-
}
|
1216
|
-
}
|
1217
|
-
catch (error) {
|
1166
|
+
await this.commentService.deleteComment(commentId);
|
1167
|
+
this.removeMessageById(commentId);
|
1218
1168
|
this.toastService.show({
|
1219
|
-
content:
|
1220
|
-
color: '
|
1169
|
+
content: 'Comment deleted successfully.',
|
1170
|
+
color: 'success',
|
1221
1171
|
location: 'bottom-center',
|
1222
1172
|
closeButton: true,
|
1223
1173
|
timeOut: 3000,
|
1224
1174
|
timeOutProgress: true,
|
1225
1175
|
});
|
1226
|
-
|
1227
|
-
|
1228
|
-
},
|
1229
|
-
{
|
1230
|
-
text: 'Cancel',
|
1231
|
-
color: 'default',
|
1232
|
-
autofocus: true,
|
1233
|
-
onClick: (e) => {
|
1234
|
-
dialog.close();
|
1235
|
-
},
|
1236
|
-
},
|
1237
|
-
],
|
1238
|
-
closeButton: false,
|
1239
|
-
});
|
1240
|
-
}
|
1241
|
-
async deleteReply(comment, reply) {
|
1242
|
-
const dialog = this.dialogService.open({
|
1243
|
-
icon: 'fa-regular fa-warning',
|
1244
|
-
content: 'Are you sure you want to delete this reply?',
|
1245
|
-
title: 'Delete Reply',
|
1246
|
-
type: 'danger',
|
1247
|
-
orientation: 'horizontal',
|
1248
|
-
buttons: [
|
1249
|
-
{
|
1250
|
-
text: 'Delete',
|
1251
|
-
color: 'danger',
|
1252
|
-
onClick: async (e) => {
|
1253
|
-
e.handled = true;
|
1254
|
-
e.source.text = 'Deleting...';
|
1255
|
-
e.source.disabled = true;
|
1256
|
-
e.source.loading = true;
|
1257
|
-
try {
|
1258
|
-
if (reply.id) {
|
1259
|
-
await this.commentService.deleteOne(reply.id);
|
1260
|
-
this.removeMessageById(comment.id, reply.id);
|
1261
|
-
this.toastService.show({
|
1262
|
-
content: 'Comment deleted successfully.',
|
1263
|
-
color: 'success',
|
1264
|
-
location: 'bottom-center',
|
1265
|
-
closeButton: true,
|
1266
|
-
timeOut: 3000,
|
1267
|
-
timeOutProgress: true,
|
1268
|
-
});
|
1269
|
-
dialog.close();
|
1176
|
+
if (this.isEditingMode() && this.activeEditComment()?.id === commentId) {
|
1177
|
+
this.resetReplyEditState();
|
1270
1178
|
}
|
1179
|
+
dialog.close();
|
1271
1180
|
}
|
1272
1181
|
catch (error) {
|
1273
1182
|
this.toastService.show({
|
@@ -1301,130 +1210,83 @@ class AXMCommentListViewComponent {
|
|
1301
1210
|
this.commentContent.set('');
|
1302
1211
|
document.getElementsByClassName('ql-editor')[0].innerHTML = '';
|
1303
1212
|
}
|
1304
|
-
async toggleLike(comment
|
1213
|
+
async toggleLike(comment) {
|
1214
|
+
const isLiked = this.isLikedByUser(comment);
|
1215
|
+
this.updateLikeStatus(comment.id, !isLiked);
|
1305
1216
|
try {
|
1306
|
-
if (
|
1307
|
-
|
1308
|
-
this.updateLikeStatus(comment.id, reply.id);
|
1309
|
-
await this.commentService.like(reply.id);
|
1310
|
-
}
|
1217
|
+
if (isLiked) {
|
1218
|
+
await this.commentService.unlikeComment(comment.id);
|
1311
1219
|
}
|
1312
1220
|
else {
|
1313
|
-
|
1314
|
-
this.updateLikeStatus(comment.id);
|
1315
|
-
await this.commentService.like(comment.id);
|
1316
|
-
}
|
1221
|
+
await this.commentService.likeComment(comment.id);
|
1317
1222
|
}
|
1318
1223
|
}
|
1319
1224
|
catch (error) {
|
1320
1225
|
console.error('Failed to toggle like:', error);
|
1321
|
-
// Revert
|
1322
|
-
|
1323
|
-
|
1324
|
-
|
1325
|
-
|
1326
|
-
|
1327
|
-
|
1328
|
-
|
1329
|
-
|
1330
|
-
|
1331
|
-
|
1332
|
-
|
1333
|
-
|
1334
|
-
if (replyId && comment.replies) {
|
1335
|
-
const updatedReplies = comment.replies.map((reply) => reply.id === replyId
|
1336
|
-
? {
|
1337
|
-
...reply,
|
1338
|
-
isLiked: !reply.isLiked,
|
1339
|
-
reactionsCount: reply.isLiked && reply.reactionsCount !== undefined
|
1340
|
-
? reply.reactionsCount - 1
|
1341
|
-
: (reply.reactionsCount || 0) + 1,
|
1342
|
-
}
|
1343
|
-
: reply);
|
1344
|
-
return {
|
1345
|
-
...comment,
|
1346
|
-
replies: updatedReplies,
|
1347
|
-
};
|
1226
|
+
this.updateLikeStatus(comment.id, isLiked); // Revert optimistic update
|
1227
|
+
}
|
1228
|
+
}
|
1229
|
+
updateLikeStatus(commentId, willBeLiked) {
|
1230
|
+
const findAndToggle = (comments) => {
|
1231
|
+
return comments.map((c) => {
|
1232
|
+
if (c.id === commentId) {
|
1233
|
+
const user = this.getCurrentUser();
|
1234
|
+
if (!user)
|
1235
|
+
return c;
|
1236
|
+
let reactions = c.reactions || [];
|
1237
|
+
if (willBeLiked) {
|
1238
|
+
reactions.push({ author: user, type: 'like' });
|
1348
1239
|
}
|
1349
1240
|
else {
|
1350
|
-
|
1351
|
-
...comment,
|
1352
|
-
isLiked: !comment.isLiked,
|
1353
|
-
reactionsCount: comment.isLiked && comment.reactionsCount !== undefined
|
1354
|
-
? comment.reactionsCount - 1
|
1355
|
-
: (comment.reactionsCount || 0) + 1,
|
1356
|
-
};
|
1241
|
+
reactions = reactions.filter((r) => r.author.id !== user.id || r.type !== 'like');
|
1357
1242
|
}
|
1243
|
+
return { ...c, reactions };
|
1244
|
+
}
|
1245
|
+
if (c.replies && c.replies.length > 0) {
|
1246
|
+
c.replies = findAndToggle(c.replies);
|
1358
1247
|
}
|
1359
|
-
return
|
1248
|
+
return c;
|
1360
1249
|
});
|
1361
|
-
}
|
1362
|
-
|
1363
|
-
|
1364
|
-
|
1365
|
-
|
1366
|
-
|
1367
|
-
|
1368
|
-
|
1369
|
-
|
1370
|
-
|
1371
|
-
};
|
1250
|
+
};
|
1251
|
+
this.comments.update((comments) => findAndToggle(comments));
|
1252
|
+
}
|
1253
|
+
removeMessageById(commentId) {
|
1254
|
+
const filterOut = (comments) => {
|
1255
|
+
return comments
|
1256
|
+
.filter((c) => c.id !== commentId)
|
1257
|
+
.map((c) => {
|
1258
|
+
if (c.replies && c.replies.length > 0) {
|
1259
|
+
c.replies = filterOut(c.replies);
|
1372
1260
|
}
|
1373
|
-
return
|
1374
|
-
})
|
1375
|
-
}
|
1376
|
-
|
1377
|
-
// Remove a whole comment
|
1378
|
-
this.comments.update((commentsList) => commentsList.filter((comment) => comment.id !== commentId));
|
1379
|
-
}
|
1261
|
+
return c;
|
1262
|
+
});
|
1263
|
+
};
|
1264
|
+
this.comments.update((comments) => filterOut(comments));
|
1380
1265
|
}
|
1381
|
-
async submitComment(
|
1266
|
+
async submitComment() {
|
1382
1267
|
if (!this.validateContent(this.commentContent()).result) {
|
1383
1268
|
return;
|
1384
1269
|
}
|
1385
1270
|
this.isSubmitting.set(true);
|
1386
|
-
|
1387
|
-
if (isPrivate) {
|
1388
|
-
const popupConfig = {
|
1389
|
-
header: true,
|
1390
|
-
size: 'md',
|
1391
|
-
draggable: true,
|
1392
|
-
hasBackdrop: true,
|
1393
|
-
closeButton: true,
|
1394
|
-
closeOnBackdropClick: false,
|
1395
|
-
};
|
1396
|
-
const popup = await this.popupService.open(AXMCommentLookupPopup, popupConfig);
|
1397
|
-
memberLookup = popup.data?.lookup;
|
1398
|
-
}
|
1271
|
+
console.log(this.commentContent());
|
1399
1272
|
try {
|
1273
|
+
let currentThread = this.thread();
|
1274
|
+
if (!currentThread) {
|
1275
|
+
currentThread = await this.commentService.createThread({ type: this.refrenceType(), id: this.refrenceId() }, this.subject());
|
1276
|
+
this.thread.set(currentThread);
|
1277
|
+
}
|
1400
1278
|
if (this.isEditingMode() && this.activeEditComment()?.id) {
|
1401
|
-
|
1402
|
-
message: {
|
1403
|
-
content: this.commentContent(),
|
1404
|
-
contentType: 'text',
|
1405
|
-
},
|
1406
|
-
};
|
1407
|
-
await this.commentService.updateOne(this.activeEditComment().id, payload);
|
1279
|
+
await this.commentService.editComment(this.activeEditComment().id, this.commentContent());
|
1408
1280
|
this.hasCooldown.set(true);
|
1409
1281
|
this.isEditingMode.set(false);
|
1410
1282
|
this.activeEditComment.set(undefined);
|
1411
1283
|
}
|
1412
1284
|
else {
|
1413
|
-
|
1414
|
-
...this.payload(),
|
1415
|
-
content: this.commentContent(),
|
1416
|
-
contentType: 'text',
|
1417
|
-
isPrivate: isPrivate,
|
1418
|
-
replyId: this.activeReplyComment()?.id ?? null,
|
1419
|
-
};
|
1420
|
-
await this.commentService.insertOne(payload);
|
1285
|
+
await this.commentService.addComment(currentThread.id, this.commentContent(), this.activeReplyComment()?.id);
|
1421
1286
|
this.hasCooldown.set(true);
|
1422
1287
|
this.isReplyingMode.set(false);
|
1423
1288
|
this.activeReplyComment.set(undefined);
|
1424
1289
|
}
|
1425
|
-
// Reload comments to get the updated list with proper hierarchy
|
1426
|
-
const response = await this.commentService.query(this.getPayload());
|
1427
|
-
this.comments.set(response.items);
|
1428
1290
|
this.commentContent.set('');
|
1429
1291
|
document.getElementsByClassName('ql-editor')[0].innerHTML = '';
|
1430
1292
|
setTimeout(() => {
|
@@ -1452,28 +1314,33 @@ class AXMCommentListViewComponent {
|
|
1452
1314
|
const el = document.getElementById(comment.id);
|
1453
1315
|
if (el) {
|
1454
1316
|
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
1455
|
-
|
1456
|
-
|
1457
|
-
|
1458
|
-
|
1459
|
-
content.style.transition = 'background 1s ease-in-out';
|
1460
|
-
content.style.background = `rgba(var(--ax-color-on-surface), var(--tw-bg-opacity))`;
|
1461
|
-
setTimeout(() => {
|
1462
|
-
content.style.background = prevBg || 'rgba(0, 0, 0, 0)';
|
1463
|
-
}, 1000);
|
1464
|
-
}
|
1317
|
+
this.highlightedCommentId.set(comment.id);
|
1318
|
+
setTimeout(() => {
|
1319
|
+
this.highlightedCommentId.set(null);
|
1320
|
+
}, 1000);
|
1465
1321
|
}
|
1466
1322
|
}
|
1467
1323
|
}
|
1468
|
-
|
1469
|
-
return date ? Date.now() - date.getTime() : undefined;
|
1470
|
-
|
1471
|
-
|
1472
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: AXMCommentListViewComponent, isStandalone: true, selector: "axm-comment-list-view", viewQueries: [{ propertyName: "wysiwygEditor", first: true, predicate: ["w"], descendants: true, isSignal: true }, { propertyName: "wysiwyg", first: true, predicate: ["w"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"ax-mt-2\">\n <ax-comment-container>\n @if (isLoading()) {\n <div class=\"ax-flex ax-items-center ax-py-12 ax-bg-lightest ax-px-5\">\n <ax-skeleton class=\"ax-min-w-16 ax-h-16 ax-rounded-full ax-me-4\"></ax-skeleton>\n <div class=\"ax-flex ax-flex-col ax-gap-2 ax-w-full\">\n <ax-skeleton class=\"ax-w-full ax-h-6 ax-rounded\"></ax-skeleton>\n <ax-skeleton class=\"ax-w-full ax-h-2 ax-rounded-full\"></ax-skeleton>\n <ax-skeleton class=\"ax-w-full ax-h-2 ax-rounded-full\"></ax-skeleton>\n <ax-skeleton class=\"ax-w-8/12 ax-h-2 ax-rounded-full\"></ax-skeleton>\n </div>\n </div>\n } @else if (!isLoading() && comments().length > 0) {\n <ax-comment-view class=\"ax-bg-lightest\">\n @for (comment of comments(); track comment.id) {\n <ax-comment-item [id]=\"comment.id!\" [replyCount]=\"comment.replies?.length ?? 0\">\n <ax-avatar [color]=\"avatarConfig().color\" [shape]=\"avatarConfig().look\">\n @if (checkImageExists(comment.id!) && comment.author && extractInitials(comment.author) !== '?') {\n <ax-image (onError)=\"handleImageError(comment.id!)\" [src]=\"''\">\n <ax-loading></ax-loading>\n </ax-image>\n } @else {\n <ax-text>\n <span class=\"ax-text-base ax-overflow-hidden\">{{ extractInitials(comment.author) }}</span>\n </ax-text>\n }\n </ax-avatar>\n <ax-title>{{ extractInitials(comment.author) }}</ax-title>\n <ax-comment-date>{{ calcDefrenetTime(comment.createdAt) | format: 'timeleft' | async }} </ax-comment-date>\n <ax-comment-menu-options>\n <ax-button class=\"ax-sm\" look=\"blank\" color=\"neutral\">\n <ax-icon icon=\"ax-icon ax-icon-solid ax-icon-more-horizontal\"></ax-icon>\n </ax-button>\n\n <ax-dropdown-panel>\n <ax-button-item-list>\n <ax-button-item text=\"Edit\" color=\"neutral\" (click)=\"editMessage(comment)\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-edit\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n\n <ax-button-item text=\"Delete\" color=\"danger\" (click)=\"deleteComment(comment)\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-trash-can\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-comment-menu-options>\n <ax-content [innerHTML]=\"sanitizeHtml(comment.message.content)\"></ax-content>\n <ax-comment-like (click)=\"toggleLike(comment)\" [liked]=\"comment.isLiked!\">\n {{ comment.reactionsCount }}\n </ax-comment-like>\n <ax-comment-reply-text (click)=\"replyMessage(comment)\"></ax-comment-reply-text>\n @for (reply of comment.replies; track reply.id) {\n <ax-comment-item [id]=\"reply.id\">\n <ax-avatar [color]=\"avatarConfig().color\" [shape]=\"avatarConfig().look\">\n @if (reply && checkImageExists(reply.id!) && reply.author && extractInitials(reply.author) !== '?') {\n <ax-image (onError)=\"handleImageError(reply.id!)\" [src]=\"''\">\n <ax-loading></ax-loading>\n </ax-image>\n } @else {\n <ax-text>\n <span class=\"ax-text-base ax-overflow-hidden\">{{ extractInitials(reply.author) }}</span>\n </ax-text>\n }\n </ax-avatar>\n <ax-title>{{ extractInitials(reply.author) }}</ax-title>\n <ax-comment-date>{{ calcDefrenetTime(reply.createdAt) | format: 'timeleft' | async }} </ax-comment-date>\n <ax-comment-menu-options>\n <ax-button class=\"ax-sm\" look=\"blank\" color=\"neutral\">\n <ax-icon icon=\"ax-icon ax-icon-solid ax-icon-more-horizontal\"></ax-icon>\n </ax-button>\n\n <ax-dropdown-panel>\n <ax-button-item-list>\n <ax-button-item text=\"Edit\" color=\"neutral\" (click)=\"editMessage(comment, reply)\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-edit\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n <ax-button-item text=\"Delete\" color=\"danger\" (click)=\"deleteReply(comment, reply)\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-trash-can\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-comment-menu-options>\n <ax-content [innerHTML]=\"sanitizeHtml(reply.message.content)\"></ax-content>\n <ax-comment-like (click)=\"toggleLike(comment, reply)\" [liked]=\"reply.isLiked!\">\n {{ reply.reactionsCount }}\n </ax-comment-like>\n <ax-comment-reply-text (click)=\"replyMessage(comment, reply)\"></ax-comment-reply-text>\n </ax-comment-item>\n }\n </ax-comment-item>\n }\n </ax-comment-view>\n } @else {\n <div>\n <div class=\"ax-flex ax-flex-col ax-gap-4 ax-justify-center ax-items-center ax-p-10\">\n <svg\n class=\"ax-mx-auto\"\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"154\"\n height=\"161\"\n viewBox=\"0 0 154 161\"\n fill=\"none\"\n >\n <path\n d=\"M0.0616455 84.4268C0.0616455 42.0213 34.435 7.83765 76.6507 7.83765C118.803 7.83765 153.224 42.0055 153.224 84.4268C153.224 102.42 147.026 118.974 136.622 132.034C122.282 150.138 100.367 161 76.6507 161C52.7759 161 30.9882 150.059 16.6633 132.034C6.25961 118.974 0.0616455 102.42 0.0616455 84.4268Z\"\n fill=\"#EEF2FF\"\n />\n <path\n d=\"M96.8189 0.632498L96.8189 0.632384L96.8083 0.630954C96.2034 0.549581 95.5931 0.5 94.9787 0.5H29.338C22.7112 0.5 17.3394 5.84455 17.3394 12.4473V142.715C17.3394 149.318 22.7112 154.662 29.338 154.662H123.948C130.591 154.662 135.946 149.317 135.946 142.715V38.9309C135.946 38.0244 135.847 37.1334 135.648 36.2586L135.648 36.2584C135.117 33.9309 133.874 31.7686 132.066 30.1333C132.066 30.1331 132.065 30.1329 132.065 30.1327L103.068 3.65203C103.068 3.6519 103.067 3.65177 103.067 3.65164C101.311 2.03526 99.1396 0.995552 96.8189 0.632498Z\"\n fill=\"white\"\n stroke=\"#E5E7EB\"\n />\n <ellipse cx=\"80.0618\" cy=\"81\" rx=\"28.0342\" ry=\"28.0342\" fill=\"#EEF2FF\" />\n <path\n d=\"M99.2393 61.3061L99.2391 61.3058C88.498 50.5808 71.1092 50.5804 60.3835 61.3061C49.6423 72.0316 49.6422 89.4361 60.3832 100.162C71.109 110.903 88.4982 110.903 99.2393 100.162C109.965 89.4363 109.965 72.0317 99.2393 61.3061ZM105.863 54.6832C120.249 69.0695 120.249 92.3985 105.863 106.785C91.4605 121.171 68.1468 121.171 53.7446 106.785C39.3582 92.3987 39.3582 69.0693 53.7446 54.683C68.1468 40.2965 91.4605 40.2966 105.863 54.6832Z\"\n stroke=\"#E5E7EB\"\n />\n <path\n d=\"M110.782 119.267L102.016 110.492C104.888 108.267 107.476 105.651 109.564 102.955L118.329 111.729L110.782 119.267Z\"\n stroke=\"#E5E7EB\"\n />\n <path\n d=\"M139.122 125.781L139.122 125.78L123.313 109.988C123.313 109.987 123.313 109.987 123.312 109.986C121.996 108.653 119.849 108.657 118.521 109.985L118.871 110.335L118.521 109.985L109.047 119.459C107.731 120.775 107.735 122.918 109.044 124.247L109.047 124.249L124.858 140.06C128.789 143.992 135.191 143.992 139.122 140.06C143.069 136.113 143.069 129.728 139.122 125.781Z\"\n fill=\"#A5B4FC\"\n stroke=\"#818CF8\"\n />\n <path\n d=\"M83.185 87.2285C82.5387 87.2285 82.0027 86.6926 82.0027 86.0305C82.0027 83.3821 77.9987 83.3821 77.9987 86.0305C77.9987 86.6926 77.4627 87.2285 76.8006 87.2285C76.1543 87.2285 75.6183 86.6926 75.6183 86.0305C75.6183 80.2294 84.3831 80.2451 84.3831 86.0305C84.3831 86.6926 83.8471 87.2285 83.185 87.2285Z\"\n fill=\"#4F46E5\"\n />\n <path\n d=\"M93.3528 77.0926H88.403C87.7409 77.0926 87.2049 76.5567 87.2049 75.8946C87.2049 75.2483 87.7409 74.7123 88.403 74.7123H93.3528C94.0149 74.7123 94.5509 75.2483 94.5509 75.8946C94.5509 76.5567 94.0149 77.0926 93.3528 77.0926Z\"\n fill=\"#4F46E5\"\n />\n <path\n d=\"M71.5987 77.0925H66.6488C65.9867 77.0925 65.4507 76.5565 65.4507 75.8945C65.4507 75.2481 65.9867 74.7122 66.6488 74.7122H71.5987C72.245 74.7122 72.781 75.2481 72.781 75.8945C72.781 76.5565 72.245 77.0925 71.5987 77.0925Z\"\n fill=\"#4F46E5\"\n />\n <rect x=\"38.3522\" y=\"21.5128\" width=\"41.0256\" height=\"2.73504\" rx=\"1.36752\" fill=\"#4F46E5\" />\n <rect x=\"38.3522\" y=\"133.65\" width=\"54.7009\" height=\"5.47009\" rx=\"2.73504\" fill=\"#A5B4FC\" />\n <rect x=\"38.3522\" y=\"29.7179\" width=\"13.6752\" height=\"2.73504\" rx=\"1.36752\" fill=\"#4F46E5\" />\n <circle cx=\"56.13\" cy=\"31.0854\" r=\"1.36752\" fill=\"#4F46E5\" />\n <circle cx=\"61.6001\" cy=\"31.0854\" r=\"1.36752\" fill=\"#4F46E5\" />\n <circle cx=\"67.0702\" cy=\"31.0854\" r=\"1.36752\" fill=\"#4F46E5\" />\n </svg>\n <div>\n <h2 class=\"ax-text-center ax-text-neutral-600 ax-font-semibold ax-leading-loose ax-pb-2\">\n There is no Comment!\n </h2>\n </div>\n </div>\n </div>\n }\n </ax-comment-container>\n <ax-form>\n <ax-form-field>\n <div>\n @if (isReplyingMode() || isEditingMode()) {\n <div\n class=\"ax-flex ax-justify-between ax-rounded-b-none ax-border ax-border-b-0 ax-rounded-lg ax-bg-on-surface ax-px-6 ax-py-3 ax-w-full ax-items-center ax-overflow-hidden ax-text-sm ax-leading-none\"\n >\n <div (click)=\"scrollMain()\" class=\"ax-flex ax-justify-start ax-items-center ax-cursor-pointer\">\n <i\n [class]=\"isReplyingMode() ? 'fa-reply' : 'fa-pen'\"\n class=\"fa-solid ax-text-primary-500 dark:ax-text-primary-300 ax-text-2xl ax-me-4\"\n ></i>\n <div\n class=\"ax-flex ax-flex-col ax-gap-2 ax-justify-between ax-align-middle ax-leading-4 ax-overflow-hidden\"\n >\n <p class=\"ax-text-primary-500 dark:ax-text-primary-300\">\n {{ isReplyingMode() ? 'Reply to ' : 'Edit Message' }}\n <span class=\"ax-font-bold\">\n {{ isReplyingMode() ? extractInitials(activeReplyComment()?.author) : '' }}\n </span>\n </p>\n <div\n class=\"ax-truncate\"\n [innerHTML]=\"\n isReplyingMode()\n ? sanitizeHtml(activeReplyComment()?.message?.content ?? '')\n : sanitizeHtml(activeEditComment()?.message?.content ?? '')\n \"\n ></div>\n </div>\n </div>\n <div><i (click)=\"resetReplyEditState()\" class=\"fa-solid ax-text-2xl fa-xmark ax-cursor-pointer\"></i></div>\n </div>\n }\n <ax-wysiwyg-container #w [look]=\"wysiwygOptions().look\" [(ngModel)]=\"commentContent\">\n <ax-wysiwyg-view class=\"ax-min-h-28\"></ax-wysiwyg-view>\n <ax-toolbar>\n <ax-content>\n <ax-wysiwyg-history></ax-wysiwyg-history>\n <ax-wysiwyg-font-style></ax-wysiwyg-font-style>\n <ax-wysiwyg-colors></ax-wysiwyg-colors>\n <ax-wysiwyg-list></ax-wysiwyg-list>\n <ax-wysiwyg-alignment></ax-wysiwyg-alignment>\n </ax-content>\n <ax-suffix>\n <ax-dropdown-button\n [disabled]=\"hasCooldown()\"\n type=\"submit\"\n color=\"primary\"\n mode=\"split\"\n text=\"Send\"\n (onClick)=\"submitComment()\"\n >\n @if (isSubmitting()) {\n <ax-loading></ax-loading>\n }\n <ax-button-item-list>\n <ax-button-item (click)=\"submitComment(true)\" text=\"Send Private ...\" name=\"private\" data=\"private\">\n <ax-prefix>\n <ax-icon icon=\"fa-regular fa-user-secret\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n </ax-button-item-list>\n </ax-dropdown-button>\n </ax-suffix>\n </ax-toolbar>\n <ax-validation-rule rule=\"callback\" [options]=\"{ validate: validateContent }\"></ax-validation-rule>\n </ax-wysiwyg-container>\n </div>\n </ax-form-field>\n </ax-form>\n</div>\n", styles: ["ax-wysiwyg-container .ax-editor-container{border-top-left-radius:0!important;border-top-right-radius:0!important}ax-wysiwyg-container .ax-error-message{padding-left:.5rem}\n"], dependencies: [{ kind: "ngmodule", type: AXWysiwygModule }, { kind: "component", type: i1.AXWysiwygContainerComponent, selector: "ax-wysiwyg-container", inputs: ["look", "placeHolder"], outputs: ["onValueChanged"] }, { kind: "component", type: i1.AXWysiwygViewComponent, selector: "ax-wysiwyg-view", inputs: ["class"] }, { kind: "component", type: i1.AXWysiwygAlignmentComponent, selector: "ax-wysiwyg-alignment" }, { kind: "component", type: i1.AXWysiwygColorsComponent, selector: "ax-wysiwyg-colors" }, { kind: "component", type: i1.AXWysiwygFontStyleComponent, selector: "ax-wysiwyg-font-style" }, { kind: "component", type: i1.AXWysiwygHistoryComponent, selector: "ax-wysiwyg-history" }, { kind: "component", type: i1.AXWysiwygListComponent, selector: "ax-wysiwyg-list" }, { kind: "ngmodule", type: AXConversationModule }, { kind: "ngmodule", type: AXSkeletonModule }, { kind: "component", type: i2$1.AXSkeletonComponent, selector: "ax-skeleton", inputs: ["animated"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i5.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i5.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXCommentModule }, { kind: "component", type: i4.AXCommentViewComponent, selector: "ax-comment-view" }, { kind: "component", type: i4.AXCommentContainerComponent, selector: "ax-comment-container" }, { kind: "component", type: i4.AxCommentItemComponent, selector: "ax-comment-item", inputs: ["replyCount"] }, { kind: "component", type: i4.AXCommentLikeComponent, selector: "ax-comment-like", inputs: ["liked"], outputs: ["likedChange", "onLiked"] }, { kind: "component", type: i4.AXMenuOptionsComponent, selector: "ax-comment-menu-options" }, { kind: "component", type: i4.AXCommentReplyTextComponent, selector: "ax-comment-reply-text" }, { kind: "component", type: i4.AXCommentDateComponent, selector: "ax-comment-date" }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i5$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "component", type: i5$1.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i5$1.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items"], outputs: ["onItemClick"] }, { kind: "ngmodule", type: AXAvatarModule }, { kind: "component", type: i6.AXAvatarComponent, selector: "ax-avatar", inputs: ["color", "size", "shape", "look"], outputs: ["sizeChange"] }, { kind: "ngmodule", type: AXImageModule }, { kind: "component", type: i7.AXImageComponent, selector: "ax-image", inputs: ["width", "height", "overlayMode", "src", "alt", "priority", "lazy"], outputs: ["onLoad", "onError"] }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i8.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "component", type: i9.AXDropdownPanelComponent, selector: "ax-dropdown-panel", inputs: ["isOpen", "fitParent", "dropdownWidth", "position", "placement", "_target", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXFormatModule }, { kind: "pipe", type: i10.AXFormatPipe, name: "format" }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "ngmodule", type: AXFormModule }, { kind: "component", type: i11.AXFormFieldComponent, selector: "ax-form-field", inputs: ["labelMode"] }, { kind: "component", type: i11.AXFormComponent, selector: "ax-form", inputs: ["labelMode", "look", "messageStyle", "updateOn"], outputs: ["onValidate", "updateOnChange"] }, { kind: "directive", type: i11.AXValidationRuleDirective, selector: "ax-validation-rule", inputs: ["rule", "options", "message", "disabled"] }, { kind: "ngmodule", type: AXToolBarModule }, { kind: "component", type: i12.AXToolBarComponent, selector: "ax-toolbar" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i13.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i13.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXDropdownButtonModule }, { kind: "component", type: i14.AXDropdownButtonComponent, selector: "ax-dropdown-button", inputs: ["disabled", "size", "color", "look", "text", "type", "mode"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "lookChange", "colorChange", "disabledChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
1324
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMCommentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
1325
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: AXMCommentComponent, isStandalone: true, selector: "axm-comment", inputs: { refrenceType: { classPropertyName: "refrenceType", publicName: "refrenceType", isSignal: true, isRequired: true, transformFunction: null }, refrenceId: { classPropertyName: "refrenceId", publicName: "refrenceId", isSignal: true, isRequired: true, transformFunction: null }, subject: { classPropertyName: "subject", publicName: "subject", isSignal: true, isRequired: true, transformFunction: null } }, viewQueries: [{ propertyName: "wysiwygEditor", first: true, predicate: ["w"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"ax-size-full ax-flex ax-flex-col ax-justify-between ax-p-4 ax-overflow-hidden\">\n <ax-comment-container class=\"ax-overflow-auto\">\n @if (isLoading()) {\n <div class=\"ax-flex ax-items-center ax-py-12 ax-bg-lightest ax-px-5\">\n <ax-skeleton class=\"ax-min-w-16 ax-h-16 ax-rounded-full ax-me-4\"></ax-skeleton>\n <div class=\"ax-flex ax-flex-col ax-gap-2 ax-w-full\">\n <ax-skeleton class=\"ax-w-full ax-h-6 ax-rounded\"></ax-skeleton>\n <ax-skeleton class=\"ax-w-full ax-h-2 ax-rounded-full\"></ax-skeleton>\n <ax-skeleton class=\"ax-w-full ax-h-2 ax-rounded-full\"></ax-skeleton>\n <ax-skeleton class=\"ax-w-8/12 ax-h-2 ax-rounded-full\"></ax-skeleton>\n </div>\n </div>\n } @else if (!isLoading() && comments().length > 0) {\n <ax-comment-view class=\"ax-bg-lightest\">\n @for (comment of comments(); track comment.id) {\n <ax-comment-item\n [id]=\"comment.id!\"\n [replyCount]=\"comment.replyCount\"\n [class.highlighted]=\"highlightedCommentId() === comment.id\"\n [@fadeIn]\n >\n <axp-user-avatar #user [size]=\"48\" [userId]=\"comment.author.id\" ngProjectAs=\"'ax-avatar'\"></axp-user-avatar>\n <ax-title>{{ user.firstName() + ' ' + user.lastName() }}</ax-title>\n <ax-comment-date>{{ comment.createdAt | format: 'timeleft' | async }} </ax-comment-date>\n <ax-comment-menu-options>\n <ax-button class=\"ax-sm\" look=\"blank\" color=\"neutral\">\n <ax-icon icon=\"ax-icon ax-icon-solid ax-icon-more-horizontal\"></ax-icon>\n </ax-button>\n\n <ax-dropdown-panel>\n <ax-button-item-list>\n <ax-button-item\n text=\"Edit\"\n color=\"neutral\"\n (click)=\"editMessage(comment, undefined, user.firstName() + ' ' + user.lastName())\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-edit\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n\n <ax-button-item text=\"Delete\" color=\"danger\" (click)=\"deleteComment(comment.id!)\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-trash-can\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-comment-menu-options>\n <ax-content [innerHTML]=\"sanitizeHtml(comment.message.content)\"></ax-content>\n <ax-comment-like (click)=\"toggleLike(comment)\" [liked]=\"isLikedByUser(comment)\">\n {{ getReactionsCount(comment) }}\n </ax-comment-like>\n <ax-comment-reply-text\n (click)=\"replyMessage(comment, undefined, user.firstName() + ' ' + user.lastName())\"\n ></ax-comment-reply-text>\n @for (reply of comment.replies; track reply.id) {\n <ax-comment-item [id]=\"reply.id\" [class.highlighted]=\"highlightedCommentId() === reply.id\" [@fadeIn]>\n <axp-user-avatar\n #user2\n [size]=\"48\"\n [userId]=\"reply.author.id\"\n ngProjectAs=\"'ax-avatar'\"\n ></axp-user-avatar>\n <ax-title>{{ user2.firstName() + ' ' + user2.lastName() }}</ax-title>\n <ax-comment-date>{{ reply.createdAt | format: 'timeleft' | async }} </ax-comment-date>\n <ax-comment-menu-options>\n <ax-button class=\"ax-sm\" look=\"blank\" color=\"neutral\">\n <ax-icon icon=\"ax-icon ax-icon-solid ax-icon-more-horizontal\"></ax-icon>\n </ax-button>\n\n <ax-dropdown-panel>\n <ax-button-item-list>\n <ax-button-item\n text=\"Edit\"\n color=\"neutral\"\n (click)=\"editMessage(comment, reply, user2.firstName() + ' ' + user2.lastName())\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-edit\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n <ax-button-item text=\"Delete\" color=\"danger\" (click)=\"deleteComment(reply.id!)\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-trash-can\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-comment-menu-options>\n <ax-content [innerHTML]=\"sanitizeHtml(reply.message.content)\"></ax-content>\n <ax-comment-like (click)=\"toggleLike(reply)\" [liked]=\"isLikedByUser(reply)\">\n {{ getReactionsCount(reply) }}\n </ax-comment-like>\n <ax-comment-reply-text\n (click)=\"replyMessage(comment, reply, user2.firstName() + ' ' + user2.lastName())\"\n ></ax-comment-reply-text>\n </ax-comment-item>\n }\n </ax-comment-item>\n }\n </ax-comment-view>\n } @else {\n <div>\n <div class=\"ax-flex ax-flex-col ax-gap-4 ax-justify-center ax-items-center ax-p-10\">\n <svg\n class=\"ax-mx-auto\"\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"154\"\n height=\"161\"\n viewBox=\"0 0 154 161\"\n fill=\"none\"\n >\n <path\n d=\"M0.0616455 84.4268C0.0616455 42.0213 34.435 7.83765 76.6507 7.83765C118.803 7.83765 153.224 42.0055 153.224 84.4268C153.224 102.42 147.026 118.974 136.622 132.034C122.282 150.138 100.367 161 76.6507 161C52.7759 161 30.9882 150.059 16.6633 132.034C6.25961 118.974 0.0616455 102.42 0.0616455 84.4268Z\"\n fill=\"#EEF2FF\"\n />\n <path\n d=\"M96.8189 0.632498L96.8189 0.632384L96.8083 0.630954C96.2034 0.549581 95.5931 0.5 94.9787 0.5H29.338C22.7112 0.5 17.3394 5.84455 17.3394 12.4473V142.715C17.3394 149.318 22.7112 154.662 29.338 154.662H123.948C130.591 154.662 135.946 149.317 135.946 142.715V38.9309C135.946 38.0244 135.847 37.1334 135.648 36.2586L135.648 36.2584C135.117 33.9309 133.874 31.7686 132.066 30.1333C132.066 30.1331 132.065 30.1329 132.065 30.1327L103.068 3.65203C103.068 3.6519 103.067 3.65177 103.067 3.65164C101.311 2.03526 99.1396 0.995552 96.8189 0.632498Z\"\n fill=\"white\"\n stroke=\"#E5E7EB\"\n />\n <ellipse cx=\"80.0618\" cy=\"81\" rx=\"28.0342\" ry=\"28.0342\" fill=\"#EEF2FF\" />\n <path\n d=\"M99.2393 61.3061L99.2391 61.3058C88.498 50.5808 71.1092 50.5804 60.3835 61.3061C49.6423 72.0316 49.6422 89.4361 60.3832 100.162C71.109 110.903 88.4982 110.903 99.2393 100.162C109.965 89.4363 109.965 72.0317 99.2393 61.3061ZM105.863 54.6832C120.249 69.0695 120.249 92.3985 105.863 106.785C91.4605 121.171 68.1468 121.171 53.7446 106.785C39.3582 92.3987 39.3582 69.0693 53.7446 54.683C68.1468 40.2965 91.4605 40.2966 105.863 54.6832Z\"\n stroke=\"#E5E7EB\"\n />\n <path\n d=\"M110.782 119.267L102.016 110.492C104.888 108.267 107.476 105.651 109.564 102.955L118.329 111.729L110.782 119.267Z\"\n stroke=\"#E5E7EB\"\n />\n <path\n d=\"M139.122 125.781L139.122 125.78L123.313 109.988C123.313 109.987 123.313 109.987 123.312 109.986C121.996 108.653 119.849 108.657 118.521 109.985L118.871 110.335L118.521 109.985L109.047 119.459C107.731 120.775 107.735 122.918 109.044 124.247L109.047 124.249L124.858 140.06C128.789 143.992 135.191 143.992 139.122 140.06C143.069 136.113 143.069 129.728 139.122 125.781Z\"\n fill=\"#A5B4FC\"\n stroke=\"#818CF8\"\n />\n <path\n d=\"M83.185 87.2285C82.5387 87.2285 82.0027 86.6926 82.0027 86.0305C82.0027 83.3821 77.9987 83.3821 77.9987 86.0305C77.9987 86.6926 77.4627 87.2285 76.8006 87.2285C76.1543 87.2285 75.6183 86.6926 75.6183 86.0305C75.6183 80.2294 84.3831 80.2451 84.3831 86.0305C84.3831 86.6926 83.8471 87.2285 83.185 87.2285Z\"\n fill=\"#4F46E5\"\n />\n <path\n d=\"M93.3528 77.0926H88.403C87.7409 77.0926 87.2049 76.5567 87.2049 75.8946C87.2049 75.2483 87.7409 74.7123 88.403 74.7123H93.3528C94.0149 74.7123 94.5509 75.2483 94.5509 75.8946C94.5509 76.5567 94.0149 77.0926 93.3528 77.0926Z\"\n fill=\"#4F46E5\"\n />\n <path\n d=\"M71.5987 77.0925H66.6488C65.9867 77.0925 65.4507 76.5565 65.4507 75.8945C65.4507 75.2481 65.9867 74.7122 66.6488 74.7122H71.5987C72.245 74.7122 72.781 75.2481 72.781 75.8945C72.781 76.5565 72.245 77.0925 71.5987 77.0925Z\"\n fill=\"#4F46E5\"\n />\n <rect x=\"38.3522\" y=\"21.5128\" width=\"41.0256\" height=\"2.73504\" rx=\"1.36752\" fill=\"#4F46E5\" />\n <rect x=\"38.3522\" y=\"133.65\" width=\"54.7009\" height=\"5.47009\" rx=\"2.73504\" fill=\"#A5B4FC\" />\n <rect x=\"38.3522\" y=\"29.7179\" width=\"13.6752\" height=\"2.73504\" rx=\"1.36752\" fill=\"#4F46E5\" />\n <circle cx=\"56.13\" cy=\"31.0854\" r=\"1.36752\" fill=\"#4F46E5\" />\n <circle cx=\"61.6001\" cy=\"31.0854\" r=\"1.36752\" fill=\"#4F46E5\" />\n <circle cx=\"67.0702\" cy=\"31.0854\" r=\"1.36752\" fill=\"#4F46E5\" />\n </svg>\n <div>\n <h2 class=\"ax-text-center ax-text-neutral-600 ax-font-semibold ax-leading-loose ax-pb-2\">\n There is no Comment!\n </h2>\n </div>\n </div>\n </div>\n }\n </ax-comment-container>\n <ax-form>\n <ax-form-field>\n <div>\n @if (isReplyingMode() || isEditingMode()) {\n <div\n class=\"ax-flex ax-justify-between ax-rounded-b-none ax-border ax-border-b-0 ax-rounded-lg ax-px-6 ax-py-3 ax-w-full ax-items-center ax-overflow-hidden ax-text-sm ax-leading-none\"\n >\n <div (click)=\"scrollMain()\" class=\"ax-flex ax-justify-start ax-items-center ax-cursor-pointer\">\n <i\n [class]=\"isReplyingMode() ? 'fa-reply' : 'fa-pen'\"\n class=\"fa-solid ax-text-primary-500 dark:ax-text-primary-300 ax-text-2xl ax-me-4\"\n ></i>\n <div\n class=\"ax-flex ax-flex-col ax-gap-2 ax-justify-between ax-align-middle ax-leading-4 ax-overflow-hidden\"\n >\n <p class=\"ax-text-primary-500 dark:ax-text-primary-300\">\n {{ isReplyingMode() ? 'Reply to ' : 'Edit Message' }}\n <span class=\"ax-font-bold\">\n {{ isReplyingMode() ? activeReplyComment()?.userName : '' }}\n </span>\n </p>\n <div\n class=\"ax-truncate\"\n [innerHTML]=\"\n isReplyingMode()\n ? sanitizeHtml(activeReplyComment()?.message?.content ?? '')\n : sanitizeHtml(activeEditComment()?.message?.content ?? '')\n \"\n ></div>\n </div>\n </div>\n <div><i (click)=\"resetReplyEditState()\" class=\"fa-solid ax-text-2xl fa-xmark ax-cursor-pointer\"></i></div>\n </div>\n }\n <ax-wysiwyg-container #w [look]=\"wysiwygOptions().look\" [(ngModel)]=\"commentContent\">\n <ax-wysiwyg-view class=\"ax-min-h-28\"></ax-wysiwyg-view>\n <ax-toolbar>\n <ax-content>\n <ax-wysiwyg-history></ax-wysiwyg-history>\n <ax-wysiwyg-font-style></ax-wysiwyg-font-style>\n <ax-wysiwyg-colors></ax-wysiwyg-colors>\n <ax-wysiwyg-list></ax-wysiwyg-list>\n <ax-wysiwyg-alignment></ax-wysiwyg-alignment>\n </ax-content>\n <ax-suffix>\n <ax-dropdown-button\n [disabled]=\"hasCooldown()\"\n type=\"submit\"\n color=\"primary\"\n mode=\"split\"\n text=\"Send\"\n (onClick)=\"submitComment()\"\n >\n @if (isSubmitting()) {\n <ax-loading></ax-loading>\n }\n <ax-button-item-list>\n <ax-button-item (click)=\"submitComment()\" text=\"Send Private ...\" name=\"private\" data=\"private\">\n <ax-prefix>\n <ax-icon icon=\"fa-regular fa-user-secret\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n </ax-button-item-list>\n </ax-dropdown-button>\n </ax-suffix>\n </ax-toolbar>\n <ax-validation-rule rule=\"callback\" [options]=\"{ validate: validateContent }\"></ax-validation-rule>\n </ax-wysiwyg-container>\n </div>\n </ax-form-field>\n </ax-form>\n</div>\n", styles: [":host{display:block;width:100%;height:100%}ax-wysiwyg-container .ax-editor-container{border-top-left-radius:0!important;border-top-right-radius:0!important}ax-wysiwyg-container .ax-error-message{padding-left:.5rem}ax-wysiwyg-container .highlighted{background:var(--ax-color-primary-050)!important;border-radius:.25rem;transition:background 1s ease-in-out}\n"], dependencies: [{ kind: "ngmodule", type: AXWysiwygModule }, { kind: "component", type: i1.AXWysiwygContainerComponent, selector: "ax-wysiwyg-container", inputs: ["look", "placeHolder"], outputs: ["onValueChanged"] }, { kind: "component", type: i1.AXWysiwygViewComponent, selector: "ax-wysiwyg-view", inputs: ["class"] }, { kind: "component", type: i1.AXWysiwygAlignmentComponent, selector: "ax-wysiwyg-alignment" }, { kind: "component", type: i1.AXWysiwygColorsComponent, selector: "ax-wysiwyg-colors" }, { kind: "component", type: i1.AXWysiwygFontStyleComponent, selector: "ax-wysiwyg-font-style" }, { kind: "component", type: i1.AXWysiwygHistoryComponent, selector: "ax-wysiwyg-history" }, { kind: "component", type: i1.AXWysiwygListComponent, selector: "ax-wysiwyg-list" }, { kind: "ngmodule", type: AXConversationModule }, { kind: "ngmodule", type: AXSkeletonModule }, { kind: "component", type: i2.AXSkeletonComponent, selector: "ax-skeleton", inputs: ["animated"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i1$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i1$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXCommentModule }, { kind: "component", type: i4.AXCommentViewComponent, selector: "ax-comment-view" }, { kind: "component", type: i4.AXCommentContainerComponent, selector: "ax-comment-container" }, { kind: "component", type: i4.AxCommentItemComponent, selector: "ax-comment-item", inputs: ["replyCount"] }, { kind: "component", type: i4.AXCommentLikeComponent, selector: "ax-comment-like", inputs: ["liked"], outputs: ["likedChange", "onLiked"] }, { kind: "component", type: i4.AXMenuOptionsComponent, selector: "ax-comment-menu-options" }, { kind: "component", type: i4.AXCommentReplyTextComponent, selector: "ax-comment-reply-text" }, { kind: "component", type: i4.AXCommentDateComponent, selector: "ax-comment-date" }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i5.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "component", type: i5.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i5.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items"], outputs: ["onItemClick"] }, { kind: "ngmodule", type: AXAvatarModule }, { kind: "ngmodule", type: AXImageModule }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i6.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "component", type: i7.AXDropdownPanelComponent, selector: "ax-dropdown-panel", inputs: ["isOpen", "fitParent", "dropdownWidth", "position", "placement", "_target", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXFormatModule }, { kind: "pipe", type: i8.AXFormatPipe, name: "format" }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "ngmodule", type: AXFormModule }, { kind: "component", type: i9.AXFormFieldComponent, selector: "ax-form-field", inputs: ["labelMode"] }, { kind: "component", type: i9.AXFormComponent, selector: "ax-form", inputs: ["labelMode", "look", "messageStyle", "updateOn"], outputs: ["onValidate", "updateOnChange"] }, { kind: "directive", type: i9.AXValidationRuleDirective, selector: "ax-validation-rule", inputs: ["rule", "options", "message", "disabled"] }, { kind: "ngmodule", type: AXToolBarModule }, { kind: "component", type: i10.AXToolBarComponent, selector: "ax-toolbar" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i11.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i11.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXDropdownButtonModule }, { kind: "component", type: i12.AXDropdownButtonComponent, selector: "ax-dropdown-button", inputs: ["disabled", "size", "color", "look", "text", "type", "mode"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "lookChange", "colorChange", "disabledChange"] }, { kind: "component", type: AXPUserAvatarComponent, selector: "axp-user-avatar", inputs: ["size", "userId"] }], animations: [
|
1326
|
+
trigger('fadeIn', [
|
1327
|
+
transition(':enter', [
|
1328
|
+
style({ opacity: 0, transform: 'translateY(10px)' }),
|
1329
|
+
animate('300ms ease-out', style({ opacity: 1, transform: 'translateY(0)' })),
|
1330
|
+
]),
|
1331
|
+
]),
|
1332
|
+
], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
1473
1333
|
}
|
1474
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.
|
1334
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMCommentComponent, decorators: [{
|
1475
1335
|
type: Component,
|
1476
|
-
args: [{ selector: 'axm-comment
|
1336
|
+
args: [{ selector: 'axm-comment', animations: [
|
1337
|
+
trigger('fadeIn', [
|
1338
|
+
transition(':enter', [
|
1339
|
+
style({ opacity: 0, transform: 'translateY(10px)' }),
|
1340
|
+
animate('300ms ease-out', style({ opacity: 1, transform: 'translateY(0)' })),
|
1341
|
+
]),
|
1342
|
+
]),
|
1343
|
+
], imports: [
|
1477
1344
|
AXWysiwygModule,
|
1478
1345
|
AXConversationModule,
|
1479
1346
|
AXSkeletonModule,
|
@@ -1490,106 +1357,356 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImpor
|
|
1490
1357
|
AXToolBarModule,
|
1491
1358
|
FormsModule,
|
1492
1359
|
AXDropdownButtonModule,
|
1493
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ax-mt-2\">\n <ax-comment-container>\n @if (isLoading()) {\n <div class=\"ax-flex ax-items-center ax-py-12 ax-bg-lightest ax-px-5\">\n <ax-skeleton class=\"ax-min-w-16 ax-h-16 ax-rounded-full ax-me-4\"></ax-skeleton>\n <div class=\"ax-flex ax-flex-col ax-gap-2 ax-w-full\">\n <ax-skeleton class=\"ax-w-full ax-h-6 ax-rounded\"></ax-skeleton>\n <ax-skeleton class=\"ax-w-full ax-h-2 ax-rounded-full\"></ax-skeleton>\n <ax-skeleton class=\"ax-w-full ax-h-2 ax-rounded-full\"></ax-skeleton>\n <ax-skeleton class=\"ax-w-8/12 ax-h-2 ax-rounded-full\"></ax-skeleton>\n </div>\n </div>\n } @else if (!isLoading() && comments().length > 0) {\n <ax-comment-view class=\"ax-bg-lightest\">\n @for (comment of comments(); track comment.id) {\n <ax-comment-item [id]=\"comment.id!\" [replyCount]=\"comment.replies?.length ?? 0\">\n <ax-avatar [color]=\"avatarConfig().color\" [shape]=\"avatarConfig().look\">\n @if (checkImageExists(comment.id!) && comment.author && extractInitials(comment.author) !== '?') {\n <ax-image (onError)=\"handleImageError(comment.id!)\" [src]=\"''\">\n <ax-loading></ax-loading>\n </ax-image>\n } @else {\n <ax-text>\n <span class=\"ax-text-base ax-overflow-hidden\">{{ extractInitials(comment.author) }}</span>\n </ax-text>\n }\n </ax-avatar>\n <ax-title>{{ extractInitials(comment.author) }}</ax-title>\n <ax-comment-date>{{ calcDefrenetTime(comment.createdAt) | format: 'timeleft' | async }} </ax-comment-date>\n <ax-comment-menu-options>\n <ax-button class=\"ax-sm\" look=\"blank\" color=\"neutral\">\n <ax-icon icon=\"ax-icon ax-icon-solid ax-icon-more-horizontal\"></ax-icon>\n </ax-button>\n\n <ax-dropdown-panel>\n <ax-button-item-list>\n <ax-button-item text=\"Edit\" color=\"neutral\" (click)=\"editMessage(comment)\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-edit\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n\n <ax-button-item text=\"Delete\" color=\"danger\" (click)=\"deleteComment(comment)\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-trash-can\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-comment-menu-options>\n <ax-content [innerHTML]=\"sanitizeHtml(comment.message.content)\"></ax-content>\n <ax-comment-like (click)=\"toggleLike(comment)\" [liked]=\"comment.isLiked!\">\n {{ comment.reactionsCount }}\n </ax-comment-like>\n <ax-comment-reply-text (click)=\"replyMessage(comment)\"></ax-comment-reply-text>\n @for (reply of comment.replies; track reply.id) {\n <ax-comment-item [id]=\"reply.id\">\n <ax-avatar [color]=\"avatarConfig().color\" [shape]=\"avatarConfig().look\">\n @if (reply && checkImageExists(reply.id!) && reply.author && extractInitials(reply.author) !== '?') {\n <ax-image (onError)=\"handleImageError(reply.id!)\" [src]=\"''\">\n <ax-loading></ax-loading>\n </ax-image>\n } @else {\n <ax-text>\n <span class=\"ax-text-base ax-overflow-hidden\">{{ extractInitials(reply.author) }}</span>\n </ax-text>\n }\n </ax-avatar>\n <ax-title>{{ extractInitials(reply.author) }}</ax-title>\n <ax-comment-date>{{ calcDefrenetTime(reply.createdAt) | format: 'timeleft' | async }} </ax-comment-date>\n <ax-comment-menu-options>\n <ax-button class=\"ax-sm\" look=\"blank\" color=\"neutral\">\n <ax-icon icon=\"ax-icon ax-icon-solid ax-icon-more-horizontal\"></ax-icon>\n </ax-button>\n\n <ax-dropdown-panel>\n <ax-button-item-list>\n <ax-button-item text=\"Edit\" color=\"neutral\" (click)=\"editMessage(comment, reply)\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-edit\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n <ax-button-item text=\"Delete\" color=\"danger\" (click)=\"deleteReply(comment, reply)\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-trash-can\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-comment-menu-options>\n <ax-content [innerHTML]=\"sanitizeHtml(reply.message.content)\"></ax-content>\n <ax-comment-like (click)=\"toggleLike(comment, reply)\" [liked]=\"reply.isLiked!\">\n {{ reply.reactionsCount }}\n </ax-comment-like>\n <ax-comment-reply-text (click)=\"replyMessage(comment, reply)\"></ax-comment-reply-text>\n </ax-comment-item>\n }\n </ax-comment-item>\n }\n </ax-comment-view>\n } @else {\n <div>\n <div class=\"ax-flex ax-flex-col ax-gap-4 ax-justify-center ax-items-center ax-p-10\">\n <svg\n class=\"ax-mx-auto\"\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"154\"\n height=\"161\"\n viewBox=\"0 0 154 161\"\n fill=\"none\"\n >\n <path\n d=\"M0.0616455 84.4268C0.0616455 42.0213 34.435 7.83765 76.6507 7.83765C118.803 7.83765 153.224 42.0055 153.224 84.4268C153.224 102.42 147.026 118.974 136.622 132.034C122.282 150.138 100.367 161 76.6507 161C52.7759 161 30.9882 150.059 16.6633 132.034C6.25961 118.974 0.0616455 102.42 0.0616455 84.4268Z\"\n fill=\"#EEF2FF\"\n />\n <path\n d=\"M96.8189 0.632498L96.8189 0.632384L96.8083 0.630954C96.2034 0.549581 95.5931 0.5 94.9787 0.5H29.338C22.7112 0.5 17.3394 5.84455 17.3394 12.4473V142.715C17.3394 149.318 22.7112 154.662 29.338 154.662H123.948C130.591 154.662 135.946 149.317 135.946 142.715V38.9309C135.946 38.0244 135.847 37.1334 135.648 36.2586L135.648 36.2584C135.117 33.9309 133.874 31.7686 132.066 30.1333C132.066 30.1331 132.065 30.1329 132.065 30.1327L103.068 3.65203C103.068 3.6519 103.067 3.65177 103.067 3.65164C101.311 2.03526 99.1396 0.995552 96.8189 0.632498Z\"\n fill=\"white\"\n stroke=\"#E5E7EB\"\n />\n <ellipse cx=\"80.0618\" cy=\"81\" rx=\"28.0342\" ry=\"28.0342\" fill=\"#EEF2FF\" />\n <path\n d=\"M99.2393 61.3061L99.2391 61.3058C88.498 50.5808 71.1092 50.5804 60.3835 61.3061C49.6423 72.0316 49.6422 89.4361 60.3832 100.162C71.109 110.903 88.4982 110.903 99.2393 100.162C109.965 89.4363 109.965 72.0317 99.2393 61.3061ZM105.863 54.6832C120.249 69.0695 120.249 92.3985 105.863 106.785C91.4605 121.171 68.1468 121.171 53.7446 106.785C39.3582 92.3987 39.3582 69.0693 53.7446 54.683C68.1468 40.2965 91.4605 40.2966 105.863 54.6832Z\"\n stroke=\"#E5E7EB\"\n />\n <path\n d=\"M110.782 119.267L102.016 110.492C104.888 108.267 107.476 105.651 109.564 102.955L118.329 111.729L110.782 119.267Z\"\n stroke=\"#E5E7EB\"\n />\n <path\n d=\"M139.122 125.781L139.122 125.78L123.313 109.988C123.313 109.987 123.313 109.987 123.312 109.986C121.996 108.653 119.849 108.657 118.521 109.985L118.871 110.335L118.521 109.985L109.047 119.459C107.731 120.775 107.735 122.918 109.044 124.247L109.047 124.249L124.858 140.06C128.789 143.992 135.191 143.992 139.122 140.06C143.069 136.113 143.069 129.728 139.122 125.781Z\"\n fill=\"#A5B4FC\"\n stroke=\"#818CF8\"\n />\n <path\n d=\"M83.185 87.2285C82.5387 87.2285 82.0027 86.6926 82.0027 86.0305C82.0027 83.3821 77.9987 83.3821 77.9987 86.0305C77.9987 86.6926 77.4627 87.2285 76.8006 87.2285C76.1543 87.2285 75.6183 86.6926 75.6183 86.0305C75.6183 80.2294 84.3831 80.2451 84.3831 86.0305C84.3831 86.6926 83.8471 87.2285 83.185 87.2285Z\"\n fill=\"#4F46E5\"\n />\n <path\n d=\"M93.3528 77.0926H88.403C87.7409 77.0926 87.2049 76.5567 87.2049 75.8946C87.2049 75.2483 87.7409 74.7123 88.403 74.7123H93.3528C94.0149 74.7123 94.5509 75.2483 94.5509 75.8946C94.5509 76.5567 94.0149 77.0926 93.3528 77.0926Z\"\n fill=\"#4F46E5\"\n />\n <path\n d=\"M71.5987 77.0925H66.6488C65.9867 77.0925 65.4507 76.5565 65.4507 75.8945C65.4507 75.2481 65.9867 74.7122 66.6488 74.7122H71.5987C72.245 74.7122 72.781 75.2481 72.781 75.8945C72.781 76.5565 72.245 77.0925 71.5987 77.0925Z\"\n fill=\"#4F46E5\"\n />\n <rect x=\"38.3522\" y=\"21.5128\" width=\"41.0256\" height=\"2.73504\" rx=\"1.36752\" fill=\"#4F46E5\" />\n <rect x=\"38.3522\" y=\"133.65\" width=\"54.7009\" height=\"5.47009\" rx=\"2.73504\" fill=\"#A5B4FC\" />\n <rect x=\"38.3522\" y=\"29.7179\" width=\"13.6752\" height=\"2.73504\" rx=\"1.36752\" fill=\"#4F46E5\" />\n <circle cx=\"56.13\" cy=\"31.0854\" r=\"1.36752\" fill=\"#4F46E5\" />\n <circle cx=\"61.6001\" cy=\"31.0854\" r=\"1.36752\" fill=\"#4F46E5\" />\n <circle cx=\"67.0702\" cy=\"31.0854\" r=\"1.36752\" fill=\"#4F46E5\" />\n </svg>\n <div>\n <h2 class=\"ax-text-center ax-text-neutral-600 ax-font-semibold ax-leading-loose ax-pb-2\">\n There is no Comment!\n </h2>\n </div>\n </div>\n </div>\n }\n </ax-comment-container>\n <ax-form>\n <ax-form-field>\n <div>\n @if (isReplyingMode() || isEditingMode()) {\n <div\n class=\"ax-flex ax-justify-between ax-rounded-b-none ax-border ax-border-b-0 ax-rounded-lg ax-bg-on-surface ax-px-6 ax-py-3 ax-w-full ax-items-center ax-overflow-hidden ax-text-sm ax-leading-none\"\n >\n <div (click)=\"scrollMain()\" class=\"ax-flex ax-justify-start ax-items-center ax-cursor-pointer\">\n <i\n [class]=\"isReplyingMode() ? 'fa-reply' : 'fa-pen'\"\n class=\"fa-solid ax-text-primary-500 dark:ax-text-primary-300 ax-text-2xl ax-me-4\"\n ></i>\n <div\n class=\"ax-flex ax-flex-col ax-gap-2 ax-justify-between ax-align-middle ax-leading-4 ax-overflow-hidden\"\n >\n <p class=\"ax-text-primary-500 dark:ax-text-primary-300\">\n {{ isReplyingMode() ? 'Reply to ' : 'Edit Message' }}\n <span class=\"ax-font-bold\">\n {{ isReplyingMode() ? extractInitials(activeReplyComment()?.author) : '' }}\n </span>\n </p>\n <div\n class=\"ax-truncate\"\n [innerHTML]=\"\n isReplyingMode()\n ? sanitizeHtml(activeReplyComment()?.message?.content ?? '')\n : sanitizeHtml(activeEditComment()?.message?.content ?? '')\n \"\n ></div>\n </div>\n </div>\n <div><i (click)=\"resetReplyEditState()\" class=\"fa-solid ax-text-2xl fa-xmark ax-cursor-pointer\"></i></div>\n </div>\n }\n <ax-wysiwyg-container #w [look]=\"wysiwygOptions().look\" [(ngModel)]=\"commentContent\">\n <ax-wysiwyg-view class=\"ax-min-h-28\"></ax-wysiwyg-view>\n <ax-toolbar>\n <ax-content>\n <ax-wysiwyg-history></ax-wysiwyg-history>\n <ax-wysiwyg-font-style></ax-wysiwyg-font-style>\n <ax-wysiwyg-colors></ax-wysiwyg-colors>\n <ax-wysiwyg-list></ax-wysiwyg-list>\n <ax-wysiwyg-alignment></ax-wysiwyg-alignment>\n </ax-content>\n <ax-suffix>\n <ax-dropdown-button\n [disabled]=\"hasCooldown()\"\n type=\"submit\"\n color=\"primary\"\n mode=\"split\"\n text=\"Send\"\n (onClick)=\"submitComment()\"\n >\n @if (isSubmitting()) {\n <ax-loading></ax-loading>\n }\n <ax-button-item-list>\n <ax-button-item (click)=\"submitComment(true)\" text=\"Send Private ...\" name=\"private\" data=\"private\">\n <ax-prefix>\n <ax-icon icon=\"fa-regular fa-user-secret\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n </ax-button-item-list>\n </ax-dropdown-button>\n </ax-suffix>\n </ax-toolbar>\n <ax-validation-rule rule=\"callback\" [options]=\"{ validate: validateContent }\"></ax-validation-rule>\n </ax-wysiwyg-container>\n </div>\n </ax-form-field>\n </ax-form>\n</div>\n", styles: ["ax-wysiwyg-container .ax-editor-container{border-top-left-radius:0!important;border-top-right-radius:0!important}ax-wysiwyg-container .ax-error-message{padding-left:.5rem}\n"] }]
|
1360
|
+
AXPUserAvatarComponent,
|
1361
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ax-size-full ax-flex ax-flex-col ax-justify-between ax-p-4 ax-overflow-hidden\">\n <ax-comment-container class=\"ax-overflow-auto\">\n @if (isLoading()) {\n <div class=\"ax-flex ax-items-center ax-py-12 ax-bg-lightest ax-px-5\">\n <ax-skeleton class=\"ax-min-w-16 ax-h-16 ax-rounded-full ax-me-4\"></ax-skeleton>\n <div class=\"ax-flex ax-flex-col ax-gap-2 ax-w-full\">\n <ax-skeleton class=\"ax-w-full ax-h-6 ax-rounded\"></ax-skeleton>\n <ax-skeleton class=\"ax-w-full ax-h-2 ax-rounded-full\"></ax-skeleton>\n <ax-skeleton class=\"ax-w-full ax-h-2 ax-rounded-full\"></ax-skeleton>\n <ax-skeleton class=\"ax-w-8/12 ax-h-2 ax-rounded-full\"></ax-skeleton>\n </div>\n </div>\n } @else if (!isLoading() && comments().length > 0) {\n <ax-comment-view class=\"ax-bg-lightest\">\n @for (comment of comments(); track comment.id) {\n <ax-comment-item\n [id]=\"comment.id!\"\n [replyCount]=\"comment.replyCount\"\n [class.highlighted]=\"highlightedCommentId() === comment.id\"\n [@fadeIn]\n >\n <axp-user-avatar #user [size]=\"48\" [userId]=\"comment.author.id\" ngProjectAs=\"'ax-avatar'\"></axp-user-avatar>\n <ax-title>{{ user.firstName() + ' ' + user.lastName() }}</ax-title>\n <ax-comment-date>{{ comment.createdAt | format: 'timeleft' | async }} </ax-comment-date>\n <ax-comment-menu-options>\n <ax-button class=\"ax-sm\" look=\"blank\" color=\"neutral\">\n <ax-icon icon=\"ax-icon ax-icon-solid ax-icon-more-horizontal\"></ax-icon>\n </ax-button>\n\n <ax-dropdown-panel>\n <ax-button-item-list>\n <ax-button-item\n text=\"Edit\"\n color=\"neutral\"\n (click)=\"editMessage(comment, undefined, user.firstName() + ' ' + user.lastName())\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-edit\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n\n <ax-button-item text=\"Delete\" color=\"danger\" (click)=\"deleteComment(comment.id!)\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-trash-can\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-comment-menu-options>\n <ax-content [innerHTML]=\"sanitizeHtml(comment.message.content)\"></ax-content>\n <ax-comment-like (click)=\"toggleLike(comment)\" [liked]=\"isLikedByUser(comment)\">\n {{ getReactionsCount(comment) }}\n </ax-comment-like>\n <ax-comment-reply-text\n (click)=\"replyMessage(comment, undefined, user.firstName() + ' ' + user.lastName())\"\n ></ax-comment-reply-text>\n @for (reply of comment.replies; track reply.id) {\n <ax-comment-item [id]=\"reply.id\" [class.highlighted]=\"highlightedCommentId() === reply.id\" [@fadeIn]>\n <axp-user-avatar\n #user2\n [size]=\"48\"\n [userId]=\"reply.author.id\"\n ngProjectAs=\"'ax-avatar'\"\n ></axp-user-avatar>\n <ax-title>{{ user2.firstName() + ' ' + user2.lastName() }}</ax-title>\n <ax-comment-date>{{ reply.createdAt | format: 'timeleft' | async }} </ax-comment-date>\n <ax-comment-menu-options>\n <ax-button class=\"ax-sm\" look=\"blank\" color=\"neutral\">\n <ax-icon icon=\"ax-icon ax-icon-solid ax-icon-more-horizontal\"></ax-icon>\n </ax-button>\n\n <ax-dropdown-panel>\n <ax-button-item-list>\n <ax-button-item\n text=\"Edit\"\n color=\"neutral\"\n (click)=\"editMessage(comment, reply, user2.firstName() + ' ' + user2.lastName())\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-edit\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n <ax-button-item text=\"Delete\" color=\"danger\" (click)=\"deleteComment(reply.id!)\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-trash-can\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-comment-menu-options>\n <ax-content [innerHTML]=\"sanitizeHtml(reply.message.content)\"></ax-content>\n <ax-comment-like (click)=\"toggleLike(reply)\" [liked]=\"isLikedByUser(reply)\">\n {{ getReactionsCount(reply) }}\n </ax-comment-like>\n <ax-comment-reply-text\n (click)=\"replyMessage(comment, reply, user2.firstName() + ' ' + user2.lastName())\"\n ></ax-comment-reply-text>\n </ax-comment-item>\n }\n </ax-comment-item>\n }\n </ax-comment-view>\n } @else {\n <div>\n <div class=\"ax-flex ax-flex-col ax-gap-4 ax-justify-center ax-items-center ax-p-10\">\n <svg\n class=\"ax-mx-auto\"\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"154\"\n height=\"161\"\n viewBox=\"0 0 154 161\"\n fill=\"none\"\n >\n <path\n d=\"M0.0616455 84.4268C0.0616455 42.0213 34.435 7.83765 76.6507 7.83765C118.803 7.83765 153.224 42.0055 153.224 84.4268C153.224 102.42 147.026 118.974 136.622 132.034C122.282 150.138 100.367 161 76.6507 161C52.7759 161 30.9882 150.059 16.6633 132.034C6.25961 118.974 0.0616455 102.42 0.0616455 84.4268Z\"\n fill=\"#EEF2FF\"\n />\n <path\n d=\"M96.8189 0.632498L96.8189 0.632384L96.8083 0.630954C96.2034 0.549581 95.5931 0.5 94.9787 0.5H29.338C22.7112 0.5 17.3394 5.84455 17.3394 12.4473V142.715C17.3394 149.318 22.7112 154.662 29.338 154.662H123.948C130.591 154.662 135.946 149.317 135.946 142.715V38.9309C135.946 38.0244 135.847 37.1334 135.648 36.2586L135.648 36.2584C135.117 33.9309 133.874 31.7686 132.066 30.1333C132.066 30.1331 132.065 30.1329 132.065 30.1327L103.068 3.65203C103.068 3.6519 103.067 3.65177 103.067 3.65164C101.311 2.03526 99.1396 0.995552 96.8189 0.632498Z\"\n fill=\"white\"\n stroke=\"#E5E7EB\"\n />\n <ellipse cx=\"80.0618\" cy=\"81\" rx=\"28.0342\" ry=\"28.0342\" fill=\"#EEF2FF\" />\n <path\n d=\"M99.2393 61.3061L99.2391 61.3058C88.498 50.5808 71.1092 50.5804 60.3835 61.3061C49.6423 72.0316 49.6422 89.4361 60.3832 100.162C71.109 110.903 88.4982 110.903 99.2393 100.162C109.965 89.4363 109.965 72.0317 99.2393 61.3061ZM105.863 54.6832C120.249 69.0695 120.249 92.3985 105.863 106.785C91.4605 121.171 68.1468 121.171 53.7446 106.785C39.3582 92.3987 39.3582 69.0693 53.7446 54.683C68.1468 40.2965 91.4605 40.2966 105.863 54.6832Z\"\n stroke=\"#E5E7EB\"\n />\n <path\n d=\"M110.782 119.267L102.016 110.492C104.888 108.267 107.476 105.651 109.564 102.955L118.329 111.729L110.782 119.267Z\"\n stroke=\"#E5E7EB\"\n />\n <path\n d=\"M139.122 125.781L139.122 125.78L123.313 109.988C123.313 109.987 123.313 109.987 123.312 109.986C121.996 108.653 119.849 108.657 118.521 109.985L118.871 110.335L118.521 109.985L109.047 119.459C107.731 120.775 107.735 122.918 109.044 124.247L109.047 124.249L124.858 140.06C128.789 143.992 135.191 143.992 139.122 140.06C143.069 136.113 143.069 129.728 139.122 125.781Z\"\n fill=\"#A5B4FC\"\n stroke=\"#818CF8\"\n />\n <path\n d=\"M83.185 87.2285C82.5387 87.2285 82.0027 86.6926 82.0027 86.0305C82.0027 83.3821 77.9987 83.3821 77.9987 86.0305C77.9987 86.6926 77.4627 87.2285 76.8006 87.2285C76.1543 87.2285 75.6183 86.6926 75.6183 86.0305C75.6183 80.2294 84.3831 80.2451 84.3831 86.0305C84.3831 86.6926 83.8471 87.2285 83.185 87.2285Z\"\n fill=\"#4F46E5\"\n />\n <path\n d=\"M93.3528 77.0926H88.403C87.7409 77.0926 87.2049 76.5567 87.2049 75.8946C87.2049 75.2483 87.7409 74.7123 88.403 74.7123H93.3528C94.0149 74.7123 94.5509 75.2483 94.5509 75.8946C94.5509 76.5567 94.0149 77.0926 93.3528 77.0926Z\"\n fill=\"#4F46E5\"\n />\n <path\n d=\"M71.5987 77.0925H66.6488C65.9867 77.0925 65.4507 76.5565 65.4507 75.8945C65.4507 75.2481 65.9867 74.7122 66.6488 74.7122H71.5987C72.245 74.7122 72.781 75.2481 72.781 75.8945C72.781 76.5565 72.245 77.0925 71.5987 77.0925Z\"\n fill=\"#4F46E5\"\n />\n <rect x=\"38.3522\" y=\"21.5128\" width=\"41.0256\" height=\"2.73504\" rx=\"1.36752\" fill=\"#4F46E5\" />\n <rect x=\"38.3522\" y=\"133.65\" width=\"54.7009\" height=\"5.47009\" rx=\"2.73504\" fill=\"#A5B4FC\" />\n <rect x=\"38.3522\" y=\"29.7179\" width=\"13.6752\" height=\"2.73504\" rx=\"1.36752\" fill=\"#4F46E5\" />\n <circle cx=\"56.13\" cy=\"31.0854\" r=\"1.36752\" fill=\"#4F46E5\" />\n <circle cx=\"61.6001\" cy=\"31.0854\" r=\"1.36752\" fill=\"#4F46E5\" />\n <circle cx=\"67.0702\" cy=\"31.0854\" r=\"1.36752\" fill=\"#4F46E5\" />\n </svg>\n <div>\n <h2 class=\"ax-text-center ax-text-neutral-600 ax-font-semibold ax-leading-loose ax-pb-2\">\n There is no Comment!\n </h2>\n </div>\n </div>\n </div>\n }\n </ax-comment-container>\n <ax-form>\n <ax-form-field>\n <div>\n @if (isReplyingMode() || isEditingMode()) {\n <div\n class=\"ax-flex ax-justify-between ax-rounded-b-none ax-border ax-border-b-0 ax-rounded-lg ax-px-6 ax-py-3 ax-w-full ax-items-center ax-overflow-hidden ax-text-sm ax-leading-none\"\n >\n <div (click)=\"scrollMain()\" class=\"ax-flex ax-justify-start ax-items-center ax-cursor-pointer\">\n <i\n [class]=\"isReplyingMode() ? 'fa-reply' : 'fa-pen'\"\n class=\"fa-solid ax-text-primary-500 dark:ax-text-primary-300 ax-text-2xl ax-me-4\"\n ></i>\n <div\n class=\"ax-flex ax-flex-col ax-gap-2 ax-justify-between ax-align-middle ax-leading-4 ax-overflow-hidden\"\n >\n <p class=\"ax-text-primary-500 dark:ax-text-primary-300\">\n {{ isReplyingMode() ? 'Reply to ' : 'Edit Message' }}\n <span class=\"ax-font-bold\">\n {{ isReplyingMode() ? activeReplyComment()?.userName : '' }}\n </span>\n </p>\n <div\n class=\"ax-truncate\"\n [innerHTML]=\"\n isReplyingMode()\n ? sanitizeHtml(activeReplyComment()?.message?.content ?? '')\n : sanitizeHtml(activeEditComment()?.message?.content ?? '')\n \"\n ></div>\n </div>\n </div>\n <div><i (click)=\"resetReplyEditState()\" class=\"fa-solid ax-text-2xl fa-xmark ax-cursor-pointer\"></i></div>\n </div>\n }\n <ax-wysiwyg-container #w [look]=\"wysiwygOptions().look\" [(ngModel)]=\"commentContent\">\n <ax-wysiwyg-view class=\"ax-min-h-28\"></ax-wysiwyg-view>\n <ax-toolbar>\n <ax-content>\n <ax-wysiwyg-history></ax-wysiwyg-history>\n <ax-wysiwyg-font-style></ax-wysiwyg-font-style>\n <ax-wysiwyg-colors></ax-wysiwyg-colors>\n <ax-wysiwyg-list></ax-wysiwyg-list>\n <ax-wysiwyg-alignment></ax-wysiwyg-alignment>\n </ax-content>\n <ax-suffix>\n <ax-dropdown-button\n [disabled]=\"hasCooldown()\"\n type=\"submit\"\n color=\"primary\"\n mode=\"split\"\n text=\"Send\"\n (onClick)=\"submitComment()\"\n >\n @if (isSubmitting()) {\n <ax-loading></ax-loading>\n }\n <ax-button-item-list>\n <ax-button-item (click)=\"submitComment()\" text=\"Send Private ...\" name=\"private\" data=\"private\">\n <ax-prefix>\n <ax-icon icon=\"fa-regular fa-user-secret\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n </ax-button-item-list>\n </ax-dropdown-button>\n </ax-suffix>\n </ax-toolbar>\n <ax-validation-rule rule=\"callback\" [options]=\"{ validate: validateContent }\"></ax-validation-rule>\n </ax-wysiwyg-container>\n </div>\n </ax-form-field>\n </ax-form>\n</div>\n", styles: [":host{display:block;width:100%;height:100%}ax-wysiwyg-container .ax-editor-container{border-top-left-radius:0!important;border-top-right-radius:0!important}ax-wysiwyg-container .ax-error-message{padding-left:.5rem}ax-wysiwyg-container .highlighted{background:var(--ax-color-primary-050)!important;border-radius:.25rem;transition:background 1s ease-in-out}\n"] }]
|
1494
1362
|
}] });
|
1495
1363
|
|
1496
|
-
|
1497
|
-
|
1364
|
+
var comment_component = /*#__PURE__*/Object.freeze({
|
1365
|
+
__proto__: null,
|
1366
|
+
AXMCommentComponent: AXMCommentComponent
|
1367
|
+
});
|
1368
|
+
|
1369
|
+
class AXMCommentPopupComponent extends AXBasePageComponent {
|
1370
|
+
constructor() {
|
1371
|
+
super(...arguments);
|
1372
|
+
this.refrenceType = input.required();
|
1373
|
+
this.refrenceId = input.required();
|
1374
|
+
this.subject = input.required();
|
1375
|
+
}
|
1376
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMCommentPopupComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
1377
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.6", type: AXMCommentPopupComponent, isStandalone: true, selector: "axm-comment-popup", inputs: { refrenceType: { classPropertyName: "refrenceType", publicName: "refrenceType", isSignal: true, isRequired: true, transformFunction: null }, refrenceId: { classPropertyName: "refrenceId", publicName: "refrenceId", isSignal: true, isRequired: true, transformFunction: null }, subject: { classPropertyName: "subject", publicName: "subject", isSignal: true, isRequired: true, transformFunction: null } }, providers: [], usesInheritance: true, ngImport: i0, template: "<ax-content>\n <div class=\"ax-p-6 ax-min-h-[30vh] ax-overflow-y-auto\">\n <axm-comment [refrenceType]=\"refrenceType()\" [refrenceId]=\"refrenceId()\" [subject]=\"subject()\"></axm-comment>\n </div>\n</ax-content>\n<ax-footer>\n <ax-prefix></ax-prefix>\n <ax-suffix>\n <ax-button [text]=\"'close' | translate | async\" look=\"solid\" color=\"primary\" (onClick)=\"close()\"> </ax-button>\n </ax-suffix>\n</ax-footer>\n", dependencies: [{ kind: "ngmodule", type:
|
1378
|
+
// Angular
|
1379
|
+
CommonModule }, { kind: "pipe", type: i1$2.AsyncPipe, name: "async" }, { kind: "ngmodule", type:
|
1380
|
+
// ACoreX
|
1381
|
+
AXDecoratorModule }, { kind: "component", type: i1$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i5.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i4$1.AXTranslatorPipe, name: "translate" }, { kind: "component", type:
|
1382
|
+
// Comment
|
1383
|
+
AXMCommentComponent, selector: "axm-comment", inputs: ["refrenceType", "refrenceId", "subject"] }], encapsulation: i0.ViewEncapsulation.None }); }
|
1498
1384
|
}
|
1499
|
-
|
1500
|
-
|
1385
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMCommentPopupComponent, decorators: [{
|
1386
|
+
type: Component,
|
1387
|
+
args: [{ selector: 'axm-comment-popup', standalone: true, imports: [
|
1388
|
+
// Angular
|
1389
|
+
CommonModule,
|
1390
|
+
// ACoreX
|
1391
|
+
AXDecoratorModule,
|
1392
|
+
AXButtonModule,
|
1393
|
+
AXTranslationModule,
|
1394
|
+
// Comment
|
1395
|
+
AXMCommentComponent,
|
1396
|
+
], encapsulation: ViewEncapsulation.None, providers: [], template: "<ax-content>\n <div class=\"ax-p-6 ax-min-h-[30vh] ax-overflow-y-auto\">\n <axm-comment [refrenceType]=\"refrenceType()\" [refrenceId]=\"refrenceId()\" [subject]=\"subject()\"></axm-comment>\n </div>\n</ax-content>\n<ax-footer>\n <ax-prefix></ax-prefix>\n <ax-suffix>\n <ax-button [text]=\"'close' | translate | async\" look=\"solid\" color=\"primary\" (onClick)=\"close()\"> </ax-button>\n </ax-suffix>\n</ax-footer>\n" }]
|
1397
|
+
}] });
|
1398
|
+
|
1399
|
+
var commentPopup_component = /*#__PURE__*/Object.freeze({
|
1400
|
+
__proto__: null,
|
1401
|
+
AXMCommentPopupComponent: AXMCommentPopupComponent
|
1402
|
+
});
|
1403
|
+
|
1404
|
+
class AXMUserLookupPopup extends AXBasePageComponent {
|
1501
1405
|
constructor() {
|
1502
|
-
|
1503
|
-
this.
|
1504
|
-
|
1505
|
-
|
1506
|
-
|
1507
|
-
|
1508
|
-
|
1509
|
-
|
1510
|
-
|
1511
|
-
|
1512
|
-
|
1513
|
-
|
1514
|
-
|
1406
|
+
super(...arguments);
|
1407
|
+
this.lookupNode = {
|
1408
|
+
name: 'form-field',
|
1409
|
+
path: 'form-field',
|
1410
|
+
type: 'form-field',
|
1411
|
+
children: [
|
1412
|
+
{
|
1413
|
+
name: 'lookup',
|
1414
|
+
path: 'lookup',
|
1415
|
+
type: 'lookup-editor',
|
1416
|
+
options: {
|
1417
|
+
entity: 'SecurityManagement.users',
|
1418
|
+
multiple: true,
|
1419
|
+
},
|
1420
|
+
},
|
1421
|
+
],
|
1422
|
+
options: {
|
1423
|
+
label: 'Select users:',
|
1424
|
+
},
|
1515
1425
|
};
|
1426
|
+
this.titleNode = {
|
1427
|
+
name: 'form-field',
|
1428
|
+
path: 'form-field',
|
1429
|
+
type: 'form-field',
|
1430
|
+
children: [
|
1431
|
+
{
|
1432
|
+
name: 'title',
|
1433
|
+
path: 'title',
|
1434
|
+
type: 'text-editor',
|
1435
|
+
options: {
|
1436
|
+
placeholder: 'Enter title',
|
1437
|
+
required: true,
|
1438
|
+
},
|
1439
|
+
},
|
1440
|
+
],
|
1441
|
+
options: {
|
1442
|
+
label: 'Title:',
|
1443
|
+
},
|
1444
|
+
};
|
1445
|
+
this.context = signal({});
|
1516
1446
|
}
|
1517
|
-
|
1518
|
-
|
1519
|
-
|
1520
|
-
|
1521
|
-
id: user.id,
|
1522
|
-
type: 'user',
|
1523
|
-
};
|
1524
|
-
}
|
1525
|
-
catch (error) {
|
1526
|
-
console.error(`Failed to get user info for ID: ${userId}`, error);
|
1527
|
-
return {
|
1528
|
-
id: userId,
|
1529
|
-
type: 'user',
|
1530
|
-
};
|
1531
|
-
}
|
1532
|
-
}
|
1533
|
-
formatMessage(message) {
|
1534
|
-
return message;
|
1535
|
-
}
|
1536
|
-
async getUnreadCount(roomId) {
|
1537
|
-
const { items } = await this.messageService.query({
|
1538
|
-
skip: 0,
|
1539
|
-
take: 99,
|
1540
|
-
filter: { field: 'roomId', value: roomId, operator: { type: 'equal' } },
|
1541
|
-
});
|
1542
|
-
const currentUserId = this.getCurrentUser().id;
|
1543
|
-
const unreadMessages = items.filter((message) => {
|
1544
|
-
const isFromCurrentUser = message.author.id === currentUserId;
|
1545
|
-
const isReadByCurrentUser = (message.seen || []).some((seen) => seen.author.id === currentUserId);
|
1546
|
-
return !isFromCurrentUser && !isReadByCurrentUser;
|
1447
|
+
handleClose() {
|
1448
|
+
this.close({
|
1449
|
+
lookup: this.context()?.lookup,
|
1450
|
+
title: this.context()?.title,
|
1547
1451
|
});
|
1548
|
-
return unreadMessages.length;
|
1549
|
-
}
|
1550
|
-
//#endregion
|
1551
|
-
//#region ---- ChatRoomService Implementations ----
|
1552
|
-
async createRoom(memberIds, title) {
|
1553
|
-
if (memberIds.length === 0) {
|
1554
|
-
throw new Error('At least one member is required to create a room');
|
1555
|
-
}
|
1556
|
-
const currentUser = this.getCurrentUser();
|
1557
|
-
const allMemberIds = [...new Set([...memberIds, currentUser.id])];
|
1558
|
-
const memberReferences = await Promise.all(allMemberIds.map((id) => this.getUserInfo(id)));
|
1559
|
-
const userNames = await Promise.all(memberReferences.map(async (ref) => {
|
1560
|
-
const user = await this.usersService.getOne(ref.id);
|
1561
|
-
return `${user.firstName} ${user.lastName}`.trim();
|
1562
|
-
}));
|
1563
|
-
const room = {
|
1564
|
-
members: memberReferences,
|
1565
|
-
title: title,
|
1566
|
-
topic: memberIds.length > 2 ? 'group' : 'personal',
|
1567
|
-
createdAt: new Date(),
|
1568
|
-
updatedAt: new Date(),
|
1569
|
-
createdBy: this.getCurrentUser().id,
|
1570
|
-
updatedBy: this.getCurrentUser().id,
|
1571
|
-
};
|
1572
|
-
const roomId = await this.roomService.insertOne(room);
|
1573
|
-
return this.getRoom(roomId);
|
1574
1452
|
}
|
1575
|
-
|
1576
|
-
|
1577
|
-
|
1578
|
-
|
1453
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMUserLookupPopup, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
1454
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: AXMUserLookupPopup, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: `<axp-widgets-container [context]="context()" (onContextChanged)="context.set($event.data)">
|
1455
|
+
<div class="ax-p-4 ax-flex ax-flex-col ax-gap-4">
|
1456
|
+
<ng-container axp-widget-renderer [node]="lookupNode" [mode]="'edit'"> </ng-container>
|
1457
|
+
@if (context()?.lookup?.length > 1) {
|
1458
|
+
<ng-container axp-widget-renderer [node]="titleNode" [mode]="'edit'"> </ng-container>
|
1579
1459
|
}
|
1580
|
-
|
1581
|
-
|
1582
|
-
|
1583
|
-
|
1584
|
-
|
1585
|
-
|
1586
|
-
|
1587
|
-
|
1588
|
-
|
1589
|
-
|
1590
|
-
|
1460
|
+
</div>
|
1461
|
+
</axp-widgets-container>
|
1462
|
+
|
1463
|
+
<ax-footer>
|
1464
|
+
<ax-suffix>
|
1465
|
+
<ax-button
|
1466
|
+
text="Accept & Send"
|
1467
|
+
color="primary"
|
1468
|
+
[disabled]="context()?.lookup?.length > 1 && !context()?.title"
|
1469
|
+
(onClick)="handleClose()"
|
1470
|
+
></ax-button>
|
1471
|
+
</ax-suffix>
|
1472
|
+
</ax-footer>`, isInline: true, dependencies: [{ kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i1$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXPLayoutBuilderModule }, { kind: "component", type: i2$1.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i2$1.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i5.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }] }); }
|
1473
|
+
}
|
1474
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMUserLookupPopup, decorators: [{
|
1475
|
+
type: Component,
|
1476
|
+
args: [{
|
1477
|
+
template: `<axp-widgets-container [context]="context()" (onContextChanged)="context.set($event.data)">
|
1478
|
+
<div class="ax-p-4 ax-flex ax-flex-col ax-gap-4">
|
1479
|
+
<ng-container axp-widget-renderer [node]="lookupNode" [mode]="'edit'"> </ng-container>
|
1480
|
+
@if (context()?.lookup?.length > 1) {
|
1481
|
+
<ng-container axp-widget-renderer [node]="titleNode" [mode]="'edit'"> </ng-container>
|
1482
|
+
}
|
1483
|
+
</div>
|
1484
|
+
</axp-widgets-container>
|
1485
|
+
|
1486
|
+
<ax-footer>
|
1487
|
+
<ax-suffix>
|
1488
|
+
<ax-button
|
1489
|
+
text="Accept & Send"
|
1490
|
+
color="primary"
|
1491
|
+
[disabled]="context()?.lookup?.length > 1 && !context()?.title"
|
1492
|
+
(onClick)="handleClose()"
|
1493
|
+
></ax-button>
|
1494
|
+
</ax-suffix>
|
1495
|
+
</ax-footer>`,
|
1496
|
+
imports: [AXDecoratorModule, AXPLayoutBuilderModule, AXButtonModule],
|
1497
|
+
}]
|
1498
|
+
}] });
|
1499
|
+
|
1500
|
+
class AXMCommentWidgetViewComponent extends AXPValueWidgetComponent {
|
1501
|
+
constructor() {
|
1502
|
+
super(...arguments);
|
1503
|
+
this.refrenceType = computed(() => this.options().refrenceType);
|
1504
|
+
this.refrenceId = computed(() => this.options().refrenceId);
|
1505
|
+
this.subject = computed(() => this.options().subject);
|
1506
|
+
}
|
1507
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMCommentWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
1508
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.0.6", type: AXMCommentWidgetViewComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: `
|
1509
|
+
<axm-comment [refrenceId]="refrenceId()" [refrenceType]="refrenceType()" [subject]="subject()"></axm-comment>
|
1510
|
+
`, isInline: true, dependencies: [{ kind: "component", type: AXMCommentComponent, selector: "axm-comment", inputs: ["refrenceType", "refrenceId", "subject"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
1511
|
+
}
|
1512
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMCommentWidgetViewComponent, decorators: [{
|
1513
|
+
type: Component,
|
1514
|
+
args: [{
|
1515
|
+
template: `
|
1516
|
+
<axm-comment [refrenceId]="refrenceId()" [refrenceType]="refrenceType()" [subject]="subject()"></axm-comment>
|
1517
|
+
`,
|
1518
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
1519
|
+
imports: [AXMCommentComponent],
|
1520
|
+
}]
|
1521
|
+
}] });
|
1522
|
+
|
1523
|
+
var commentWidgetView_component = /*#__PURE__*/Object.freeze({
|
1524
|
+
__proto__: null,
|
1525
|
+
AXMCommentWidgetViewComponent: AXMCommentWidgetViewComponent
|
1526
|
+
});
|
1527
|
+
|
1528
|
+
const AXPCommentWidget = {
|
1529
|
+
name: 'comment',
|
1530
|
+
title: 'Comments',
|
1531
|
+
description: 'Display and manage comments for entities',
|
1532
|
+
type: 'view',
|
1533
|
+
categories: [],
|
1534
|
+
groups: [AXPWidgetGroupEnum.FormElement],
|
1535
|
+
icon: 'fa-solid fa-comments',
|
1536
|
+
properties: [],
|
1537
|
+
components: {
|
1538
|
+
view: {
|
1539
|
+
component: () => Promise.resolve().then(function () { return commentWidgetView_component; }).then((c) => c.AXMCommentWidgetViewComponent),
|
1540
|
+
},
|
1541
|
+
},
|
1542
|
+
};
|
1543
|
+
|
1544
|
+
class AXMCommentPopupStartAction extends AXPWorkflowAction {
|
1545
|
+
constructor() {
|
1546
|
+
super(...arguments);
|
1547
|
+
this.popupService = inject(AXPopupService);
|
1548
|
+
this.translate = inject(AXTranslationService);
|
1549
|
+
}
|
1550
|
+
async execute(context) {
|
1551
|
+
const comp = (await Promise.resolve().then(function () { return commentPopup_component; })).AXMCommentPopupComponent;
|
1552
|
+
this.popupService.open(comp, {
|
1553
|
+
title: await this.translate.translateAsync('Comments'),
|
1554
|
+
size: 'lg',
|
1555
|
+
data: {
|
1556
|
+
refrenceType: signal(context.getVariable('options.refType')),
|
1557
|
+
refrenceId: signal(context.getVariable('options.refId')),
|
1558
|
+
subject: signal(context.getVariable('options.subject')),
|
1559
|
+
},
|
1560
|
+
});
|
1561
|
+
}
|
1562
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMCommentPopupStartAction, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
1563
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMCommentPopupStartAction }); }
|
1564
|
+
}
|
1565
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMCommentPopupStartAction, decorators: [{
|
1566
|
+
type: Injectable
|
1567
|
+
}] });
|
1568
|
+
const AXMCommentPopupWorkflow = {
|
1569
|
+
startStepId: 'start',
|
1570
|
+
steps: {
|
1571
|
+
start: {
|
1572
|
+
action: 'show-comment-popup-action',
|
1573
|
+
},
|
1574
|
+
},
|
1575
|
+
};
|
1576
|
+
|
1577
|
+
//#region ---- Abstract Chat Service ----
|
1578
|
+
class AXMChatService {
|
1579
|
+
}
|
1580
|
+
//#endregion
|
1581
|
+
class AXMChatServiceImpl {
|
1582
|
+
constructor() {
|
1583
|
+
this.roomService = inject(AXMRoomService);
|
1584
|
+
this.messageService = inject(AXMMessageService);
|
1585
|
+
this.sessionService = inject(AXPSessionService);
|
1586
|
+
this.usersService = inject(AXMUsersEntityService);
|
1587
|
+
this._messageSent$ = new Subject();
|
1588
|
+
this.messageSent$ = this._messageSent$.asObservable();
|
1589
|
+
this._messageRemoved$ = new Subject();
|
1590
|
+
this.messageRemoved$ = this._messageRemoved$.asObservable();
|
1591
|
+
this._messageSeen$ = new Subject();
|
1592
|
+
this.messageSeen$ = this._messageSeen$.asObservable();
|
1593
|
+
this._roomAdded$ = new Subject();
|
1594
|
+
this.roomAdded$ = this._roomAdded$.asObservable();
|
1595
|
+
this._roomRemoved$ = new Subject();
|
1596
|
+
this.roomRemoved$ = this._roomRemoved$.asObservable();
|
1597
|
+
this._roomSeen$ = new Subject();
|
1598
|
+
this.roomSeen$ = this._roomSeen$.asObservable();
|
1599
|
+
this._messageReacted$ = new Subject();
|
1600
|
+
this.messageReacted$ = this._messageReacted$.asObservable();
|
1601
|
+
this._typingStatus$ = new Subject();
|
1602
|
+
this.typingStatus$ = this._typingStatus$.asObservable();
|
1603
|
+
}
|
1604
|
+
//#region ---- Helper Methods ----
|
1605
|
+
getCurrentUser() {
|
1606
|
+
const user = this.sessionService.user;
|
1607
|
+
return {
|
1608
|
+
id: user?.id || 'guest-user',
|
1609
|
+
type: 'user',
|
1610
|
+
fullName: user?.title?.trim() || 'Guest User',
|
1611
|
+
username: user?.name?.trim() || 'guest-user',
|
1612
|
+
};
|
1613
|
+
}
|
1614
|
+
async getUserInfo(userId) {
|
1615
|
+
try {
|
1616
|
+
const user = await this.usersService.getOne(userId);
|
1617
|
+
return {
|
1618
|
+
id: user.id,
|
1619
|
+
type: 'user',
|
1620
|
+
fullName: `${user.firstName} ${user.lastName}`.trim(),
|
1621
|
+
username: user.username?.trim(),
|
1622
|
+
};
|
1623
|
+
}
|
1624
|
+
catch (error) {
|
1625
|
+
console.error(`Failed to get user info for ID: ${userId}`, error);
|
1626
|
+
return {
|
1627
|
+
id: userId,
|
1628
|
+
type: 'user',
|
1629
|
+
fullName: 'Unknown User',
|
1630
|
+
username: 'Unknown User',
|
1631
|
+
};
|
1632
|
+
}
|
1633
|
+
}
|
1634
|
+
async formatMessage(message) {
|
1635
|
+
if (message.author && !message.author.fullName) {
|
1636
|
+
const authorInfo = await this.getUserInfo(message.author.id);
|
1637
|
+
return {
|
1638
|
+
...message,
|
1639
|
+
author: authorInfo,
|
1640
|
+
};
|
1641
|
+
}
|
1642
|
+
return message;
|
1643
|
+
}
|
1644
|
+
async getUnreadCount(roomId) {
|
1645
|
+
const { items } = await this.messageService.query({
|
1646
|
+
skip: 0,
|
1647
|
+
take: 99,
|
1648
|
+
filter: { field: 'roomId', value: roomId, operator: { type: 'equal' } },
|
1649
|
+
});
|
1650
|
+
const currentUserId = this.getCurrentUser().id;
|
1651
|
+
const unreadMessages = items.filter((message) => {
|
1652
|
+
const isFromCurrentUser = message.author.id === currentUserId;
|
1653
|
+
const isReadByCurrentUser = (message.seen || []).some((seen) => seen.author.id === currentUserId);
|
1654
|
+
return !isFromCurrentUser && !isReadByCurrentUser;
|
1655
|
+
});
|
1656
|
+
return unreadMessages.length;
|
1657
|
+
}
|
1658
|
+
//#endregion
|
1659
|
+
//#region ---- ChatRoomService Implementations ----
|
1660
|
+
async createRoom(memberIds, title) {
|
1661
|
+
if (memberIds.length === 0) {
|
1662
|
+
throw new Error('At least one member is required to create a room');
|
1663
|
+
}
|
1664
|
+
const currentUser = this.getCurrentUser();
|
1665
|
+
const allMemberIds = [...new Set([...memberIds, currentUser.id])];
|
1666
|
+
const memberReferences = await Promise.all(allMemberIds.map((id) => this.getUserInfo(id)));
|
1667
|
+
const room = {
|
1668
|
+
members: memberReferences,
|
1669
|
+
title: title,
|
1670
|
+
topic: memberIds.length > 1 ? 'group' : 'personal',
|
1671
|
+
createdAt: new Date(),
|
1672
|
+
updatedAt: new Date(),
|
1673
|
+
type: 'chat',
|
1674
|
+
createdBy: this.getCurrentUser().id,
|
1675
|
+
updatedBy: this.getCurrentUser().id,
|
1676
|
+
};
|
1677
|
+
const roomId = await this.roomService.insertOne(room);
|
1678
|
+
const newRoom = await this.getRoom(roomId);
|
1679
|
+
this._roomAdded$.next(newRoom);
|
1680
|
+
return newRoom;
|
1681
|
+
}
|
1682
|
+
async getRoom(roomId) {
|
1683
|
+
const room = await this.roomService.getOne(roomId);
|
1684
|
+
if (!room || room.type !== 'chat') {
|
1685
|
+
throw new Error(`Chat room with ID ${roomId} not found.`);
|
1686
|
+
}
|
1687
|
+
const messages = await this.getMessages(roomId, 0, 1);
|
1688
|
+
const lastMessage = messages.items.length > 0 ? messages.items[0] : undefined;
|
1689
|
+
const unreadCount = await this.getUnreadCount(roomId);
|
1690
|
+
const currentUserId = this.getCurrentUser().id;
|
1691
|
+
const members = await Promise.all(room.members.map(async (member) => {
|
1692
|
+
if (member.fullName) {
|
1693
|
+
return member;
|
1694
|
+
}
|
1695
|
+
return this.getUserInfo(member.id);
|
1696
|
+
}));
|
1697
|
+
return {
|
1698
|
+
...room,
|
1699
|
+
lastMessage,
|
1700
|
+
unreadCount,
|
1701
|
+
members: members.filter((m) => m.id !== currentUserId),
|
1702
|
+
};
|
1703
|
+
}
|
1591
1704
|
async listRooms(skip = 0, take = 100) {
|
1592
|
-
const { items, total } = await this.roomService.query({
|
1705
|
+
const { items, total } = await this.roomService.query({
|
1706
|
+
skip,
|
1707
|
+
take,
|
1708
|
+
filter: { field: 'type', value: 'chat', operator: { type: 'equal' } },
|
1709
|
+
});
|
1593
1710
|
const settledRooms = await Promise.allSettled(items.map((room) => this.getRoom(room.id)));
|
1594
1711
|
const chatRooms = settledRooms
|
1595
1712
|
.filter((result) => {
|
@@ -1609,6 +1726,7 @@ class AXMChatServiceImpl {
|
|
1609
1726
|
async deleteRoom(roomId) {
|
1610
1727
|
try {
|
1611
1728
|
await this.roomService.deleteOne(roomId);
|
1729
|
+
this._roomRemoved$.next(roomId);
|
1612
1730
|
return true;
|
1613
1731
|
}
|
1614
1732
|
catch (error) {
|
@@ -1638,8 +1756,8 @@ class AXMChatServiceImpl {
|
|
1638
1756
|
}
|
1639
1757
|
//#endregion
|
1640
1758
|
//#region ---- ChatMessageService Implementations ----
|
1641
|
-
async sendMessage(roomId, content, contentType = 'text', replyId) {
|
1642
|
-
const author = this.getCurrentUser();
|
1759
|
+
async sendMessage(roomId, content, contentType = 'text', replyId, userId) {
|
1760
|
+
const author = userId ? await this.getUserInfo(userId) : this.getCurrentUser();
|
1643
1761
|
const messageContent = { content, contentType };
|
1644
1762
|
const message = {
|
1645
1763
|
roomId,
|
@@ -1655,7 +1773,7 @@ class AXMChatServiceImpl {
|
|
1655
1773
|
};
|
1656
1774
|
const messageId = await this.messageService.insertOne({ ...message });
|
1657
1775
|
const newMessage = await this.messageService.getOne(messageId);
|
1658
|
-
const formattedMessage = this.formatMessage(newMessage);
|
1776
|
+
const formattedMessage = await this.formatMessage(newMessage);
|
1659
1777
|
this._messageSent$.next(formattedMessage);
|
1660
1778
|
return formattedMessage;
|
1661
1779
|
}
|
@@ -1666,7 +1784,7 @@ class AXMChatServiceImpl {
|
|
1666
1784
|
filter: { field: 'roomId', value: roomId, operator: { type: 'equal' } },
|
1667
1785
|
sort: [{ field: 'createdAt', dir: 'desc' }],
|
1668
1786
|
});
|
1669
|
-
const formattedMessages = result.items.map((m) => this.formatMessage(m));
|
1787
|
+
const formattedMessages = await Promise.all(result.items.map((m) => this.formatMessage(m)));
|
1670
1788
|
return { items: formattedMessages, total: result.total };
|
1671
1789
|
}
|
1672
1790
|
async getMessage(messageId) {
|
@@ -1684,6 +1802,7 @@ class AXMChatServiceImpl {
|
|
1684
1802
|
async deleteMessage(messageId) {
|
1685
1803
|
try {
|
1686
1804
|
await this.messageService.deleteOne(messageId);
|
1805
|
+
this._messageRemoved$.next(messageId);
|
1687
1806
|
return true;
|
1688
1807
|
}
|
1689
1808
|
catch (error) {
|
@@ -1718,21 +1837,25 @@ class AXMChatServiceImpl {
|
|
1718
1837
|
return message;
|
1719
1838
|
}
|
1720
1839
|
const updatedReactions = [...reactions, { author, type }];
|
1721
|
-
|
1840
|
+
const res = await this.messageService.updateOne(messageId, {
|
1722
1841
|
reactions: updatedReactions,
|
1723
1842
|
updatedAt: new Date(),
|
1724
1843
|
updatedBy: this.getCurrentUser().id,
|
1725
1844
|
});
|
1845
|
+
this._messageReacted$.next(res);
|
1846
|
+
return res;
|
1726
1847
|
}
|
1727
1848
|
async removeReaction(messageId, type) {
|
1728
1849
|
const author = this.getCurrentUser();
|
1729
1850
|
const message = await this.messageService.getOne(messageId);
|
1730
1851
|
const updatedReactions = (message.reactions || []).filter((r) => !(r.author.id === author.id && r.type === type));
|
1731
|
-
|
1852
|
+
const res = await this.messageService.updateOne(messageId, {
|
1732
1853
|
reactions: updatedReactions,
|
1733
1854
|
updatedAt: new Date(),
|
1734
1855
|
updatedBy: this.getCurrentUser().id,
|
1735
1856
|
});
|
1857
|
+
this._messageReacted$.next(res);
|
1858
|
+
return res;
|
1736
1859
|
}
|
1737
1860
|
async getReactions(messageId) {
|
1738
1861
|
const message = await this.messageService.getOne(messageId);
|
@@ -1748,11 +1871,13 @@ class AXMChatServiceImpl {
|
|
1748
1871
|
return message;
|
1749
1872
|
}
|
1750
1873
|
const updatedSeen = [...seen, { author, type: 'read' }];
|
1751
|
-
|
1874
|
+
const updatedMessage = await this.messageService.updateOne(messageId, {
|
1752
1875
|
seen: updatedSeen,
|
1753
1876
|
updatedAt: new Date(),
|
1754
1877
|
updatedBy: this.getCurrentUser().id,
|
1755
1878
|
});
|
1879
|
+
this._messageSeen$.next(await this.formatMessage(updatedMessage));
|
1880
|
+
return updatedMessage;
|
1756
1881
|
}
|
1757
1882
|
async getSeenBy(messageId) {
|
1758
1883
|
const message = await this.messageService.getOne(messageId);
|
@@ -1769,6 +1894,7 @@ class AXMChatServiceImpl {
|
|
1769
1894
|
if (unreadMessages.length > 0) {
|
1770
1895
|
await Promise.all(unreadMessages.map((message) => this.markSeen(message.id)));
|
1771
1896
|
}
|
1897
|
+
this._roomSeen$.next(roomId);
|
1772
1898
|
return true;
|
1773
1899
|
}
|
1774
1900
|
catch (error) {
|
@@ -1776,10 +1902,20 @@ class AXMChatServiceImpl {
|
|
1776
1902
|
return false;
|
1777
1903
|
}
|
1778
1904
|
}
|
1779
|
-
|
1780
|
-
|
1905
|
+
//#endregion
|
1906
|
+
//#region ---- Typing Status Implementations ----
|
1907
|
+
async startTyping(roomId, userId) {
|
1908
|
+
const user = userId ? await this.getUserInfo(userId) : this.getCurrentUser();
|
1909
|
+
this._typingStatus$.next({ roomId, user, isTyping: true });
|
1910
|
+
}
|
1911
|
+
async stopTyping(roomId, userId) {
|
1912
|
+
const user = userId ? await this.getUserInfo(userId) : this.getCurrentUser();
|
1913
|
+
this._typingStatus$.next({ roomId, user, isTyping: false });
|
1914
|
+
}
|
1915
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMChatServiceImpl, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
1916
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMChatServiceImpl, providedIn: 'root' }); }
|
1781
1917
|
}
|
1782
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.
|
1918
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMChatServiceImpl, decorators: [{
|
1783
1919
|
type: Injectable,
|
1784
1920
|
args: [{
|
1785
1921
|
providedIn: 'root',
|
@@ -1790,31 +1926,37 @@ class AXMChatItemComponent {
|
|
1790
1926
|
constructor() {
|
1791
1927
|
// Input
|
1792
1928
|
this.data = input.required();
|
1929
|
+
this.typing = input(false);
|
1930
|
+
this.lastMessageReaction = input(null);
|
1793
1931
|
// Output
|
1794
1932
|
this.pressChatItem = output();
|
1795
1933
|
// Services
|
1796
1934
|
this.sessionService = inject(AXPSessionService);
|
1797
|
-
this.userService = inject(AXMUsersEntityService);
|
1798
1935
|
this.datePipe = inject(DatePipe);
|
1799
|
-
this.chatName = signal({
|
1936
|
+
this.chatName = signal({
|
1937
|
+
fullName: 'Loading...',
|
1938
|
+
id: '',
|
1939
|
+
isPrivate: false,
|
1940
|
+
});
|
1800
1941
|
this.#chatInfoEffect = effect(async () => {
|
1801
1942
|
const { members, title, id } = this.data();
|
1802
1943
|
if (members.length > 1) {
|
1803
1944
|
this.chatName.set({
|
1804
1945
|
fullName: title || 'Group Chat',
|
1805
1946
|
id,
|
1947
|
+
isPrivate: false,
|
1806
1948
|
});
|
1807
1949
|
return;
|
1808
1950
|
}
|
1809
1951
|
const member = members[0];
|
1810
1952
|
if (!member) {
|
1811
|
-
this.chatName.set({ fullName: 'Unknown User', id: '' });
|
1953
|
+
this.chatName.set({ fullName: 'Unknown User', id: '', isPrivate: true });
|
1812
1954
|
return;
|
1813
1955
|
}
|
1814
|
-
const data = await this.userService.getOne(member.id);
|
1815
1956
|
this.chatName.set({
|
1816
|
-
fullName:
|
1957
|
+
fullName: member.fullName || 'Unknown User',
|
1817
1958
|
id: member.id,
|
1959
|
+
isPrivate: true,
|
1818
1960
|
});
|
1819
1961
|
});
|
1820
1962
|
this.formattedLastMessageDate = computed(() => {
|
@@ -1835,12 +1977,14 @@ class AXMChatItemComponent {
|
|
1835
1977
|
}
|
1836
1978
|
});
|
1837
1979
|
this.lastMessage = computed(() => {
|
1838
|
-
const message = this.data().lastMessage
|
1980
|
+
const message = this.data().lastMessage;
|
1839
1981
|
if (!message)
|
1840
|
-
return { content: 'No messages yet', contentType: 'text' };
|
1982
|
+
return { content: 'No messages yet', contentType: 'text', reactions: [] };
|
1841
1983
|
return {
|
1842
|
-
content: message.contentType === 'text' ? message.content : message.contentType,
|
1843
|
-
contentType: message.contentType,
|
1984
|
+
content: message.message.contentType === 'text' ? message.message.content : message.message.contentType,
|
1985
|
+
contentType: message.message.contentType,
|
1986
|
+
reactions: message.reactions || [],
|
1987
|
+
author: message.author,
|
1844
1988
|
};
|
1845
1989
|
});
|
1846
1990
|
this.hasUnread = computed(() => {
|
@@ -1865,12 +2009,12 @@ class AXMChatItemComponent {
|
|
1865
2009
|
}
|
1866
2010
|
return '';
|
1867
2011
|
}
|
1868
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.
|
1869
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.
|
2012
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMChatItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
2013
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: AXMChatItemComponent, isStandalone: true, selector: "axm-chat-item", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, typing: { classPropertyName: "typing", publicName: "typing", isSignal: true, isRequired: false, transformFunction: null }, lastMessageReaction: { classPropertyName: "lastMessageReaction", publicName: "lastMessageReaction", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { pressChatItem: "pressChatItem" }, ngImport: i0, template: "<div\n [id]=\"data().id\"\n class=\"ax-cursor-pointer ax-p-4 ax-flex ax-items-center ax-justify-between ax-gap-4 ax-border-b ax-border-divider\"\n (click)=\"onPressChatItem(data().id)\"\n>\n <!-- Avatar and User Info Section -->\n <div class=\"ax-flex ax-min-w-0 ax-gap-4 ax-flex-1\">\n <!-- Avatar with Online Status -->\n <div class=\"ax-flex-shrink-0\">\n @if (chatName().isPrivate) {\n <axp-user-avatar [size]=\"48\" [userId]=\"chatName().id\"></axp-user-avatar>\n } @else {\n <ax-avatar [size]=\"48\">\n <ax-text class=\"ax-primary-lightest\">\n <small class=\"ax-text-xs ax-font-semibold fas fa-users\"></small>\n </ax-text>\n </ax-avatar>\n }\n <!--Temp-->\n </div>\n\n <!-- User Details and Last Message -->\n <div class=\"ax-flex ax-flex-col ax-min-w-0 ax-flex-1 ax-gap-1\">\n <div class=\"ax-flex ax-items-center ax-justify-between ax-gap-2\">\n <p class=\"ax-font-semibold ax-text-on-surface ax-truncate ax-py-1\" [title]=\"chatName().fullName\">\n {{ chatName().fullName }}\n </p>\n <div class=\"ax-flex ax-items-center ax-gap-1\">\n @if (messageSeenStatus()) {\n <ax-icon class=\"ax-icon ax-text-success ax-size-5\" [class]=\"messageSeenStatus()\"></ax-icon>\n }\n @if (this.data().lastMessage) {\n <span class=\"ax-text-xs ax-whitespace-nowrap\">\n {{ formattedLastMessageDate() }}\n </span>\n }\n </div>\n </div>\n <div class=\"ax-flex ax-items-center ax-justify-between ax-gap-2 ax-mt-1 ax-overflow-hidden\">\n @if (typing()) {\n <div class=\"ax-pb-1 ax-flex ax-justify-center ax-items-end ax-gap-1\">\n <span>is typing</span>\n <div class=\"typing-indicator\">\n <span></span>\n <span></span>\n <span></span>\n </div>\n </div>\n } @else {\n <div class=\"ax-flex ax-items-center ax-gap-2 ax-text-sm ax-shrink ax-min-w-0\">\n @if ((lastMessage().author?.fullName || lastMessage().author?.username) && !chatName().isPrivate) {\n <span class=\"ax-text-on-surface-light ax-font-semibold ax-capitalize\">\n {{ lastMessage().author?.fullName || lastMessage().author?.username + ': ' }}\n </span>\n }\n @switch (lastMessage().contentType) {\n @case ('image') {\n <i class=\"fa-regular fa-image\"></i>\n }\n @case ('video') {\n <i class=\"fa-regular fa-video\"></i>\n }\n @case ('file') {\n <i class=\"fa-regular fa-file\"></i>\n }\n @case ('audio') {\n <i class=\"fa-regular fa-microphone\"></i>\n }\n @case ('link') {\n <i class=\"fa-regular fa-link\"></i>\n }\n }\n\n <span class=\"ax-truncate ax-capitalize\">\n {{ lastMessage().content }}\n </span>\n </div>\n }\n <div class=\"ax-flex ax-items-center ax-gap-2\">\n @if (hasUnread()) {\n <ax-badge color=\"primary\" [text]=\"unreadCount()\" class=\"ax-flex-shrink-0 ax-ml-auto\"></ax-badge>\n }\n <!-- @if (lastMessageReaction()) {\n <div class=\"ax-flex ax-items-center ax-gap-1 ax-bg-surface ax-rounded-full ax-p-1 ax-px-2\">\n <span class=\"ax-text-sm\">{{ lastMessageReaction() }}</span>\n <span class=\"ax-text-xs\">{{ lastMessage().reactions.length }}</span>\n </div>\n } -->\n </div>\n </div>\n </div>\n </div>\n</div>\n", styles: [":host{display:block;width:100%}.typing-indicator{display:flex;align-items:center;padding-bottom:.1rem}.typing-indicator span{height:6px;width:6px;margin:0 1px;background-color:#9e9ea1;border-radius:50%;display:inline-block;animation:bounce 1.4s infinite ease-in-out both}.typing-indicator span:nth-child(1){animation-delay:-.32s}.typing-indicator span:nth-child(2){animation-delay:-.16s}@keyframes bounce{0%,80%,to{transform:scale(0)}40%{transform:scale(1)}}\n"], dependencies: [{ kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i1$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i1$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i2$2.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "component", type: AXPUserAvatarComponent, selector: "axp-user-avatar", inputs: ["size", "userId"] }, { kind: "ngmodule", type: AXAvatarModule }, { kind: "component", type: i3.AXAvatarComponent, selector: "ax-avatar", inputs: ["color", "size", "shape", "look"], outputs: ["sizeChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
1870
2014
|
}
|
1871
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.
|
2015
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMChatItemComponent, decorators: [{
|
1872
2016
|
type: Component,
|
1873
|
-
args: [{ selector: 'axm-chat-item', changeDetection: ChangeDetectionStrategy.OnPush, imports: [AXDecoratorModule, AXBadgeModule, AXPUserAvatarComponent], template: "<div\n [id]=\"data().id\"\n class=\"ax-cursor-pointer ax-p-4 ax-flex ax-items-center ax-justify-between ax-gap-4 ax-border-b ax-border-divider\"\n (click)=\"onPressChatItem(data().id)\"\n>\n <!-- Avatar and User Info Section -->\n <div class=\"ax-flex ax-min-w-0 ax-gap-4 ax-flex-1\">\n <!-- Avatar with Online Status -->\n <div class=\"ax-flex-shrink-0\">\n <axp-user-avatar [size]=\"48\" [userId]=\"chatName().id\"></axp-user-avatar>\n <!--Temp-->\n </div>\n\n <!-- User Details and Last Message -->\n <div class=\"ax-flex ax-flex-col ax-min-w-0 ax-flex-1 ax-gap-
|
2017
|
+
args: [{ selector: 'axm-chat-item', changeDetection: ChangeDetectionStrategy.OnPush, imports: [AXDecoratorModule, AXBadgeModule, AXPUserAvatarComponent, AXAvatarModule, AXDecoratorModule], template: "<div\n [id]=\"data().id\"\n class=\"ax-cursor-pointer ax-p-4 ax-flex ax-items-center ax-justify-between ax-gap-4 ax-border-b ax-border-divider\"\n (click)=\"onPressChatItem(data().id)\"\n>\n <!-- Avatar and User Info Section -->\n <div class=\"ax-flex ax-min-w-0 ax-gap-4 ax-flex-1\">\n <!-- Avatar with Online Status -->\n <div class=\"ax-flex-shrink-0\">\n @if (chatName().isPrivate) {\n <axp-user-avatar [size]=\"48\" [userId]=\"chatName().id\"></axp-user-avatar>\n } @else {\n <ax-avatar [size]=\"48\">\n <ax-text class=\"ax-primary-lightest\">\n <small class=\"ax-text-xs ax-font-semibold fas fa-users\"></small>\n </ax-text>\n </ax-avatar>\n }\n <!--Temp-->\n </div>\n\n <!-- User Details and Last Message -->\n <div class=\"ax-flex ax-flex-col ax-min-w-0 ax-flex-1 ax-gap-1\">\n <div class=\"ax-flex ax-items-center ax-justify-between ax-gap-2\">\n <p class=\"ax-font-semibold ax-text-on-surface ax-truncate ax-py-1\" [title]=\"chatName().fullName\">\n {{ chatName().fullName }}\n </p>\n <div class=\"ax-flex ax-items-center ax-gap-1\">\n @if (messageSeenStatus()) {\n <ax-icon class=\"ax-icon ax-text-success ax-size-5\" [class]=\"messageSeenStatus()\"></ax-icon>\n }\n @if (this.data().lastMessage) {\n <span class=\"ax-text-xs ax-whitespace-nowrap\">\n {{ formattedLastMessageDate() }}\n </span>\n }\n </div>\n </div>\n <div class=\"ax-flex ax-items-center ax-justify-between ax-gap-2 ax-mt-1 ax-overflow-hidden\">\n @if (typing()) {\n <div class=\"ax-pb-1 ax-flex ax-justify-center ax-items-end ax-gap-1\">\n <span>is typing</span>\n <div class=\"typing-indicator\">\n <span></span>\n <span></span>\n <span></span>\n </div>\n </div>\n } @else {\n <div class=\"ax-flex ax-items-center ax-gap-2 ax-text-sm ax-shrink ax-min-w-0\">\n @if ((lastMessage().author?.fullName || lastMessage().author?.username) && !chatName().isPrivate) {\n <span class=\"ax-text-on-surface-light ax-font-semibold ax-capitalize\">\n {{ lastMessage().author?.fullName || lastMessage().author?.username + ': ' }}\n </span>\n }\n @switch (lastMessage().contentType) {\n @case ('image') {\n <i class=\"fa-regular fa-image\"></i>\n }\n @case ('video') {\n <i class=\"fa-regular fa-video\"></i>\n }\n @case ('file') {\n <i class=\"fa-regular fa-file\"></i>\n }\n @case ('audio') {\n <i class=\"fa-regular fa-microphone\"></i>\n }\n @case ('link') {\n <i class=\"fa-regular fa-link\"></i>\n }\n }\n\n <span class=\"ax-truncate ax-capitalize\">\n {{ lastMessage().content }}\n </span>\n </div>\n }\n <div class=\"ax-flex ax-items-center ax-gap-2\">\n @if (hasUnread()) {\n <ax-badge color=\"primary\" [text]=\"unreadCount()\" class=\"ax-flex-shrink-0 ax-ml-auto\"></ax-badge>\n }\n <!-- @if (lastMessageReaction()) {\n <div class=\"ax-flex ax-items-center ax-gap-1 ax-bg-surface ax-rounded-full ax-p-1 ax-px-2\">\n <span class=\"ax-text-sm\">{{ lastMessageReaction() }}</span>\n <span class=\"ax-text-xs\">{{ lastMessage().reactions.length }}</span>\n </div>\n } -->\n </div>\n </div>\n </div>\n </div>\n</div>\n", styles: [":host{display:block;width:100%}.typing-indicator{display:flex;align-items:center;padding-bottom:.1rem}.typing-indicator span{height:6px;width:6px;margin:0 1px;background-color:#9e9ea1;border-radius:50%;display:inline-block;animation:bounce 1.4s infinite ease-in-out both}.typing-indicator span:nth-child(1){animation-delay:-.32s}.typing-indicator span:nth-child(2){animation-delay:-.16s}@keyframes bounce{0%,80%,to{transform:scale(0)}40%{transform:scale(1)}}\n"] }]
|
1874
2018
|
}] });
|
1875
2019
|
|
1876
2020
|
class AXMChatComponent extends AXPPageLayoutBaseComponent {
|
@@ -1878,8 +2022,8 @@ class AXMChatComponent extends AXPPageLayoutBaseComponent {
|
|
1878
2022
|
super(...arguments);
|
1879
2023
|
this.activatedRoute = inject(ActivatedRoute);
|
1880
2024
|
this.chatService = inject(AXMChatService);
|
1881
|
-
this.userService = inject(AXMUsersEntityService);
|
1882
2025
|
this.popupService = inject(AXPopupService);
|
2026
|
+
this.dialogService = inject(AXDialogService);
|
1883
2027
|
this.router = inject(Router);
|
1884
2028
|
this.unsubscribe = inject(AXUnsubscriber);
|
1885
2029
|
// View Children
|
@@ -1890,6 +2034,7 @@ class AXMChatComponent extends AXPPageLayoutBaseComponent {
|
|
1890
2034
|
this.allRooms = signal([]);
|
1891
2035
|
this.selectedRoom = signal(null);
|
1892
2036
|
this.isLoading = signal(false);
|
2037
|
+
this.typingStatus = signal({});
|
1893
2038
|
this.error = signal(null);
|
1894
2039
|
this.activeTab = signal(0);
|
1895
2040
|
this.isSearching = signal(false);
|
@@ -1931,10 +2076,9 @@ class AXMChatComponent extends AXPPageLayoutBaseComponent {
|
|
1931
2076
|
roomName = room.title || '';
|
1932
2077
|
}
|
1933
2078
|
else if (room.members && room.members.length === 1) {
|
1934
|
-
const
|
1935
|
-
if (
|
1936
|
-
|
1937
|
-
roomName = `${user.firstName} ${user.lastName}` || '';
|
2079
|
+
const member = room.members[0];
|
2080
|
+
if (member) {
|
2081
|
+
roomName = member.fullName || '';
|
1938
2082
|
}
|
1939
2083
|
}
|
1940
2084
|
const lastMessage = room.lastMessage?.message?.content || '';
|
@@ -1958,6 +2102,12 @@ class AXMChatComponent extends AXPPageLayoutBaseComponent {
|
|
1958
2102
|
this.allCount = computed(() => this.allRooms().length);
|
1959
2103
|
this.hasUnread = computed(() => this.allRooms().filter((i) => i.unreadCount > 0).length > 0);
|
1960
2104
|
this.totalCount = computed(() => this.allRooms().length || 0);
|
2105
|
+
//switch tab to unread if there is no unread
|
2106
|
+
this.autoSwitchTab = effect(() => {
|
2107
|
+
if (this.activeTab() === 1 && !this.hasUnread()) {
|
2108
|
+
this.activeTab.set(0);
|
2109
|
+
}
|
2110
|
+
});
|
1961
2111
|
this.af = afterNextRender(() => {
|
1962
2112
|
const tabComponent = this.tab();
|
1963
2113
|
if (tabComponent) {
|
@@ -1984,14 +2134,96 @@ class AXMChatComponent extends AXPPageLayoutBaseComponent {
|
|
1984
2134
|
await this.loadFromRoute();
|
1985
2135
|
});
|
1986
2136
|
//
|
1987
|
-
this.
|
1988
|
-
this.
|
2137
|
+
this.chatService.roomRemoved$.pipe(this.unsubscribe.takeUntilDestroy).subscribe((roomId) => {
|
2138
|
+
this.allRooms.update((rooms) => rooms.filter((r) => r.id !== roomId));
|
2139
|
+
if (roomId === this.selectedRoom()?.id) {
|
2140
|
+
this.selectedRoom.set(null);
|
2141
|
+
this.router.navigate(['./'], { relativeTo: this.activatedRoute });
|
2142
|
+
}
|
2143
|
+
});
|
2144
|
+
this.chatService.roomSeen$.pipe(this.unsubscribe.takeUntilDestroy).subscribe((roomId) => {
|
2145
|
+
const currentRooms = this.allRooms();
|
2146
|
+
const updatedRooms = currentRooms.map((room) => {
|
2147
|
+
if (room.id === roomId) {
|
2148
|
+
return { ...room, unreadCount: 0 };
|
2149
|
+
}
|
2150
|
+
return room;
|
2151
|
+
});
|
2152
|
+
this.allRooms.set(updatedRooms);
|
2153
|
+
});
|
2154
|
+
this.chatService.messageSeen$.pipe(this.unsubscribe.takeUntilDestroy).subscribe((message) => {
|
2155
|
+
const currentRooms = this.allRooms();
|
2156
|
+
const updatedRooms = currentRooms.map((room) => {
|
2157
|
+
if (room.id === message.roomId) {
|
2158
|
+
return { ...room, unreadCount: room.unreadCount - 1 };
|
2159
|
+
}
|
2160
|
+
return room;
|
2161
|
+
});
|
2162
|
+
this.allRooms.set(updatedRooms);
|
2163
|
+
});
|
2164
|
+
this.chatService.typingStatus$.pipe(this.unsubscribe.takeUntilDestroy).subscribe(async (status) => {
|
2165
|
+
const currentUserId = this.sessionService.user?.id;
|
2166
|
+
if (status.user.id !== currentUserId) {
|
2167
|
+
if (status.isTyping) {
|
2168
|
+
this.typingStatus.update((value) => ({
|
2169
|
+
...value,
|
2170
|
+
[status.roomId]: { user: status.user.fullName || '', isTyping: true },
|
2171
|
+
}));
|
2172
|
+
}
|
2173
|
+
else {
|
2174
|
+
this.typingStatus.update((value) => {
|
2175
|
+
const { [status.roomId]: _, ...rest } = value;
|
2176
|
+
return rest;
|
2177
|
+
});
|
2178
|
+
}
|
2179
|
+
}
|
2180
|
+
});
|
2181
|
+
this.chatService.messageSent$.pipe(this.unsubscribe.takeUntilDestroy).subscribe((message) => {
|
2182
|
+
const rooms = this.allRooms();
|
2183
|
+
const roomIndex = rooms.findIndex((r) => r.id === message.roomId);
|
2184
|
+
if (roomIndex > -1) {
|
2185
|
+
const roomToUpdate = rooms[roomIndex];
|
2186
|
+
const updatedRoom = {
|
2187
|
+
...roomToUpdate,
|
2188
|
+
lastMessage: message,
|
2189
|
+
unreadCount: message.author.id !== this.sessionService.user?.id
|
2190
|
+
? (roomToUpdate.unreadCount || 0) + 1
|
2191
|
+
: roomToUpdate.unreadCount,
|
2192
|
+
};
|
2193
|
+
const newRooms = [updatedRoom, ...rooms.filter((r) => r.id !== message.roomId)];
|
2194
|
+
this.allRooms.set(newRooms);
|
2195
|
+
}
|
2196
|
+
else {
|
2197
|
+
// New room, fetch it and add it to the top.
|
2198
|
+
this.chatService.getRoom(message.roomId).then((newRoom) => {
|
2199
|
+
this.allRooms.update((currentRooms) => {
|
2200
|
+
// Prepending the new room
|
2201
|
+
return [newRoom, ...currentRooms];
|
2202
|
+
});
|
2203
|
+
});
|
2204
|
+
}
|
2205
|
+
});
|
2206
|
+
this.chatService.messageReacted$.pipe(this.unsubscribe.takeUntilDestroy).subscribe((message) => {
|
2207
|
+
this.allRooms.update((rooms) => {
|
2208
|
+
return rooms.map((room) => {
|
2209
|
+
if (room.lastMessage?.id === message.id) {
|
2210
|
+
return {
|
2211
|
+
...room,
|
2212
|
+
lastMessage: {
|
2213
|
+
...room.lastMessage,
|
2214
|
+
reactions: message.reactions,
|
2215
|
+
},
|
2216
|
+
};
|
2217
|
+
}
|
2218
|
+
return room;
|
2219
|
+
});
|
2220
|
+
});
|
1989
2221
|
});
|
1990
2222
|
}
|
1991
2223
|
async loadFromRoute() {
|
1992
2224
|
const chatId = this.activatedRoute.snapshot.firstChild?.paramMap.get('id');
|
1993
2225
|
if (chatId) {
|
1994
|
-
this.
|
2226
|
+
this.openChat(chatId);
|
1995
2227
|
}
|
1996
2228
|
else {
|
1997
2229
|
this.selectedRoom.set(null);
|
@@ -2000,6 +2232,9 @@ class AXMChatComponent extends AXPPageLayoutBaseComponent {
|
|
2000
2232
|
// Page Interface Implementation
|
2001
2233
|
async getPageTitle() {
|
2002
2234
|
const room = this.selectedRoom();
|
2235
|
+
if (!room && this.layoutService.isMobileDevice()) {
|
2236
|
+
return await this.translateService.translateAsync('plural-title', { scope: 'conversation' });
|
2237
|
+
}
|
2003
2238
|
if (!room) {
|
2004
2239
|
return '';
|
2005
2240
|
}
|
@@ -2011,10 +2246,14 @@ class AXMChatComponent extends AXPPageLayoutBaseComponent {
|
|
2011
2246
|
if (!member) {
|
2012
2247
|
return 'Unknown User';
|
2013
2248
|
}
|
2014
|
-
|
2015
|
-
return `${user.firstName} ${user.lastName}` || 'Unknown User';
|
2249
|
+
return member.fullName || 'Unknown User';
|
2016
2250
|
}
|
2017
2251
|
getPageDescription() {
|
2252
|
+
const typing = this.typingStatus();
|
2253
|
+
const selectedRoomId = this.selectedRoom()?.id;
|
2254
|
+
if (selectedRoomId && typing[selectedRoomId]?.isTyping) {
|
2255
|
+
return `${typing[selectedRoomId].user} is typing...`;
|
2256
|
+
}
|
2018
2257
|
const room = this.selectedRoom();
|
2019
2258
|
return room?.topic || '';
|
2020
2259
|
}
|
@@ -2027,10 +2266,44 @@ class AXMChatComponent extends AXPPageLayoutBaseComponent {
|
|
2027
2266
|
else
|
2028
2267
|
return null;
|
2029
2268
|
}
|
2269
|
+
async getSecondaryMenuItems() {
|
2270
|
+
return this.layoutService.isMobileDevice()
|
2271
|
+
? []
|
2272
|
+
: [
|
2273
|
+
{
|
2274
|
+
title: await this.translateService.translateAsync('remove-chat', { scope: 'conversation' }),
|
2275
|
+
icon: 'fa-light fa-trash-can',
|
2276
|
+
color: 'danger',
|
2277
|
+
command: {
|
2278
|
+
name: 'remove-chat',
|
2279
|
+
},
|
2280
|
+
},
|
2281
|
+
];
|
2282
|
+
}
|
2283
|
+
async execute(command) {
|
2284
|
+
switch (command.name) {
|
2285
|
+
case 'remove-chat':
|
2286
|
+
const result = await this.dialogService.confirm('Remove Chat', 'Are you sure you want to remove this chat?');
|
2287
|
+
if (result) {
|
2288
|
+
await this.chatService.deleteRoom(this.selectedRoom()?.id);
|
2289
|
+
this.router.navigate(['./'], { relativeTo: this.activatedRoute });
|
2290
|
+
}
|
2291
|
+
break;
|
2292
|
+
}
|
2293
|
+
}
|
2030
2294
|
onBackButtonClick() {
|
2031
2295
|
this.selectedRoom.set(null);
|
2296
|
+
this.typingStatus.update((value) => {
|
2297
|
+
const { [this.selectedRoom()?.id]: _, ...rest } = value;
|
2298
|
+
return rest;
|
2299
|
+
});
|
2032
2300
|
this.router.navigate(['./'], { relativeTo: this.activatedRoute });
|
2033
2301
|
}
|
2302
|
+
onKeydownHandler(event) {
|
2303
|
+
if (this.selectedRoom()) {
|
2304
|
+
this.onBackButtonClick();
|
2305
|
+
}
|
2306
|
+
}
|
2034
2307
|
// Methods
|
2035
2308
|
async loadChats() {
|
2036
2309
|
try {
|
@@ -2053,8 +2326,12 @@ class AXMChatComponent extends AXPPageLayoutBaseComponent {
|
|
2053
2326
|
async refreshChat() {
|
2054
2327
|
await this.loadChats();
|
2055
2328
|
}
|
2056
|
-
async
|
2329
|
+
async openChat(chatId) {
|
2057
2330
|
try {
|
2331
|
+
this.typingStatus.update((value) => {
|
2332
|
+
const { [chatId]: _, ...rest } = value;
|
2333
|
+
return rest;
|
2334
|
+
});
|
2058
2335
|
// Use the service method to mark chat as read
|
2059
2336
|
await this.chatService.markRoomSeen(chatId);
|
2060
2337
|
// Update local state without making another network request
|
@@ -2101,7 +2378,7 @@ class AXMChatComponent extends AXPPageLayoutBaseComponent {
|
|
2101
2378
|
closeButton: true,
|
2102
2379
|
closeOnBackdropClick: false,
|
2103
2380
|
};
|
2104
|
-
const popup = await this.popupService.open(
|
2381
|
+
const popup = await this.popupService.open(AXMUserLookupPopup, popupConfig);
|
2105
2382
|
const members = popup.data?.lookup;
|
2106
2383
|
try {
|
2107
2384
|
if (members) {
|
@@ -2114,25 +2391,31 @@ class AXMChatComponent extends AXPPageLayoutBaseComponent {
|
|
2114
2391
|
this.toastService.danger('Failed to create room');
|
2115
2392
|
}
|
2116
2393
|
}
|
2117
|
-
ngOnDestroy() {
|
2118
|
-
|
2119
|
-
}
|
2120
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXMChatComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
2121
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: AXMChatComponent, isStandalone: true, selector: "axm-chat", providers: [
|
2394
|
+
ngOnDestroy() { }
|
2395
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMChatComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
2396
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: AXMChatComponent, isStandalone: true, selector: "axm-chat", host: { listeners: { "document:keydown.escape": "onKeydownHandler($event)" } }, providers: [
|
2122
2397
|
{
|
2123
2398
|
provide: AXPPageLayoutBase,
|
2124
2399
|
useExisting: AXMChatComponent,
|
2125
2400
|
},
|
2126
2401
|
AXUnsubscriber,
|
2127
|
-
], viewQueries: [{ propertyName: "tab", first: true, predicate: ["tab"], descendants: true, isSignal: true }, { propertyName: "container", first: true, predicate: ["container"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<axp-page-layout #container>\n <axp-layout-start-side
|
2402
|
+
], viewQueries: [{ propertyName: "tab", first: true, predicate: ["tab"], descendants: true, isSignal: true }, { propertyName: "container", first: true, predicate: ["container"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<axp-page-layout #container>\n <axp-layout-start-side class=\"ax-border-e ax-lightest-surface ax-h-full\">\n <axp-layout-header>\n <axp-layout-title>{{ 'module-name' | translate: { scope: 'conversation' } | async }}</axp-layout-title>\n <axp-layout-toolbar>\n <ax-search-box\n #searchInput\n look=\"solid\"\n [placeholder]=\"placeholder()\"\n [value]=\"searchQuery()\"\n (onValueChanged)=\"onSearch($event.value)\"\n class=\"ax-w-full\"\n >\n <ax-clear-button></ax-clear-button>\n </ax-search-box>\n </axp-layout-toolbar>\n </axp-layout-header>\n <axp-layout-content class=\"ax-flex ax-flex-col ax-min-h-0 ax-max-w-80\">\n @if (!layoutService.isMobileDevice()) {\n <ng-container [ngTemplateOutlet]=\"template\"></ng-container>\n }\n </axp-layout-content>\n </axp-layout-start-side>\n\n <axp-page-content style=\"height: calc(100vh - 22rem)\">\n @if (selectedRoom()) {\n <router-outlet></router-outlet>\n } @else if (layoutService.isMobileDevice()) {\n <ax-search-box\n #searchInput\n look=\"solid\"\n [placeholder]=\"placeholder()\"\n [value]=\"searchQuery()\"\n (onValueChanged)=\"onSearch($event.value)\"\n class=\"ax-w-full\"\n >\n <ax-clear-button></ax-clear-button>\n </ax-search-box>\n <ng-container [ngTemplateOutlet]=\"template\"></ng-container>\n }\n </axp-page-content>\n</axp-page-layout>\n\n<ng-template #template>\n <!-- Tabs -->\n <div class=\"ax-px-4\">\n @if (hasUnread()) {\n <ax-tabs\n #tab\n class=\"ax-text-neutral-400\"\n [look]=\"'with-line'\"\n [location]=\"'bottom'\"\n [fitParent]=\"true\"\n (onActiveTabChanged)=\"onTabChange($event)\"\n >\n <ax-tab-item text=\"All\" [active]=\"activeTab() === 0\">\n <ax-suffix>\n <ax-badge\n [text]=\"totalCount().toString()\"\n [color]=\"activeTab() === 0 ? 'primary' : 'secondary'\"\n class=\"ax-min-w-[1.5rem] ax-justify-center\"\n ></ax-badge>\n </ax-suffix>\n </ax-tab-item>\n <ax-tab-item text=\"Unread\" [active]=\"activeTab() === 1\">\n <ax-suffix>\n <ax-badge\n [text]=\"unreadCount().toString()\"\n [color]=\"activeTab() === 1 ? 'primary' : 'secondary'\"\n class=\"ax-min-w-[1.5rem] ax-justify-center\"\n ></ax-badge>\n </ax-suffix>\n </ax-tab-item>\n </ax-tabs>\n }\n </div>\n\n <!-- Chat List Content -->\n <div\n class=\"ax-flex-1 ax-overflow-hidden ax-flex ax-flex-col ax-justify-between ax-min-w-80\"\n [class.ax-border-t]=\"hasUnread()\"\n >\n <!-- Loading State -->\n @if (isLoading()) {\n <div class=\"ax-p-4 ax-space-y-4\">\n @for (_ of [1, 2, 3, 4, 5, 6]; track $index) {\n <div class=\"ax-flex ax-items-center ax-space-x-3\">\n <ax-skeleton [animated]=\"true\" class=\"ax-w-12 ax-h-12 ax-rounded-full\"></ax-skeleton>\n <div class=\"ax-flex-1 ax-space-y-2\">\n <ax-skeleton [animated]=\"true\" class=\"ax-w-3/4 ax-h-4 ax-rounded-md\"></ax-skeleton>\n <ax-skeleton [animated]=\"true\" class=\"ax-w-1/2 ax-h-3 ax-rounded-md\"></ax-skeleton>\n </div>\n </div>\n }\n </div>\n }\n\n <!-- Error State -->\n @if (error()) {\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-h-full ax-p-4 ax-text-center\">\n <ax-icon class=\"ax-text-danger ax-text-5xl ax-mb-3\">\n <i class=\"fa-light fa-circle-exclamation\"></i>\n </ax-icon>\n <p class=\"ax-font-semibold ax-text-lg\">\n {{ 'chat-error' | translate: { scope: 'conversation' } | async }}\n </p>\n <p class=\"ax-font-semibold ax-text-lg\">\n {{ 'chat-try-again' | translate: { scope: 'conversation' } | async }}\n </p>\n <p class=\"ax-text-secondary ax-mb-4\">{{ error() }}</p>\n <ax-button\n [text]=\"'try-again' | translate: { scope: 'conversation' } | async\"\n color=\"primary\"\n (onClick)=\"refreshChat()\"\n ></ax-button>\n </div>\n }\n\n <!-- Chat List -->\n @if (!isLoading() && !error()) {\n <div class=\"ax-flex-1 ax-overflow-y-auto\">\n @for (i of filteredRooms(); track i.id) {\n <axm-chat-item\n [data]=\"i\"\n [typing]=\"$any(typingStatus()[i.id])?.isTyping || false\"\n [lastMessageReaction]=\"i.lastMessage?.reactions?.[0]?.type ?? null\"\n [attr.data-id]=\"i.id\"\n (click)=\"openChat(i.id)\"\n [class.ax-bg-dark]=\"selectedRoom()?.id === i.id\"\n class=\"ax-transition-all ax-duration-100 hover:ax-bg-surface\"\n [@fadeIn]\n tabindex=\"0\"\n (keydown.enter)=\"openChat(i.id)\"\n role=\"button\"\n ></axm-chat-item>\n }\n\n <!-- Empty State -->\n @empty {\n <div class=\"ax-p-4 ax-font-medium ax-text-center ax-text-secondary\">\n @if (isSearching()) {\n No chats found matching your search\n } @else {\n No chats available\n }\n </div>\n }\n </div>\n }\n\n <!-- Footer Content -->\n <div class=\"ax-border-t ax-border-divider ax-bg-lightest ax-p-4\">\n <ax-button class=\"ax-w-full\" color=\"primary\" text=\"New Conversation\" (onClick)=\"onNewConversation()\">\n <ax-prefix>\n <ax-icon>\n <i class=\"fa-solid fa-plus\"></i>\n </ax-icon>\n </ax-prefix>\n </ax-button>\n </div>\n </div>\n</ng-template>\n", styles: [""], dependencies: [{ kind: "component", type: AXMChatItemComponent, selector: "axm-chat-item", inputs: ["data", "typing", "lastMessageReaction"], outputs: ["pressChatItem"] }, { kind: "ngmodule", type:
|
2128
2403
|
// Common Modules
|
2129
|
-
CommonModule }, { kind: "directive", type: i1$
|
2404
|
+
CommonModule }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1$2.AsyncPipe, name: "async" }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i2$3.RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "ngmodule", type:
|
2130
2405
|
// Acorex Core Modules
|
2131
|
-
AXFormatModule }, { kind: "ngmodule", type: AXConversationModule }, { kind: "ngmodule", type: AXCommentModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type:
|
2406
|
+
AXFormatModule }, { kind: "ngmodule", type: AXConversationModule }, { kind: "ngmodule", type: AXCommentModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i4$1.AXTranslatorPipe, name: "translate" }, { kind: "ngmodule", type:
|
2132
2407
|
// Acorex Component Modules
|
2133
|
-
AXResizableDirective,
|
2408
|
+
// AXResizableDirective,
|
2409
|
+
AXImageModule }, { kind: "ngmodule", type: AXAvatarModule }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i2$2.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i1$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i1$1.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }, { kind: "component", type: i1$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXTextBoxModule }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "component", type: i6$1.AXSearchBoxComponent, selector: "ax-search-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "value", "state", "name", "id", "look", "class", "delayTime", "type"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXTabsModule }, { kind: "component", type: i7$1.AXTabsComponent, selector: "ax-tabs", inputs: ["look", "location", "fitParent", "minWidth", "content"], outputs: ["onActiveTabChanged"] }, { kind: "component", type: i7$1.AXTabItemComponent, selector: "ax-tab-item", inputs: ["disabled", "text", "key", "headerTemplate", "active"], outputs: ["disabledChange", "onClick", "onBlur", "onFocus", "activeChange"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i5.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "ngmodule", type: AXWysiwygModule }, { kind: "ngmodule", type: AXLabelModule }, { kind: "ngmodule", type: AXSelectBoxModule }, { kind: "ngmodule", type: AXFormModule }, { kind: "ngmodule", type: AXDropdownButtonModule }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "ngmodule", type: AXToolBarModule }, { kind: "ngmodule", type: AXSkeletonModule }, { kind: "component", type: i2.AXSkeletonComponent, selector: "ax-skeleton", inputs: ["animated"] }, { kind: "component", type: AXPPageLayoutComponent, selector: "axp-page-layout" }, { kind: "component", type: AXPThemeLayoutBlockComponent, selector: " axp-page-content, axp-page-footer-container, axp-page-footer, axp-page-header, axp-page-header-container, axp-page-toolbar, axp-layout-content, axp-layout-page-content, axp-layout-sections, axp-layout-body, axp-layout-page-body, axp-layout-prefix, axp-layout-suffix, axp-layout-title-bar, axp-layout-title, axp-layout-title-actions, axp-layout-nav-button, axp-layout-description, axp-layout-breadcrumbs, axp-layout-list-action, " }, { kind: "component", type: AXPThemeLayoutStartSideComponent, selector: "axp-layout-page-start-side, axp-layout-start-side" }, { kind: "component", type: AXPThemeLayoutHeaderComponent, selector: "axp-layout-header" }, { kind: "component", type: AXPThemeLayoutToolbarComponent, selector: "axp-layout-toolbar" }], animations: [
|
2410
|
+
trigger('fadeIn', [
|
2411
|
+
transition(':enter', [
|
2412
|
+
style({ opacity: 0, transform: 'translateY(10px)' }),
|
2413
|
+
animate('300ms ease-out', style({ opacity: 1, transform: 'translateY(0)' })),
|
2414
|
+
]),
|
2415
|
+
]),
|
2416
|
+
], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
2134
2417
|
}
|
2135
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.
|
2418
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMChatComponent, decorators: [{
|
2136
2419
|
type: Component,
|
2137
2420
|
args: [{ selector: 'axm-chat', changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
2138
2421
|
{
|
@@ -2152,7 +2435,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImpor
|
|
2152
2435
|
AXCommentModule,
|
2153
2436
|
AXTranslationModule,
|
2154
2437
|
// Acorex Component Modules
|
2155
|
-
AXResizableDirective,
|
2438
|
+
// AXResizableDirective,
|
2156
2439
|
AXImageModule,
|
2157
2440
|
AXAvatarModule,
|
2158
2441
|
AXBadgeModule,
|
@@ -2175,8 +2458,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImpor
|
|
2175
2458
|
AXPThemeLayoutStartSideComponent,
|
2176
2459
|
AXPThemeLayoutHeaderComponent,
|
2177
2460
|
AXPThemeLayoutToolbarComponent,
|
2178
|
-
],
|
2179
|
-
|
2461
|
+
], animations: [
|
2462
|
+
trigger('fadeIn', [
|
2463
|
+
transition(':enter', [
|
2464
|
+
style({ opacity: 0, transform: 'translateY(10px)' }),
|
2465
|
+
animate('300ms ease-out', style({ opacity: 1, transform: 'translateY(0)' })),
|
2466
|
+
]),
|
2467
|
+
]),
|
2468
|
+
], template: "<axp-page-layout #container>\n <axp-layout-start-side class=\"ax-border-e ax-lightest-surface ax-h-full\">\n <axp-layout-header>\n <axp-layout-title>{{ 'module-name' | translate: { scope: 'conversation' } | async }}</axp-layout-title>\n <axp-layout-toolbar>\n <ax-search-box\n #searchInput\n look=\"solid\"\n [placeholder]=\"placeholder()\"\n [value]=\"searchQuery()\"\n (onValueChanged)=\"onSearch($event.value)\"\n class=\"ax-w-full\"\n >\n <ax-clear-button></ax-clear-button>\n </ax-search-box>\n </axp-layout-toolbar>\n </axp-layout-header>\n <axp-layout-content class=\"ax-flex ax-flex-col ax-min-h-0 ax-max-w-80\">\n @if (!layoutService.isMobileDevice()) {\n <ng-container [ngTemplateOutlet]=\"template\"></ng-container>\n }\n </axp-layout-content>\n </axp-layout-start-side>\n\n <axp-page-content style=\"height: calc(100vh - 22rem)\">\n @if (selectedRoom()) {\n <router-outlet></router-outlet>\n } @else if (layoutService.isMobileDevice()) {\n <ax-search-box\n #searchInput\n look=\"solid\"\n [placeholder]=\"placeholder()\"\n [value]=\"searchQuery()\"\n (onValueChanged)=\"onSearch($event.value)\"\n class=\"ax-w-full\"\n >\n <ax-clear-button></ax-clear-button>\n </ax-search-box>\n <ng-container [ngTemplateOutlet]=\"template\"></ng-container>\n }\n </axp-page-content>\n</axp-page-layout>\n\n<ng-template #template>\n <!-- Tabs -->\n <div class=\"ax-px-4\">\n @if (hasUnread()) {\n <ax-tabs\n #tab\n class=\"ax-text-neutral-400\"\n [look]=\"'with-line'\"\n [location]=\"'bottom'\"\n [fitParent]=\"true\"\n (onActiveTabChanged)=\"onTabChange($event)\"\n >\n <ax-tab-item text=\"All\" [active]=\"activeTab() === 0\">\n <ax-suffix>\n <ax-badge\n [text]=\"totalCount().toString()\"\n [color]=\"activeTab() === 0 ? 'primary' : 'secondary'\"\n class=\"ax-min-w-[1.5rem] ax-justify-center\"\n ></ax-badge>\n </ax-suffix>\n </ax-tab-item>\n <ax-tab-item text=\"Unread\" [active]=\"activeTab() === 1\">\n <ax-suffix>\n <ax-badge\n [text]=\"unreadCount().toString()\"\n [color]=\"activeTab() === 1 ? 'primary' : 'secondary'\"\n class=\"ax-min-w-[1.5rem] ax-justify-center\"\n ></ax-badge>\n </ax-suffix>\n </ax-tab-item>\n </ax-tabs>\n }\n </div>\n\n <!-- Chat List Content -->\n <div\n class=\"ax-flex-1 ax-overflow-hidden ax-flex ax-flex-col ax-justify-between ax-min-w-80\"\n [class.ax-border-t]=\"hasUnread()\"\n >\n <!-- Loading State -->\n @if (isLoading()) {\n <div class=\"ax-p-4 ax-space-y-4\">\n @for (_ of [1, 2, 3, 4, 5, 6]; track $index) {\n <div class=\"ax-flex ax-items-center ax-space-x-3\">\n <ax-skeleton [animated]=\"true\" class=\"ax-w-12 ax-h-12 ax-rounded-full\"></ax-skeleton>\n <div class=\"ax-flex-1 ax-space-y-2\">\n <ax-skeleton [animated]=\"true\" class=\"ax-w-3/4 ax-h-4 ax-rounded-md\"></ax-skeleton>\n <ax-skeleton [animated]=\"true\" class=\"ax-w-1/2 ax-h-3 ax-rounded-md\"></ax-skeleton>\n </div>\n </div>\n }\n </div>\n }\n\n <!-- Error State -->\n @if (error()) {\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-h-full ax-p-4 ax-text-center\">\n <ax-icon class=\"ax-text-danger ax-text-5xl ax-mb-3\">\n <i class=\"fa-light fa-circle-exclamation\"></i>\n </ax-icon>\n <p class=\"ax-font-semibold ax-text-lg\">\n {{ 'chat-error' | translate: { scope: 'conversation' } | async }}\n </p>\n <p class=\"ax-font-semibold ax-text-lg\">\n {{ 'chat-try-again' | translate: { scope: 'conversation' } | async }}\n </p>\n <p class=\"ax-text-secondary ax-mb-4\">{{ error() }}</p>\n <ax-button\n [text]=\"'try-again' | translate: { scope: 'conversation' } | async\"\n color=\"primary\"\n (onClick)=\"refreshChat()\"\n ></ax-button>\n </div>\n }\n\n <!-- Chat List -->\n @if (!isLoading() && !error()) {\n <div class=\"ax-flex-1 ax-overflow-y-auto\">\n @for (i of filteredRooms(); track i.id) {\n <axm-chat-item\n [data]=\"i\"\n [typing]=\"$any(typingStatus()[i.id])?.isTyping || false\"\n [lastMessageReaction]=\"i.lastMessage?.reactions?.[0]?.type ?? null\"\n [attr.data-id]=\"i.id\"\n (click)=\"openChat(i.id)\"\n [class.ax-bg-dark]=\"selectedRoom()?.id === i.id\"\n class=\"ax-transition-all ax-duration-100 hover:ax-bg-surface\"\n [@fadeIn]\n tabindex=\"0\"\n (keydown.enter)=\"openChat(i.id)\"\n role=\"button\"\n ></axm-chat-item>\n }\n\n <!-- Empty State -->\n @empty {\n <div class=\"ax-p-4 ax-font-medium ax-text-center ax-text-secondary\">\n @if (isSearching()) {\n No chats found matching your search\n } @else {\n No chats available\n }\n </div>\n }\n </div>\n }\n\n <!-- Footer Content -->\n <div class=\"ax-border-t ax-border-divider ax-bg-lightest ax-p-4\">\n <ax-button class=\"ax-w-full\" color=\"primary\" text=\"New Conversation\" (onClick)=\"onNewConversation()\">\n <ax-prefix>\n <ax-icon>\n <i class=\"fa-solid fa-plus\"></i>\n </ax-icon>\n </ax-prefix>\n </ax-button>\n </div>\n </div>\n</ng-template>\n" }]
|
2469
|
+
}], propDecorators: { onKeydownHandler: [{
|
2470
|
+
type: HostListener,
|
2471
|
+
args: ['document:keydown.escape', ['$event']]
|
2472
|
+
}] } });
|
2180
2473
|
|
2181
2474
|
var chat_component = /*#__PURE__*/Object.freeze({
|
2182
2475
|
__proto__: null,
|
@@ -2188,7 +2481,7 @@ var chat_component = /*#__PURE__*/Object.freeze({
|
|
2188
2481
|
* @param chatResponse - The response from chat service containing items and total
|
2189
2482
|
* @returns Array of formatted chat preview messages
|
2190
2483
|
*/
|
2191
|
-
function convertToChatPreview(currentUserId, chatResponse) {
|
2484
|
+
function convertToChatPreview(currentUserId, chatResponse, userName) {
|
2192
2485
|
if (!chatResponse || !chatResponse.items?.length) {
|
2193
2486
|
return [];
|
2194
2487
|
}
|
@@ -2235,11 +2528,15 @@ function convertToChatPreview(currentUserId, chatResponse) {
|
|
2235
2528
|
type: messageType,
|
2236
2529
|
content: message.message?.content || '',
|
2237
2530
|
name: name,
|
2531
|
+
userName,
|
2238
2532
|
};
|
2239
2533
|
// Add fromId if the message is not from current user
|
2240
2534
|
if (currentUserId !== message.author.id) {
|
2241
2535
|
previewMessage.fromId = message.author?.id;
|
2242
2536
|
}
|
2537
|
+
else {
|
2538
|
+
previewMessage.showActionButton = true;
|
2539
|
+
}
|
2243
2540
|
// Note: Reply information would need to be looked up from the actual messages
|
2244
2541
|
// This would typically be done by the service that has access to all messages
|
2245
2542
|
return previewMessage;
|
@@ -2250,7 +2547,7 @@ function convertToChatPreview(currentUserId, chatResponse) {
|
|
2250
2547
|
* @param message - The original message that is being referenced
|
2251
2548
|
* @returns A ChatPreviewMessage formatted for use as a replyTo
|
2252
2549
|
*/
|
2253
|
-
function createReplyPreview(currentUserId, message) {
|
2550
|
+
function createReplyPreview(currentUserId, message, userName) {
|
2254
2551
|
if (!message)
|
2255
2552
|
return undefined;
|
2256
2553
|
return {
|
@@ -2267,6 +2564,8 @@ function createReplyPreview(currentUserId, message) {
|
|
2267
2564
|
content: message.message?.content || '',
|
2268
2565
|
name: message.author?.id || 'Unknown',
|
2269
2566
|
fromId: currentUserId !== message.author.id ? message.author?.id : undefined,
|
2567
|
+
showActionButton: true,
|
2568
|
+
userName,
|
2270
2569
|
};
|
2271
2570
|
}
|
2272
2571
|
/**
|
@@ -2458,12 +2757,17 @@ class AXMChatPreviewComponent {
|
|
2458
2757
|
this.chatService = inject(AXMChatService);
|
2459
2758
|
this.sessionService = inject(AXPSessionService);
|
2460
2759
|
this.toastService = inject(AXToastService);
|
2760
|
+
this.inputRef = viewChild(AXConversationInputComponent);
|
2761
|
+
this.activeMessage = signal(null);
|
2762
|
+
this.typing$ = new Subject();
|
2461
2763
|
this.chatData = signal([]);
|
2764
|
+
this.room = signal(null);
|
2462
2765
|
this.isEditing = signal(false);
|
2463
2766
|
this.editId = signal(null);
|
2464
2767
|
this.height = signal(0);
|
2465
2768
|
this.isLoading = signal(false);
|
2466
2769
|
this.error = signal(null);
|
2770
|
+
this.isChannel = computed(() => this.room()?.topic === 'channel');
|
2467
2771
|
this.options = signal({
|
2468
2772
|
disabled: false,
|
2469
2773
|
readonly: false,
|
@@ -2477,11 +2781,38 @@ class AXMChatPreviewComponent {
|
|
2477
2781
|
ngOnInit() {
|
2478
2782
|
this.activatedRoute.params.subscribe((params) => {
|
2479
2783
|
this.roomId = params['id'];
|
2480
|
-
|
2481
|
-
|
2482
|
-
|
2483
|
-
|
2784
|
+
if (this.roomId) {
|
2785
|
+
this.loadMessages(this.roomId);
|
2786
|
+
this.loadRoomInfo(this.roomId);
|
2787
|
+
}
|
2788
|
+
});
|
2789
|
+
this.chatService.messageSent$.subscribe(async (message) => {
|
2790
|
+
// Only add messages that are not from the current user and belong to the current room
|
2791
|
+
if (message.author.id !== this.sessionService.user?.id && message.roomId === this.roomId) {
|
2792
|
+
await this.chatService.markSeen(message.id);
|
2793
|
+
this.chatData.update((values) => {
|
2794
|
+
const newMessage = convertToChatPreview(this.sessionService.user?.id || '', {
|
2795
|
+
items: [message],
|
2796
|
+
total: 1,
|
2797
|
+
})[0];
|
2798
|
+
return [...values, newMessage];
|
2799
|
+
});
|
2800
|
+
}
|
2484
2801
|
});
|
2802
|
+
// this.typingSubscription = this.typing$.pipe(debounceTime(1000)).subscribe(() => {
|
2803
|
+
// if (this.roomId) {
|
2804
|
+
// this.chatService.stopTyping(this.roomId);
|
2805
|
+
// }
|
2806
|
+
// });
|
2807
|
+
}
|
2808
|
+
ngOnDestroy() {
|
2809
|
+
this.typingSubscription?.unsubscribe();
|
2810
|
+
}
|
2811
|
+
handleTyping(event) {
|
2812
|
+
if (this.roomId) {
|
2813
|
+
this.chatService.startTyping(this.roomId);
|
2814
|
+
this.typing$.next();
|
2815
|
+
}
|
2485
2816
|
}
|
2486
2817
|
handleFileChange(event) {
|
2487
2818
|
console.log('File Changed:', event);
|
@@ -2541,6 +2872,11 @@ class AXMChatPreviewComponent {
|
|
2541
2872
|
}
|
2542
2873
|
}
|
2543
2874
|
}
|
2875
|
+
handleEnter() {
|
2876
|
+
if (this.options().value && this.roomId) {
|
2877
|
+
this.handleOnSend({ data: { value: this.options().value } });
|
2878
|
+
}
|
2879
|
+
}
|
2544
2880
|
handleOnAction(e) {
|
2545
2881
|
console.log('Action Triggered:', e);
|
2546
2882
|
}
|
@@ -2574,10 +2910,20 @@ class AXMChatPreviewComponent {
|
|
2574
2910
|
this.isLoading.set(false);
|
2575
2911
|
}
|
2576
2912
|
}
|
2577
|
-
|
2578
|
-
|
2579
|
-
|
2580
|
-
|
2913
|
+
async loadRoomInfo(roomId) {
|
2914
|
+
try {
|
2915
|
+
const roomData = await this.chatService.getRoom(roomId);
|
2916
|
+
this.room.set(roomData);
|
2917
|
+
}
|
2918
|
+
catch (error) {
|
2919
|
+
console.error('Failed to load room info:', error);
|
2920
|
+
}
|
2921
|
+
}
|
2922
|
+
addItemHandler(e) {
|
2923
|
+
this.activeMessage.set(e.data);
|
2924
|
+
if (e.data.fromId) {
|
2925
|
+
e.canceled = true;
|
2926
|
+
return;
|
2581
2927
|
}
|
2582
2928
|
const userItem = [];
|
2583
2929
|
if (e.data.type === 'text') {
|
@@ -2590,6 +2936,7 @@ class AXMChatPreviewComponent {
|
|
2590
2936
|
this.isEditing.set(true);
|
2591
2937
|
this.editId.set(e.data.id);
|
2592
2938
|
this.options.update((prev) => ({ ...prev, value: e.data.content }));
|
2939
|
+
this.addInputOverlay('edit', e.data);
|
2593
2940
|
}
|
2594
2941
|
catch (error) {
|
2595
2942
|
this.toastService.danger('Failed to edit message');
|
@@ -2619,479 +2966,26 @@ class AXMChatPreviewComponent {
|
|
2619
2966
|
}
|
2620
2967
|
e.items.push(...userItem);
|
2621
2968
|
}
|
2622
|
-
|
2623
|
-
|
2624
|
-
|
2625
|
-
|
2626
|
-
|
2627
|
-
args: [{ selector: 'axm-chat-preview', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, FormsModule, AXDomChangeDirective, AXConversationModule, AXLoadingModule], template: "@if (isLoading()) {\n <div class=\"ax-h-full ax-w-full ax-flex ax-items-center ax-justify-center\">\n <ax-loading></ax-loading>\n </div>\n} @else if (error()) {\n <div class=\"ax-h-full ax-w-full ax-flex ax-items-center ax-justify-center\">\n <div class=\"ax-text-center\">\n <p class=\"ax-text-danger\">{{ error() }}</p>\n <button (click)=\"loadMessages(roomId)\" class=\"ax-mt-2 ax-button ax-primary\">Retry</button>\n </div>\n </div>\n} @else {\n <div\n axDomChange\n (axResizeObserver)=\"setHeight($event[0].contentRect.height)\"\n class=\"ax-bg-surface-container ax-h-full\"\n >\n <!-- Messages Container -->\n <ax-conversation-container class=\"ax-overflow-hidden\" [chatData]=\"chatData()\">\n <ax-conversation-view\n (onActionMenuOpening)=\"addItemHandler($event)\"\n (onAction)=\"handleOnAction($event)\"\n [chatBoxHeight]=\"height() - 60 + 'px'\"\n ></ax-conversation-view>\n <ax-conversation-input\n class=\"ax-p-1\"\n placeholder=\"Type a message...\"\n [(ngModel)]=\"options().value\"\n (onSendClick)=\"handleOnSend($event)\"\n (onFileChange)=\"handleFileChange($event)\"\n (onStopRecording)=\"handleEndRecord($event)\"\n (onCancelRecording)=\"handleCancelRecord($event)\"\n ></ax-conversation-input>\n </ax-conversation-container>\n </div>\n}\n", styles: [":host{display:block;width:100%;height:100%}\n"] }]
|
2628
|
-
}] });
|
2629
|
-
|
2630
|
-
var chatPreview_component = /*#__PURE__*/Object.freeze({
|
2631
|
-
__proto__: null,
|
2632
|
-
AXMChatPreviewComponent: AXMChatPreviewComponent
|
2633
|
-
});
|
2634
|
-
|
2635
|
-
class AXMCommentWidgetViewComponent extends AXPLayoutWidgetComponent {
|
2636
|
-
constructor() {
|
2637
|
-
super(...arguments);
|
2638
|
-
this.hasCooldown = signal(false);
|
2639
|
-
this.commentContent = signal('');
|
2640
|
-
this.isSubmitting = signal(false);
|
2641
|
-
this.isReplyingMode = signal(false);
|
2642
|
-
this.isEditingMode = signal(false);
|
2643
|
-
this.isLoading = signal(true);
|
2644
|
-
this.failedImageIds = signal([]);
|
2645
|
-
this.activeReplyComment = signal(undefined);
|
2646
|
-
this.activeEditComment = signal(undefined);
|
2647
|
-
this.wysiwygEditor = viewChild.required('w');
|
2648
|
-
this.commentService = inject(AXMCommentService);
|
2649
|
-
this.platform = inject(AXPlatform);
|
2650
|
-
this.popupService = inject(AXPopupService);
|
2651
|
-
this.toastService = inject(AXToastService);
|
2652
|
-
this.dialogService = inject(AXDialogService);
|
2653
|
-
this.sanitize = inject(DomSanitizer);
|
2654
|
-
this.getPayload = computed(() => ({
|
2655
|
-
params: this.payload(),
|
2656
|
-
skip: 0,
|
2657
|
-
take: 10,
|
2658
|
-
}));
|
2659
|
-
this.payload = computed(() => ({
|
2660
|
-
roomType: 'default',
|
2661
|
-
entityId: this.options().entityId,
|
2662
|
-
instanceId: this.options().instanceId,
|
2663
|
-
}));
|
2664
|
-
this.comments = signal([]);
|
2665
|
-
this.wysiwyg = viewChild('w');
|
2666
|
-
this.wysiwygOptions = signal({
|
2667
|
-
look: 'solid',
|
2668
|
-
});
|
2669
|
-
this.avatarConfig = signal({
|
2670
|
-
color: 'primary',
|
2671
|
-
look: 'rounded',
|
2672
|
-
type: 'solid', // 'image' | 'text' | 'icon' | 'default'
|
2673
|
-
});
|
2674
|
-
this.validateContent = (content) => {
|
2675
|
-
let isValid = true;
|
2676
|
-
if (!content || content === '<p><br></p>') {
|
2677
|
-
isValid = false;
|
2678
|
-
}
|
2679
|
-
return {
|
2680
|
-
rule: 'callback',
|
2681
|
-
result: isValid,
|
2682
|
-
message: isValid ? '' : 'Please fill the content',
|
2683
|
-
value: content,
|
2684
|
-
};
|
2685
|
-
};
|
2686
|
-
}
|
2687
|
-
ngOnInit() {
|
2688
|
-
super.ngOnInit();
|
2689
|
-
this.loadComments();
|
2690
|
-
}
|
2691
|
-
sanitizeHtml(htmlContent) {
|
2692
|
-
if (!htmlContent)
|
2693
|
-
return this.sanitize.bypassSecurityTrustHtml('');
|
2694
|
-
return this.sanitize.bypassSecurityTrustHtml(htmlContent);
|
2695
|
-
}
|
2696
|
-
handleImageError(imageId) {
|
2697
|
-
this.failedImageIds.update((ids) => [...ids, imageId]);
|
2698
|
-
}
|
2699
|
-
checkImageExists(imageId) {
|
2700
|
-
return !this.failedImageIds().includes(imageId);
|
2701
|
-
}
|
2702
|
-
extractInitials(name) {
|
2703
|
-
if (!name)
|
2704
|
-
return '?';
|
2705
|
-
// Handle the case where name is an object with fullName property
|
2706
|
-
const nameStr = typeof name === 'object' && name.fullName ? name.fullName : String(name);
|
2707
|
-
const words = nameStr.split(' ');
|
2708
|
-
const initials = words.map((word) => word.charAt(0).toUpperCase());
|
2709
|
-
return initials.join('');
|
2710
|
-
}
|
2711
|
-
async loadComments() {
|
2712
|
-
this.isLoading.set(true);
|
2713
|
-
try {
|
2714
|
-
const response = await this.commentService.query(this.getPayload());
|
2715
|
-
this.comments.set(response.items);
|
2716
|
-
}
|
2717
|
-
catch (error) {
|
2718
|
-
console.error('Failed to load comments:', error);
|
2719
|
-
this.toastService.show({
|
2720
|
-
content: 'Failed to load comments. Please try again.',
|
2721
|
-
color: 'danger',
|
2722
|
-
location: 'bottom-center',
|
2723
|
-
closeButton: true,
|
2724
|
-
timeOut: 3000,
|
2725
|
-
timeOutProgress: true,
|
2726
|
-
});
|
2727
|
-
this.comments.set([]);
|
2728
|
-
}
|
2729
|
-
finally {
|
2730
|
-
setTimeout(() => {
|
2731
|
-
this.isLoading.set(false);
|
2732
|
-
}, 250);
|
2733
|
-
}
|
2734
|
-
}
|
2735
|
-
editMessage(comment, reply) {
|
2736
|
-
this.isReplyingMode.set(false);
|
2737
|
-
this.activeReplyComment.set(undefined);
|
2738
|
-
this.isEditingMode.set(true);
|
2739
|
-
this.activeEditComment.set(comment);
|
2740
|
-
const contentToEdit = reply ? reply.message?.content : comment.message?.content;
|
2741
|
-
this.commentContent.set(contentToEdit || '');
|
2742
|
-
this.wysiwygEditor().getHostElement().scrollIntoView({ behavior: 'smooth', block: 'start' });
|
2743
|
-
}
|
2744
|
-
replyMessage(comment, reply) {
|
2745
|
-
this.isEditingMode.set(false);
|
2746
|
-
this.activeEditComment.set(undefined);
|
2747
|
-
this.isReplyingMode.set(true);
|
2748
|
-
this.activeReplyComment.set(comment);
|
2749
|
-
if (reply) {
|
2750
|
-
const author = reply.author.fullName || reply.author.id;
|
2751
|
-
const mention = `<a data-id="${reply.id}">@${author}</a> `;
|
2752
|
-
this.commentContent.set(mention);
|
2753
|
-
this.wysiwyg()?.focus();
|
2754
|
-
document.getElementsByClassName('ql-editor')[0].innerHTML = mention;
|
2755
|
-
}
|
2756
|
-
this.wysiwygEditor().getHostElement().scrollIntoView({ behavior: 'smooth', block: 'start' });
|
2757
|
-
}
|
2758
|
-
async deleteComment(comment) {
|
2759
|
-
const dialog = this.dialogService.open({
|
2760
|
-
icon: 'fa-regular fa-warning',
|
2761
|
-
content: 'Are you sure you want to delete this comment?',
|
2762
|
-
title: 'Delete Comment',
|
2763
|
-
type: 'danger',
|
2764
|
-
orientation: 'horizontal',
|
2765
|
-
buttons: [
|
2766
|
-
{
|
2767
|
-
text: 'Delete',
|
2768
|
-
color: 'danger',
|
2769
|
-
onClick: async (e) => {
|
2770
|
-
e.handled = true;
|
2771
|
-
e.source.text = 'Deleting...';
|
2772
|
-
e.source.disabled = true;
|
2773
|
-
e.source.loading = true;
|
2774
|
-
try {
|
2775
|
-
if (comment.id) {
|
2776
|
-
await this.commentService.deleteOne(comment.id);
|
2777
|
-
this.removeMessageById(comment.id);
|
2778
|
-
this.toastService.show({
|
2779
|
-
content: 'Comment deleted successfully.',
|
2780
|
-
color: 'success',
|
2781
|
-
location: 'bottom-center',
|
2782
|
-
closeButton: true,
|
2783
|
-
timeOut: 3000,
|
2784
|
-
timeOutProgress: true,
|
2785
|
-
});
|
2786
|
-
if (this.isEditingMode() && this.activeEditComment()?.id === comment.id) {
|
2787
|
-
this.resetReplyEditState();
|
2788
|
-
}
|
2789
|
-
dialog.close();
|
2790
|
-
}
|
2791
|
-
}
|
2792
|
-
catch (error) {
|
2793
|
-
this.toastService.show({
|
2794
|
-
content: typeof error === 'string' ? error : 'Failed to delete comment!',
|
2795
|
-
color: 'danger',
|
2796
|
-
location: 'bottom-center',
|
2797
|
-
closeButton: true,
|
2798
|
-
timeOut: 3000,
|
2799
|
-
timeOutProgress: true,
|
2800
|
-
});
|
2801
|
-
}
|
2802
|
-
},
|
2803
|
-
},
|
2804
|
-
{
|
2805
|
-
text: 'Cancel',
|
2806
|
-
color: 'default',
|
2807
|
-
autofocus: true,
|
2808
|
-
onClick: (e) => {
|
2809
|
-
dialog.close();
|
2810
|
-
},
|
2811
|
-
},
|
2812
|
-
],
|
2813
|
-
closeButton: false,
|
2814
|
-
});
|
2815
|
-
}
|
2816
|
-
async deleteReply(comment, reply) {
|
2817
|
-
const dialog = this.dialogService.open({
|
2818
|
-
icon: 'fa-regular fa-warning',
|
2819
|
-
content: 'Are you sure you want to delete this reply?',
|
2820
|
-
title: 'Delete Reply',
|
2821
|
-
type: 'danger',
|
2822
|
-
orientation: 'horizontal',
|
2823
|
-
buttons: [
|
2824
|
-
{
|
2825
|
-
text: 'Delete',
|
2826
|
-
color: 'danger',
|
2827
|
-
onClick: async (e) => {
|
2828
|
-
e.handled = true;
|
2829
|
-
e.source.text = 'Deleting...';
|
2830
|
-
e.source.disabled = true;
|
2831
|
-
e.source.loading = true;
|
2832
|
-
try {
|
2833
|
-
if (reply.id) {
|
2834
|
-
await this.commentService.deleteOne(reply.id);
|
2835
|
-
this.removeMessageById(comment.id, reply.id);
|
2836
|
-
this.toastService.show({
|
2837
|
-
content: 'Comment deleted successfully.',
|
2838
|
-
color: 'success',
|
2839
|
-
location: 'bottom-center',
|
2840
|
-
closeButton: true,
|
2841
|
-
timeOut: 3000,
|
2842
|
-
timeOutProgress: true,
|
2843
|
-
});
|
2844
|
-
dialog.close();
|
2845
|
-
}
|
2846
|
-
}
|
2847
|
-
catch (error) {
|
2848
|
-
this.toastService.show({
|
2849
|
-
content: typeof error === 'string' ? error : 'Failed to delete comment!',
|
2850
|
-
color: 'danger',
|
2851
|
-
location: 'bottom-center',
|
2852
|
-
closeButton: true,
|
2853
|
-
timeOut: 3000,
|
2854
|
-
timeOutProgress: true,
|
2855
|
-
});
|
2856
|
-
}
|
2857
|
-
},
|
2858
|
-
},
|
2859
|
-
{
|
2860
|
-
text: 'Cancel',
|
2861
|
-
color: 'default',
|
2862
|
-
autofocus: true,
|
2863
|
-
onClick: (e) => {
|
2864
|
-
dialog.close();
|
2865
|
-
},
|
2866
|
-
},
|
2867
|
-
],
|
2868
|
-
closeButton: false,
|
2869
|
-
});
|
2870
|
-
}
|
2871
|
-
resetReplyEditState() {
|
2872
|
-
this.isEditingMode.set(false);
|
2873
|
-
this.activeEditComment.set(undefined);
|
2874
|
-
this.isReplyingMode.set(false);
|
2875
|
-
this.activeReplyComment.set(undefined);
|
2876
|
-
this.commentContent.set('');
|
2877
|
-
document.getElementsByClassName('ql-editor')[0].innerHTML = '';
|
2878
|
-
}
|
2879
|
-
async toggleLike(comment, reply) {
|
2880
|
-
try {
|
2881
|
-
if (reply) {
|
2882
|
-
if (reply.id) {
|
2883
|
-
this.updateLikeStatus(comment.id, reply.id);
|
2884
|
-
await this.commentService.like(reply.id);
|
2885
|
-
}
|
2886
|
-
}
|
2887
|
-
else {
|
2888
|
-
if (comment.id) {
|
2889
|
-
this.updateLikeStatus(comment.id);
|
2890
|
-
await this.commentService.like(comment.id);
|
2891
|
-
}
|
2892
|
-
}
|
2893
|
-
}
|
2894
|
-
catch (error) {
|
2895
|
-
console.error('Failed to toggle like:', error);
|
2896
|
-
// Revert the optimistic update if the server call fails
|
2897
|
-
if (reply && reply.id) {
|
2898
|
-
this.updateLikeStatus(comment.id, reply.id);
|
2899
|
-
}
|
2900
|
-
else if (comment.id) {
|
2901
|
-
this.updateLikeStatus(comment.id);
|
2902
|
-
}
|
2903
|
-
}
|
2904
|
-
}
|
2905
|
-
updateLikeStatus(commentId, replyId) {
|
2906
|
-
this.comments.update((commentsList) => {
|
2907
|
-
return commentsList.map((comment) => {
|
2908
|
-
if (comment.id === commentId) {
|
2909
|
-
if (replyId && comment.replies) {
|
2910
|
-
const updatedReplies = comment.replies.map((reply) => reply.id === replyId
|
2911
|
-
? {
|
2912
|
-
...reply,
|
2913
|
-
isLiked: !reply.isLiked,
|
2914
|
-
reactionsCount: reply.isLiked && reply.reactionsCount !== undefined
|
2915
|
-
? reply.reactionsCount - 1
|
2916
|
-
: (reply.reactionsCount || 0) + 1,
|
2917
|
-
}
|
2918
|
-
: reply);
|
2919
|
-
return {
|
2920
|
-
...comment,
|
2921
|
-
replies: updatedReplies,
|
2922
|
-
};
|
2923
|
-
}
|
2924
|
-
else {
|
2925
|
-
return {
|
2926
|
-
...comment,
|
2927
|
-
isLiked: !comment.isLiked,
|
2928
|
-
reactionsCount: comment.isLiked && comment.reactionsCount !== undefined
|
2929
|
-
? comment.reactionsCount - 1
|
2930
|
-
: (comment.reactionsCount || 0) + 1,
|
2931
|
-
};
|
2932
|
-
}
|
2933
|
-
}
|
2934
|
-
return comment;
|
2935
|
-
});
|
2936
|
-
});
|
2937
|
-
}
|
2938
|
-
removeMessageById(commentId, replyId) {
|
2939
|
-
if (replyId) {
|
2940
|
-
// Remove a reply from a comment
|
2941
|
-
this.comments.update((commentsList) => commentsList.map((comment) => {
|
2942
|
-
if (comment.id === commentId && comment.replies) {
|
2943
|
-
return {
|
2944
|
-
...comment,
|
2945
|
-
replies: comment.replies.filter((reply) => reply.id !== replyId),
|
2946
|
-
};
|
2947
|
-
}
|
2948
|
-
return comment;
|
2949
|
-
}));
|
2950
|
-
}
|
2951
|
-
else {
|
2952
|
-
// Remove a whole comment
|
2953
|
-
this.comments.update((commentsList) => commentsList.filter((comment) => comment.id !== commentId));
|
2969
|
+
addInputOverlay(type, message) {
|
2970
|
+
const input = this.inputRef();
|
2971
|
+
const icon = type === 'reply' ? 'fa-solid fa-reply' : 'fa-solid fa-pencil';
|
2972
|
+
if (input) {
|
2973
|
+
input.setActionBoxContainer(icon, message?.content || this.activeMessage()?.content || '');
|
2954
2974
|
}
|
2955
2975
|
}
|
2956
|
-
|
2957
|
-
if (!
|
2958
|
-
return;
|
2959
|
-
}
|
2960
|
-
this.isSubmitting.set(true);
|
2961
|
-
let memberLookup;
|
2962
|
-
if (isPrivate) {
|
2963
|
-
const popupConfig = {
|
2964
|
-
header: true,
|
2965
|
-
size: 'md',
|
2966
|
-
draggable: true,
|
2967
|
-
hasBackdrop: true,
|
2968
|
-
closeButton: true,
|
2969
|
-
closeOnBackdropClick: false,
|
2970
|
-
};
|
2971
|
-
const popup = await this.popupService.open(AXMCommentLookupPopup, popupConfig);
|
2972
|
-
memberLookup = popup.data?.data?.lookup;
|
2973
|
-
}
|
2974
|
-
try {
|
2975
|
-
if (this.isEditingMode() && this.activeEditComment()?.id) {
|
2976
|
-
const payload = {
|
2977
|
-
message: {
|
2978
|
-
content: this.commentContent(),
|
2979
|
-
contentType: 'text',
|
2980
|
-
},
|
2981
|
-
};
|
2982
|
-
await this.commentService.updateOne(this.activeEditComment().id, payload);
|
2983
|
-
this.hasCooldown.set(true);
|
2984
|
-
this.isEditingMode.set(false);
|
2985
|
-
this.activeEditComment.set(undefined);
|
2986
|
-
}
|
2987
|
-
else {
|
2988
|
-
const payload = {
|
2989
|
-
...this.payload(),
|
2990
|
-
content: this.commentContent(),
|
2991
|
-
contentType: 'text',
|
2992
|
-
isPrivate: isPrivate,
|
2993
|
-
replyId: this.activeReplyComment()?.id ?? null,
|
2994
|
-
};
|
2995
|
-
await this.commentService.insertOne(payload);
|
2996
|
-
this.hasCooldown.set(true);
|
2997
|
-
this.isReplyingMode.set(false);
|
2998
|
-
this.activeReplyComment.set(undefined);
|
2999
|
-
}
|
3000
|
-
// Reload comments to get the updated list with proper hierarchy
|
3001
|
-
const response = await this.commentService.query(this.getPayload());
|
3002
|
-
this.comments.set(response.items);
|
3003
|
-
this.commentContent.set('');
|
3004
|
-
document.getElementsByClassName('ql-editor')[0].innerHTML = '';
|
3005
|
-
setTimeout(() => {
|
3006
|
-
this.hasCooldown.set(false);
|
3007
|
-
}, 1000);
|
3008
|
-
}
|
3009
|
-
catch (error) {
|
3010
|
-
console.error('Error submitting comment:', error);
|
3011
|
-
this.toastService.show({
|
3012
|
-
content: typeof error === 'string' ? error : 'Failed to submit comment. Please try again.',
|
3013
|
-
color: 'danger',
|
3014
|
-
location: 'bottom-center',
|
3015
|
-
closeButton: true,
|
3016
|
-
timeOut: 3000,
|
3017
|
-
timeOutProgress: true,
|
3018
|
-
});
|
3019
|
-
}
|
3020
|
-
finally {
|
3021
|
-
this.isSubmitting.set(false);
|
3022
|
-
}
|
3023
|
-
}
|
3024
|
-
scrollMain() {
|
3025
|
-
const comment = this.isReplyingMode() ? this.activeReplyComment() : this.activeEditComment();
|
3026
|
-
if (comment && comment.id) {
|
3027
|
-
const el = document.getElementById(comment.id);
|
3028
|
-
if (el) {
|
3029
|
-
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
3030
|
-
const content = el?.firstElementChild?.children[1];
|
3031
|
-
if (content) {
|
3032
|
-
const prevBg = content.style.background;
|
3033
|
-
content.style.borderRadius = '0.25rem';
|
3034
|
-
content.style.transition = 'background 1s ease-in-out';
|
3035
|
-
content.style.background = `rgba(var(--ax-color-on-surface), var(--tw-bg-opacity))`;
|
3036
|
-
setTimeout(() => {
|
3037
|
-
content.style.background = prevBg || 'rgba(0, 0, 0, 0)';
|
3038
|
-
}, 1000);
|
3039
|
-
}
|
3040
|
-
}
|
3041
|
-
}
|
3042
|
-
}
|
3043
|
-
calcDefrenetTime(date) {
|
3044
|
-
return date ? Date.now() - date.getTime() : undefined;
|
3045
|
-
}
|
3046
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXMCommentWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
3047
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: AXMCommentWidgetViewComponent, isStandalone: true, selector: "axm-comment-widget-view", viewQueries: [{ propertyName: "wysiwygEditor", first: true, predicate: ["w"], descendants: true, isSignal: true }, { propertyName: "wysiwyg", first: true, predicate: ["w"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"ax-mt-2 ax-p-2\">\n <ax-comment-container>\n @if (isLoading()) {\n <div class=\"ax-flex ax-items-center ax-py-12 ax-bg-lightest ax-px-5\">\n <ax-skeleton class=\"ax-min-w-16 ax-h-16 ax-rounded-full ax-me-4\"></ax-skeleton>\n <div class=\"ax-flex ax-flex-col ax-gap-2 ax-w-full\">\n <ax-skeleton class=\"ax-w-full ax-h-6 ax-rounded\"></ax-skeleton>\n <ax-skeleton class=\"ax-w-full ax-h-2 ax-rounded-full\"></ax-skeleton>\n <ax-skeleton class=\"ax-w-full ax-h-2 ax-rounded-full\"></ax-skeleton>\n <ax-skeleton class=\"ax-w-8/12 ax-h-2 ax-rounded-full\"></ax-skeleton>\n </div>\n </div>\n } @else if (!isLoading() && comments().length > 0) {\n <ax-comment-view class=\"ax-bg-lightest\">\n @for (comment of comments(); track comment.id) {\n <ax-comment-item [id]=\"comment.id!\" [replyCount]=\"comment.replies?.length ?? 0\">\n <ax-avatar [color]=\"avatarConfig().color\" [shape]=\"avatarConfig().look\">\n @if (checkImageExists(comment.id!) && comment.author && extractInitials(comment.author) !== '?') {\n <ax-image (onError)=\"handleImageError(comment.id!)\" [src]=\"''\">\n <ax-loading></ax-loading>\n </ax-image>\n } @else {\n <ax-text>\n <span class=\"ax-text-base ax-overflow-hidden\">{{ extractInitials(comment.author) }}</span>\n </ax-text>\n }\n </ax-avatar>\n <ax-title>{{ extractInitials(comment.author) }}</ax-title>\n <ax-comment-date>{{ calcDefrenetTime(comment.createdAt) | format: 'timeleft' | async }} </ax-comment-date>\n <ax-comment-menu-options>\n <ax-button class=\"ax-sm\" look=\"blank\" color=\"neutral\">\n <ax-icon icon=\"ax-icon ax-icon-solid ax-icon-more-horizontal\"></ax-icon>\n </ax-button>\n\n <ax-dropdown-panel>\n <ax-button-item-list>\n <ax-button-item text=\"Edit\" color=\"neutral\" (click)=\"editMessage(comment)\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-edit\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n\n <ax-button-item text=\"Delete\" color=\"danger\" (click)=\"deleteComment(comment)\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-trash-can\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-comment-menu-options>\n <ax-content [innerHTML]=\"sanitizeHtml(comment.message.content)\"></ax-content>\n <ax-comment-like (click)=\"toggleLike(comment)\" [liked]=\"comment.isLiked!\">\n {{ comment.reactionsCount }}\n </ax-comment-like>\n <ax-comment-reply-text (click)=\"replyMessage(comment)\"></ax-comment-reply-text>\n @for (reply of comment.replies; track reply.id) {\n <ax-comment-item [id]=\"reply.id\">\n <ax-avatar [color]=\"avatarConfig().color\" [shape]=\"avatarConfig().look\">\n @if (reply && checkImageExists(reply.id!) && reply.author && extractInitials(reply.author) !== '?') {\n <ax-image (onError)=\"handleImageError(reply.id!)\" [src]=\"''\">\n <ax-loading></ax-loading>\n </ax-image>\n } @else {\n <ax-text>\n <span class=\"ax-text-base ax-overflow-hidden\">{{ extractInitials(reply.author) }}</span>\n </ax-text>\n }\n </ax-avatar>\n <ax-title>{{ extractInitials(reply.author) }}</ax-title>\n <ax-comment-date>{{ calcDefrenetTime(reply.createdAt) | format: 'timeleft' | async }} </ax-comment-date>\n <ax-comment-menu-options>\n <ax-button class=\"ax-sm\" look=\"blank\" color=\"neutral\">\n <ax-icon icon=\"ax-icon ax-icon-solid ax-icon-more-horizontal\"></ax-icon>\n </ax-button>\n\n <ax-dropdown-panel>\n <ax-button-item-list>\n <ax-button-item text=\"Edit\" color=\"neutral\" (click)=\"editMessage(comment, reply)\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-edit\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n <ax-button-item text=\"Delete\" color=\"danger\" (click)=\"deleteReply(comment, reply)\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-trash-can\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-comment-menu-options>\n <ax-content [innerHTML]=\"sanitizeHtml(reply.message.content)\"></ax-content>\n <ax-comment-like (click)=\"toggleLike(comment, reply)\" [liked]=\"reply.isLiked!\">\n {{ reply.reactionsCount }}\n </ax-comment-like>\n <ax-comment-reply-text (click)=\"replyMessage(comment, reply)\"></ax-comment-reply-text>\n </ax-comment-item>\n }\n </ax-comment-item>\n }\n </ax-comment-view>\n } @else {\n <div>\n <div class=\"ax-flex ax-flex-col ax-gap-4 ax-justify-center ax-items-center ax-p-10\">\n <svg\n class=\"ax-mx-auto\"\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"154\"\n height=\"161\"\n viewBox=\"0 0 154 161\"\n fill=\"none\"\n >\n <path\n d=\"M0.0616455 84.4268C0.0616455 42.0213 34.435 7.83765 76.6507 7.83765C118.803 7.83765 153.224 42.0055 153.224 84.4268C153.224 102.42 147.026 118.974 136.622 132.034C122.282 150.138 100.367 161 76.6507 161C52.7759 161 30.9882 150.059 16.6633 132.034C6.25961 118.974 0.0616455 102.42 0.0616455 84.4268Z\"\n fill=\"#EEF2FF\"\n />\n <path\n d=\"M96.8189 0.632498L96.8189 0.632384L96.8083 0.630954C96.2034 0.549581 95.5931 0.5 94.9787 0.5H29.338C22.7112 0.5 17.3394 5.84455 17.3394 12.4473V142.715C17.3394 149.318 22.7112 154.662 29.338 154.662H123.948C130.591 154.662 135.946 149.317 135.946 142.715V38.9309C135.946 38.0244 135.847 37.1334 135.648 36.2586L135.648 36.2584C135.117 33.9309 133.874 31.7686 132.066 30.1333C132.066 30.1331 132.065 30.1329 132.065 30.1327L103.068 3.65203C103.068 3.6519 103.067 3.65177 103.067 3.65164C101.311 2.03526 99.1396 0.995552 96.8189 0.632498Z\"\n fill=\"white\"\n stroke=\"#E5E7EB\"\n />\n <ellipse cx=\"80.0618\" cy=\"81\" rx=\"28.0342\" ry=\"28.0342\" fill=\"#EEF2FF\" />\n <path\n d=\"M99.2393 61.3061L99.2391 61.3058C88.498 50.5808 71.1092 50.5804 60.3835 61.3061C49.6423 72.0316 49.6422 89.4361 60.3832 100.162C71.109 110.903 88.4982 110.903 99.2393 100.162C109.965 89.4363 109.965 72.0317 99.2393 61.3061ZM105.863 54.6832C120.249 69.0695 120.249 92.3985 105.863 106.785C91.4605 121.171 68.1468 121.171 53.7446 106.785C39.3582 92.3987 39.3582 69.0693 53.7446 54.683C68.1468 40.2965 91.4605 40.2966 105.863 54.6832Z\"\n stroke=\"#E5E7EB\"\n />\n <path\n d=\"M110.782 119.267L102.016 110.492C104.888 108.267 107.476 105.651 109.564 102.955L118.329 111.729L110.782 119.267Z\"\n stroke=\"#E5E7EB\"\n />\n <path\n d=\"M139.122 125.781L139.122 125.78L123.313 109.988C123.313 109.987 123.313 109.987 123.312 109.986C121.996 108.653 119.849 108.657 118.521 109.985L118.871 110.335L118.521 109.985L109.047 119.459C107.731 120.775 107.735 122.918 109.044 124.247L109.047 124.249L124.858 140.06C128.789 143.992 135.191 143.992 139.122 140.06C143.069 136.113 143.069 129.728 139.122 125.781Z\"\n fill=\"#A5B4FC\"\n stroke=\"#818CF8\"\n />\n <path\n d=\"M83.185 87.2285C82.5387 87.2285 82.0027 86.6926 82.0027 86.0305C82.0027 83.3821 77.9987 83.3821 77.9987 86.0305C77.9987 86.6926 77.4627 87.2285 76.8006 87.2285C76.1543 87.2285 75.6183 86.6926 75.6183 86.0305C75.6183 80.2294 84.3831 80.2451 84.3831 86.0305C84.3831 86.6926 83.8471 87.2285 83.185 87.2285Z\"\n fill=\"#4F46E5\"\n />\n <path\n d=\"M93.3528 77.0926H88.403C87.7409 77.0926 87.2049 76.5567 87.2049 75.8946C87.2049 75.2483 87.7409 74.7123 88.403 74.7123H93.3528C94.0149 74.7123 94.5509 75.2483 94.5509 75.8946C94.5509 76.5567 94.0149 77.0926 93.3528 77.0926Z\"\n fill=\"#4F46E5\"\n />\n <path\n d=\"M71.5987 77.0925H66.6488C65.9867 77.0925 65.4507 76.5565 65.4507 75.8945C65.4507 75.2481 65.9867 74.7122 66.6488 74.7122H71.5987C72.245 74.7122 72.781 75.2481 72.781 75.8945C72.781 76.5565 72.245 77.0925 71.5987 77.0925Z\"\n fill=\"#4F46E5\"\n />\n <rect x=\"38.3522\" y=\"21.5128\" width=\"41.0256\" height=\"2.73504\" rx=\"1.36752\" fill=\"#4F46E5\" />\n <rect x=\"38.3522\" y=\"133.65\" width=\"54.7009\" height=\"5.47009\" rx=\"2.73504\" fill=\"#A5B4FC\" />\n <rect x=\"38.3522\" y=\"29.7179\" width=\"13.6752\" height=\"2.73504\" rx=\"1.36752\" fill=\"#4F46E5\" />\n <circle cx=\"56.13\" cy=\"31.0854\" r=\"1.36752\" fill=\"#4F46E5\" />\n <circle cx=\"61.6001\" cy=\"31.0854\" r=\"1.36752\" fill=\"#4F46E5\" />\n <circle cx=\"67.0702\" cy=\"31.0854\" r=\"1.36752\" fill=\"#4F46E5\" />\n </svg>\n <div>\n <h2 class=\"ax-text-center ax-text-neutral-600 ax-font-semibold ax-leading-loose ax-pb-2\">\n There is no Comment!\n </h2>\n </div>\n </div>\n </div>\n }\n </ax-comment-container>\n <ax-form>\n <ax-form-field>\n <div>\n @if (isReplyingMode() || isEditingMode()) {\n <div\n class=\"ax-flex ax-justify-between ax-rounded-b-none ax-border ax-border-b-0 ax-rounded-lg ax-bg-on-surface ax-px-6 ax-py-3 ax-w-full ax-items-center ax-overflow-hidden ax-text-sm ax-leading-none\"\n >\n <div (click)=\"scrollMain()\" class=\"ax-flex ax-justify-start ax-items-center ax-cursor-pointer\">\n <i\n [class]=\"isReplyingMode() ? 'fa-reply' : 'fa-pen'\"\n class=\"fa-solid ax-text-primary-500 dark:ax-text-primary-300 ax-text-2xl ax-me-4\"\n ></i>\n <div\n class=\"ax-flex ax-flex-col ax-gap-2 ax-justify-between ax-align-middle ax-leading-4 ax-overflow-hidden\"\n >\n <p class=\"ax-text-primary-500 dark:ax-text-primary-300\">\n {{ isReplyingMode() ? 'Reply to ' : 'Edit Message' }}\n <span class=\"ax-font-bold\">\n {{ isReplyingMode() ? extractInitials(activeReplyComment()?.author) : '' }}\n </span>\n </p>\n <div\n class=\"ax-truncate\"\n [innerHTML]=\"\n isReplyingMode()\n ? sanitizeHtml(activeReplyComment()?.message?.content ?? '')\n : sanitizeHtml(activeEditComment()?.message?.content ?? '')\n \"\n ></div>\n </div>\n </div>\n <div><i (click)=\"resetReplyEditState()\" class=\"fa-solid ax-text-2xl fa-xmark ax-cursor-pointer\"></i></div>\n </div>\n }\n <ax-wysiwyg-container #w [look]=\"wysiwygOptions().look\" [(ngModel)]=\"commentContent\">\n <ax-wysiwyg-view class=\"ax-min-h-28\"></ax-wysiwyg-view>\n <ax-toolbar>\n <ax-content>\n <ax-wysiwyg-history></ax-wysiwyg-history>\n <ax-wysiwyg-font-style></ax-wysiwyg-font-style>\n <ax-wysiwyg-colors></ax-wysiwyg-colors>\n <ax-wysiwyg-list></ax-wysiwyg-list>\n <ax-wysiwyg-alignment></ax-wysiwyg-alignment>\n </ax-content>\n <ax-suffix>\n <ax-dropdown-button\n [disabled]=\"hasCooldown()\"\n type=\"submit\"\n color=\"primary\"\n mode=\"split\"\n text=\"Send\"\n (onClick)=\"submitComment()\"\n >\n @if (isSubmitting()) {\n <ax-loading></ax-loading>\n }\n <ax-button-item-list>\n <ax-button-item (click)=\"submitComment(true)\" text=\"Send Private ...\" name=\"private\" data=\"private\">\n <ax-prefix>\n <ax-icon icon=\"fa-regular fa-user-secret\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n </ax-button-item-list>\n </ax-dropdown-button>\n </ax-suffix>\n </ax-toolbar>\n <ax-validation-rule rule=\"callback\" [options]=\"{ validate: validateContent }\"></ax-validation-rule>\n </ax-wysiwyg-container>\n </div>\n </ax-form-field>\n </ax-form>\n</div>\n", styles: ["ax-wysiwyg-container .ax-editor-container{border-top-left-radius:0!important;border-top-right-radius:0!important}ax-wysiwyg-container .ax-error-message{padding-left:.5rem}\n"], dependencies: [{ kind: "component", type: AXWysiwygContainerComponent, selector: "ax-wysiwyg-container", inputs: ["look", "placeHolder"], outputs: ["onValueChanged"] }, { kind: "ngmodule", type: AXAvatarModule }, { kind: "component", type: i6.AXAvatarComponent, selector: "ax-avatar", inputs: ["color", "size", "shape", "look"], outputs: ["sizeChange"] }, { kind: "ngmodule", type: AXConversationModule }, { kind: "ngmodule", type: AXSkeletonModule }, { kind: "component", type: i2$1.AXSkeletonComponent, selector: "ax-skeleton", inputs: ["animated"] }, { kind: "ngmodule", type: AXCommentModule }, { kind: "component", type: i4.AXCommentViewComponent, selector: "ax-comment-view" }, { kind: "component", type: i4.AXCommentContainerComponent, selector: "ax-comment-container" }, { kind: "component", type: i4.AxCommentItemComponent, selector: "ax-comment-item", inputs: ["replyCount"] }, { kind: "component", type: i4.AXCommentLikeComponent, selector: "ax-comment-like", inputs: ["liked"], outputs: ["likedChange", "onLiked"] }, { kind: "component", type: i4.AXMenuOptionsComponent, selector: "ax-comment-menu-options" }, { kind: "component", type: i4.AXCommentReplyTextComponent, selector: "ax-comment-reply-text" }, { kind: "component", type: i4.AXCommentDateComponent, selector: "ax-comment-date" }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i5$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "component", type: i5$1.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i5$1.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items"], outputs: ["onItemClick"] }, { kind: "ngmodule", type: AXImageModule }, { kind: "component", type: i7.AXImageComponent, selector: "ax-image", inputs: ["width", "height", "overlayMode", "src", "alt", "priority", "lazy"], outputs: ["onLoad", "onError"] }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i8.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "component", type: i9.AXDropdownPanelComponent, selector: "ax-dropdown-panel", inputs: ["isOpen", "fitParent", "dropdownWidth", "position", "placement", "_target", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i5.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i5.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXWysiwygModule }, { kind: "component", type: i1.AXWysiwygViewComponent, selector: "ax-wysiwyg-view", inputs: ["class"] }, { kind: "component", type: i1.AXWysiwygAlignmentComponent, selector: "ax-wysiwyg-alignment" }, { kind: "component", type: i1.AXWysiwygColorsComponent, selector: "ax-wysiwyg-colors" }, { kind: "component", type: i1.AXWysiwygFontStyleComponent, selector: "ax-wysiwyg-font-style" }, { kind: "component", type: i1.AXWysiwygHistoryComponent, selector: "ax-wysiwyg-history" }, { kind: "component", type: i1.AXWysiwygListComponent, selector: "ax-wysiwyg-list" }, { kind: "ngmodule", type: AXToolBarModule }, { kind: "component", type: i12.AXToolBarComponent, selector: "ax-toolbar" }, { kind: "ngmodule", type: AXDropdownButtonModule }, { kind: "component", type: i14.AXDropdownButtonComponent, selector: "ax-dropdown-button", inputs: ["disabled", "size", "color", "look", "text", "type", "mode"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "lookChange", "colorChange", "disabledChange"] }, { kind: "ngmodule", type: AXValidationModule }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "ngmodule", type: AXFormModule }, { kind: "component", type: i11.AXFormFieldComponent, selector: "ax-form-field", inputs: ["labelMode"] }, { kind: "component", type: i11.AXFormComponent, selector: "ax-form", inputs: ["labelMode", "look", "messageStyle", "updateOn"], outputs: ["onValidate", "updateOnChange"] }, { kind: "directive", type: i11.AXValidationRuleDirective, selector: "ax-validation-rule", inputs: ["rule", "options", "message", "disabled"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i13.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i13.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXFormatModule }, { kind: "pipe", type: i10.AXFormatPipe, name: "format" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
2976
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMChatPreviewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
2977
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: AXMChatPreviewComponent, isStandalone: true, selector: "axm-chat-preview", viewQueries: [{ propertyName: "inputRef", first: true, predicate: AXConversationInputComponent, descendants: true, isSignal: true }], ngImport: i0, template: "@if (isLoading()) {\n <div class=\"ax-h-full ax-w-full ax-flex ax-items-center ax-justify-center\">\n <ax-loading></ax-loading>\n </div>\n} @else if (error()) {\n <div class=\"ax-h-full ax-w-full ax-flex ax-items-center ax-justify-center\">\n <div class=\"ax-text-center\">\n <p class=\"ax-text-danger\">{{ error() }}</p>\n <button (click)=\"loadMessages(roomId)\" class=\"ax-mt-2 ax-button ax-primary\">Retry</button>\n </div>\n </div>\n} @else {\n <div\n axDomChange\n (axResizeObserver)=\"setHeight($event[0].contentRect.height)\"\n class=\"ax-bg-surface-container ax-h-full\"\n >\n <!-- Messages Container -->\n <ax-conversation-container class=\"ax-overflow-hidden\" [chatData]=\"chatData()\">\n <ax-conversation-view\n (onActionMenuOpening)=\"addItemHandler($event)\"\n (onAction)=\"handleOnAction($event)\"\n (onReplyClick)=\"addInputOverlay('reply', $event.data)\"\n [chatBoxHeight]=\"height() - 60 + 'px'\"\n ></ax-conversation-view>\n @if (!isChannel()) {\n <ax-conversation-input\n class=\"ax-p-1\"\n placeholder=\"Type a message...\"\n [(ngModel)]=\"options().value\"\n (ngModelChange)=\"handleTyping($event)\"\n (onSendClick)=\"handleOnSend($event)\"\n (onFileChange)=\"handleFileChange($event)\"\n (onStopRecording)=\"handleEndRecord($event)\"\n (onCancelRecording)=\"handleCancelRecord($event)\"\n (onEnterPressed)=\"handleEnter()\"\n ></ax-conversation-input>\n }\n </ax-conversation-container>\n </div>\n}\n", styles: [":host{display:block;width:100%;height:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i11.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i11.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: AXDomChangeDirective, selector: "[axDomChange]", outputs: ["axMutationObserver", "axResizeObserver"] }, { kind: "ngmodule", type: AXConversationModule }, { kind: "component", type: i2$4.AXConversationViewComponent, selector: "ax-conversation-view", inputs: ["chatBoxHeight", "isReplyArrowShown", "avatar"], outputs: ["onScrollEnd", "onActionMenuOpening", "onAction", "onReplyClick"] }, { kind: "component", type: i2$4.AXConversationInputComponent, selector: "ax-conversation-input", inputs: ["look", "placeholder", "maxLength", "hasAttachment", "hasVoice", "hasEmoji", "isLoading", "acceptFileType"], outputs: ["onSendClick", "onStartRecording", "onCancelRecording", "onEnterPressed"] }, { kind: "component", type: i2$4.AXConversationContainerComponent, selector: "ax-conversation-container", inputs: ["chatData"] }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i6.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
3048
2978
|
}
|
3049
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.
|
2979
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMChatPreviewComponent, decorators: [{
|
3050
2980
|
type: Component,
|
3051
|
-
args: [{ selector: 'axm-
|
3052
|
-
AXWysiwygContainerComponent,
|
3053
|
-
AXAvatarModule,
|
3054
|
-
AXConversationModule,
|
3055
|
-
AXSkeletonModule,
|
3056
|
-
AXCommentModule,
|
3057
|
-
AXButtonModule,
|
3058
|
-
AXImageModule,
|
3059
|
-
AXLoadingModule,
|
3060
|
-
AXDropdownModule,
|
3061
|
-
AXDecoratorModule,
|
3062
|
-
AXWysiwygModule,
|
3063
|
-
AXToolBarModule,
|
3064
|
-
AXDropdownModule,
|
3065
|
-
AXDropdownButtonModule,
|
3066
|
-
AXValidationModule,
|
3067
|
-
AsyncPipe,
|
3068
|
-
AXFormModule,
|
3069
|
-
FormsModule,
|
3070
|
-
AXFormatModule,
|
3071
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ax-mt-2 ax-p-2\">\n <ax-comment-container>\n @if (isLoading()) {\n <div class=\"ax-flex ax-items-center ax-py-12 ax-bg-lightest ax-px-5\">\n <ax-skeleton class=\"ax-min-w-16 ax-h-16 ax-rounded-full ax-me-4\"></ax-skeleton>\n <div class=\"ax-flex ax-flex-col ax-gap-2 ax-w-full\">\n <ax-skeleton class=\"ax-w-full ax-h-6 ax-rounded\"></ax-skeleton>\n <ax-skeleton class=\"ax-w-full ax-h-2 ax-rounded-full\"></ax-skeleton>\n <ax-skeleton class=\"ax-w-full ax-h-2 ax-rounded-full\"></ax-skeleton>\n <ax-skeleton class=\"ax-w-8/12 ax-h-2 ax-rounded-full\"></ax-skeleton>\n </div>\n </div>\n } @else if (!isLoading() && comments().length > 0) {\n <ax-comment-view class=\"ax-bg-lightest\">\n @for (comment of comments(); track comment.id) {\n <ax-comment-item [id]=\"comment.id!\" [replyCount]=\"comment.replies?.length ?? 0\">\n <ax-avatar [color]=\"avatarConfig().color\" [shape]=\"avatarConfig().look\">\n @if (checkImageExists(comment.id!) && comment.author && extractInitials(comment.author) !== '?') {\n <ax-image (onError)=\"handleImageError(comment.id!)\" [src]=\"''\">\n <ax-loading></ax-loading>\n </ax-image>\n } @else {\n <ax-text>\n <span class=\"ax-text-base ax-overflow-hidden\">{{ extractInitials(comment.author) }}</span>\n </ax-text>\n }\n </ax-avatar>\n <ax-title>{{ extractInitials(comment.author) }}</ax-title>\n <ax-comment-date>{{ calcDefrenetTime(comment.createdAt) | format: 'timeleft' | async }} </ax-comment-date>\n <ax-comment-menu-options>\n <ax-button class=\"ax-sm\" look=\"blank\" color=\"neutral\">\n <ax-icon icon=\"ax-icon ax-icon-solid ax-icon-more-horizontal\"></ax-icon>\n </ax-button>\n\n <ax-dropdown-panel>\n <ax-button-item-list>\n <ax-button-item text=\"Edit\" color=\"neutral\" (click)=\"editMessage(comment)\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-edit\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n\n <ax-button-item text=\"Delete\" color=\"danger\" (click)=\"deleteComment(comment)\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-trash-can\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-comment-menu-options>\n <ax-content [innerHTML]=\"sanitizeHtml(comment.message.content)\"></ax-content>\n <ax-comment-like (click)=\"toggleLike(comment)\" [liked]=\"comment.isLiked!\">\n {{ comment.reactionsCount }}\n </ax-comment-like>\n <ax-comment-reply-text (click)=\"replyMessage(comment)\"></ax-comment-reply-text>\n @for (reply of comment.replies; track reply.id) {\n <ax-comment-item [id]=\"reply.id\">\n <ax-avatar [color]=\"avatarConfig().color\" [shape]=\"avatarConfig().look\">\n @if (reply && checkImageExists(reply.id!) && reply.author && extractInitials(reply.author) !== '?') {\n <ax-image (onError)=\"handleImageError(reply.id!)\" [src]=\"''\">\n <ax-loading></ax-loading>\n </ax-image>\n } @else {\n <ax-text>\n <span class=\"ax-text-base ax-overflow-hidden\">{{ extractInitials(reply.author) }}</span>\n </ax-text>\n }\n </ax-avatar>\n <ax-title>{{ extractInitials(reply.author) }}</ax-title>\n <ax-comment-date>{{ calcDefrenetTime(reply.createdAt) | format: 'timeleft' | async }} </ax-comment-date>\n <ax-comment-menu-options>\n <ax-button class=\"ax-sm\" look=\"blank\" color=\"neutral\">\n <ax-icon icon=\"ax-icon ax-icon-solid ax-icon-more-horizontal\"></ax-icon>\n </ax-button>\n\n <ax-dropdown-panel>\n <ax-button-item-list>\n <ax-button-item text=\"Edit\" color=\"neutral\" (click)=\"editMessage(comment, reply)\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-edit\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n <ax-button-item text=\"Delete\" color=\"danger\" (click)=\"deleteReply(comment, reply)\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-trash-can\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-comment-menu-options>\n <ax-content [innerHTML]=\"sanitizeHtml(reply.message.content)\"></ax-content>\n <ax-comment-like (click)=\"toggleLike(comment, reply)\" [liked]=\"reply.isLiked!\">\n {{ reply.reactionsCount }}\n </ax-comment-like>\n <ax-comment-reply-text (click)=\"replyMessage(comment, reply)\"></ax-comment-reply-text>\n </ax-comment-item>\n }\n </ax-comment-item>\n }\n </ax-comment-view>\n } @else {\n <div>\n <div class=\"ax-flex ax-flex-col ax-gap-4 ax-justify-center ax-items-center ax-p-10\">\n <svg\n class=\"ax-mx-auto\"\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"154\"\n height=\"161\"\n viewBox=\"0 0 154 161\"\n fill=\"none\"\n >\n <path\n d=\"M0.0616455 84.4268C0.0616455 42.0213 34.435 7.83765 76.6507 7.83765C118.803 7.83765 153.224 42.0055 153.224 84.4268C153.224 102.42 147.026 118.974 136.622 132.034C122.282 150.138 100.367 161 76.6507 161C52.7759 161 30.9882 150.059 16.6633 132.034C6.25961 118.974 0.0616455 102.42 0.0616455 84.4268Z\"\n fill=\"#EEF2FF\"\n />\n <path\n d=\"M96.8189 0.632498L96.8189 0.632384L96.8083 0.630954C96.2034 0.549581 95.5931 0.5 94.9787 0.5H29.338C22.7112 0.5 17.3394 5.84455 17.3394 12.4473V142.715C17.3394 149.318 22.7112 154.662 29.338 154.662H123.948C130.591 154.662 135.946 149.317 135.946 142.715V38.9309C135.946 38.0244 135.847 37.1334 135.648 36.2586L135.648 36.2584C135.117 33.9309 133.874 31.7686 132.066 30.1333C132.066 30.1331 132.065 30.1329 132.065 30.1327L103.068 3.65203C103.068 3.6519 103.067 3.65177 103.067 3.65164C101.311 2.03526 99.1396 0.995552 96.8189 0.632498Z\"\n fill=\"white\"\n stroke=\"#E5E7EB\"\n />\n <ellipse cx=\"80.0618\" cy=\"81\" rx=\"28.0342\" ry=\"28.0342\" fill=\"#EEF2FF\" />\n <path\n d=\"M99.2393 61.3061L99.2391 61.3058C88.498 50.5808 71.1092 50.5804 60.3835 61.3061C49.6423 72.0316 49.6422 89.4361 60.3832 100.162C71.109 110.903 88.4982 110.903 99.2393 100.162C109.965 89.4363 109.965 72.0317 99.2393 61.3061ZM105.863 54.6832C120.249 69.0695 120.249 92.3985 105.863 106.785C91.4605 121.171 68.1468 121.171 53.7446 106.785C39.3582 92.3987 39.3582 69.0693 53.7446 54.683C68.1468 40.2965 91.4605 40.2966 105.863 54.6832Z\"\n stroke=\"#E5E7EB\"\n />\n <path\n d=\"M110.782 119.267L102.016 110.492C104.888 108.267 107.476 105.651 109.564 102.955L118.329 111.729L110.782 119.267Z\"\n stroke=\"#E5E7EB\"\n />\n <path\n d=\"M139.122 125.781L139.122 125.78L123.313 109.988C123.313 109.987 123.313 109.987 123.312 109.986C121.996 108.653 119.849 108.657 118.521 109.985L118.871 110.335L118.521 109.985L109.047 119.459C107.731 120.775 107.735 122.918 109.044 124.247L109.047 124.249L124.858 140.06C128.789 143.992 135.191 143.992 139.122 140.06C143.069 136.113 143.069 129.728 139.122 125.781Z\"\n fill=\"#A5B4FC\"\n stroke=\"#818CF8\"\n />\n <path\n d=\"M83.185 87.2285C82.5387 87.2285 82.0027 86.6926 82.0027 86.0305C82.0027 83.3821 77.9987 83.3821 77.9987 86.0305C77.9987 86.6926 77.4627 87.2285 76.8006 87.2285C76.1543 87.2285 75.6183 86.6926 75.6183 86.0305C75.6183 80.2294 84.3831 80.2451 84.3831 86.0305C84.3831 86.6926 83.8471 87.2285 83.185 87.2285Z\"\n fill=\"#4F46E5\"\n />\n <path\n d=\"M93.3528 77.0926H88.403C87.7409 77.0926 87.2049 76.5567 87.2049 75.8946C87.2049 75.2483 87.7409 74.7123 88.403 74.7123H93.3528C94.0149 74.7123 94.5509 75.2483 94.5509 75.8946C94.5509 76.5567 94.0149 77.0926 93.3528 77.0926Z\"\n fill=\"#4F46E5\"\n />\n <path\n d=\"M71.5987 77.0925H66.6488C65.9867 77.0925 65.4507 76.5565 65.4507 75.8945C65.4507 75.2481 65.9867 74.7122 66.6488 74.7122H71.5987C72.245 74.7122 72.781 75.2481 72.781 75.8945C72.781 76.5565 72.245 77.0925 71.5987 77.0925Z\"\n fill=\"#4F46E5\"\n />\n <rect x=\"38.3522\" y=\"21.5128\" width=\"41.0256\" height=\"2.73504\" rx=\"1.36752\" fill=\"#4F46E5\" />\n <rect x=\"38.3522\" y=\"133.65\" width=\"54.7009\" height=\"5.47009\" rx=\"2.73504\" fill=\"#A5B4FC\" />\n <rect x=\"38.3522\" y=\"29.7179\" width=\"13.6752\" height=\"2.73504\" rx=\"1.36752\" fill=\"#4F46E5\" />\n <circle cx=\"56.13\" cy=\"31.0854\" r=\"1.36752\" fill=\"#4F46E5\" />\n <circle cx=\"61.6001\" cy=\"31.0854\" r=\"1.36752\" fill=\"#4F46E5\" />\n <circle cx=\"67.0702\" cy=\"31.0854\" r=\"1.36752\" fill=\"#4F46E5\" />\n </svg>\n <div>\n <h2 class=\"ax-text-center ax-text-neutral-600 ax-font-semibold ax-leading-loose ax-pb-2\">\n There is no Comment!\n </h2>\n </div>\n </div>\n </div>\n }\n </ax-comment-container>\n <ax-form>\n <ax-form-field>\n <div>\n @if (isReplyingMode() || isEditingMode()) {\n <div\n class=\"ax-flex ax-justify-between ax-rounded-b-none ax-border ax-border-b-0 ax-rounded-lg ax-bg-on-surface ax-px-6 ax-py-3 ax-w-full ax-items-center ax-overflow-hidden ax-text-sm ax-leading-none\"\n >\n <div (click)=\"scrollMain()\" class=\"ax-flex ax-justify-start ax-items-center ax-cursor-pointer\">\n <i\n [class]=\"isReplyingMode() ? 'fa-reply' : 'fa-pen'\"\n class=\"fa-solid ax-text-primary-500 dark:ax-text-primary-300 ax-text-2xl ax-me-4\"\n ></i>\n <div\n class=\"ax-flex ax-flex-col ax-gap-2 ax-justify-between ax-align-middle ax-leading-4 ax-overflow-hidden\"\n >\n <p class=\"ax-text-primary-500 dark:ax-text-primary-300\">\n {{ isReplyingMode() ? 'Reply to ' : 'Edit Message' }}\n <span class=\"ax-font-bold\">\n {{ isReplyingMode() ? extractInitials(activeReplyComment()?.author) : '' }}\n </span>\n </p>\n <div\n class=\"ax-truncate\"\n [innerHTML]=\"\n isReplyingMode()\n ? sanitizeHtml(activeReplyComment()?.message?.content ?? '')\n : sanitizeHtml(activeEditComment()?.message?.content ?? '')\n \"\n ></div>\n </div>\n </div>\n <div><i (click)=\"resetReplyEditState()\" class=\"fa-solid ax-text-2xl fa-xmark ax-cursor-pointer\"></i></div>\n </div>\n }\n <ax-wysiwyg-container #w [look]=\"wysiwygOptions().look\" [(ngModel)]=\"commentContent\">\n <ax-wysiwyg-view class=\"ax-min-h-28\"></ax-wysiwyg-view>\n <ax-toolbar>\n <ax-content>\n <ax-wysiwyg-history></ax-wysiwyg-history>\n <ax-wysiwyg-font-style></ax-wysiwyg-font-style>\n <ax-wysiwyg-colors></ax-wysiwyg-colors>\n <ax-wysiwyg-list></ax-wysiwyg-list>\n <ax-wysiwyg-alignment></ax-wysiwyg-alignment>\n </ax-content>\n <ax-suffix>\n <ax-dropdown-button\n [disabled]=\"hasCooldown()\"\n type=\"submit\"\n color=\"primary\"\n mode=\"split\"\n text=\"Send\"\n (onClick)=\"submitComment()\"\n >\n @if (isSubmitting()) {\n <ax-loading></ax-loading>\n }\n <ax-button-item-list>\n <ax-button-item (click)=\"submitComment(true)\" text=\"Send Private ...\" name=\"private\" data=\"private\">\n <ax-prefix>\n <ax-icon icon=\"fa-regular fa-user-secret\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n </ax-button-item-list>\n </ax-dropdown-button>\n </ax-suffix>\n </ax-toolbar>\n <ax-validation-rule rule=\"callback\" [options]=\"{ validate: validateContent }\"></ax-validation-rule>\n </ax-wysiwyg-container>\n </div>\n </ax-form-field>\n </ax-form>\n</div>\n", styles: ["ax-wysiwyg-container .ax-editor-container{border-top-left-radius:0!important;border-top-right-radius:0!important}ax-wysiwyg-container .ax-error-message{padding-left:.5rem}\n"] }]
|
2981
|
+
args: [{ selector: 'axm-chat-preview', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, FormsModule, AXDomChangeDirective, AXConversationModule, AXLoadingModule], template: "@if (isLoading()) {\n <div class=\"ax-h-full ax-w-full ax-flex ax-items-center ax-justify-center\">\n <ax-loading></ax-loading>\n </div>\n} @else if (error()) {\n <div class=\"ax-h-full ax-w-full ax-flex ax-items-center ax-justify-center\">\n <div class=\"ax-text-center\">\n <p class=\"ax-text-danger\">{{ error() }}</p>\n <button (click)=\"loadMessages(roomId)\" class=\"ax-mt-2 ax-button ax-primary\">Retry</button>\n </div>\n </div>\n} @else {\n <div\n axDomChange\n (axResizeObserver)=\"setHeight($event[0].contentRect.height)\"\n class=\"ax-bg-surface-container ax-h-full\"\n >\n <!-- Messages Container -->\n <ax-conversation-container class=\"ax-overflow-hidden\" [chatData]=\"chatData()\">\n <ax-conversation-view\n (onActionMenuOpening)=\"addItemHandler($event)\"\n (onAction)=\"handleOnAction($event)\"\n (onReplyClick)=\"addInputOverlay('reply', $event.data)\"\n [chatBoxHeight]=\"height() - 60 + 'px'\"\n ></ax-conversation-view>\n @if (!isChannel()) {\n <ax-conversation-input\n class=\"ax-p-1\"\n placeholder=\"Type a message...\"\n [(ngModel)]=\"options().value\"\n (ngModelChange)=\"handleTyping($event)\"\n (onSendClick)=\"handleOnSend($event)\"\n (onFileChange)=\"handleFileChange($event)\"\n (onStopRecording)=\"handleEndRecord($event)\"\n (onCancelRecording)=\"handleCancelRecord($event)\"\n (onEnterPressed)=\"handleEnter()\"\n ></ax-conversation-input>\n }\n </ax-conversation-container>\n </div>\n}\n", styles: [":host{display:block;width:100%;height:100%}\n"] }]
|
3072
2982
|
}] });
|
3073
2983
|
|
3074
|
-
var
|
2984
|
+
var chatPreview_component = /*#__PURE__*/Object.freeze({
|
3075
2985
|
__proto__: null,
|
3076
|
-
|
2986
|
+
AXMChatPreviewComponent: AXMChatPreviewComponent
|
3077
2987
|
});
|
3078
2988
|
|
3079
|
-
const AXPCommentWidget = {
|
3080
|
-
name: 'comment',
|
3081
|
-
title: 'Comments',
|
3082
|
-
description: 'Display and manage comments for entities',
|
3083
|
-
type: 'view',
|
3084
|
-
categories: [],
|
3085
|
-
groups: [AXPWidgetGroupEnum.FormElement],
|
3086
|
-
icon: 'fa-solid fa-comments',
|
3087
|
-
properties: [],
|
3088
|
-
components: {
|
3089
|
-
view: {
|
3090
|
-
component: () => Promise.resolve().then(function () { return commentWidgetView_component; }).then((c) => c.AXMCommentWidgetViewComponent),
|
3091
|
-
},
|
3092
|
-
},
|
3093
|
-
};
|
3094
|
-
|
3095
2989
|
function routesFactory() {
|
3096
2990
|
const routes = [
|
3097
2991
|
{
|
@@ -3100,6 +2994,7 @@ function routesFactory() {
|
|
3100
2994
|
loadComponent: () => {
|
3101
2995
|
return AXPRootLayoutComponent;
|
3102
2996
|
},
|
2997
|
+
title: 'Chat',
|
3103
2998
|
children: [
|
3104
2999
|
{
|
3105
3000
|
path: '',
|
@@ -3115,18 +3010,49 @@ function routesFactory() {
|
|
3115
3010
|
],
|
3116
3011
|
},
|
3117
3012
|
{
|
3118
|
-
path: ':app/comments/
|
3119
|
-
|
3013
|
+
path: ':app/comments/t/:refrenceType/i/:refrenceId/s/:subject',
|
3014
|
+
title: 'Comments',
|
3015
|
+
canActivate: [AXPAuthGuard],
|
3016
|
+
loadComponent: () => AXPRootLayoutComponent,
|
3017
|
+
// resolve: {
|
3018
|
+
// refrenceType: {
|
3019
|
+
// resolve: refrenceTypeResolver,
|
3020
|
+
// },
|
3021
|
+
// refrenceId: {
|
3022
|
+
// resolve: refrenceIdResolver,
|
3023
|
+
// },
|
3024
|
+
// subject: {
|
3025
|
+
// resolve: subjectResolver,
|
3026
|
+
// },
|
3027
|
+
// },
|
3028
|
+
children: [
|
3029
|
+
{
|
3030
|
+
path: '',
|
3031
|
+
loadComponent: () => Promise.resolve().then(function () { return comment_component; }).then((c) => c.AXMCommentComponent),
|
3032
|
+
},
|
3033
|
+
],
|
3034
|
+
},
|
3035
|
+
{
|
3036
|
+
path: ':app/comments/',
|
3037
|
+
title: 'Comments',
|
3038
|
+
canActivate: [AXPAuthGuard],
|
3039
|
+
loadComponent: () => AXPRootLayoutComponent,
|
3040
|
+
children: [
|
3041
|
+
{
|
3042
|
+
path: '',
|
3043
|
+
loadComponent: () => Promise.resolve().then(function () { return comment_component; }).then((c) => c.AXMCommentComponent),
|
3044
|
+
},
|
3045
|
+
],
|
3120
3046
|
},
|
3121
3047
|
];
|
3122
3048
|
return routes;
|
3123
3049
|
}
|
3124
3050
|
class AXMConversationModule {
|
3125
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.
|
3126
|
-
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.0.
|
3051
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMConversationModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
3052
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.0.6", ngImport: i0, type: AXMConversationModule, imports: [i2$1.AXPLayoutBuilderModule, i2$5.AXPWorkflowModule], exports: [
|
3127
3053
|
// Modules
|
3128
3054
|
RouterModule] }); }
|
3129
|
-
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.0.
|
3055
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMConversationModule, providers: [
|
3130
3056
|
// Services
|
3131
3057
|
{
|
3132
3058
|
provide: AXMMessageService,
|
@@ -3151,6 +3077,11 @@ class AXMConversationModule {
|
|
3151
3077
|
useClass: AXMConversationModuleEntityProvider,
|
3152
3078
|
multi: true,
|
3153
3079
|
},
|
3080
|
+
{
|
3081
|
+
provide: AXP_MENU_PROVIDER,
|
3082
|
+
useClass: AXMMenuProvider,
|
3083
|
+
multi: true,
|
3084
|
+
},
|
3154
3085
|
{
|
3155
3086
|
provide: ROUTES,
|
3156
3087
|
multi: true,
|
@@ -3165,15 +3096,37 @@ class AXMConversationModule {
|
|
3165
3096
|
// Conversation Module
|
3166
3097
|
importProvidersFrom(AXConversationModule.forRoot()),
|
3167
3098
|
DatePipe,
|
3168
|
-
], imports: [
|
3099
|
+
], imports: [AXPLayoutBuilderModule.forChild({
|
3100
|
+
widgets: [AXPCommentWidget],
|
3101
|
+
}),
|
3102
|
+
AXPWorkflowModule.forChild({
|
3103
|
+
actions: {
|
3104
|
+
'show-comment-popup-action': AXMCommentPopupStartAction,
|
3105
|
+
},
|
3106
|
+
workflows: {
|
3107
|
+
'show-comment-popup': AXMCommentPopupWorkflow,
|
3108
|
+
},
|
3109
|
+
}),
|
3169
3110
|
// Modules
|
3170
3111
|
RouterModule] }); }
|
3171
3112
|
}
|
3172
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.
|
3113
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AXMConversationModule, decorators: [{
|
3173
3114
|
type: NgModule,
|
3174
3115
|
args: [{
|
3175
3116
|
declarations: [],
|
3176
|
-
imports: [
|
3117
|
+
imports: [
|
3118
|
+
AXPLayoutBuilderModule.forChild({
|
3119
|
+
widgets: [AXPCommentWidget],
|
3120
|
+
}),
|
3121
|
+
AXPWorkflowModule.forChild({
|
3122
|
+
actions: {
|
3123
|
+
'show-comment-popup-action': AXMCommentPopupStartAction,
|
3124
|
+
},
|
3125
|
+
workflows: {
|
3126
|
+
'show-comment-popup': AXMCommentPopupWorkflow,
|
3127
|
+
},
|
3128
|
+
}),
|
3129
|
+
],
|
3177
3130
|
exports: [
|
3178
3131
|
// Modules
|
3179
3132
|
RouterModule,
|
@@ -3203,6 +3156,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImpor
|
|
3203
3156
|
useClass: AXMConversationModuleEntityProvider,
|
3204
3157
|
multi: true,
|
3205
3158
|
},
|
3159
|
+
{
|
3160
|
+
provide: AXP_MENU_PROVIDER,
|
3161
|
+
useClass: AXMMenuProvider,
|
3162
|
+
multi: true,
|
3163
|
+
},
|
3206
3164
|
{
|
3207
3165
|
provide: ROUTES,
|
3208
3166
|
multi: true,
|
@@ -3225,5 +3183,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImpor
|
|
3225
3183
|
* Generated bundle index. Do not edit.
|
3226
3184
|
*/
|
3227
3185
|
|
3228
|
-
export { AXMChatComponent, AXMChatItemComponent, AXMChatPreviewComponent, AXMChatService, AXMChatServiceImpl,
|
3186
|
+
export { AXMChatComponent, AXMChatItemComponent, AXMChatPreviewComponent, AXMChatService, AXMChatServiceImpl, AXMCommentComponent, AXMCommentPopupComponent, AXMCommentPopupStartAction, AXMCommentPopupWorkflow, AXMCommentService, AXMCommentServiceImpl, AXMCommentWidgetViewComponent, AXMConversationModule, AXMMessageService, AXMMessageServiceImpl, AXMRoomService, AXMRoomServiceImpl, AXMUserLookupPopup, AXPCommentWidget, RootConfig, messageFactory, roomFactory };
|
3229
3187
|
//# sourceMappingURL=acorex-modules-conversation.mjs.map
|