From 08e6801fc4ee55ca6646811e1c273cb40875b8fd Mon Sep 17 00:00:00 2001 From: Abhinav Raut Date: Sun, 20 Sep 2026 18:48:51 +0530 Subject: [PATCH] polish widget UI and fix proactive message delete Widget: - home background stays pinned while the content scrolls, fade sits on it - one radius and shadow scale across cards, buttons and inputs - live search in the help tab with a "no results" state - attachment-only messages show "Image" in the conversation preview - launcher and panel use the same shadows as the header Admin: - preview column is a fixed width so zoom does not resize it, hidden on small screens - preview matches the real widget again - search spinner replaces the magnifier instead of covering the page Fixes: - deleting a proactive message did nothing, the dialog cleared the pending id before the handler read it - an inbox created through the API could not be saved from the form, it jumped to the pre-chat tab with no error Adds livechatWidgetTabs.cy.js covering the proactive message and help center tabs. --- cmd/chat.go | 8 +- cmd/widget_campaign.go | 13 + .../src/components/datatable/DataTable.vue | 20 +- .../admin/help-center/ArticleEditSheet.vue | 20 +- .../admin/inbox/LivechatInboxForm.vue | 42 +-- .../admin/inbox/LivechatWidgetPreview.vue | 130 ++++---- .../admin/inbox/PreChatFormConfig.vue | 1 - .../features/admin/inbox/WidgetCampaigns.vue | 20 +- .../features/admin/inbox/WidgetHelpConfig.vue | 5 +- .../admin/inbox/livechatFormSchema.js | 2 + .../admin/inbox/livechatFormSchema.test.js | 13 + .../src/layouts/admin/AdminSplitLayout.vue | 13 +- .../admin/help-center/HelpCenterTree.vue | 48 +-- .../main/src/views/admin/inbox/InboxView.vue | 2 +- .../apps/main/src/views/search/SearchView.vue | 60 ++-- frontend/apps/widget/src/App.vue | 9 +- .../src/components/AnnouncementCard.vue | 2 +- .../widget/src/components/ArticleReader.vue | 3 + .../src/components/CSATMessageBubble.vue | 26 +- .../apps/widget/src/components/ChatHeader.vue | 4 +- .../widget/src/components/ChatMessages.vue | 14 +- .../src/components/CloseWidgetButton.vue | 8 +- .../src/components/ConversationsList.vue | 3 +- .../src/components/HomeExternalLink.vue | 20 +- .../apps/widget/src/components/HomeHeader.vue | 66 +--- .../apps/widget/src/components/HomeHelp.vue | 4 +- .../src/components/MessageAttachment.vue | 4 +- .../widget/src/components/MessageInput.vue | 9 +- .../widget/src/components/NoticeBanner.vue | 2 +- .../src/components/RecentConversationCard.vue | 5 +- .../widget/src/components/ReplyButtons.vue | 7 +- .../components/StartConversationButton.vue | 23 ++ .../widget/src/composables/useHeaderTheme.js | 50 +++ .../src/composables/useReplyPreviews.js | 2 +- .../src/composables/useStartConversation.js | 32 ++ .../apps/widget/src/layouts/MainLayout.vue | 11 +- .../apps/widget/src/layouts/WidgetHeader.vue | 5 +- .../apps/widget/src/utils/messagePreview.js | 14 + .../widget/src/views/ConversationsView.vue | 39 +-- frontend/apps/widget/src/views/HelpView.vue | 48 ++- frontend/apps/widget/src/views/HomeView.vue | 86 ++--- .../cypress/e2e/ui/livechatInboxForm.cy.js | 2 + .../cypress/e2e/ui/livechatWidgetTabs.cy.js | 314 ++++++++++++++++++ frontend/shared-ui/components/SearchInput.vue | 62 ++++ i18n/en-US.json | 20 +- scripts/tools-server/README.md | 7 +- scripts/widget-jwt-test/README.md | 2 +- scripts/widget-jwt-test/index.html | 13 +- .../web-templates/help/classic/layout.html | 1 + .../web-templates/help/docs/layout.html | 1 + .../web-templates/help/shared/partials.html | 13 + static/widget.js | 21 +- 52 files changed, 923 insertions(+), 426 deletions(-) create mode 100644 frontend/apps/widget/src/components/StartConversationButton.vue create mode 100644 frontend/apps/widget/src/composables/useHeaderTheme.js create mode 100644 frontend/apps/widget/src/composables/useStartConversation.js create mode 100644 frontend/apps/widget/src/utils/messagePreview.js create mode 100644 frontend/cypress/e2e/ui/livechatWidgetTabs.cy.js create mode 100644 frontend/shared-ui/components/SearchInput.vue diff --git a/cmd/chat.go b/cmd/chat.go index 5e0bd3cc..46160845 100644 --- a/cmd/chat.go +++ b/cmd/chat.go @@ -97,6 +97,7 @@ type handoffFormReq struct { type chatSettingsResponse struct { Campaigns *struct{} `json:"campaigns,omitempty"` HasCampaigns bool `json:"has_campaigns"` + CampaignDelaySeconds int `json:"campaign_delay_seconds"` livechat.Config // Hide server-side fields from the public widget response. TrustedDomains *struct{} `json:"trusted_domains,omitempty"` @@ -149,9 +150,10 @@ func handleGetChatSettings(r *fastglue.Request) error { } response := chatSettingsResponse{ - Config: config, - HasCampaigns: slices.ContainsFunc(config.Campaigns, func(c proactive.Campaign) bool { return c.Enabled }), - CustomAttributes: customAttributes, + Config: config, + HasCampaigns: slices.ContainsFunc(config.Campaigns, func(c proactive.Campaign) bool { return c.Enabled }), + CampaignDelaySeconds: earliestCampaignDelay(config.Campaigns), + CustomAttributes: customAttributes, } // Get business hours data if office hours feature is enabled. diff --git a/cmd/widget_campaign.go b/cmd/widget_campaign.go index 3dc435c3..3f4a1915 100644 --- a/cmd/widget_campaign.go +++ b/cmd/widget_campaign.go @@ -213,6 +213,19 @@ func campaignSender(app *App, id int) (umodels.User, error) { return app.user.GetAgent(id, "") } +func earliestCampaignDelay(campaigns []proactive.Campaign) int { + delay := 0 + for _, campaign := range campaigns { + if !campaign.Enabled { + continue + } + if delay == 0 || campaign.DelaySeconds < delay { + delay = campaign.DelaySeconds + } + } + return delay +} + func validCampaignKey(key string) bool { id, err := uuid.Parse(key) return err == nil && id != uuid.Nil diff --git a/frontend/apps/main/src/components/datatable/DataTable.vue b/frontend/apps/main/src/components/datatable/DataTable.vue index 5c7e8ee3..a251c603 100644 --- a/frontend/apps/main/src/components/datatable/DataTable.vue +++ b/frontend/apps/main/src/components/datatable/DataTable.vue @@ -1,13 +1,13 @@