Correcao Sidebar Classico e Rail, Correcao Layout, Ajuste de Breakpoint para Tailwind, Ajuste AppTopbar, Ajuste Menu PopOver, Recriado Paleta de Cores, Inserido algumas animações leves, Reajuste Cor items NOVOS da tabela, Drawer Ajuda Corrigido no Logout, Whatsapp, sms, email, recursos extras
This commit is contained in:
+214
-247
@@ -15,332 +15,299 @@
|
||||
|--------------------------------------------------------------------------
|
||||
-->
|
||||
<script setup>
|
||||
import { useLayout } from '@/layout/composables/layout'
|
||||
import { computed, ref, nextTick, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useLayout } from '@/layout/composables/layout';
|
||||
import { computed, ref, nextTick, onMounted } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import Popover from 'primevue/popover'
|
||||
import PatientCadastroDialog from '@/components/ui/PatientCadastroDialog.vue'
|
||||
import Popover from 'primevue/popover';
|
||||
import PatientCadastroDialog from '@/components/ui/PatientCadastroDialog.vue';
|
||||
|
||||
import { useTenantStore } from '@/stores/tenantStore'
|
||||
import { useEntitlementsStore } from '@/stores/entitlementsStore'
|
||||
import { useMenuBadges } from '@/composables/useMenuBadges'
|
||||
import { useTenantStore } from '@/stores/tenantStore';
|
||||
import { useEntitlementsStore } from '@/stores/entitlementsStore';
|
||||
import { useMenuBadges } from '@/composables/useMenuBadges';
|
||||
|
||||
const { layoutState, isDesktop } = useLayout()
|
||||
const router = useRouter()
|
||||
const pop = ref(null)
|
||||
const { layoutState, isDesktop } = useLayout();
|
||||
const router = useRouter();
|
||||
const pop = ref(null);
|
||||
|
||||
const tenantStore = useTenantStore()
|
||||
const entitlementsStore = useEntitlementsStore()
|
||||
const menuBadges = useMenuBadges()
|
||||
const tenantStore = useTenantStore();
|
||||
const entitlementsStore = useEntitlementsStore();
|
||||
const menuBadges = useMenuBadges();
|
||||
|
||||
function menuBadgeLabel (item) {
|
||||
const key = item?.badgeKey
|
||||
if (!key) return null
|
||||
const val = menuBadges[key]?.value || 0
|
||||
if (!val) return null
|
||||
return key === 'agendaHoje' ? `${val} hoje` : String(val)
|
||||
function menuBadgeLabel(item) {
|
||||
const key = item?.badgeKey;
|
||||
if (!key) return null;
|
||||
const val = menuBadges[key]?.value || 0;
|
||||
if (!val) return null;
|
||||
return key === 'agendaHoje' ? `${val} hoje` : String(val);
|
||||
}
|
||||
|
||||
const emit = defineEmits(['quick-create'])
|
||||
const emit = defineEmits(['quick-create']);
|
||||
|
||||
const props = defineProps({
|
||||
item: { type: Object, default: () => ({}) },
|
||||
root: { type: Boolean, default: false },
|
||||
parentPath: { type: String, default: null }
|
||||
})
|
||||
item: { type: Object, default: () => ({}) },
|
||||
root: { type: Boolean, default: false },
|
||||
parentPath: { type: String, default: null }
|
||||
});
|
||||
|
||||
const fullPath = computed(() =>
|
||||
props.item?.path
|
||||
? (props.parentPath ? props.parentPath + props.item.path : props.item.path)
|
||||
: null
|
||||
)
|
||||
const fullPath = computed(() => (props.item?.path ? (props.parentPath ? props.parentPath + props.item.path : props.item.path) : null));
|
||||
|
||||
// ==============================
|
||||
// Visible: boolean OU function() -> boolean
|
||||
// ==============================
|
||||
const isVisible = computed(() => {
|
||||
const v = props.item?.visible
|
||||
if (typeof v === 'function') return !!v()
|
||||
if (v === undefined || v === null) return true
|
||||
return v !== false
|
||||
})
|
||||
const v = props.item?.visible;
|
||||
if (typeof v === 'function') return !!v();
|
||||
if (v === undefined || v === null) return true;
|
||||
return v !== false;
|
||||
});
|
||||
|
||||
// ==============================
|
||||
// Helpers de rota: aceita string OU objeto
|
||||
// ==============================
|
||||
function toPath (to) {
|
||||
if (!to) return ''
|
||||
if (typeof to === 'string') return to
|
||||
try { return router.resolve(to).path || '' } catch { return '' }
|
||||
function toPath(to) {
|
||||
if (!to) return '';
|
||||
if (typeof to === 'string') return to;
|
||||
try {
|
||||
return router.resolve(to).path || '';
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
// ==============================
|
||||
// Active logic
|
||||
// ==============================
|
||||
function isSameRoute (current, target) {
|
||||
const cur = typeof current === 'string' ? current : toPath(current)
|
||||
const tar = typeof target === 'string' ? target : toPath(target)
|
||||
if (!cur || !tar) return false
|
||||
if (cur === tar) return true
|
||||
// Prefix match apenas para paths com 2+ segmentos (ex: /therapist/patients).
|
||||
// Paths de 1 segmento (ex: /therapist) só ativam em match exato,
|
||||
// evitando que o Dashboard fique ativo em todas as sub-rotas.
|
||||
const segments = tar.split('/').filter(Boolean)
|
||||
return segments.length >= 2 && cur.startsWith(tar + '/')
|
||||
function isSameRoute(current, target) {
|
||||
const cur = typeof current === 'string' ? current : toPath(current);
|
||||
const tar = typeof target === 'string' ? target : toPath(target);
|
||||
if (!cur || !tar) return false;
|
||||
if (cur === tar) return true;
|
||||
// Prefix match apenas para paths com 2+ segmentos (ex: /therapist/patients).
|
||||
// Paths de 1 segmento (ex: /therapist) só ativam em match exato,
|
||||
// evitando que o Dashboard fique ativo em todas as sub-rotas.
|
||||
const segments = tar.split('/').filter(Boolean);
|
||||
return segments.length >= 2 && cur.startsWith(tar + '/');
|
||||
}
|
||||
|
||||
function hasActiveDescendant (node, currentPath) {
|
||||
const children = node?.items || []
|
||||
for (const child of children) {
|
||||
const childTo = toPath(child?.to)
|
||||
if (childTo && isSameRoute(currentPath, childTo)) return true
|
||||
if (child?.items?.length && hasActiveDescendant(child, currentPath)) return true
|
||||
}
|
||||
return false
|
||||
function hasActiveDescendant(node, currentPath) {
|
||||
const children = node?.items || [];
|
||||
for (const child of children) {
|
||||
const childTo = toPath(child?.to);
|
||||
if (childTo && isSameRoute(currentPath, childTo)) return true;
|
||||
if (child?.items?.length && hasActiveDescendant(child, currentPath)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const isActive = computed(() => {
|
||||
const current = typeof layoutState.activePath === 'string'
|
||||
? layoutState.activePath
|
||||
: toPath(layoutState.activePath)
|
||||
const current = typeof layoutState.activePath === 'string' ? layoutState.activePath : toPath(layoutState.activePath);
|
||||
|
||||
const item = props.item
|
||||
const item = props.item;
|
||||
|
||||
if (item?.items?.length) {
|
||||
if (hasActiveDescendant(item, current)) return true
|
||||
return item.path ? current.startsWith(fullPath.value || '') : false
|
||||
}
|
||||
if (item?.items?.length) {
|
||||
if (hasActiveDescendant(item, current)) return true;
|
||||
return item.path ? current.startsWith(fullPath.value || '') : false;
|
||||
}
|
||||
|
||||
const leafTo = toPath(item?.to)
|
||||
return leafTo ? isSameRoute(current, leafTo) : false
|
||||
})
|
||||
const leafTo = toPath(item?.to);
|
||||
return leafTo ? isSameRoute(current, leafTo) : false;
|
||||
});
|
||||
|
||||
// ==============================
|
||||
// ✅ PRO badge (agora 100% por entitlementsStore)
|
||||
// ==============================
|
||||
const showProBadge = computed(() => {
|
||||
const feature = props.item?.feature
|
||||
if (!props.item?.proBadge || !feature) return false
|
||||
const feature = props.item?.feature;
|
||||
if (!props.item?.proBadge || !feature) return false;
|
||||
|
||||
// se tiver a feature, NÃO é PRO (não mostra badge)
|
||||
// se NÃO tiver, mostra PRO
|
||||
try {
|
||||
return !entitlementsStore.has(feature)
|
||||
} catch {
|
||||
// se der erro, não mostra (evita "PRO fantasma")
|
||||
return false
|
||||
}
|
||||
})
|
||||
// se tiver a feature, NÃO é PRO (não mostra badge)
|
||||
// se NÃO tiver, mostra PRO
|
||||
try {
|
||||
return !entitlementsStore.has(feature);
|
||||
} catch {
|
||||
// se der erro, não mostra (evita "PRO fantasma")
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// 🔒 locked quando precisa mostrar PRO (ou seja, não tem feature)
|
||||
const isLocked = computed(() => !!(props.item?.proBadge && showProBadge.value))
|
||||
const isLocked = computed(() => !!(props.item?.proBadge && showProBadge.value));
|
||||
|
||||
const itemDisabled = computed(() => !!props.item?.disabled)
|
||||
const isBlocked = computed(() => itemDisabled.value || isLocked.value)
|
||||
const itemDisabled = computed(() => !!props.item?.disabled);
|
||||
const isBlocked = computed(() => itemDisabled.value || isLocked.value);
|
||||
|
||||
const labelText = computed(() => {
|
||||
return props.item?.label || ''
|
||||
})
|
||||
return props.item?.label || '';
|
||||
});
|
||||
|
||||
const itemClick = async (event, item) => {
|
||||
// 🔒 locked -> CTA upgrade
|
||||
if (props.item?.proBadge && isLocked.value) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
// 🔒 locked -> CTA upgrade
|
||||
if (props.item?.proBadge && isLocked.value) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
layoutState.overlayMenuActive = false
|
||||
layoutState.mobileMenuActive = false
|
||||
layoutState.menuHoverActive = false
|
||||
layoutState.overlayMenuActive = false;
|
||||
layoutState.mobileMenuActive = false;
|
||||
layoutState.menuHoverActive = false;
|
||||
|
||||
await nextTick()
|
||||
await router.push({ name: 'upgrade', query: { feature: props.item?.feature || '' } })
|
||||
return
|
||||
}
|
||||
|
||||
if (itemDisabled.value) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
return
|
||||
}
|
||||
|
||||
if (item?.command) item.command({ originalEvent: event, item })
|
||||
|
||||
if (item?.items?.length) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
|
||||
if (isActive.value) {
|
||||
layoutState.activePath = props.parentPath || ''
|
||||
} else {
|
||||
layoutState.activePath = fullPath.value || ''
|
||||
layoutState.menuHoverActive = true
|
||||
await nextTick();
|
||||
await router.push({ name: 'upgrade', query: { feature: props.item?.feature || '' } });
|
||||
return;
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (item?.to) layoutState.activePath = toPath(item.to)
|
||||
}
|
||||
if (itemDisabled.value) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
if (item?.command) item.command({ originalEvent: event, item });
|
||||
|
||||
if (item?.items?.length) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
if (isActive.value) {
|
||||
layoutState.activePath = props.parentPath || '';
|
||||
} else {
|
||||
layoutState.activePath = fullPath.value || '';
|
||||
layoutState.menuHoverActive = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (item?.to) layoutState.activePath = toPath(item.to);
|
||||
};
|
||||
|
||||
const onMouseEnter = () => {
|
||||
if (isDesktop() && props.root && props.item?.items && layoutState.menuHoverActive) {
|
||||
layoutState.activePath = fullPath.value || ''
|
||||
}
|
||||
}
|
||||
if (isDesktop() && props.root && props.item?.items && layoutState.menuHoverActive) {
|
||||
layoutState.activePath = fullPath.value || '';
|
||||
}
|
||||
};
|
||||
|
||||
const showCadastroDialog = ref(false)
|
||||
const showCadastroDialog = ref(false);
|
||||
|
||||
/* ---------- POPUP + ---------- */
|
||||
function togglePopover (event) {
|
||||
if (isBlocked.value) return
|
||||
pop.value?.toggle(event)
|
||||
function togglePopover(event) {
|
||||
if (isBlocked.value) return;
|
||||
pop.value?.toggle(event);
|
||||
}
|
||||
|
||||
function closePopover () {
|
||||
try { pop.value?.hide() } catch {}
|
||||
function closePopover() {
|
||||
try {
|
||||
pop.value?.hide();
|
||||
} catch {}
|
||||
}
|
||||
|
||||
function abrirCadastroRapido () {
|
||||
closePopover()
|
||||
emit('quick-create', { entity: props.item?.quickCreateEntity || 'patient', mode: 'rapido' })
|
||||
function abrirCadastroRapido() {
|
||||
closePopover();
|
||||
emit('quick-create', { entity: props.item?.quickCreateEntity || 'patient', mode: 'rapido' });
|
||||
}
|
||||
|
||||
function irCadastroCompleto () {
|
||||
closePopover()
|
||||
function irCadastroCompleto() {
|
||||
closePopover();
|
||||
|
||||
layoutState.overlayMenuActive = false
|
||||
layoutState.mobileMenuActive = false
|
||||
layoutState.menuHoverActive = false
|
||||
layoutState.overlayMenuActive = false;
|
||||
layoutState.mobileMenuActive = false;
|
||||
layoutState.menuHoverActive = false;
|
||||
|
||||
showCadastroDialog.value = true
|
||||
showCadastroDialog.value = true;
|
||||
}
|
||||
|
||||
async function irLinkCadastro () {
|
||||
closePopover()
|
||||
async function irLinkCadastro() {
|
||||
closePopover();
|
||||
|
||||
layoutState.overlayMenuActive = false
|
||||
layoutState.mobileMenuActive = false
|
||||
layoutState.menuHoverActive = false
|
||||
layoutState.overlayMenuActive = false;
|
||||
layoutState.mobileMenuActive = false;
|
||||
layoutState.menuHoverActive = false;
|
||||
|
||||
await nextTick()
|
||||
const linkTo = props.item?.quickCreateLinkTo || '/therapist/patients/link-externo'
|
||||
router.push(linkTo)
|
||||
await nextTick();
|
||||
const linkTo = props.item?.quickCreateLinkTo || '/therapist/patients/link-externo';
|
||||
router.push(linkTo);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<PatientCadastroDialog v-if="item.quickCreate" v-model="showCadastroDialog" />
|
||||
<PatientCadastroDialog v-if="item.quickCreate" v-model="showCadastroDialog" />
|
||||
|
||||
<li v-show="isVisible" :class="{ 'layout-root-menuitem': root, 'active-menuitem': isActive }">
|
||||
<div v-if="root" class="layout-menuitem-root-text">
|
||||
{{ item.label }}
|
||||
</div>
|
||||
<li v-show="isVisible" :class="{ 'layout-root-menuitem': root, 'active-menuitem': isActive }">
|
||||
<div v-if="root" class="layout-menuitem-root-text">
|
||||
{{ item.label }}
|
||||
</div>
|
||||
|
||||
<div v-if="!root" class="flex align-items-center justify-content-between w-full">
|
||||
<component
|
||||
:is="item.to && !item.items ? 'router-link' : 'a'"
|
||||
v-bind="item.to && !item.items ? { to: item.to } : { href: item.url }"
|
||||
@click="itemClick($event, item)"
|
||||
:class="[item.class, isBlocked ? 'opacity-60 cursor-pointer' : '', { 'active-route': isActive && !item.items }]"
|
||||
:target="item.target"
|
||||
tabindex="0"
|
||||
@mouseenter="onMouseEnter"
|
||||
class="flex align-items-center flex-1"
|
||||
:aria-disabled="isBlocked ? 'true' : 'false'"
|
||||
>
|
||||
<i :class="item.icon" class="layout-menuitem-icon" />
|
||||
<div v-if="!root" class="flex align-items-center justify-content-between w-full">
|
||||
<component
|
||||
:is="item.to && !item.items ? 'router-link' : 'a'"
|
||||
v-bind="item.to && !item.items ? { to: item.to } : { href: item.url }"
|
||||
@click="itemClick($event, item)"
|
||||
:class="[item.class, isBlocked ? 'opacity-60 cursor-pointer' : '', { 'active-route': isActive && !item.items }]"
|
||||
:target="item.target"
|
||||
tabindex="0"
|
||||
@mouseenter="onMouseEnter"
|
||||
class="flex align-items-center flex-1"
|
||||
:aria-disabled="isBlocked ? 'true' : 'false'"
|
||||
>
|
||||
<i :class="item.icon" class="layout-menuitem-icon" />
|
||||
|
||||
<span class="layout-menuitem-text">
|
||||
{{ labelText }}
|
||||
</span>
|
||||
<span class="layout-menuitem-text">
|
||||
{{ labelText }}
|
||||
</span>
|
||||
|
||||
<!-- ✅ Badge PRO some quando tem entitlements -->
|
||||
<span
|
||||
v-if="item.proBadge && showProBadge"
|
||||
class="ml-2 text-xs px-2 py-0.5 rounded border border-[var(--surface-border)] opacity-80"
|
||||
>
|
||||
PRO
|
||||
</span>
|
||||
<!-- ✅ Badge PRO some quando tem entitlements -->
|
||||
<span v-if="item.proBadge && showProBadge" class="ml-2 text-xs px-2 py-0.5 rounded border border-[var(--surface-border)] opacity-80"> PRO </span>
|
||||
|
||||
<!-- Badge contador (agenda hoje / cadastros / agendamentos) -->
|
||||
<span
|
||||
v-if="menuBadgeLabel(item)"
|
||||
class="ml-auto text-[0.62rem] font-bold px-1.5 py-px rounded-full bg-[var(--primary-color)] text-white leading-none"
|
||||
>
|
||||
{{ menuBadgeLabel(item) }}
|
||||
</span>
|
||||
<!-- Badge contador (agenda hoje / cadastros / agendamentos) -->
|
||||
<span v-if="menuBadgeLabel(item)" class="ml-auto text-[0.62rem] font-bold px-1.5 py-px rounded-full bg-[var(--primary-color)] text-white leading-none">
|
||||
{{ menuBadgeLabel(item) }}
|
||||
</span>
|
||||
|
||||
<i v-if="item.items" class="pi pi-fw pi-angle-down layout-submenu-toggler" />
|
||||
</component>
|
||||
<i v-if="item.items" class="pi pi-fw pi-angle-down layout-submenu-toggler" />
|
||||
</component>
|
||||
|
||||
<Button
|
||||
v-if="item.quickCreate"
|
||||
icon="pi pi-plus"
|
||||
text
|
||||
rounded
|
||||
size="small"
|
||||
class="ml-2"
|
||||
:disabled="isBlocked"
|
||||
@click.stop="togglePopover"
|
||||
/>
|
||||
</div>
|
||||
<Button v-if="item.quickCreate" icon="pi pi-plus" text rounded size="small" class="ml-2" :disabled="isBlocked" @click.stop="togglePopover" />
|
||||
</div>
|
||||
|
||||
<Popover v-if="item.quickCreate" ref="pop">
|
||||
<div class="flex flex-col gap-0.5 min-w-[190px] py-0.5">
|
||||
<button
|
||||
class="flex items-center gap-2.5 px-3 py-2 rounded-md cursor-pointer border-0 bg-transparent text-left w-full transition-colors duration-100 hover:bg-[var(--surface-ground,#f8fafc)]"
|
||||
@click="abrirCadastroRapido"
|
||||
>
|
||||
<div class="w-7 h-7 rounded-md flex items-center justify-center flex-shrink-0 bg-indigo-500/10 text-indigo-500">
|
||||
<i class="pi pi-bolt text-xs" />
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-sm font-semibold text-[var(--text-color)]">Cadastro Rápido</div>
|
||||
<div class="text-[0.68rem] text-[var(--text-color-secondary)]">Nome, e-mail e telefone</div>
|
||||
</div>
|
||||
</button>
|
||||
<Popover v-if="item.quickCreate" ref="pop">
|
||||
<div class="flex flex-col gap-0.5 min-w-[190px] py-0.5">
|
||||
<button class="flex items-center gap-2.5 px-3 py-2 rounded-md cursor-pointer border-0 bg-transparent text-left w-full transition-colors duration-100 hover:bg-[var(--surface-ground,#f8fafc)]" @click="abrirCadastroRapido">
|
||||
<div class="w-7 h-7 rounded-md flex items-center justify-center flex-shrink-0 bg-indigo-500/10 text-indigo-500">
|
||||
<i class="pi pi-bolt text-xs" />
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-sm font-semibold text-[var(--text-color)]">Cadastro Rápido</div>
|
||||
<div class="text-[0.68rem] text-[var(--text-color-secondary)]">Nome, e-mail e telefone</div>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="flex items-center gap-2.5 px-3 py-2 rounded-md cursor-pointer border-0 bg-transparent text-left w-full transition-colors duration-100 hover:bg-[var(--surface-ground,#f8fafc)]"
|
||||
@click="irCadastroCompleto"
|
||||
>
|
||||
<div class="w-7 h-7 rounded-md flex items-center justify-center flex-shrink-0 bg-emerald-500/10 text-emerald-600">
|
||||
<i class="pi pi-user-plus text-xs" />
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-sm font-semibold text-[var(--text-color)]">Cadastro Completo</div>
|
||||
<div class="text-[0.68rem] text-[var(--text-color-secondary)]">Formulário detalhado</div>
|
||||
</div>
|
||||
</button>
|
||||
<button class="flex items-center gap-2.5 px-3 py-2 rounded-md cursor-pointer border-0 bg-transparent text-left w-full transition-colors duration-100 hover:bg-[var(--surface-ground,#f8fafc)]" @click="irCadastroCompleto">
|
||||
<div class="w-7 h-7 rounded-md flex items-center justify-center flex-shrink-0 bg-emerald-500/10 text-emerald-600">
|
||||
<i class="pi pi-user-plus text-xs" />
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-sm font-semibold text-[var(--text-color)]">Cadastro Completo</div>
|
||||
<div class="text-[0.68rem] text-[var(--text-color-secondary)]">Formulário detalhado</div>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<div class="mx-3 my-1 border-t border-[var(--surface-border,#e2e8f0)]" />
|
||||
<div class="mx-3 my-1 border-t border-[var(--surface-border,#e2e8f0)]" />
|
||||
|
||||
<button
|
||||
class="flex items-center gap-2.5 px-3 py-2 rounded-md cursor-pointer border-0 bg-transparent text-left w-full transition-colors duration-100 hover:bg-[var(--surface-ground,#f8fafc)]"
|
||||
@click="irLinkCadastro"
|
||||
>
|
||||
<div class="w-7 h-7 rounded-md flex items-center justify-center flex-shrink-0 bg-sky-500/10 text-sky-600">
|
||||
<i class="pi pi-link text-xs" />
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-sm font-semibold text-[var(--text-color)]">Link de Cadastro</div>
|
||||
<div class="text-[0.68rem] text-[var(--text-color-secondary)]">Enviar link ao paciente</div>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</Popover>
|
||||
<button class="flex items-center gap-2.5 px-3 py-2 rounded-md cursor-pointer border-0 bg-transparent text-left w-full transition-colors duration-100 hover:bg-[var(--surface-ground,#f8fafc)]" @click="irLinkCadastro">
|
||||
<div class="w-7 h-7 rounded-md flex items-center justify-center flex-shrink-0 bg-sky-500/10 text-sky-600">
|
||||
<i class="pi pi-link text-xs" />
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-sm font-semibold text-[var(--text-color)]">Link de Cadastro</div>
|
||||
<div class="text-[0.68rem] text-[var(--text-color-secondary)]">Enviar link ao paciente</div>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</Popover>
|
||||
|
||||
<Transition v-if="item.items" name="layout-submenu">
|
||||
<ul v-show="root ? true : isActive" class="layout-submenu">
|
||||
<app-menu-item
|
||||
v-for="child in item.items"
|
||||
:key="(child.to || '') + '|' + (child.path || '') + '|' + child.label"
|
||||
:item="child"
|
||||
:root="false"
|
||||
:parentPath="fullPath"
|
||||
@quick-create="emit('quick-create', $event)"
|
||||
/>
|
||||
</ul>
|
||||
</Transition>
|
||||
</li>
|
||||
</template>
|
||||
<Transition v-if="item.items" name="layout-submenu">
|
||||
<ul v-show="root ? true : isActive" class="layout-submenu">
|
||||
<app-menu-item v-for="child in item.items" :key="(child.to || '') + '|' + (child.path || '') + '|' + child.label" :item="child" :root="false" :parentPath="fullPath" @quick-create="emit('quick-create', $event)" />
|
||||
</ul>
|
||||
</Transition>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user