mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-10-31 19:17:48 +00:00 
			
		
		
		
	 7fe94dc1a2
			
		
	
	7fe94dc1a2
	
	
	
		
			
			## Description This introduces a reusable Call button used in the Contacts details header (between Block contact and Send message) and in the conversation contact panel. The button shows only when the account has at least one Voice inbox and the contact has a phone number. If multiple Voice inboxes are present, clicking opens a picker modal; otherwise, a “Calling is under development” toast is shown > Actual wiring to functionality will available in follow up PRs references: #11602 , #11481 ## Screens <img width="250" alt="Screenshot 2025-08-18 at 8 33 02 PM" src="https://github.com/user-attachments/assets/d7a09a9d-8eff-4461-a75f-27854540c2a0" /> <img width="250" alt="Screenshot 2025-08-18 at 8 32 31 PM" src="https://github.com/user-attachments/assets/682ae66e-dd5f-4750-9c30-0a210e120250" /> <img width="250" alt="Screenshot 2025-08-18 at 8 32 40 PM" src="https://github.com/user-attachments/assets/7de0d753-eefc-4b7f-942b-ecca1964fcd7" /> ## Test Cases - Enable voice feature and create inboxes and test the cases for both contact details view and contact card view in conversation - Details: 0 Voice inboxes → no Call button. - Details: 1+ Voice inboxes, no phone number for contact → no Call button. - Details: 1 Voice inbox + phone number for contact → button visible; click → toast. - Details: >1 Voice inboxes + phone number for contact → click → modal → choose → toast. --------- Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com> Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
		
			
				
	
	
		
			92 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			92 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
| <script setup>
 | |
| import { computed, ref, useAttrs } from 'vue';
 | |
| import { useI18n } from 'vue-i18n';
 | |
| import { useMapGetter } from 'dashboard/composables/store';
 | |
| import { INBOX_TYPES } from 'dashboard/helper/inbox';
 | |
| import { useAlert } from 'dashboard/composables';
 | |
| 
 | |
| import Button from 'dashboard/components-next/button/Button.vue';
 | |
| import Dialog from 'dashboard/components-next/dialog/Dialog.vue';
 | |
| 
 | |
| const props = defineProps({
 | |
|   phone: { type: String, default: '' },
 | |
|   label: { type: String, default: '' },
 | |
|   icon: { type: [String, Object, Function], default: '' },
 | |
|   size: { type: String, default: 'sm' },
 | |
|   tooltipLabel: { type: String, default: '' },
 | |
| });
 | |
| 
 | |
| defineOptions({ inheritAttrs: false });
 | |
| const attrs = useAttrs();
 | |
| 
 | |
| const { t } = useI18n();
 | |
| 
 | |
| const inboxesList = useMapGetter('inboxes/getInboxes');
 | |
| const voiceInboxes = computed(() =>
 | |
|   (inboxesList.value || []).filter(
 | |
|     inbox => inbox.channel_type === INBOX_TYPES.VOICE
 | |
|   )
 | |
| );
 | |
| const hasVoiceInboxes = computed(() => voiceInboxes.value.length > 0);
 | |
| 
 | |
| // Unified behavior: hide when no phone
 | |
| const shouldRender = computed(() => hasVoiceInboxes.value && !!props.phone);
 | |
| 
 | |
| const dialogRef = ref(null);
 | |
| 
 | |
| const onClick = () => {
 | |
|   if (voiceInboxes.value.length > 1) {
 | |
|     dialogRef.value?.open();
 | |
|     return;
 | |
|   }
 | |
|   useAlert(t('CONTACT_PANEL.CALL_UNDER_DEVELOPMENT'));
 | |
| };
 | |
| 
 | |
| const onPickInbox = () => {
 | |
|   // Placeholder until actual call wiring happens
 | |
|   useAlert(t('CONTACT_PANEL.CALL_UNDER_DEVELOPMENT'));
 | |
|   dialogRef.value?.close();
 | |
| };
 | |
| </script>
 | |
| 
 | |
| <template>
 | |
|   <span class="contents">
 | |
|     <Button
 | |
|       v-if="shouldRender"
 | |
|       v-tooltip.top-end="tooltipLabel || null"
 | |
|       v-bind="attrs"
 | |
|       :label="label"
 | |
|       :icon="icon"
 | |
|       :size="size"
 | |
|       @click="onClick"
 | |
|     />
 | |
| 
 | |
|     <Dialog
 | |
|       v-if="shouldRender && voiceInboxes.length > 1"
 | |
|       ref="dialogRef"
 | |
|       :title="$t('CONTACT_PANEL.VOICE_INBOX_PICKER.TITLE')"
 | |
|       show-cancel-button
 | |
|       :show-confirm-button="false"
 | |
|       width="md"
 | |
|     >
 | |
|       <div class="flex flex-col gap-2">
 | |
|         <button
 | |
|           v-for="inbox in voiceInboxes"
 | |
|           :key="inbox.id"
 | |
|           type="button"
 | |
|           class="flex items-center justify-between w-full px-4 py-2 text-left rounded-lg hover:bg-n-alpha-2"
 | |
|           @click="onPickInbox(inbox)"
 | |
|         >
 | |
|           <div class="flex items-center gap-2">
 | |
|             <span class="i-ri-phone-fill text-n-slate-10" />
 | |
|             <span class="text-sm text-n-slate-12">{{ inbox.name }}</span>
 | |
|           </div>
 | |
|           <span v-if="inbox.phone_number" class="text-xs text-n-slate-10">
 | |
|             {{ inbox.phone_number }}
 | |
|           </span>
 | |
|         </button>
 | |
|       </div>
 | |
|     </Dialog>
 | |
|   </span>
 | |
| </template>
 |