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:
Leonardo
2026-03-24 21:26:58 -03:00
parent a89d1f5560
commit 53a4980396
453 changed files with 121427 additions and 174407 deletions
+127 -136
View File
@@ -14,177 +14,168 @@
| © 2026 — Todos os direitos reservados
|--------------------------------------------------------------------------
*/
import { createApp } from 'vue'
import App from './App.vue'
import router from '@/router'
import { pinia } from '@/plugins/pinia' // ← singleton criado antes do router
import { setOnSignedOut, initSession, listenAuthChanges, refreshSession } from '@/app/session'
import { createApp } from 'vue';
import App from './App.vue';
import router from '@/router';
import { pinia } from '@/plugins/pinia'; // ← singleton criado antes do router
import { setOnSignedOut, initSession, listenAuthChanges, refreshSession } from '@/app/session';
import Aura from '@primeuix/themes/aura'
import PrimeVue from 'primevue/config'
import ConfirmationService from 'primevue/confirmationservice'
import ToastService from 'primevue/toastservice'
import AppLoadingPhrases from '@/components/ui/AppLoadingPhrases.vue'
import LoadedPhraseBlock from '@/components/ui/LoadedPhraseBlock.vue'
import Aura from '@primeuix/themes/aura';
import PrimeVue from 'primevue/config';
import ConfirmationService from 'primevue/confirmationservice';
import ToastService from 'primevue/toastservice';
import AppLoadingPhrases from '@/components/ui/AppLoadingPhrases.vue';
import LoadedPhraseBlock from '@/components/ui/LoadedPhraseBlock.vue';
// ── Componentes PrimeVue globais (≥ 10 usos no projeto) ──────────────────────
import Button from 'primevue/button'
import InputText from 'primevue/inputtext'
import Tag from 'primevue/tag'
import FloatLabel from 'primevue/floatlabel'
import Toast from 'primevue/toast'
import IconField from 'primevue/iconfield'
import InputIcon from 'primevue/inputicon'
import Divider from 'primevue/divider'
import Card from 'primevue/card'
import SelectButton from 'primevue/selectbutton'
import Dialog from 'primevue/dialog'
import DataTable from 'primevue/datatable'
import Column from 'primevue/column'
import ConfirmDialog from 'primevue/confirmdialog'
import Menu from 'primevue/menu'
import Button from 'primevue/button';
import InputText from 'primevue/inputtext';
import Tag from 'primevue/tag';
import FloatLabel from 'primevue/floatlabel';
import Toast from 'primevue/toast';
import IconField from 'primevue/iconfield';
import InputIcon from 'primevue/inputicon';
import Divider from 'primevue/divider';
import Card from 'primevue/card';
import SelectButton from 'primevue/selectbutton';
import Dialog from 'primevue/dialog';
import DataTable from 'primevue/datatable';
import Column from 'primevue/column';
import ConfirmDialog from 'primevue/confirmdialog';
import Menu from 'primevue/menu';
// ─────────────────────────────────────────────────────────────────────────────
import '@/assets/tailwind.css'
import '@/assets/styles.scss'
import '@/assets/tailwind.css';
import '@/assets/styles.scss';
import { supabase } from '@/lib/supabase/client'
import { supabase } from '@/lib/supabase/client';
// ✅ pt-BR (PrimeVue locale global)
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'
}
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'
};
async function applyUserThemeEarly () {
try {
const { data } = await supabase.auth.getUser()
const user = data?.user
if (!user) return
async function applyUserThemeEarly() {
try {
const { data } = await supabase.auth.getUser();
const user = data?.user;
if (!user) return;
const { data: settings, error } = await supabase
.from('user_settings')
.select('theme_mode')
.eq('user_id', user.id)
.maybeSingle()
const { data: settings, error } = await supabase.from('user_settings').select('theme_mode').eq('user_id', user.id).maybeSingle();
if (error || !settings?.theme_mode) return
if (error || !settings?.theme_mode) return;
const isDark = settings.theme_mode === 'dark'
document.documentElement.classList.toggle('app-dark', isDark)
localStorage.setItem('ui_theme_mode', settings.theme_mode)
} catch {}
const isDark = settings.theme_mode === 'dark';
document.documentElement.classList.toggle('app-dark', isDark);
localStorage.setItem('ui_theme_mode', settings.theme_mode);
} catch {}
}
setOnSignedOut(() => {
router.replace('/auth/login')
})
router.replace('/auth/login');
});
// ===== flags globais (debug/controle) =====
window.__sessionRefreshing = false
window.__fromVisibilityRefresh = false
window.__appBootstrapped = false
window.__sessionRefreshing = false;
window.__fromVisibilityRefresh = false;
window.__appBootstrapped = false;
// ========================================
let lastVisibilityRefreshAt = 0
let lastVisibilityRefreshAt = 0;
document.addEventListener('visibilitychange', async () => {
if (document.visibilityState !== 'visible') return
if (!window.__appBootstrapped) return
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 {}
lastVisibilityRefreshAt = now
console.log('[VISIBILITY] Aba voltou -> refreshSession()')
try {
window.__sessionRefreshing = true
window.__fromVisibilityRefresh = true
await refreshSession()
const now = Date.now();
if (now - lastVisibilityRefreshAt < 10_000) return;
if (window.__sessionRefreshing) return;
try {
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' } })
)
} else {
console.log('[VISIBILITY] refresh ok (skip event) - area não-tenant:', path)
}
const { data } = await supabase.auth.getUser();
if (!data?.user) return;
} catch {}
} finally {
window.__fromVisibilityRefresh = false
window.__sessionRefreshing = false
}
})
async function bootstrap () {
await initSession({ initial: true })
listenAuthChanges()
lastVisibilityRefreshAt = now;
console.log('[VISIBILITY] Aba voltou -> refreshSession()');
await applyUserThemeEarly()
try {
window.__sessionRefreshing = true;
window.__fromVisibilityRefresh = true;
const app = createApp(App)
await refreshSession();
// ✅ usa o pinia singleton — o mesmo que o router/guards já conhecem
app.use(pinia)
app.use(router)
try {
const path = router.currentRoute.value?.path || '';
const isTenantArea = path.startsWith('/admin') || path.startsWith('/therapist') || path.startsWith('/saas');
await router.isReady()
app.use(PrimeVue, {
locale: ptBR,
theme: {
preset: Aura,
options: { darkModeSelector: '.app-dark' }
if (isTenantArea) {
window.dispatchEvent(new CustomEvent('app:session-refreshed', { detail: { source: 'visibility' } }));
} else {
console.log('[VISIBILITY] refresh ok (skip event) - area não-tenant:', path);
}
} catch {}
} finally {
window.__fromVisibilityRefresh = false;
window.__sessionRefreshing = false;
}
})
});
app.use(ToastService)
app.use(ConfirmationService)
async function bootstrap() {
await initSession({ initial: true });
listenAuthChanges();
app.component('Button', Button)
app.component('InputText', InputText)
app.component('Tag', Tag)
app.component('FloatLabel', FloatLabel)
app.component('Toast', Toast)
app.component('IconField', IconField)
app.component('InputIcon', InputIcon)
app.component('Divider', Divider)
app.component('Card', Card)
app.component('SelectButton', SelectButton)
app.component('Dialog', Dialog)
app.component('DataTable', DataTable)
app.component('Column', Column)
app.component('ConfirmDialog', ConfirmDialog)
app.component('Menu', Menu)
app.component('AppLoadingPhrases', AppLoadingPhrases)
app.component('LoadedPhraseBlock', LoadedPhraseBlock)
await applyUserThemeEarly();
app.mount('#app')
const app = createApp(App);
window.__appBootstrapped = true
// ✅ usa o pinia singleton — o mesmo que o router/guards já conhecem
app.use(pinia);
app.use(router);
await router.isReady();
app.use(PrimeVue, {
locale: ptBR,
theme: {
preset: Aura,
options: { darkModeSelector: '.app-dark' }
}
});
app.use(ToastService);
app.use(ConfirmationService);
app.component('Button', Button);
app.component('InputText', InputText);
app.component('Tag', Tag);
app.component('FloatLabel', FloatLabel);
app.component('Toast', Toast);
app.component('IconField', IconField);
app.component('InputIcon', InputIcon);
app.component('Divider', Divider);
app.component('Card', Card);
app.component('SelectButton', SelectButton);
app.component('Dialog', Dialog);
app.component('DataTable', DataTable);
app.component('Column', Column);
app.component('ConfirmDialog', ConfirmDialog);
app.component('Menu', Menu);
app.component('AppLoadingPhrases', AppLoadingPhrases);
app.component('LoadedPhraseBlock', LoadedPhraseBlock);
app.mount('#app');
window.__appBootstrapped = true;
}
bootstrap()
bootstrap();