gigafibre-fsm/apps/ops/src/components/shared/ReaderStack.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

34 lines
1.5 KiB
Vue

<template>
<div v-if="others.length" class="rstack">
<q-avatar v-for="r in head" :key="r.email" :size="size + 'px'" class="rstack-av"
:style="{ background: staffColor(r.email), color: '#fff', fontSize: Math.round(size * 0.42) + 'px' }">
{{ staffInitials(noteAuthorName(r.email)) }}
<q-tooltip>{{ shortAgent(r.email) }}<template v-if="r.readAt"> · {{ relTime(r.readAt) }}</template></q-tooltip>
</q-avatar>
<span v-if="extra > 0" class="rstack-more">+{{ extra }}</span>
</div>
</template>
<script setup>
import { computed } from 'vue'
import { staffColor, staffInitials, noteAuthorName, shortAgent, relTime } from 'src/composables/useFormatters'
const props = defineProps({
readers: { type: Array, default: () => [] }, // [{ email, readAt }]
me: { type: String, default: '' },
max: { type: Number, default: 3 },
size: { type: Number, default: 20 },
})
// Exclut soi-même (façon Messenger : on voit les AUTRES qui ont lu)
const others = computed(() => (props.readers || []).filter(r => r && r.email && r.email !== props.me))
const head = computed(() => others.value.slice(0, props.max))
const extra = computed(() => Math.max(0, others.value.length - props.max))
</script>
<style scoped>
.rstack { display: flex; align-items: center; }
.rstack-av { margin-left: -6px; border: 1.5px solid #fff; font-weight: 600; }
.rstack-av:first-child { margin-left: 0; }
.rstack-more { font-size: 0.66rem; color: #64748b; margin-left: 5px; font-weight: 600; }
</style>