mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-10-31 19:17:48 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			200 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			200 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
| <template>
 | |
|   <div class="flex flex-col w-full max-h-[12.5rem]">
 | |
|     <div class="flex items-center justify-center mb-1">
 | |
|       <h4
 | |
|         class="text-sm text-slate-800 dark:text-slate-100 m-0 overflow-hidden whitespace-nowrap text-ellipsis flex-grow"
 | |
|       >
 | |
|         {{ $t('CONTACT_PANEL.LABELS.LABEL_SELECT.TITLE') }}
 | |
|       </h4>
 | |
|       <hotkey>L</hotkey>
 | |
|     </div>
 | |
|     <div class="mb-2 flex-shrink-0 flex-grow-0 flex-auto max-h-8">
 | |
|       <input
 | |
|         ref="searchbar"
 | |
|         v-model="search"
 | |
|         type="text"
 | |
|         class="search-input"
 | |
|         autofocus="true"
 | |
|         :placeholder="$t('CONTACT_PANEL.LABELS.LABEL_SELECT.PLACEHOLDER')"
 | |
|       />
 | |
|     </div>
 | |
|     <div
 | |
|       class="flex justify-start items-start flex-grow flex-shrink flex-auto overflow-auto"
 | |
|     >
 | |
|       <div class="w-full">
 | |
|         <woot-dropdown-menu>
 | |
|           <label-dropdown-item
 | |
|             v-for="label in filteredActiveLabels"
 | |
|             :key="label.title"
 | |
|             :title="label.title"
 | |
|             :color="label.color"
 | |
|             :selected="selectedLabels.includes(label.title)"
 | |
|             @click="onAddRemove(label)"
 | |
|           />
 | |
|         </woot-dropdown-menu>
 | |
|         <div
 | |
|           v-if="noResult"
 | |
|           class="flex justify-center py-4 px-2.5 font-medium text-xs text-slate-700 dark:text-slate-200"
 | |
|         >
 | |
|           {{ $t('CONTACT_PANEL.LABELS.LABEL_SELECT.NO_RESULT') }}
 | |
|         </div>
 | |
|         <div
 | |
|           v-if="allowCreation && shouldShowCreate"
 | |
|           class="flex pt-1 border-t border-solid border-slate-100 dark:border-slate-900"
 | |
|         >
 | |
|           <woot-button
 | |
|             size="small"
 | |
|             variant="clear"
 | |
|             color-scheme="secondary"
 | |
|             icon="add"
 | |
|             is-expanded
 | |
|             class="button-new-label"
 | |
|             :is-disabled="hasExactMatchInResults"
 | |
|             @click="showCreateModal"
 | |
|           >
 | |
|             {{ createLabelPlaceholder }}
 | |
|             {{ parsedSearch }}
 | |
|           </woot-button>
 | |
| 
 | |
|           <woot-modal
 | |
|             :show.sync="createModalVisible"
 | |
|             :on-close="hideCreateModal"
 | |
|           >
 | |
|             <add-label-modal
 | |
|               :prefill-title="parsedSearch"
 | |
|               @close="hideCreateModal"
 | |
|             />
 | |
|           </woot-modal>
 | |
|         </div>
 | |
|       </div>
 | |
|     </div>
 | |
|   </div>
 | |
| </template>
 | |
| 
 | |
| <script>
 | |
| import LabelDropdownItem from './LabelDropdownItem';
 | |
| import Hotkey from 'dashboard/components/base/Hotkey';
 | |
| import AddLabelModal from 'dashboard/routes/dashboard/settings/labels/AddLabel';
 | |
| import { picoSearch } from '@scmmishra/pico-search';
 | |
| import { sanitizeLabel } from 'shared/helpers/sanitizeData';
 | |
| 
 | |
| export default {
 | |
|   components: {
 | |
|     LabelDropdownItem,
 | |
|     AddLabelModal,
 | |
|     Hotkey,
 | |
|   },
 | |
| 
 | |
|   props: {
 | |
|     accountLabels: {
 | |
|       type: Array,
 | |
|       default: () => [],
 | |
|     },
 | |
|     selectedLabels: {
 | |
|       type: Array,
 | |
|       default: () => [],
 | |
|     },
 | |
|     allowCreation: {
 | |
|       type: Boolean,
 | |
|       default: false,
 | |
|     },
 | |
|   },
 | |
| 
 | |
|   data() {
 | |
|     return {
 | |
|       search: '',
 | |
|       createModalVisible: false,
 | |
|     };
 | |
|   },
 | |
| 
 | |
|   computed: {
 | |
|     createLabelPlaceholder() {
 | |
|       const label = this.$t('CONTACT_PANEL.LABELS.LABEL_SELECT.CREATE_LABEL');
 | |
|       return this.search ? `${label}:` : label;
 | |
|     },
 | |
| 
 | |
|     filteredActiveLabels() {
 | |
|       if (!this.search) return this.accountLabels;
 | |
| 
 | |
|       return picoSearch(this.accountLabels, this.search, ['title'], {
 | |
|         threshold: 0.9,
 | |
|       });
 | |
|     },
 | |
| 
 | |
|     noResult() {
 | |
|       return this.filteredActiveLabels.length === 0;
 | |
|     },
 | |
| 
 | |
|     hasExactMatchInResults() {
 | |
|       return this.filteredActiveLabels.some(
 | |
|         label => label.title === this.search
 | |
|       );
 | |
|     },
 | |
| 
 | |
|     shouldShowCreate() {
 | |
|       return this.allowCreation && this.filteredActiveLabels.length < 3;
 | |
|     },
 | |
| 
 | |
|     parsedSearch() {
 | |
|       return sanitizeLabel(this.search);
 | |
|     },
 | |
|   },
 | |
| 
 | |
|   mounted() {
 | |
|     this.focusInput();
 | |
|   },
 | |
| 
 | |
|   methods: {
 | |
|     focusInput() {
 | |
|       this.$refs.searchbar.focus();
 | |
|     },
 | |
| 
 | |
|     updateLabels(label) {
 | |
|       this.$emit('update', label);
 | |
|     },
 | |
| 
 | |
|     onAdd(label) {
 | |
|       this.$emit('add', label);
 | |
|     },
 | |
| 
 | |
|     onRemove(label) {
 | |
|       this.$emit('remove', label);
 | |
|     },
 | |
| 
 | |
|     onAddRemove(label) {
 | |
|       if (this.selectedLabels.includes(label.title)) {
 | |
|         this.onRemove(label.title);
 | |
|       } else {
 | |
|         this.onAdd(label);
 | |
|       }
 | |
|     },
 | |
| 
 | |
|     showCreateModal() {
 | |
|       this.createModalVisible = true;
 | |
|     },
 | |
| 
 | |
|     hideCreateModal() {
 | |
|       this.createModalVisible = false;
 | |
|     },
 | |
|   },
 | |
| };
 | |
| </script>
 | |
| 
 | |
| <style lang="scss" scoped>
 | |
| .hotkey {
 | |
|   @apply flex-shrink-0;
 | |
| }
 | |
| 
 | |
| .search-input {
 | |
|   @apply m-0 w-full border border-solid border-transparent h-8 text-sm text-slate-700 dark:text-slate-100 rounded-md focus:border-woot-500 bg-slate-50 dark:bg-slate-900;
 | |
| }
 | |
| 
 | |
| .button-new-label {
 | |
|   @apply whitespace-nowrap text-ellipsis overflow-hidden items-center;
 | |
| 
 | |
|   .icon {
 | |
|     @apply min-w-0;
 | |
|   }
 | |
| }
 | |
| </style>
 | 
