mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-01 11:37:58 +00:00
# Pull Request Template ## Description This PR introduces basic customization options for the CSAT survey: * **Display Type**: Option to use star ratings instead of emojis. * **Message Text**: Customize the survey message (up to 200 characters). * **Survey Rules**: Send surveys based on labels — trigger when a conversation has or doesn't have a specific label. Fixes https://linear.app/chatwoot/document/improve-csat-responses-a61cf30e054e ## Type of change - [x] New feature (non-breaking change which adds functionality) ## How Has This Been Tested? ### Loom videos **Website Channel (Widget)** https://www.loom.com/share/7f47836cde7940ae9d17b7997d060a18?sid=aad2ad0a-140a-4a09-8829-e01fa2e102c5 **Email Channel (Survey link)** https://www.loom.com/share/e92f4c4c0f73417ba300a25885e093ce?sid=4bb006f0-1c2a-4352-a232-8bf684e3d757 ## 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: Pranav <pranavrajs@gmail.com>
66 lines
1.6 KiB
Vue
66 lines
1.6 KiB
Vue
<script setup>
|
|
import { ref, defineProps, defineEmits } from 'vue';
|
|
|
|
const props = defineProps({
|
|
selectedRating: {
|
|
type: Number,
|
|
default: null,
|
|
},
|
|
isDisabled: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
});
|
|
|
|
const emit = defineEmits(['selectRating']);
|
|
|
|
const starRatings = [1, 2, 3, 4, 5];
|
|
const hoveredRating = ref(0);
|
|
|
|
const onHoverRating = value => {
|
|
if (props.isDisabled) return;
|
|
hoveredRating.value = value;
|
|
};
|
|
|
|
const selectRating = value => {
|
|
if (props.isDisabled) return;
|
|
emit('selectRating', value);
|
|
};
|
|
|
|
const getStarClass = value => {
|
|
const isStarActive =
|
|
(hoveredRating.value > 0 &&
|
|
!props.isDisabled &&
|
|
hoveredRating.value >= value) ||
|
|
props.selectedRating >= value;
|
|
|
|
const starTypeClass = isStarActive
|
|
? 'i-ri-star-fill text-n-amber-9'
|
|
: 'i-ri-star-line text-n-slate-10';
|
|
|
|
return starTypeClass;
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<div class="flex justify-center py-5 px-4 gap-3">
|
|
<button
|
|
v-for="value in starRatings"
|
|
:key="value"
|
|
type="button"
|
|
class="rounded-full p-1 transition-all duration-200 focus:enabled:scale-[1.2] focus-within:enabled:scale-[1.2] hover:enabled:scale-[1.2] focus:outline-none flex items-center flex-shrink-0"
|
|
:class="{ 'cursor-not-allowed opacity-50': isDisabled }"
|
|
:disabled="isDisabled"
|
|
:aria-label="'Star ' + value"
|
|
@click="selectRating(value)"
|
|
@mouseenter="onHoverRating(value)"
|
|
@mouseleave="onHoverRating(0)"
|
|
>
|
|
<span
|
|
:class="getStarClass(value)"
|
|
class="transition-all duration-500 text-2xl"
|
|
/>
|
|
</button>
|
|
</div>
|
|
</template>
|