6 Commits
Author SHA1 Message Date
c4089f2226 fix(csat): Require confirmation before submitting rating (#14450)
Customers reported that the CSAT survey was recording their rating the
instant they tapped a star — leaving no chance to correct an accidental
pick. This change lets the customer freely change their selection until
they actually submit the comment/feedback. The rating still saves on
click (so we don't lose ratings when a customer never types a comment),
but it stays editable until the comment form is submitted. Once that
happens, the rating locks.

The flow on both surfaces:

- Customer taps a star/emoji → rating is saved.
- Customer taps a different star/emoji → previous save is overwritten
with the new value.
- Customer types a comment and submits → latest rating + comment are
saved together.
- After that submit, the rating is locked and can't be changed.

Two surfaces are updated:

- **Standalone survey page** (`/survey/responses/:uuid`) — the rating
buttons remain re-tappable until the Feedback form is submitted; once
submitted, both rating and feedback lock.
- **In-conversation widget CSAT** — same behavior, the inline
arrow-submit button on the feedback form is the locking action.

In-flight guards prevent a race where the customer changes their pick
mid-network-call (raised by the codex review on the earlier revision):
while a save is in flight, the rating controls are temporarily disabled
so the request and the displayed selection can't diverge.

## Closes

-
https://linear.app/chatwoot/issue/CW-7061/csat-star-rating-submits-on-first-click-needs-confirmation-step

## How to test

**Standalone survey page**
1. Enable CSAT on any inbox (Settings → Inboxes → Configuration → CSAT
survey).
2. Resolve a conversation in that inbox so a CSAT message is generated.
3. Open the survey URL:
`{FRONTEND_URL}/survey/responses/{conversation.uuid}` (easiest: `bundle
exec rails runner 'puts Conversation.joins(:messages).where(messages: {
content_type: "input_csat" }).last.csat_survey_link'`).
4. Tap a star/emoji — confirm the rating saves (Network panel shows a
PUT to `/public/api/v1/csat_survey/{uuid}`).
5. Tap a different star/emoji — confirm a second PUT goes out with the
new value; the latest selection is reflected.
6. Type a comment and hit Submit feedback — confirm rating + feedback
persist; both controls now lock.
7. Reload the page — the locked state is rehydrated correctly.

**Widget CSAT**
1. From an inbox with CSAT enabled, resolve a conversation that has an
active widget session.
2. In the widget, the CSAT card appears with stars/emojis + the inline
comment box.
3. Tap a star/emoji — confirm a PATCH goes out and the selection visibly
updates.
4. Tap different stars/emojis — confirm each overrides the previous
save.
5. Type a comment and click the arrow — rating + comment submit
together; stars lock.

Both display types (emoji and 5-star) should behave consistently.

## What changed

- `app/javascript/survey/views/Response.vue` — `selectRating()` saves on
every tap and short-circuits while a save is in flight (or after
feedback was submitted). Rating components are disabled by
`isFeedbackSubmitted || isUpdating` so the lock follows the feedback
submission, not the first rating tap.
- `app/javascript/survey/components/Rating.vue` — new `isDisabled` prop.
The disabled / hover styling and click guard key off it instead of the
presence of `selectedRating`, so emojis stay re-clickable until the
feedback step locks them.
- `app/javascript/shared/components/CustomerSatisfaction.vue` — same
shape for the widget: rating click auto-submits and re-clicks override
the previous save; controls disabled while a submit is in flight;
emoji-button styling and the inline `StarRating` lock on
`isFeedbackSubmitted || isUpdating`.

---------

Co-authored-by: Muhsin <12408980+muhsin-k@users.noreply.github.com>
Co-authored-by: Sony Mathew <2040199+sony-mathew@users.noreply.github.com>
2026-05-18 21:46:30 +05:30
Shivam MishraandGitHub c51a458c25 style: apply fixes for eslint issues [cw-3590] (#10210)
These fixes are all auto generated and can be merged directly

Fixes the following issues

1. Event used on components should be hypenated
2. Attribute orders in components
3. Use `unmounted` instead of `destroyed`
4. Add explicit `emits` declarations for components, autofixed [using
this
script](https://gist.github.com/scmmishra/6f549109b96400006bb69bbde392eddf)


We ignore the top level v-if for now, we will fix it later
2024-10-03 15:02:12 +05:30
b4b308336f feat: Eslint rules (#9839)
# Pull Request Template

## Description

This PR adds new eslint rules to the code base.

**Error rules**

|    Rule name     | Type | Files updated |
| ----------------- | --- | - |
| `vue/block-order`  | error  |    |
| `vue/component-name-in-template-casing`  | error  |    |
| `vue/component-options-name-casing`  | error  |    |
| `vue/custom-event-name-casing`  | error  |    |
| `vue/define-emits-declaration`  | error  |    |
| `vue/no-unused-properties`  | error  |    |
| `vue/define-macros-order`  | error  |    |
| `vue/define-props-declaration`  | error  |    |
| `vue/match-component-import-name`  | error  |    |
| `vue/next-tick-style`  | error  |    |
| `vue/no-bare-strings-in-template`  | error  |    |
| `vue/no-empty-component-block`  | error  |    |
| `vue/no-multiple-objects-in-class`  | error  |    |
| `vue/no-required-prop-with-default`  | error  |    |
| `vue/no-static-inline-styles`  | error  |    |
| `vue/no-template-target-blank`  | error  |    |
| `vue/no-this-in-before-route-enter`  | error  |    |
| `vue/no-undef-components`  | error  |    |
| `vue/no-unused-emit-declarations`  | error  |    |
| `vue/no-unused-refs`  | error  |    |
| `vue/no-use-v-else-with-v-for`  | error  |    |
| `vue/no-useless-v-bind`  | error  |    |
| `vue/no-v-text`  | error  |    |
| `vue/padding-line-between-blocks`  | error  |    |
| ~`vue/prefer-prop-type-boolean-first`~ | ~error~ |  (removed this
rule, cause a bug in displaying custom attributes) |
| `vue/prefer-separate-static-class`  | error  |    |
| `vue/prefer-true-attribute-shorthand`  | error  |    |
| `vue/require-explicit-slots`  | error  |    |
| `vue/require-macro-variable-name`  | error  |    |


**Warn rules**

|    Rule name     | Type | Files updated |
| ---- | ------------- | ------------- |
| `vue/no-root-v-if`  | warn  |    |


Fixes https://linear.app/chatwoot/issue/CW-3492/vue-eslint-rules

## 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
- [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

---------

Co-authored-by: Fayaz Ahmed <fayazara@gmail.com>
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Shivam Mishra <scm.mymail@gmail.com>
Co-authored-by: Pranav <pranav@chatwoot.com>
2024-08-05 14:02:16 +05:30
Pranav Raj SandGitHub dace97b7b0 feat: Update design - CSAT survey page (#2964) 2021-09-06 11:42:02 +05:30
Muhsin KelothandGitHub 6515b69560 feat: CSAT for all channels (#2749) 2021-08-23 22:00:47 +05:30
Muhsin KelothandGitHub 92c14fa87d feat: CSAT response collection public page (#2685) 2021-08-03 18:22:50 +05:30