Melissa polish + Prontuario Visao Geral + agenda historico
Sprints B (05-03) e C (05-04) acumulados: - NotificationDrawer/Item redesign (visual mais limpo, ações inline) - Dock pins compose (useMelissaDockPins) + cache store global (melissaCacheStore) - MelissaAgenda: timeline FullCalendar parity + cards resumo, histórico card com useMelissaAgendaHistorico, MelissaEventoPanel ajustado - useFeriados: cache opt-in pra evitar fetch redundante de feriados - PatientProntuario: aba Visão Geral nova; PatientConversationsTab polish - AgendaClinicMosaic / AgendaTerapeutaPage / useAgendaSettings: ajustes de paridade com Melissa - DocumentsListPage: pequenos ajustes - DB migration 20260504000001: fix do trigger pra status 'excluido' nas cancel_notifications Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -16,7 +16,7 @@
|
||||
-->
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import { useToast } from 'primevue/usetoast';
|
||||
import { isToday, isYesterday, differenceInDays } from 'date-fns';
|
||||
import {
|
||||
@@ -29,6 +29,7 @@ import NotificationItem from './NotificationItem.vue';
|
||||
|
||||
const store = useNotificationStore();
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const toast = useToast();
|
||||
|
||||
const filter = ref('unread'); // 'unread' | 'all'
|
||||
@@ -101,7 +102,10 @@ function handleArchive(id) {
|
||||
}
|
||||
|
||||
function goToHistory() {
|
||||
router.push('/therapist/notificacoes');
|
||||
// Se o user está em /melissa/*, navega pra equivalente Melissa
|
||||
// (preserva o overlay) — senão cai na rota do role.
|
||||
const target = route.path?.startsWith('/melissa') ? '/melissa/notificacoes' : '/therapist/notificacoes';
|
||||
router.push(target);
|
||||
store.drawerOpen = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
-->
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import { formatDistanceToNow } from 'date-fns';
|
||||
import { ptBR } from 'date-fns/locale';
|
||||
import { useNotificationStore } from '@/stores/notificationStore';
|
||||
@@ -30,6 +30,7 @@ const props = defineProps({
|
||||
const emit = defineEmits(['read', 'archive']);
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const store = useNotificationStore();
|
||||
const conversationDrawer = useConversationDrawerStore();
|
||||
const tenantStore = useTenantStore();
|
||||
@@ -52,6 +53,32 @@ const DEEPLINK_ALIASES = {
|
||||
'/conversas': { therapist: '/therapist/conversas', clinic_admin: '/admin/conversas' }
|
||||
};
|
||||
|
||||
// Mapeamento de slug "última parte da rota" → seção Melissa equivalente.
|
||||
// Usado quando o user está no layout Melissa (/melissa/*) pra evitar que
|
||||
// uma notificação o jogue pro layout rail (rota do role) e perca o overlay.
|
||||
// Slugs cobertos: páginas dedicadas + embeds (financeiro, documentos, etc).
|
||||
const MELISSA_SLUG_MAP = {
|
||||
agenda: 'agenda',
|
||||
conversas: 'conversas',
|
||||
patients: 'pacientes',
|
||||
pacientes: 'pacientes',
|
||||
medicos: 'medicos',
|
||||
recorrencias: 'recorrencias',
|
||||
compromissos: 'compromissos',
|
||||
grupos: 'grupos',
|
||||
tags: 'tags',
|
||||
'cadastros-recebidos': 'cadastros-recebidos',
|
||||
financeiro: 'financeiro',
|
||||
'financeiro-lancamentos': 'financeiro-lancamentos',
|
||||
documentos: 'documentos',
|
||||
'documentos-templates': 'documentos-templates',
|
||||
'agendamentos-recebidos': 'agendamentos-recebidos',
|
||||
'online-scheduling': 'online-scheduling',
|
||||
relatorios: 'relatorios',
|
||||
notificacoes: 'notificacoes',
|
||||
'link-externo': 'link-externo'
|
||||
};
|
||||
|
||||
function resolveDeeplink(link) {
|
||||
if (!link || typeof link !== 'string') return link;
|
||||
const alias = DEEPLINK_ALIASES[link];
|
||||
@@ -60,6 +87,22 @@ function resolveDeeplink(link) {
|
||||
return alias[role] || alias.therapist;
|
||||
}
|
||||
|
||||
// Se o user está em /melissa/*, traduz o destino pra equivalente Melissa
|
||||
// quando possível. Pra rotas sem mapping conhecido, retorna o path original
|
||||
// (vai navegar pro layout rail — caso raro, geralmente é uma rota muito
|
||||
// específica que não tem versão Melissa ainda).
|
||||
function applyMelissaContext(path) {
|
||||
if (!path || typeof path !== 'string') return path;
|
||||
if (path.startsWith('/melissa')) return path; // já é Melissa
|
||||
if (!route.path?.startsWith('/melissa')) return path; // user não está em Melissa
|
||||
// Strip prefixos de role e pega o último segmento significativo
|
||||
const cleaned = path.replace(/^\/(therapist|admin|clinic|crm)/, '');
|
||||
const parts = cleaned.split('/').filter(Boolean);
|
||||
if (!parts.length) return path;
|
||||
const slug = MELISSA_SLUG_MAP[parts[parts.length - 1]] || MELISSA_SLUG_MAP[parts[0]];
|
||||
return slug ? `/melissa/${slug}` : path;
|
||||
}
|
||||
|
||||
const meta = computed(() => typeMap[props.item.type] || DEFAULT_TYPE);
|
||||
const isUnread = computed(() => !props.item.read_at);
|
||||
|
||||
@@ -128,8 +171,9 @@ async function handleRowClick() {
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: segue deeplink resolvido por alias
|
||||
const deeplink = resolveDeeplink(payload.deeplink);
|
||||
// Fallback: segue deeplink resolvido por alias e (se user está em
|
||||
// Melissa) traduzido pra equivalente do layout Melissa.
|
||||
const deeplink = applyMelissaContext(resolveDeeplink(payload.deeplink));
|
||||
if (deeplink) {
|
||||
router.push(deeplink);
|
||||
store.drawerOpen = false;
|
||||
@@ -150,7 +194,7 @@ async function handleOpenConversation(e) {
|
||||
function handleOpenDeeplink(e) {
|
||||
e.stopPropagation();
|
||||
const payload = props.item.payload || {};
|
||||
const deeplink = resolveDeeplink(payload.deeplink);
|
||||
const deeplink = applyMelissaContext(resolveDeeplink(payload.deeplink));
|
||||
if (deeplink) {
|
||||
router.push(deeplink);
|
||||
store.drawerOpen = false;
|
||||
|
||||
Reference in New Issue
Block a user