ButtonFloating
Dois componentes flutuantes que vivem fora do fluxo normal da página.
ButtonFloating gerencia dois elementos fixos: um botão circular de ajuda (right:0, top:45vh) com link para vídeo tutorial ou dropdown de múltiplos vídeos, e uma barra de chat interna em forma de pílula (bottom:0, right:1rem, z-index:4000) com badge de mensagens não lidas. Toda a lógica é interna — sem props. A visibilidade é controlada por feature flag (hasDpsp) e condições de sessão.
ButtonIncidentFloating exibe o status operacional do sistema (via InStatus API) como pílula colorida. Ao clicar, abre dropdown com nome do incidente, impacto, componentes afetados e timestamp. Aceita 1 prop (isOutPedbot) para ajustar o posicionamento em contextos de dashboard.
Help — link direto (1 vídeo)
Quando a rota atual possui exatamente 1 vídeo tutorial associado, o botão circular de ajuda funciona como link direto — clique abre o vídeo imediatamente.
Posicionamento: position:fixed; right:0; top:45vh. O botão usa vs-button circular com ícone help-circle do Feather.
<!-- Main.vue — uso do ButtonFloating -->
<ButtonFloating v-if="!disablePedbotReferences"/>
<!-- ButtonFloating.vue — botão de ajuda (link direto, 1 vídeo) -->
<vs-button
v-if="videos.length === 1"
:href="videos[0].link"
target="_blank"
color="primary"
type="filled"
icon="help_circle"
radius
style="position:fixed; right:0; top:45vh; z-index:4000;"
/>
Help — dropdown (múltiplos vídeos)
Quando há mais de 1 vídeo tutorial para a rota atual, o botão de ajuda abre um vs-dropdown listando todos os vídeos disponíveis. Cada item é um link externo (target="_blank").
<!-- Dropdown com múltiplos vídeos -->
<vs-dropdown
v-if="videos.length > 1"
style="position:fixed; right:0; top:45vh; z-index:4000;"
>
<vs-button
color="primary"
type="filled"
icon="help_circle"
radius
/>
<vs-dropdown-menu>
<vs-dropdown-item
v-for="video in videos"
:key="video.id"
>
<a :href="video.link" target="_blank">
<feather-icon icon="VideoIcon" svgClasses="w-4 h-4 mr-2"/>
{{ video.title }}
</a>
</vs-dropdown-item>
</vs-dropdown-menu>
</vs-dropdown>
Barra de Chat Interno
Pílula fixa no rodapé do lado direito. Exibe "Chat Interno", avatar do usuário com badge de mensagens não lidas, e um chevron indicando que o painel pode ser expandido. Dimensões: width:16rem; height:3.3rem. Border-radius: 2rem 2rem 0 0 (apenas cantos superiores arredondados). Ao clicar, emite o evento de bus OpenInternalChat.
<!-- Chat bar pill — ButtonFloating.vue -->
<div
v-if="validate && !twoFactorActivated && !interChatIsActive && !isChatAttendancePage"
class="chat-bar-pill"
style="
position: fixed;
bottom: 0;
right: 1rem;
width: 16rem;
height: 3.3rem;
background: var(--vs-primary);
border-radius: 2rem 2rem 0 0;
z-index: 4000;
display: flex;
align-items: center;
padding: 0 14px;
cursor: pointer;
"
@click="$bus.$emit('OpenInternalChat')"
>
<span style="flex:1; color:#fff; font-weight:600;">Chat Interno</span>
<vs-avatar
size="28px"
:src="AppActiveUser.photoURL"
style="position:relative;"
>
<!-- badge de não lidas -->
<span
v-if="unseenMessages > 0"
class="badge-unseen"
>{{ unseenMessages }}</span>
</vs-avatar>
<feather-icon icon="ChevronUpIcon" svgClasses="w-4 h-4 ml-2 text-white"/>
</div>
ButtonIncidentFloating — Sem Incidentes
Quando o status é operational, a pílula exibe fundo verde (#28C76F) e o texto "Sem Incidentes" com ícone de wifi. Clicar nesta versão não abre dropdown — não há incidente para mostrar.
A cor da pílula varia conforme o status retornado pela InStatus API (veja tabela de cores abaixo).
Status atual
Todos os status
<!-- App.vue -->
<ButtonIncidentFloating
v-if="showIncidentButton"
class="select-none"
:isOutPedbot="isOutPedbot"
/>
<!-- ButtonIncidentFloating.vue — pílula operacional -->
<div
class="incident-pill"
:style="{ background: statusColor }"
@click="openDropdown"
>
<feather-icon icon="WifiIcon" svgClasses="w-4 h-4"/>
<span>{{ statusLabel }}</span>
</div>
<!-- computed -->
<script>
const STATUS_COLORS = {
operational: '#28C76F',
partialoutage: '#EC8C19',
undermaintenance: '#555555',
degradedperformance: '#F4CB16',
majoroutage: '#FE4304',
}
computed: {
statusColor() {
return STATUS_COLORS[this.incidentInfos?.status] || '#28C76F'
},
statusLabel() {
return this.incidentInfos?.status === 'operational'
? 'Sem Incidentes'
: 'Incidente'
}
}
</script>
ButtonIncidentFloating — Incidente Ativo + Dropdown
Quando há um incidente ativo (ex: partialoutage), a pílula muda para laranja e o texto passa a "Incidente". Ao clicar, abre um dropdown de 30em de largura com: nome do incidente, chip de impacto (vs-chip), lista de componentes afetados com indicador colorido, e timestamp da última atualização.
Em telas de atendimento (chat-attendance) o posicionamento é relative; em rotas de dashboard é fixed alinhado à direita; demais contextos usam absolute; right:60px; top:25px.
<!-- Index.vue (chat-attendance) -->
<ButtonIncidentFloating
class="button-incident-floating"
:isOutPedbot="false"
/>
<!-- ButtonIncidentFloating.vue — dropdown de incidente -->
<vs-dropdown vs-trigger-click>
<div
class="incident-pill select-none"
:style="{ background: statusColor }"
>
<feather-icon icon="WifiIcon" svgClasses="w-4 h-4"/>
<span>{{ statusLabel }}</span>
</div>
<vs-dropdown-menu style="width: 30em;">
<div class="incident-header">
<p class="incident-name">{{ incidentInfos.name }}</p>
<vs-chip :color="statusColor">{{ incidentInfos.impact }}</vs-chip>
</div>
<vs-list>
<vs-list-item
v-for="comp in incidentInfos.components"
:key="comp.id"
:title="comp.name"
:subtitle="comp.status"
/>
</vs-list>
<p class="incident-timestamp">
Última atualização: {{ formattedDate }}
</p>
</vs-dropdown-menu>
</vs-dropdown>
API
ButtonFloating — Sem props (lógica interna)
| Estado interno | Tipo | Descrição |
|---|---|---|
videos |
Array | Lista de vídeos tutoriais buscados pela rota atual via tutorialVideosApi. length === 1 → link direto; length > 1 → dropdown. |
validate |
Boolean | Usuário autenticado + rota válida. Controla visibilidade da barra de chat. |
interChatIsActive |
Boolean | Quando true, o painel de chat já está aberto — oculta a pílula. |
twoFactorActivated |
Boolean | Quando true (2FA pendente), oculta a barra de chat. Lido de AppActiveUser.twofactor_activity. |
isChatAttendancePage |
Boolean | Detectado pela rota atual — oculta a pílula de chat nas telas de atendimento. |
unseenMessages |
Number | Total de mensagens não lidas no chat interno. Exibido como badge vermelho. Lido de store/internalUsers. |
ButtonFloating — Eventos (Event Bus)
| Evento | Direção | Descrição |
|---|---|---|
OpenInternalChat |
Emite / Escuta | Emitido ao clicar na barra de chat. Também escutado para abrir o painel programaticamente de qualquer lugar da aplicação. |
ButtonFloating — Condições de visibilidade
!disablePedbotReferences (feature flag hasDpsp) deve ser false para renderizar o componente em Main.vue
validate === true — usuário autenticado
twoFactorActivated === true → pílula de chat oculta
interChatIsActive === true → pílula de chat oculta (painel já aberto)
isChatAttendancePage === true → pílula de chat oculta na tela de atendimento
ButtonFloating — Responsividade
| Breakpoint | Dimensão | Fonte |
|---|---|---|
| Padrão (desktop) | width:16rem; height:3.3rem |
— |
| iOS (≤ 430×932) | 130px × 36px; font-size:12px |
Media query @media (max-width:430px) |
| Android (≤ 393×873) | Similar ao iOS — redução proporcional | Media query @media (max-width:393px) |
ButtonIncidentFloating — Props
| Nome | Tipo | Default | Obrig. | Descrição |
|---|---|---|---|---|
isOutPedbot |
Boolean | false |
Não | Quando true, desativa o posicionamento needToFix (usado em dashboards). Quando false, o componente infere o posicionamento correto pela rota. |
ButtonIncidentFloating — Status e cores
| Status (InStatus) | Cor | Texto da pílula |
|---|---|---|
operational |
#28C76F | Sem Incidentes |
partialoutage |
#EC8C19 | Incidente |
undermaintenance |
#555555 | Incidente |
degradedperformance |
#F4CB16 | Incidente |
majoroutage |
#FE4304 | Incidente |
ButtonIncidentFloating — Posicionamento por contexto
| Contexto | Position | Alinhamento |
|---|---|---|
Tela de atendimento (chat-attendance) |
relative |
Menor, integrado ao layout |
Rotas de dashboard (isOutPedbot=false) |
fixed |
justify-content: flex-end |
| Padrão / outros contextos | absolute |
right:60px; top:25px |
| URL contém "admin-beta" | Detectado como ambiente beta — pode alterar comportamento de posicionamento | |
Dependências
| Tipo | Dependência |
|---|---|
| Vuesax | vs-button, vs-dropdown, vs-dropdown-menu, vs-dropdown-item, vs-avatar, vs-chip, vs-list, vs-list-item |
| Custom | InternalChatContact — src/layouts/components/internal-chat-message/InternalChatContact.vue |
| Custom | feather-icon — ícones HelpCircle, ChevronUp, Wifi, Video |
| Store | layout.features.hasDpsp — feature flag DPSP |
| Store | user.internalUsers — unseenMsg por usuário |
| Store | AppActiveUser — twofactor_activity, photoURL |
| Store | internalChatMessages/resetInternalChatMessage — mensagens do chat interno |
| Store | inStatus.incidentInfos — dados de incidente da InStatus API |
| HTTP | tutorialVideosApi — vídeos tutoriais por rota (Pedbot API) |
| HTTP | InStatus API — status operacional e incidentes ativos (via store) |
| Event Bus | $bus.$emit / $bus.$on('OpenInternalChat') |
Onde é usado
| Arquivo | Componente | Nota |
|---|---|---|
src/layouts/main/Main.vue:142 |
ButtonFloating | Uso principal — layout raiz do admin. Condicionado por !disablePedbotReferences. |
src/App.vue:3 |
ButtonIncidentFloating | Montado na raiz da aplicação. :isOutPedbot varia por rota. |
src/views/chat-attendance/Index.vue:171 |
ButtonIncidentFloating | Versão menor com posicionamento relativo. :isOutPedbot="false". |
src/views/chat-attendance/NewIndex.vue |
ButtonIncidentFloating | Nova versão da tela de atendimento. Mesmo padrão do Index.vue. |