gigafibre-fsm/apps/ops/src/composables/useSoftphone.js
louispaulb 512c4a5f1b feat(ops): dispatch auto complet + perf Boîte/rapports + fix session
Planificateur « Suggérer » : 4 stratégies (smart / meilleurs d'abord / équilibré /
juste ce qu'il faut), compétences+niveaux par tech (édition inline), niveau requis
par compétence + par job, carte des tournées (1 couleur/tech, domicile→arrêts,
sélecteur de jour), fenêtre de dispatch auj.+demain (dates sélectionnées), règle
week-end + placeholder « en attente du quart », clustering + lasso + filtre-date
sur la carte, accès rapide « À assigner » (badge).

Boîte : liste /conversations allégée (45 Mo → ~1 Mo, 17×) + messages chargés à
l'ouverture. Rapports : cache SWR sur revenue-explorer (22×). Session : keep-alive
+ timeout fetch global + authFetch durci → fin des rechargements manuels.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 08:49:35 -04:00

44 lines
2.3 KiB
JavaScript

import { ref } from 'vue'
import { Notify } from 'quasar'
import { createDoc } from 'src/api/erp'
// Softphone PARTAGÉ (Twilio WebRTC + repli SIP) — état singleton pilotable de n'importe où (ConversationPanel, fiche client…).
// Le dialer lui-même = <PhoneModal> monté UNE seule fois globalement (MainLayout) et lié à cet état. Remplace l'ancien
// montage exclusif dans ChatterPanel → l'appel intégré existe maintenant dans le panneau de comms unifié.
const open = ref(false)
const number = ref('')
const customer = ref('') // nom ERPNext (C-…) pour lier le log d'appel à la bonne fiche
const customerName = ref('') // nom affiché dans le dialer
const provider = ref('twilio')
// Ouvre le dialer pré-rempli + (si fournie) la fiche à laquelle lier le log d'appel.
function call (num, ctx = {}) {
number.value = String(num || '').trim()
customer.value = ctx.customer || ''
customerName.value = ctx.customerName || ''
provider.value = ctx.provider || 'twilio'
open.value = true
}
// Log d'appel = créateur UNIQUE (corrige l'ancien double-log PhoneModal+ChatterPanel) : un seul doc Communication par appel.
async function handleCallEnded (info) {
const phone = (info && info.remote) || number.value
if (!customer.value || !phone) return // pas de fiche liée → on ne crée pas de Communication orpheline
const dur = (info && info.duration) || 0
const durationStr = `${Math.floor(dur / 60)}m${String(dur % 60).padStart(2, '0')}s`
const incoming = info && info.direction === 'in'
try {
await createDoc('Communication', {
subject: (incoming ? 'Appel de ' : 'Appel vers ') + phone,
communication_type: 'Communication', communication_medium: 'Phone',
sent_or_received: incoming ? 'Received' : 'Sent',
status: 'Linked', phone_no: phone, sender: 'sms@gigafibre.ca',
sender_full_name: incoming ? ((info && info.remoteName) || phone) : 'Targo Ops',
content: `Appel ${incoming ? 'reçu de' : 'vers'} ${phone} — Durée: ${durationStr}`,
reference_doctype: 'Customer', reference_name: customer.value,
})
} catch (e) { Notify.create({ type: 'negative', message: 'Erreur enregistrement appel : ' + (e.message || e), timeout: 3000 }) }
}
export function useSoftphone () { return { open, number, customer, customerName, provider, call, handleCallEnded } }