gigafibre-fsm/apps/ops/src/pages/ConversationFullPage.vue
louispaulb 0f65c02d83 feat(fsm): platform build — comms UI, F→ERPNext sync/billing, roster, campaigns, network, reports
Accumulated work on the dispatch/legacy-writeback branch:
- Communications UI: CommunicationsPage, ConversationFullPage, DepartmentBoard,
  PipelineBoard, ReaderStack, Orchestrator/NewTicket/ServiceStatus/Outbox dialogs;
  hub gmail.js, ticket-collab.js, outbox.js, coupon-triage.js, client-diag.js.
- Billing/sync mirror (F→ERPNext): legacy-payments.js, legacy-sync.js,
  sync-orchestrator.js, supplier-invoices.js, municipality.js + incremental
  migration scripts; LegacySyncPage, SupplierInvoices + negative-billing /
  terminated-active reports.
- Roster/campaigns/network/voice: roster + roster-assistant, campaigns, giftbit,
  olt-snmp, traccar, twilio, vision, tech-absence-sms, ai/agent/config/helpers,
  legacy-dispatch-sync; ops PlanificationPage, RapportsPage, Settings, Tickets,
  ClientDetail updates.
- docs/ PLATFORM_GUIDE + UI_AND_OPTIMIZATION; .gitignore __pycache__.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 06:12:12 -04:00

40 lines
1.8 KiB
Vue

<template>
<q-page class="cfp-page">
<div class="cfp-bar">
<q-btn flat dense icon="arrow_back" label="Boîte" no-caps color="indigo-7" @click="$router.push('/communications')" />
</div>
<ConversationPanel inline />
</q-page>
</template>
<script setup>
import { onMounted, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import ConversationPanel from 'src/components/shared/ConversationPanel.vue'
import { useConversations } from 'src/composables/useConversations'
const route = useRoute()
const router = useRouter()
const { discussions, activeDiscussion, fetchList, openDiscussion, openConversation } = useConversations()
async function openByToken (token) {
if (!token) return
const find = () => (discussions.value || []).find(d => d.token === token || (d.conversations || []).some(c => c.token === token))
let disc = find()
if (!disc) { await fetchList(); disc = find() }
if (disc) { openDiscussion(disc); return } // ouvre le fil (active la vue thread plein écran)
await openConversation(token) // repli : ouverture directe par jeton (pose aussi activeDiscussion)
if (!activeDiscussion.value) router.push('/communications') // introuvable/supprimée → retour à la boîte, pas de loader infini
}
onMounted(() => openByToken(route.params.token))
watch(() => route.params.token, t => openByToken(t))
</script>
<style scoped>
/* Plein écran : la page occupe la hauteur du viewport (moins l'en-tête) → le fil défile à l'intérieur, le bloc de réponse reste ancré en bas */
.cfp-page { padding: 0; height: calc(100vh - 50px); display: flex; flex-direction: column; overflow: hidden; }
.cfp-bar { padding: 4px 8px; border-bottom: 1px solid var(--ops-border, #e2e8f0); background: #fff; flex: 0 0 auto; }
.cfp-page :deep(.conv-fullpage) { flex: 1 1 auto; min-height: 0; }
</style>