Documentos Pacientes, Template Documentos Pacientes Saas, Documentos prontuários, Documentos Externos, Visualização Externa, Permissão de Visualização, Render Otimização

This commit is contained in:
Leonardo
2026-03-30 14:08:19 -03:00
parent 0658e2e9bf
commit d088a89fb7
112 changed files with 115867 additions and 5266 deletions
+67 -48
View File
@@ -1,9 +1,18 @@
/*
|--------------------------------------------------------------------------
| Agência PSI (OTIMIZADO)
| Agência PSI — main.js
|--------------------------------------------------------------------------
*/
(function applyDarkModeImmediate() {
try {
const saved = localStorage.getItem('ui_theme_mode');
if (saved === 'dark' || saved === 'light') {
document.documentElement.classList.toggle('app-dark', saved === 'dark');
}
} catch { }
})();
import { pinia } from '@/plugins/pinia';
import router from '@/router';
import { createApp } from 'vue';
@@ -11,32 +20,25 @@ import App from './App.vue';
import { initSession, listenAuthChanges, refreshSession, setOnSignedOut } from '@/app/session';
// PrimeVue core
import Aura from '@primeuix/themes/aura';
import PrimeVue from 'primevue/config';
import { applyThemeEngine } from '@/theme/theme.options';
import { useLayout } from '@/layout/composables/layout';
// serviços (ok global)
import ConfirmationService from 'primevue/confirmationservice';
import ToastService from 'primevue/toastservice';
// ✅ SOMENTE COMPONENTES LEVES GLOBAIS
import Button from 'primevue/button';
import Divider from 'primevue/divider';
import InputText from 'primevue/inputtext';
import Tag from 'primevue/tag';
import Toast from 'primevue/toast';
// seus componentes leves
import AppLoadingPhrases from '@/components/ui/AppLoadingPhrases.vue';
import LoadedPhraseBlock from '@/components/ui/LoadedPhraseBlock.vue';
// estilos
import '@/assets/styles.scss';
import '@/assets/tailwind.css';
import { supabase } from '@/lib/supabase/client';
// locale
const ptBR = {
firstDayOfWeek: 1,
dayNames: ['domingo', 'segunda-feira', 'terça-feira', 'quarta-feira', 'quinta-feira', 'sexta-feira', 'sábado'],
@@ -50,29 +52,49 @@ const ptBR = {
dateFormat: 'dd/mm/yy'
};
// theme antecipado
async function applyUserThemeEarly() {
try {
const { data } = await supabase.auth.getUser();
const user = data?.user;
if (!user) return;
function syncThemeFromDB() {
const run = async () => {
try {
const { data } = await supabase.auth.getUser();
if (!data?.user) return;
const { data: settings } = await supabase.from('user_settings').select('theme_mode').eq('user_id', user.id).maybeSingle();
const { data: settings } = await supabase
.from('user_settings')
.select('theme_mode, preset, primary_color, surface_color, menu_mode')
.eq('user_id', data.user.id)
.maybeSingle();
if (!settings?.theme_mode) return;
if (!settings) return;
const isDark = settings.theme_mode === 'dark';
document.documentElement.classList.toggle('app-dark', isDark);
localStorage.setItem('ui_theme_mode', settings.theme_mode);
} catch {}
if (settings.theme_mode) {
document.documentElement.classList.toggle('app-dark', settings.theme_mode === 'dark');
localStorage.setItem('ui_theme_mode', settings.theme_mode);
}
const cfg = {};
if (settings.preset) cfg.preset = settings.preset;
if (settings.primary_color) cfg.primary = settings.primary_color;
if (settings.surface_color) cfg.surface = settings.surface_color;
if (settings.menu_mode) cfg.menuMode = settings.menu_mode;
if (Object.keys(cfg).length) {
try {
const prev = JSON.parse(localStorage.getItem('ui_theme_config') || '{}');
localStorage.setItem('ui_theme_config', JSON.stringify({ ...prev, ...cfg }));
} catch { }
}
} catch { }
};
if ('requestIdleCallback' in window) {
requestIdleCallback(run, { timeout: 4000 });
} else {
setTimeout(run, 300);
}
}
// logout
setOnSignedOut(() => {
router.replace('/auth/login');
});
setOnSignedOut(() => router.replace('/auth/login'));
// flags
window.__sessionRefreshing = false;
window.__fromVisibilityRefresh = false;
window.__appBootstrapped = false;
@@ -84,13 +106,15 @@ document.addEventListener('visibilitychange', async () => {
if (!window.__appBootstrapped) return;
const now = Date.now();
if (now - lastVisibilityRefreshAt < 10000) return;
if (now - lastVisibilityRefreshAt < 10_000) return;
if (window.__sessionRefreshing) return;
try {
const { data } = await supabase.auth.getUser();
if (!data?.user) return;
} catch {}
} catch {
return;
}
lastVisibilityRefreshAt = now;
@@ -100,15 +124,14 @@ document.addEventListener('visibilitychange', async () => {
await refreshSession();
const path = router.currentRoute.value?.path || '';
const isTenantArea = path.startsWith('/admin') || path.startsWith('/therapist') || path.startsWith('/saas');
const path = router.currentRoute.value?.path ?? '';
const isTenantArea =
path.startsWith('/admin') ||
path.startsWith('/therapist') ||
path.startsWith('/saas');
if (isTenantArea) {
window.dispatchEvent(
new CustomEvent('app:session-refreshed', {
detail: { source: 'visibility' }
})
);
window.dispatchEvent(new CustomEvent('app:session-refreshed', { detail: { source: 'visibility' } }));
}
} finally {
window.__fromVisibilityRefresh = false;
@@ -118,39 +141,35 @@ document.addEventListener('visibilitychange', async () => {
async function bootstrap() {
await initSession({ initial: true });
listenAuthChanges();
await applyUserThemeEarly();
const app = createApp(App);
app.use(pinia);
app.use(router);
await router.isReady();
listenAuthChanges();
syncThemeFromDB();
const { layoutConfig } = useLayout();
app.use(PrimeVue, {
locale: ptBR,
theme: {
preset: Aura,
options: { darkModeSelector: '.app-dark' }
}
theme: { options: { darkModeSelector: '.app-dark' } }
});
applyThemeEngine(layoutConfig);
app.use(ToastService);
app.use(ConfirmationService);
// ✅ globais leves
app.component('Button', Button);
app.component('InputText', InputText);
app.component('Tag', Tag);
app.component('Divider', Divider);
app.component('Toast', Toast);
app.component('AppLoadingPhrases', AppLoadingPhrases);
app.component('LoadedPhraseBlock', LoadedPhraseBlock);
app.mount('#app');
window.__appBootstrapped = true;
}