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:
+127
-136
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user