mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-11-03 20:48:07 +00:00 
			
		
		
		
	This PR introduces a new channel type for voice conversations. ref: #11481 ## Changes - Add database migration for channel_voice table with phone_number and provider_config - Create Channel::Voice model with E.164 phone number validation and Twilio config validation - Add voice channel association to Account model - Extend inbox helpers and types to support voice channels - Add voice channel setup UI with Twilio configuration form - Include voice channel in channel factory and list components - Add API routes and store actions for voice channel creation - Add comprehensive translations for voice channel management --------- Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com> Co-authored-by: iamsivin <iamsivin@gmail.com>
		
			
				
	
	
		
			163 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			163 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
export const INBOX_TYPES = {
 | 
						|
  WEB: 'Channel::WebWidget',
 | 
						|
  FB: 'Channel::FacebookPage',
 | 
						|
  TWITTER: 'Channel::TwitterProfile',
 | 
						|
  TWILIO: 'Channel::TwilioSms',
 | 
						|
  WHATSAPP: 'Channel::Whatsapp',
 | 
						|
  API: 'Channel::Api',
 | 
						|
  EMAIL: 'Channel::Email',
 | 
						|
  TELEGRAM: 'Channel::Telegram',
 | 
						|
  LINE: 'Channel::Line',
 | 
						|
  SMS: 'Channel::Sms',
 | 
						|
  INSTAGRAM: 'Channel::Instagram',
 | 
						|
  VOICE: 'Channel::Voice',
 | 
						|
};
 | 
						|
 | 
						|
const INBOX_ICON_MAP_FILL = {
 | 
						|
  [INBOX_TYPES.WEB]: 'i-ri-global-fill',
 | 
						|
  [INBOX_TYPES.FB]: 'i-ri-messenger-fill',
 | 
						|
  [INBOX_TYPES.TWITTER]: 'i-ri-twitter-x-fill',
 | 
						|
  [INBOX_TYPES.WHATSAPP]: 'i-ri-whatsapp-fill',
 | 
						|
  [INBOX_TYPES.API]: 'i-ri-cloudy-fill',
 | 
						|
  [INBOX_TYPES.EMAIL]: 'i-ri-mail-fill',
 | 
						|
  [INBOX_TYPES.TELEGRAM]: 'i-ri-telegram-fill',
 | 
						|
  [INBOX_TYPES.LINE]: 'i-ri-line-fill',
 | 
						|
  [INBOX_TYPES.INSTAGRAM]: 'i-ri-instagram-fill',
 | 
						|
  [INBOX_TYPES.VOICE]: 'i-ri-phone-fill',
 | 
						|
};
 | 
						|
 | 
						|
const DEFAULT_ICON_FILL = 'i-ri-chat-1-fill';
 | 
						|
 | 
						|
const INBOX_ICON_MAP_LINE = {
 | 
						|
  [INBOX_TYPES.WEB]: 'i-ri-global-line',
 | 
						|
  [INBOX_TYPES.FB]: 'i-ri-messenger-line',
 | 
						|
  [INBOX_TYPES.TWITTER]: 'i-ri-twitter-x-line',
 | 
						|
  [INBOX_TYPES.WHATSAPP]: 'i-ri-whatsapp-line',
 | 
						|
  [INBOX_TYPES.API]: 'i-ri-cloudy-line',
 | 
						|
  [INBOX_TYPES.EMAIL]: 'i-ri-mail-line',
 | 
						|
  [INBOX_TYPES.TELEGRAM]: 'i-ri-telegram-line',
 | 
						|
  [INBOX_TYPES.LINE]: 'i-ri-line-line',
 | 
						|
  [INBOX_TYPES.INSTAGRAM]: 'i-ri-instagram-line',
 | 
						|
  [INBOX_TYPES.VOICE]: 'i-ri-phone-line',
 | 
						|
};
 | 
						|
 | 
						|
const DEFAULT_ICON_LINE = 'i-ri-chat-1-line';
 | 
						|
 | 
						|
export const getInboxSource = (type, phoneNumber, inbox) => {
 | 
						|
  switch (type) {
 | 
						|
    case INBOX_TYPES.WEB:
 | 
						|
      return inbox.website_url || '';
 | 
						|
 | 
						|
    case INBOX_TYPES.TWILIO:
 | 
						|
    case INBOX_TYPES.WHATSAPP:
 | 
						|
    case INBOX_TYPES.VOICE:
 | 
						|
      return phoneNumber || '';
 | 
						|
 | 
						|
    case INBOX_TYPES.EMAIL:
 | 
						|
      return inbox.email || '';
 | 
						|
 | 
						|
    default:
 | 
						|
      return '';
 | 
						|
  }
 | 
						|
};
 | 
						|
export const getReadableInboxByType = (type, phoneNumber) => {
 | 
						|
  switch (type) {
 | 
						|
    case INBOX_TYPES.WEB:
 | 
						|
      return 'livechat';
 | 
						|
 | 
						|
    case INBOX_TYPES.FB:
 | 
						|
      return 'facebook';
 | 
						|
 | 
						|
    case INBOX_TYPES.TWITTER:
 | 
						|
      return 'twitter';
 | 
						|
 | 
						|
    case INBOX_TYPES.TWILIO:
 | 
						|
      return phoneNumber?.startsWith('whatsapp') ? 'whatsapp' : 'sms';
 | 
						|
 | 
						|
    case INBOX_TYPES.WHATSAPP:
 | 
						|
      return 'whatsapp';
 | 
						|
 | 
						|
    case INBOX_TYPES.API:
 | 
						|
      return 'api';
 | 
						|
 | 
						|
    case INBOX_TYPES.EMAIL:
 | 
						|
      return 'email';
 | 
						|
 | 
						|
    case INBOX_TYPES.TELEGRAM:
 | 
						|
      return 'telegram';
 | 
						|
 | 
						|
    case INBOX_TYPES.LINE:
 | 
						|
      return 'line';
 | 
						|
 | 
						|
    case INBOX_TYPES.VOICE:
 | 
						|
      return 'voice';
 | 
						|
 | 
						|
    default:
 | 
						|
      return 'chat';
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
export const getInboxClassByType = (type, phoneNumber) => {
 | 
						|
  switch (type) {
 | 
						|
    case INBOX_TYPES.WEB:
 | 
						|
      return 'globe-desktop';
 | 
						|
 | 
						|
    case INBOX_TYPES.FB:
 | 
						|
      return 'brand-facebook';
 | 
						|
 | 
						|
    case INBOX_TYPES.TWITTER:
 | 
						|
      return 'brand-twitter';
 | 
						|
 | 
						|
    case INBOX_TYPES.TWILIO:
 | 
						|
      return phoneNumber?.startsWith('whatsapp')
 | 
						|
        ? 'brand-whatsapp'
 | 
						|
        : 'brand-sms';
 | 
						|
 | 
						|
    case INBOX_TYPES.WHATSAPP:
 | 
						|
      return 'brand-whatsapp';
 | 
						|
 | 
						|
    case INBOX_TYPES.API:
 | 
						|
      return 'cloud';
 | 
						|
 | 
						|
    case INBOX_TYPES.EMAIL:
 | 
						|
      return 'mail';
 | 
						|
 | 
						|
    case INBOX_TYPES.TELEGRAM:
 | 
						|
      return 'brand-telegram';
 | 
						|
 | 
						|
    case INBOX_TYPES.LINE:
 | 
						|
      return 'brand-line';
 | 
						|
 | 
						|
    case INBOX_TYPES.INSTAGRAM:
 | 
						|
      return 'brand-instagram';
 | 
						|
 | 
						|
    case INBOX_TYPES.VOICE:
 | 
						|
      return 'phone';
 | 
						|
 | 
						|
    default:
 | 
						|
      return 'chat';
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
export const getInboxIconByType = (type, phoneNumber, variant = 'fill') => {
 | 
						|
  const iconMap =
 | 
						|
    variant === 'fill' ? INBOX_ICON_MAP_FILL : INBOX_ICON_MAP_LINE;
 | 
						|
  const defaultIcon =
 | 
						|
    variant === 'fill' ? DEFAULT_ICON_FILL : DEFAULT_ICON_LINE;
 | 
						|
 | 
						|
  // Special case for Twilio (whatsapp and sms)
 | 
						|
  if (type === INBOX_TYPES.TWILIO && phoneNumber?.startsWith('whatsapp')) {
 | 
						|
    return iconMap[INBOX_TYPES.WHATSAPP];
 | 
						|
  }
 | 
						|
 | 
						|
  return iconMap[type] ?? defaultIcon;
 | 
						|
};
 | 
						|
 | 
						|
export const getInboxWarningIconClass = (type, reauthorizationRequired) => {
 | 
						|
  const allowedInboxTypes = [INBOX_TYPES.FB, INBOX_TYPES.EMAIL];
 | 
						|
  if (allowedInboxTypes.includes(type) && reauthorizationRequired) {
 | 
						|
    return 'warning';
 | 
						|
  }
 | 
						|
  return '';
 | 
						|
};
 |