25 Commits

Author SHA1 Message Date
Francisco Gaona
fd989648fc Add twilio softphone with integrated AI assistant 2026-01-04 08:48:43 +01:00
Francisco Gaona
6593fecca7 WIP - saving expires at for sharing records 2025-12-31 05:01:27 +01:00
Francisco Gaona
75b7325cea WIP - use objection for record shares 2025-12-30 21:46:37 +01:00
Francisco Gaona
c50098a55c WIP - add and remove shares 2025-12-30 21:42:42 +01:00
Francisco Gaona
e73126bcb7 WIP - manually sharing records 2025-12-30 18:29:20 +01:00
Francisco Gaona
6c29d18696 WIP - more admin users and roles 2025-12-30 09:10:45 +01:00
Francisco Gaona
3fbc019083 WIP - admin users and roles 2025-12-30 09:06:42 +01:00
Francisco Gaona
3086f78d34 WIp - manage role permissions per object 2025-12-30 06:16:54 +01:00
Francisco Gaona
d15fc918d1 WIP - field level permission 2025-12-30 05:54:56 +01:00
Francisco Gaona
56c0c3838d WIP - permissions working as expected 2025-12-30 04:50:51 +01:00
Francisco Gaona
9ac69e30d0 WIP - better handling of viewAll modifyAll 2025-12-30 04:43:51 +01:00
Francisco Gaona
d37183ba45 WIp - fix displaying related model names in lookup fields 2025-12-30 04:22:56 +01:00
Francisco Gaona
b4bdeeb9f6 WIP - permissions progress 2025-12-30 03:26:50 +01:00
Francisco Gaona
f4143ab106 WIP - Fix objection and model registry 2025-12-27 06:08:25 +01:00
Francisco Gaona
516e132611 WIP - move docs 2025-12-24 21:46:05 +01:00
Francisco Gaona
c5305490c1 WIP - use objection and working lookup field to owner 2025-12-24 21:43:58 +01:00
Francisco Gaona
4520f94b69 WIP - using objection base model to handle objects operations 2025-12-24 20:18:43 +01:00
Francisco Gaona
e4f1ba96ad WIP - custom migrations when object is created 2025-12-24 19:54:13 +01:00
Francisco Gaona
52c0849de2 WIP - manage tenant users from central 2025-12-24 12:17:22 +01:00
Francisco Gaona
b9fa3bd008 WIP - improve login to tenants by domains 2025-12-24 11:42:44 +01:00
Francisco Gaona
2bc672e4c5 WIP - some fixes 2025-12-24 10:54:19 +01:00
Francisco Gaona
962c84e6d2 WIP - fix lookup field 2025-12-24 00:05:15 +01:00
Francisco Gaona
fc1bec4de7 WIP - related lists and look up field 2025-12-23 23:59:04 +01:00
Francisco Gaona
0275b96014 WIP - central operations 2025-12-23 23:38:45 +01:00
Francisco Gaona
e4f3bad971 WIp - fix login into central 2025-12-23 22:16:58 +01:00
2 changed files with 30 additions and 15 deletions

View File

@@ -101,18 +101,23 @@ export function useSoftphone() {
} }
const { api } = useApi(); const { api } = useApi();
console.log('Requesting Twilio token from /api/voice/token...');
const response = await api.get('/voice/token'); const response = await api.get('/voice/token');
const token = response.data.token; const token = response.data.token;
console.log('Token received, creating Device...');
// Log the token payload to see what identity is being used // Log the token payload to see what identity is being used
try { try {
const tokenPayload = JSON.parse(atob(token.split('.')[1])); const tokenPayload = JSON.parse(atob(token.split('.')[1]));
console.log('Token identity:', tokenPayload.sub);
console.log('Token grants:', tokenPayload.grants);
} catch (e) { } catch (e) {
console.log('Could not parse token payload'); console.log('Could not parse token payload');
} }
twilioDevice.value = new Device(token, { twilioDevice.value = new Device(token, {
logLevel: 3, logLevel: 1,
codecPreferences: ['opus', 'pcmu'], codecPreferences: ['opus', 'pcmu'],
enableImprovedSignalingErrorPrecision: true, enableImprovedSignalingErrorPrecision: true,
edge: 'ashburn', edge: 'ashburn',
@@ -120,10 +125,12 @@ export function useSoftphone() {
// Device events // Device events
twilioDevice.value.on('registered', () => { twilioDevice.value.on('registered', () => {
console.log('✓ Twilio Device registered - ready to receive calls');
toast.success('Softphone ready'); toast.success('Softphone ready');
}); });
twilioDevice.value.on('unregistered', () => { twilioDevice.value.on('unregistered', () => {
console.log('⚠ Twilio Device unregistered');
}); });
twilioDevice.value.on('error', (error) => { twilioDevice.value.on('error', (error) => {
@@ -132,8 +139,14 @@ export function useSoftphone() {
}); });
twilioDevice.value.on('incoming', (call: TwilioCall) => { twilioDevice.value.on('incoming', (call: TwilioCall) => {
console.log('🔔 Twilio Device INCOMING event received:', call.parameters);
console.log('Call parameters:', {
CallSid: call.parameters.CallSid,
From: call.parameters.From,
To: call.parameters.To,
});
twilioCall.value = call; twilioCall.value = call;
// Update state // Update state
incomingCall.value = { incomingCall.value = {
callSid: call.parameters.CallSid || '', callSid: call.parameters.CallSid || '',
@@ -154,11 +167,16 @@ export function useSoftphone() {
// Setup call handlers // Setup call handlers
setupCallHandlers(call); setupCallHandlers(call);
// Twilio Device will handle ringtone automatically // Play ringtone
playRingtone();
}); });
// Register the device // Register the device
console.log('Registering Twilio Device...');
await twilioDevice.value.register(); await twilioDevice.value.register();
console.log('✓ Twilio Device register() completed');
console.log('Device identity:', twilioDevice.value.identity);
console.log('Device state:', twilioDevice.value.state);
} catch (error: any) { } catch (error: any) {
console.error('Failed to initialize Twilio Device:', error); console.error('Failed to initialize Twilio Device:', error);
@@ -227,7 +245,7 @@ export function useSoftphone() {
return 'http://localhost:3000'; return 'http://localhost:3000';
}; };
// Connect to /voice namespace with proper auth header // Connect to /voice namespace
socket.value = io(`${getBackendUrl()}/voice`, { socket.value = io(`${getBackendUrl()}/voice`, {
auth: { auth: {
token: token, token: token,
@@ -237,26 +255,25 @@ export function useSoftphone() {
reconnectionDelay: 1000, reconnectionDelay: 1000,
reconnectionDelayMax: 5000, reconnectionDelayMax: 5000,
reconnectionAttempts: 5, reconnectionAttempts: 5,
query: {}, // Explicitly set empty query to prevent token leaking
}); });
// Connection events // Connection events
socket.value.on('connect', () => { socket.value.on('connect', () => {
console.log('🔌 Softphone WebSocket connected');
console.log('📋 Token payload (check userId):', parseJwt(token));
isConnected.value = true; isConnected.value = true;
// Initialize Twilio Device after WebSocket connects // Initialize Twilio Device after WebSocket connects
// Suppress warnings by catching them before they log initializeTwilioDevice();
initializeTwilioDevice().catch(err => {
// Device initialization errors are already shown to user via toast
console.debug('Device init issue (non-critical):', err.message);
});
}); });
socket.value.on('disconnect', () => { socket.value.on('disconnect', () => {
console.log('Softphone WebSocket disconnected');
isConnected.value = false; isConnected.value = false;
}); });
socket.value.on('connect_error', (error) => { socket.value.on('connect_error', (error) => {
console.error('Softphone connection error:', error);
toast.error('Failed to connect to voice service'); toast.error('Failed to connect to voice service');
}); });
@@ -535,7 +552,8 @@ export function useSoftphone() {
let ringtoneAudio: HTMLAudioElement | null = null; let ringtoneAudio: HTMLAudioElement | null = null;
const playRingtone = () => { const playRingtone = () => {
// Play a simple beep tone using Web Audio API // Optional: Play a simple beep tone using Web Audio API
// This is a nice-to-have enhancement but not required for incoming calls to work
try { try {
const audioContext = new (window.AudioContext || (window as any).webkitAudioContext)(); const audioContext = new (window.AudioContext || (window as any).webkitAudioContext)();
const oscillator = audioContext.createOscillator(); const oscillator = audioContext.createOscillator();

View File

@@ -58,10 +58,7 @@ export default defineNuxtConfig({
}, },
server: { server: {
hmr: { hmr: {
host: 'tenant1.routebox.co', clientPort: 3001,
port: 443,
protocol: 'wss',
// Don't use _nuxt path - HMR handles its own path
}, },
allowedHosts: ['.routebox.co', 'localhost', '127.0.0.1'], allowedHosts: ['.routebox.co', 'localhost', '127.0.0.1'],
}, },