chore: new floating widget design

This commit is contained in:
Sojan
2025-05-08 03:42:47 -07:00
parent ce468bac01
commit 2879a0cd42
7 changed files with 1748 additions and 999 deletions
+25
View File
@@ -146,6 +146,27 @@ export default {
this.showCallWidget = false;
this.$store.dispatch('calls/clearActiveCall');
this.$store.dispatch('calls/clearIncomingCall');
// Clear the activeCallConversation state in all ContactInfo components
this.$nextTick(() => {
const clearContactInfoCallState = (components) => {
if (!components) return;
components.forEach(component => {
if (component.$options && component.$options.name === 'ContactInfo') {
if (component.activeCallConversation) {
component.activeCallConversation = null;
component.$forceUpdate();
}
}
if (component.$children && component.$children.length) {
clearContactInfoCallState(component.$children);
}
});
};
clearContactInfoCallState(this.$children);
});
},
handleCallJoined() {
this.showCallWidget = true;
@@ -249,6 +270,10 @@ export default {
:contact-name="activeCall ? activeCall.contactName : (incomingCall ? incomingCall.contactName : '')"
:contact-id="activeCall ? activeCall.contactId : (incomingCall ? incomingCall.contactId : null)"
:inbox-id="activeCall ? activeCall.inboxId : (incomingCall ? incomingCall.inboxId : null)"
:inbox-avatar-url="activeCall ? activeCall.inboxAvatarUrl : (incomingCall ? incomingCall.inboxAvatarUrl : '')"
:inbox-phone-number="activeCall ? activeCall.inboxPhoneNumber : (incomingCall ? incomingCall.inboxPhoneNumber : '')"
:avatar-url="activeCall ? activeCall.avatarUrl : (incomingCall ? incomingCall.avatarUrl : '')"
:phone-number="activeCall ? activeCall.phoneNumber : (incomingCall ? incomingCall.phoneNumber : '')"
:use-web-rtc="true"
@callEnded="handleCallEnded"
@callJoined="handleCallJoined"
File diff suppressed because it is too large Load Diff
+6 -10
View File
@@ -203,17 +203,19 @@ class ActionCableConnector extends BaseActionCableConnector {
conversationId: data.conversation_id,
inboxId: data.inbox_id,
inboxName: data.inbox_name,
contactName: data.contact_name,
inboxAvatarUrl: data.inbox_avatar_url, // Inbox avatar URL
inboxPhoneNumber: data.inbox_phone_number, // Inbox phone number
contactName: data.contact_name || 'Unknown Caller', // Add fallback name
contactId: data.contact_id,
accountId: data.account_id,
isOutbound: data.is_outbound || false, // Check if this is an outbound call requiring agent join
conference_sid: data.conference_sid, // Pass the conference_sid directly to the floating widget
requiresAgentJoin: data.requires_agent_join || false, // Flag for calls needing immediate agent join
callDirection: data.call_direction // Add call direction for additional context
callDirection: data.call_direction, // Add call direction for additional context
phoneNumber: data.phone_number, // Include phone number for display in the UI
avatarUrl: data.avatar_url // Include avatar URL for display in the UI
};
// Process outbound calls
// Update store
this.app.$store.dispatch('calls/setIncomingCall', normalizedPayload);
@@ -221,8 +223,6 @@ class ActionCableConnector extends BaseActionCableConnector {
if (window.app && window.app.$data) {
window.app.$data.showCallWidget = true;
}
// For outbound calls, we don't need to play a ringtone as we're initiating the call
};
onCallStatusChanged = data => {
@@ -240,20 +240,16 @@ class ActionCableConnector extends BaseActionCableConnector {
// For terminal statuses, clear the active call to close the widget
if (['ended', 'missed', 'completed', 'failed', 'busy', 'no_answer'].includes(data.status)) {
console.log(`ActionCable: Call status changed to terminal status: ${data.status}`);
// Clear active call for terminal statuses
this.app.$store.dispatch('calls/clearActiveCall');
// Ensure window.app.$data exists before modifying it
if (window.app && window.app.$data) {
console.log('ActionCable: Hiding call widget');
window.app.$data.showCallWidget = false;
}
// Update conversation list to show current status
if (data.conversation_id) {
console.log(`ActionCable: Updating conversation last activity for conversation ${data.conversation_id}`);
this.app.$store.dispatch('updateConversationLastActivity', {
conversationId: data.conversation_id,
lastActivityAt: new Date().toISOString(),
@@ -63,7 +63,15 @@ export default {
};
},
computed: {
...mapGetters({ uiFlags: 'contacts/getUIFlags' }),
...mapGetters({
uiFlags: 'contacts/getUIFlags',
storeActiveCall: 'calls/getActiveCall',
storeHasActiveCall: 'calls/hasActiveCall',
}),
// Check if there's an active call either in store or local component
hasActiveCall() {
return this.storeHasActiveCall || !!this.activeCallConversation;
},
contactProfileLink() {
return `/app/accounts/${this.$route.params.accountId}/contacts/${this.contact.id}`;
},
@@ -242,9 +250,15 @@ export default {
},
handleCallEnded() {
// Immediately reset local state
this.activeCallConversation = null;
this.isCallLoading = false;
// Clear global call state
this.$store.dispatch('calls/clearActiveCall');
// Force re-render the component to ensure button state updates
this.$forceUpdate();
},
// Simplified emergency end call function
@@ -446,12 +460,29 @@ export default {
this.showMergeModal = true;
},
onCallButtonClick() {
if (this.activeCallConversation) {
useAlert('Call already ongoing', 'warning');
// If there's an active call in the store, just show widget
if (this.storeHasActiveCall) {
useAlert('Call already active, showing call widget', 'info');
if (window.app && window.app.$data) {
window.app.$data.showCallWidget = true;
}
return;
}
// Check if we have a stale local state
if (this.activeCallConversation) {
// Reset our local state
this.activeCallConversation = null;
this.$forceUpdate();
// If store is clear, initiate a new call after state reset
if (!this.storeHasActiveCall) {
this.$nextTick(() => {
this.initiateVoiceCall();
});
}
} else {
// No active call, proceed with initiating a new one
this.initiateVoiceCall();
}
},
@@ -570,15 +601,13 @@ export default {
</ComposeConversation>
<NextButton
v-if="contact.phone_number"
v-tooltip.top-end="
activeCallConversation ? 'Call already ongoing' : 'Call'
"
v-tooltip.top-end="hasActiveCall ? 'Call already ongoing' : 'Call'"
icon="i-ph-phone"
slate
faded
sm
:is-loading="!activeCallConversation && isCallLoading"
:color="activeCallConversation ? 'teal' : undefined"
:is-loading="!hasActiveCall && isCallLoading"
:color="hasActiveCall ? 'teal' : undefined"
@click.stop.prevent="onCallButtonClick"
/>
<NextButton