mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-11-04 13:07:55 +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>
 |