## Description
The widget email-transcript button (`ChatFooter.vue`) had no client-side
guard. Its visibility depends only on whether the contact has an email,
and the click handler fired a request on every click with no in-flight
lock, no disabled state, and no post-send handling. A user could
therefore trigger a large number of duplicate transcript emails from a
single conversation just by clicking repeatedly.
This adds a re-entry guard in the handler, disables the button while a
send is in flight, and applies a short cooldown (15s) after a successful
send. Normal use is unaffected: the button sends once, shows the success
toast, then briefly disables and automatically re-enables so a genuine
later re-request still works. On failure the button stays enabled so the
user can retry immediately. The cooldown timer is cleared on unmount.
Using a timed cooldown (rather than a permanent post-send lock) also
avoids the button getting stuck disabled if a resolved conversation is
reopened and later re-resolved.
This is the client-side complement to the server-side rate limit added
in #15085.
Fixes https://linear.app/chatwoot/issue/CW-7640
Enables Uzbek as a selectable Chatwoot language and wires the `uz`
locale into the dashboard, widget, and survey translation loaders.
## Closes
Closes https://github.com/chatwoot/chatwoot/issues/15030
## Why
Uzbek is now available in the Chatwoot Crowdin project. The widget
translation has been proofread and is 100% translated and approved.
## What changed
- Adds Uzbek to the supported language registry
- Registers the `uz` locale with the dashboard, widget, and survey i18n
loaders
## Validation
- Proofread the Uzbek widget translation in Crowdin
- Verified placeholder preservation and corrected wording where needed
- Confirmed the widget file is 100% translated and 100% approved
This draft intentionally remains blocked until the Crowdin sync adds the
generated Uzbek locale files. It should only be marked ready and merged
after that sync lands.
# Pull Request Template
## Description
This PR fixes the white background bleed visible in the widget, article
viewer, and Help Center when dark mode is active.
This change was previously merged but later reverted due to a background
being added for the unread bubble.
Reverted PR: https://github.com/chatwoot/chatwoot/pull/13955,
https://github.com/chatwoot/chatwoot/pull/13981
**What was happening**
While scrolling, the `<body>` element retained a white background in
dark mode. This occurred because dark mode classes were only applied to
inner container elements, not the root.
**What changed**
* **Widget:** Updated the `useDarkMode` composable to sync the `dark`
class to `<html>` using `watchEffect`, allowing `<body>` to inherit dark
theme variables. Also added background styles to `html`, `body`, and
`#app` in `woot.scss`.
* **Help center portal:** Moved `bg-white dark:bg-slate-900` from
`<main>` to `<body>` in the portal layout so the entire page background
responds correctly to dark mode, including within the widget iframe.
* **ArticleViewer:** Replaced hardcoded `bg-white` with `bg-n-solid-1`
to ensure better theming.
Fixes
https://linear.app/chatwoot/issue/CW-6704/widget-body-colour-not-implemented
## Type of change
- [x] Bug fix (non-breaking change which fixes an issue)
## How Has This Been Tested?
### Screencasts
### Before
**Widget**
https://github.com/user-attachments/assets/e0224ad1-81a6-440a-a824-e115fb806728
**Help center**
https://github.com/user-attachments/assets/40a8ded5-5360-474d-9ec5-fd23e037c845
### After
**Widget**
https://github.com/user-attachments/assets/dd37cc68-99fc-4d60-b2ae-cf41f9d4d38c
<img width="347" height="265" alt="image"
src="https://github.com/user-attachments/assets/89460b36-c8ed-4579-9737-c258c6fe5da5"
/>
**Help center**
https://github.com/user-attachments/assets/bc998c4e-ef77-46fa-ac7f-4ea16d912ce3
## Checklist:
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [ ] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
---------
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Contact custom attributes filled in the pre-chat form (e.g. a CPF field)
were silently lost when the visitor's email or phone matched an existing
contact. The widget sent the attributes in a separate request that raced
the conversation create: creating the conversation merges the widget
contact into the existing contact, so the attribute update landed on the
destroyed contact and vanished without an error. New visitors were
unaffected, which made the bug hard to spot.
The fix sends contact custom attributes inside the same request that
identifies the contact. The widget conversation create endpoint now
accepts `contact.custom_attributes` and applies them through
`ContactIdentifyAction` in the same transaction as the merge, so the
submitted values always land on the surviving contact. The campaign path
folds the attributes into the existing contact update call the same way.
<details>
<summary>Reproduction script (rails runner, concurrent
threads)</summary>
```ruby
# Concurrent reproduction of the pre-chat form race that loses contact
# custom attributes when the visitor's email matches an existing contact.
#
# The old widget fired two unawaited requests on pre-chat submit. Each
# iteration replays them as real concurrent threads:
# - create thread = POST /widget/conversations: resolves the widget contact,
# then runs ContactIdentifyAction (which merges the widget contact into the
# existing contact) inside a transaction held open while the conversation
# and message are created.
# - patch thread = PATCH /widget/contact: resolves the widget contact via its
# contact inbox and applies the custom attributes through
# ContactIdentifyAction, exactly like Widget::ContactsController#update.
#
# Run with: bundle exec rails runner confirm_prechat_race.rb
# Creates throwaway contacts on Account.first and deletes them afterwards.
ITERATIONS = 20
CPF = '123.456.789-09'.freeze
account = Account.first!
inbox = account.inboxes.first!
losses = 0
ITERATIONS.times do |i|
existing = account.contacts.create!(name: 'Existing Contact', email: "race-existing-#{SecureRandom.hex(6)}@example.com")
temp = account.contacts.create!(name: 'Widget Visitor')
contact_inbox = ContactInbox.create!(contact: temp, inbox: inbox, source_id: SecureRandom.uuid)
begin
create_request = Thread.new do
ActiveRecord::Base.connection_pool.with_connection do
widget_contact = ContactInbox.find(contact_inbox.id).contact # set_contact before_action
ActiveRecord::Base.transaction do
ContactIdentifyAction.new(
contact: widget_contact,
params: { email: existing.email, phone_number: nil, name: 'Widget Visitor' },
retain_original_contact_name: true,
discard_invalid_attrs: true
).perform
sleep(0.02) # conversation + message creation keeps the transaction open
end
end
end
patch_request = Thread.new do
ActiveRecord::Base.connection_pool.with_connection do
sleep(rand * 0.02) # network jitter between the two requests
widget_contact = ContactInbox.find(contact_inbox.id).contact # set_contact before_action
ContactIdentifyAction.new(
contact: widget_contact,
params: { custom_attributes: { cpf: CPF } },
discard_invalid_attrs: true
).perform
end
end
create_request.join
patch_request.join
survivor = existing.reload
if survivor.custom_attributes['cpf'] == CPF
puts "iteration #{i + 1}: CPF survived"
else
losses += 1
puts "iteration #{i + 1}: CPF LOST (survivor custom_attributes: #{survivor.custom_attributes.inspect})"
end
ensure
account.contacts.where(id: [existing.id, temp.id]).find_each(&:destroy!)
end
end
puts
puts "#{losses}/#{ITERATIONS} iterations lost the CPF -- race #{losses.positive? ? 'confirmed' : 'not reproduced in this run'}"
```
Result: **20/20 iterations lose the CPF** (consistent across repeated
runs). The conversation create holds its transaction open across the
contact merge, so the fast attribute update either resolves the
soon-to-be-destroyed widget contact or blocks on its row lock and then
updates 0 rows — silently, with no error. This is why the customer sees
the loss every time, not intermittently.
Note: the script replays the old two-request flow at the service layer,
so it reproduces the loss even with this fix applied — the fix works by
removing the second request from the widget, not by changing the raced
code paths. The new request spec (`saves contact custom attributes on
the surviving contact when merged into an existing contact`) covers the
fixed contract.
</details>
## Closes
- Reported via support conversation:
https://app.chatwoot.com/app/accounts/1/conversations/84465
## How to reproduce
1. Create a website inbox with a pre-chat form that has a contact custom
attribute field (e.g. CPF).
2. Create a contact with a known email address.
3. As a visitor, open the widget and fill the pre-chat form using that
same email plus a value for the custom attribute.
4. Before: the attribute never appears on the contact profile. After: it
is saved on the existing contact, overwriting any stale value.
## What changed
- `POST /api/v1/widget/conversations` now permits
`contact.custom_attributes` and passes it to `ContactIdentifyAction`,
which deep-merges it atomically with the contact merge.
- The widget pre-chat form sends contact custom attributes inside the
conversation create payload instead of a separate `setCustomAttributes`
call; the campaign path includes them in the `contacts/update` payload.
When an inbox has **"Allow messages after conversation is resolved"**
disabled, the live-chat widget should hide the reply box once a
conversation is resolved — but users could still send a reply, silently
reopening it. This syncs the widget's conversation status on reconnect
so the reply box hides correctly.
## Closes
- CW-7272
## How to reproduce
1. Disable **Allow messages after conversation is resolved** on an
inbox.
2. Open the widget, then let its websocket drop (background tab / lose
network).
3. While disconnected, get the conversation resolved (e.g. auto-resolve
on inactivity).
4. Reconnect → reply box is still visible and a sent message reopens the
resolved conversation.
## Why
Reply-box hiding is gated on the widget's local status, updated via the
`conversation.status_changed` socket event. If the resolve happens while
disconnected, the event is missed — and on reconnect the widget only
re-synced messages, never the status, so it stayed stale at `open`.
## What changed
- `onReconnect` now also dispatches
`conversationAttributes/getAttributes` to refresh status after a missed
event.
- Added a spec covering the reconnect behavior.
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Translate missing Simplified Chinese live-chat widget availability and
reply-time strings so visitors using `zh_CN` no longer see English
fallbacks in offline and pre-chat states.
## Closes
N/A
## How to test
- Open the widget with `Widget Locale = 中文 (zh_CN)` and set the team
offline. The availability card should stay in Chinese.
- Configure working hours so the widget shows minute, hour, tomorrow,
and day-specific return states. The `{time}`, `{n}`, and `{day}`
placeholders should render correctly.
## What changed
- Translated missing `THUMBNAIL.AUTHOR.NOT_AVAILABLE`,
`TEAM_AVAILABILITY.BACK_AS_SOON_AS_POSSIBLE`, and `REPLY_TIME.*` strings
in `app/javascript/widget/i18n/locale/zh_CN.json`.
- Kept the scope limited to Simplified Chinese.
Co-authored-by: Sojan Jose <sojan@pepalo.com>
Fixes the web widget select dropdown styling in dark mode so native
select options remain readable against the widget's dark UI.
Closes
None
## Screenshots
Previous state:
<img width="426" height="764" alt="Previous dark mode dropdown issue"
src="https://github.com/user-attachments/assets/812fa88c-ae5a-4769-be14-748fbbaf7dfe"
/>
Current state:
<img width="1210" height="610" alt="Current dark mode dropdown styling"
src="https://github.com/user-attachments/assets/0ec9b6d7-025d-4b97-b43e-ef026857f9c4"
/>
## How to test
1. Enable the web widget pre-chat form with a list/select field.
2. Load the widget with dark mode enabled.
3. Open the select field and verify the select control and option text
remain readable in dark mode.
## What changed
- Adds light/dark color-scheme handling for widget native selects.
- Applies explicit option background and text colors so dark-mode select
options do not inherit unreadable colors from the browser popup.
---------
Co-authored-by: iamsivin <iamsivin@gmail.com>
# Pull Request Template
## Description
There were English strings in the Spanish i18n file for the widget. This
PR translates them.
## Type of change
Please delete options that are not relevant.
- [x] Bug fix (non-breaking change which fixes an issue)
## How Has This Been Tested?
## Checklist:
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented on my code, particularly in hard-to-understand
areas
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [x] Any dependent changes have been merged and published in downstream
modules
Co-authored-by: Sojan Jose <sojan@pepalo.com>
# Pull Request Template
## Description
This PR fixes multiple issues related to regex patterns and validation
for custom attributes.
1. Fixed regex patterns being double-escaped when saving from Add and
Edit flows
2. Fixed regex validation not being enforced in the widget pre-chat form
3. Minor UI improvements in the Add/Edit custom attribute dialog
Fixes
[CW-6625](https://linear.app/chatwoot/issue/CW-6625/bug-report-custom-attribute-regex-validation-not-working-in-ui),
https://github.com/chatwoot/chatwoot/issues/13771
## Type of change
- [x] Bug fix (non-breaking change which fixes an issue)
## How Has This Been Tested?
**Loom video**
**Before**
https://www.loom.com/share/14f1983a8bc84f9fabc3663afd83cd50
**After**
https://www.loom.com/share/867c0484741140c1944fcbd43914c9c0
## Checklist:
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
### Description
When integrating the web widget via the JS SDK, customers call
setConversationCustomAttributes and setLabel on chatwoot:ready — before
any conversation exists. These API calls silently fail because the
backend endpoints require an existing conversation. When the visitor
sends their first message, the conversation is created without those
attributes/labels, so the message_created webhook payload is missing the
expected metadata.
This change queues SDK-set conversation custom attributes and labels in
the widget store when no conversation exists yet, and includes them in
the API request when the first message (or attachment) creates the
conversation. The backend now permits and applies these params during
conversation creation — before the message is saved and webhooks fire.
### How to test
1. Configure a web widget without a pre-chat form.
2. Open the widget on a test page and run the following in the browser
console after chatwoot:ready:
`window.$chatwoot.setConversationCustomAttributes({ plan: 'enterprise'
});`
`window.$chatwoot.setLabel('vip');` // must be a label that exists in
the account
3. Send the first message from the widget.
4. Verify in the Chatwoot dashboard that the conversation has plan:
enterprise in custom attributes and the vip label applied.
5. Set up a webhook subscriber for `message_created` confirm the first
payload includes the conversation metadata.
6. Verify that calling `setConversationCustomAttributes` / `setLabel` on
an existing conversation still works as before (direct API path, no
regression).
7. Verify the pre-chat form flow still works as expected.
# Pull Request Template
## Description
This PR fixes the white background bleed visible in the widget, widget
article viewer and help center when dark mode is active.
**What was happening**
While scrolling, the `<body>` element retained a white background in
dark mode. This occurred because dark mode classes were only applied to
inner container elements, not the root.
**What changed**
* **Widget:** Updated the `useDarkMode` composable to sync the `dark`
class to `<html>` using `watchEffect`, allowing `<body>` to inherit dark
theme variables. Also added background styles to `html`, `body`, and
`#app` in `woot.scss`.
* **Help center portal:** Moved `bg-white dark:bg-slate-900` from
`<main>` to `<body>` in the portal layout so the entire page background
responds correctly to dark mode, including within the widget iframe.
* **ArticleViewer:** Replaced hardcoded `bg-white` with `bg-n-solid-1`
to ensure better theming.
Fixes
https://linear.app/chatwoot/issue/CW-6704/widget-body-colour-not-implemented
## Type of change
- [x] Bug fix (non-breaking change which fixes an issue)
## How Has This Been Tested?
### Screencasts
### Before
**Widget**
https://github.com/user-attachments/assets/e0224ad1-81a6-440a-a824-e115fb806728
**Help center**
https://github.com/user-attachments/assets/40a8ded5-5360-474d-9ec5-fd23e037c845
### After
**Widget**
https://github.com/user-attachments/assets/dd37cc68-99fc-4d60-b2ae-cf41f9d4d38c
**Help center**
https://github.com/user-attachments/assets/bc998c4e-ef77-46fa-ac7f-4ea16d912ce3
## Checklist:
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [ ] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
## Description
This PR improves the Ukrainian translation for the Chatwoot widget
(`app/javascript/widget/i18n/locale/uk.json`).
Key changes:
- Fixed typo: `Звантажити` → `Завантажити`
- Translated missing English strings
- Improved reply time messages
- Updated day names to match `{day}` usage in `BACK_ON_DAY`
- Improved UX wording in form placeholders
- Fixed typography in `ім’я`
- Improved consistency with other Chatwoot translations
These updates improve readability and correctness of the Ukrainian
widget interface.
## Type of change
- [x] Bug fix (non-breaking change which fixes an issue)
## How Has This Been Tested?
Reviewed the updated translations and verified that:
- Ukrainian translations render correctly
- Reply time messages display properly
- `{day}` values work correctly with the `BACK_ON_DAY` message
- Form placeholders appear correctly
- No untranslated English strings remain
## Checklist:
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] My changes generate no new warnings
---------
Co-authored-by: Sojan Jose <sojan@pepalo.com>
This updates the Traditional Chinese (`zh_TW`) locale coverage across
Chatwoot so the app no longer falls back to English for missing backend,
dashboard, widget, and survey strings.
## How to test
1. Start Chatwoot locally and switch the UI locale to Traditional
Chinese (`zh_TW`).
2. Walk through the main product areas: dashboard, settings, inbox
management, help center, automations, reports, widget, and survey flows.
3. Confirm the UI surfaces translated Traditional Chinese copy instead
of English fallbacks.
4. Spot-check newly added locale surfaces such as secure password
messaging and snooze UI copy.
---------
Co-authored-by: Sojan Jose <sojan@pepalo.com>
## Description
Reduces the frequency of update_presence WebSocket calls from the live
chat widget and fixes agents appearing offline when the dashboard is in
a background tab.
## Fixes # (issue)
https://github.com/chatwoot/chatwoot/issues/13720
## Type of change
- [ ] Bug fix (non-breaking change which fixes an issue)
## Checklist:
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my code
- [ ] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
# Pull Request Template
## Description
This PR includes the following updates:
1. Updated the design system color tokens by introducing new tokens for
surfaces, overlays, buttons, labels, and cards, along with refinements
to existing shades.
2. Refreshed both light and dark themes with adjusted background,
border, and solid colors.
3. Replaced static Inter font files with the Inter variable font
(including italic), supporting weights from 100–900.
4. Added custom font weights (420, 440, 460, 520) along with custom
typography classes to enable more fine-grained and consistent typography
control.
## Type of change
- [x] New feature (non-breaking change which adds functionality)
## Checklist:
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
---------
Co-authored-by: Pranav <pranav@chatwoot.com>
Text in hebrew was broken and incomplete - i have completed the
translation and fixed some annoying terms for better understanding and
user experience.
Description
This pull request updates several Lithuanian (lt.json) translations in
the Chatwoot widget.
The previous versions contained grammatical issues, unnatural phrasing,
and direct machine-translated structures.
The updated translations now follow proper Lithuanian grammar, natural
wording, and are consistent with the tone used across the rest of the
UI.
Fixes: No linked issue (translation improvement).
### Problem
Currently, the attachment button visibility in the widget uses both the
SDK's `enableFileUpload` flag AND the inbox's attachment settings with
an AND condition. This creates an issue for users who want to control
attachments solely through inbox settings, since the SDK flag defaults
to `true` even when not explicitly provided.
**Before:**
- SDK not set → `enableFileUpload: true` (default) + inbox setting =
attachment shown only if both true
- SDK set to false → `enableFileUpload: false` + inbox setting =
attachment always hidden
- SDK set to true → `enableFileUpload: true` + inbox setting =
attachment shown only if both true
This meant users couldn't rely solely on inbox settings when the SDK
flag wasn't explicitly provided.
### Solution
Changed the logic to prioritize explicit SDK configuration when
provided, and fall back to inbox settings when not provided:
**After:**
- SDK not set → `enableFileUpload: undefined` → use inbox setting only
- SDK set to false → `enableFileUpload: false` → hide attachment (SDK
controls)
- SDK set to true → `enableFileUpload: true` → show attachment (SDK
controls)
---------
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
## Description
Fixes#12868
This PR fixes a Vue 3 reactivity bug that causes the widget to display
"We are away at the moment" on initial page load, even when agents are
online and the API correctly returns their availability.
## Problem
The widget welcome screen shows "We are away" on first render, only
updating to show correct agent status after navigating to the
conversation view and back. This misleads visitors into thinking no
agents are available.
**Reproduction:** Open website with widget in fresh incognito window,
click bubble immediately → shows "away" despite agents being online.
## Root Cause
Vue 3 reactivity chain breaks in the `useAvailability` composable:
**Before (broken):**
```javascript
// AvailabilityContainer.vue
const { isOnline } = useAvailability(props.agents); // Passes VALUE
// useAvailability.js
const availableAgents = toRef(agents); // Creates ref from VALUE, doesn't track changes
```
When the API responds and updates the Vuex store, the parent component's
computed `props.agents` updates correctly, but the composable's
`toRef()` doesn't know about the change because it was created from a
static value, not a reactive source.
## Solution
**After (fixed):**
```javascript
// AvailabilityContainer.vue
const { isOnline } = useAvailability(toRef(props, 'agents')); // Passes REACTIVE REF
// useAvailability.js
const availableAgents = computed(() => unref(agents)); // Unwraps ref and tracks changes
```
Now when `props.agents` updates after the API response, the `computed()`
re-evaluates and all downstream reactive properties (`hasOnlineAgents`,
`isOnline`) update correctly.
## Testing
- ✅ Initial page load shows correct agent status immediately
- ✅ Status changes via WebSocket update correctly
- ✅ No configuration changes or workarounds needed
- ✅ Tested with network monitoring (Puppeteer) confirming API returns
correct data
## Files Changed
1.
`app/javascript/widget/components/Availability/AvailabilityContainer.vue`
- Pass `toRef(props, 'agents')` instead of `props.agents`
2. `app/javascript/widget/composables/useAvailability.js`
- Use `computed(() => unref(agents))` instead of `toRef(agents)`
- Added explanatory comments
## Related Issues
- #5918 - Similar symptoms, closed with workaround (business hours
toggle) rather than fixing root cause
- #5763 - Different issue (mobile app presence)
This is a genuine Vue 3 reactivity bug affecting all widgets,
independent of business hours configuration.
Co-authored-by: rcoenen <rcoenen@users.noreply.github.com>
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Co-authored-by: Shivam Mishra <scm.mymail@gmail.com>
## Summary
- add a configurable MAXIMUM_FILE_UPLOAD_SIZE installation setting and
surface it through super admin and global config payloads
- apply the configurable limit to attachment validations and shared
upload helpers on dashboard and widget
- introduce a reusable helper with unit tests for parsing the limit and
extend attachment specs for configurability
------
[Codex
Task](https://chatgpt.com/codex/tasks/task_e_6912644786b08326bc8dee9401af6d0a)
---------
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Co-authored-by: iamsivin <iamsivin@gmail.com>
# Pull Request Template
## Description
This PR fixes an issue (CW-5529) where articles displayed on the widget
were not respecting the current locale set in the URL (e.g., `/ar` was
showing English articles).
The root cause was that the article queries in the
`_featured_articles.html.erb` and `_uncategorized-block.html.erb` view
templates were missing locale filtering.
The fix involves adding `locale: @locale` to the `articles.where`
clauses in these templates to ensure that only articles matching the
current portal locale are displayed.
Fixes #CW-5529
## Type of change
- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality not to work as expected)
- [ ] This change requires a documentation update
## How Has This Been Tested?
The changes were verified against existing test cases that confirm the
expected behavior for locale-specific article filtering. Specifically,
tests for the articles controller's `index` action and article count by
locale were reviewed, which align with the implemented fixes.
## Checklist:
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [ ] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works (N/A, relied on existing tests)
- [ ] New and existing unit tests pass locally with my changes (Unable
to run tests in this environment)
- [ ] Any dependent changes have been merged and published in downstream
modules
---
Linear Issue:
[CW-5529](https://linear.app/chatwoot/issue/CW-5529/articles-from-the-correct-locale-is-not-shown-on-the-widget)
<a
href="https://cursor.com/background-agent?bcId=bc-2f944ea8-863e-4e80-b137-c05ce0b017cc">
<picture>
<source media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/open-in-cursor-dark.svg">
<source media="(prefers-color-scheme: light)"
srcset="https://cursor.com/open-in-cursor-light.svg">
<img alt="Open in Cursor" src="https://cursor.com/open-in-cursor.svg">
</picture>
</a>
<a
href="https://cursor.com/agents?id=bc-2f944ea8-863e-4e80-b137-c05ce0b017cc">
<picture>
<source media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/open-in-web-dark.svg">
<source media="(prefers-color-scheme: light)"
srcset="https://cursor.com/open-in-web-light.svg">
<img alt="Open in Web" src="https://cursor.com/open-in-web.svg">
</picture>
</a>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
# Pull Request Template
## Description
**This PR includes:**
* Refactored two legacy mixins (`availability.js`,
`nextAvailability.js`) into a Vue 3 composable (`useAvailability`),
helper module and component based rendering logic.
* Fixed an issue where the widget wouldn't load if business hours were
enabled but all days were unchecked.
* Fixed translation issue
[[#11280](https://github.com/chatwoot/chatwoot/issues/11280)](https://github.com/chatwoot/chatwoot/issues/11280).
* Reduced code complexity and size.
* Added test coverage for both the composable and helper functions.
## Type of change
- [x] Bug fix (non-breaking change which fixes an issue)
## How Has This Been Tested?
### Loom video
https://www.loom.com/share/2bc3ed694b4349419505e275d14d0b98?sid=22d585e4-0dc7-4242-bcb6-e3edc16e3aee
### Story
<img width="995" height="442" alt="image"
src="https://github.com/user-attachments/assets/d6340738-07db-41d5-86fa-a8ecf734cc70"
/>
## Checklist:
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
Fixes https://github.com/chatwoot/chatwoot/issues/12012
---------
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Pranav <pranav@chatwoot.com>
Co-authored-by: Shivam Mishra <scm.mymail@gmail.com>