/* |-------------------------------------------------------------------------- | 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'; import App from './App.vue'; import { initSession, listenAuthChanges, refreshSession, setOnSignedOut } from '@/app/session'; import PrimeVue from 'primevue/config'; import { applyThemeEngine } from '@/theme/theme.options'; import { useLayout } from '@/layout/composables/layout'; import ConfirmationService from 'primevue/confirmationservice'; import ToastService from 'primevue/toastservice'; import Button from 'primevue/button'; import InputText from 'primevue/inputtext'; import Tag from 'primevue/tag'; import AppLoadingPhrases from '@/components/ui/AppLoadingPhrases.vue'; import LoadedPhraseBlock from '@/components/ui/LoadedPhraseBlock.vue'; import '@/assets/styles.scss'; import '@/assets/tailwind.css'; import { supabase } from '@/lib/supabase/client'; const ptBR = { firstDayOfWeek: 1, dayNames: ['domingo', 'segunda-feira', 'terça-feira', 'quarta-feira', 'quinta-feira', 'sexta-feira', 'sábado'], dayNamesShort: ['dom', 'seg', 'ter', 'qua', 'qui', 'sex', 'sáb'], dayNamesMin: ['D', 'S', 'T', 'Q', 'Q', 'S', 'S'], monthNames: ['janeiro', 'fevereiro', 'março', 'abril', 'maio', 'junho', 'julho', 'agosto', 'setembro', 'outubro', 'novembro', 'dezembro'], monthNamesShort: ['jan', 'fev', 'mar', 'abr', 'mai', 'jun', 'jul', 'ago', 'set', 'out', 'nov', 'dez'], today: 'Hoje', clear: 'Limpar', weekHeader: 'Sm', dateFormat: 'dd/mm/yy' }; 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, preset, primary_color, surface_color, menu_mode') .eq('user_id', data.user.id) .maybeSingle(); if (!settings) return; 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); } } setOnSignedOut(() => router.replace('/auth/login')); window.__sessionRefreshing = false; window.__fromVisibilityRefresh = false; window.__appBootstrapped = false; let lastVisibilityRefreshAt = 0; document.addEventListener('visibilitychange', async () => { if (document.visibilityState !== 'visible') return; if (!window.__appBootstrapped) return; const now = Date.now(); if (now - lastVisibilityRefreshAt < 10_000) return; if (window.__sessionRefreshing) return; try { const { data } = await supabase.auth.getUser(); if (!data?.user) return; } catch { return; } lastVisibilityRefreshAt = now; try { window.__sessionRefreshing = true; window.__fromVisibilityRefresh = true; await refreshSession(); 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' } })); } } finally { window.__fromVisibilityRefresh = false; window.__sessionRefreshing = false; } }); async function bootstrap() { await initSession({ initial: true }); const app = createApp(App); app.use(pinia); app.use(router); await router.isReady(); listenAuthChanges(); syncThemeFromDB(); const { layoutConfig } = useLayout(); app.use(PrimeVue, { locale: ptBR, theme: { options: { darkModeSelector: '.app-dark' } } }); applyThemeEngine(layoutConfig); app.use(ToastService); app.use(ConfirmationService); app.component('Button', Button); app.component('InputText', InputText); app.component('Tag', Tag); app.component('AppLoadingPhrases', AppLoadingPhrases); app.component('LoadedPhraseBlock', LoadedPhraseBlock); app.mount('#app'); window.__appBootstrapped = true; } bootstrap();