M1: features/medicos + features/insurance + ComponentCadastroRapido refactor
Modulo 1 da Fase 1 de padronizacao. Novos features/medicos (services + composable useMedicos) e features/insurance (idem). 3 cadastros rapidos (medicos, convenios, ComponentCadastroRapido + Insurance PlanQuickCreateDialog) migrados pra usar os composables novos — zero supabase.from() em UI components. TEST_ACCOUNTS extraido pra src/config/devTestAccounts.js. Topbar ganhou switcher de layout + atalhos M1 via novo useTopbarDevMenuExtras. M1.6 MelissaLayout 90 imports deferida pra sessao dedicada (memoria padronizacao_sweep). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Agência PSI
|
||||
|--------------------------------------------------------------------------
|
||||
| Arquivo: src/composables/useTopbarDevMenuExtras.js
|
||||
|
|
||||
| Extras DEV-only que aparecem dentro do mesmo botão "sliders" do topbar
|
||||
| (junto com o switcher de planos do useTopbarPlanMenu). Adiciona:
|
||||
|
|
||||
| 1) Switcher de layout (rail | melissa) — UPDATE em user_settings +
|
||||
| localStorage + hard reload pra router decidir redirect.
|
||||
|
|
||||
| 2) Atalhos rápidos pra testar M1.3 (ComponentCadastroRapido nos
|
||||
| diversos callers) e M1.1/M1.2 (CadastroRapidoMedico/Convenio).
|
||||
|
|
||||
| Visibilidade: assume que o caller só renderiza o menu se `showPlanDevMenu`
|
||||
| já estiver true (DEV + permissão). Não duplica essa lógica aqui.
|
||||
|
|
||||
| Uso em AppTopbar.vue / MelissaLayout.vue:
|
||||
| const { devExtrasModel } = useTopbarDevMenuExtras();
|
||||
| const combinedDevMenuModel = computed(() => [
|
||||
| ...planMenuModel.value,
|
||||
| { separator: true },
|
||||
| ...devExtrasModel.value
|
||||
| ]);
|
||||
| <Menu :model="combinedDevMenuModel" ... />
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
import { computed } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useToast } from 'primevue/usetoast';
|
||||
import { supabase } from '@/lib/supabase/client';
|
||||
import { useLayout } from '@/layout/composables/layout';
|
||||
|
||||
export function useTopbarDevMenuExtras() {
|
||||
const router = useRouter();
|
||||
const toast = useToast();
|
||||
const { layoutConfig } = useLayout();
|
||||
|
||||
const currentVariant = computed(() => layoutConfig.variant || 'classic');
|
||||
const isRailLike = computed(() => currentVariant.value === 'rail' || currentVariant.value === 'classic');
|
||||
const isMelissa = computed(() => currentVariant.value === 'melissa');
|
||||
|
||||
async function setLayoutAndReload(variant) {
|
||||
try {
|
||||
const { data, error: authErr } = await supabase.auth.getUser();
|
||||
if (authErr) throw authErr;
|
||||
const uid = data?.user?.id;
|
||||
if (!uid) throw new Error('Sem sessão.');
|
||||
|
||||
const { error } = await supabase
|
||||
.from('user_settings')
|
||||
.upsert(
|
||||
{
|
||||
user_id: uid,
|
||||
layout_variant: variant,
|
||||
updated_at: new Date().toISOString()
|
||||
},
|
||||
{ onConflict: 'user_id' }
|
||||
);
|
||||
if (error) throw error;
|
||||
|
||||
// Fast path: router.beforeEach/guards lêem localStorage antes do fetch
|
||||
try {
|
||||
localStorage.setItem('layout_variant', variant);
|
||||
} catch (_) {
|
||||
// ignore (Safari private mode etc.)
|
||||
}
|
||||
|
||||
toast.add({ severity: 'success', summary: `Layout: ${variant}`, life: 1200 });
|
||||
|
||||
// Hard reload pra router redirecionar pra raiz correta
|
||||
setTimeout(() => window.location.assign('/'), 250);
|
||||
} catch (e) {
|
||||
toast.add({
|
||||
severity: 'error',
|
||||
summary: 'Erro ao trocar layout',
|
||||
detail: e?.message || 'Falha desconhecida.',
|
||||
life: 4500
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function goto(path) {
|
||||
// router.push em vez de location.assign — mantém SPA + dev tools abertos.
|
||||
// Se o guard redirecionar (ex: Melissa mode bloqueia /therapist/...),
|
||||
// o usuário verá o redirect — sinal de que precisa trocar layout primeiro.
|
||||
router.push(path).catch(() => {});
|
||||
}
|
||||
|
||||
const devExtrasModel = computed(() => [
|
||||
// ─── Layout ────────────────────────────────────────
|
||||
{ label: 'Layout (DEV)', icon: 'pi pi-th-large', disabled: true },
|
||||
{
|
||||
label: isRailLike.value ? 'Rail (atual)' : 'Rail',
|
||||
icon: isRailLike.value ? 'pi pi-check' : 'pi pi-bars',
|
||||
disabled: isRailLike.value,
|
||||
command: () => setLayoutAndReload('rail')
|
||||
},
|
||||
{
|
||||
label: isMelissa.value ? 'Melissa (atual)' : 'Melissa',
|
||||
icon: isMelissa.value ? 'pi pi-check' : 'pi pi-window-maximize',
|
||||
disabled: isMelissa.value,
|
||||
command: () => setLayoutAndReload('melissa')
|
||||
},
|
||||
|
||||
{ separator: true },
|
||||
|
||||
// ─── Atalhos pra testar Módulo 1 ───────────────────
|
||||
{ label: 'Testar Módulo 1 (DEV)', icon: 'pi pi-bullseye', disabled: true },
|
||||
{
|
||||
label: '→ Cadastro Paciente (M1.1 + M1.2)',
|
||||
icon: 'pi pi-user-plus',
|
||||
command: () => goto('/therapist/patients/cadastro')
|
||||
},
|
||||
{
|
||||
label: '→ Lista de Pacientes (M1.3-E)',
|
||||
icon: 'pi pi-list',
|
||||
command: () => goto('/therapist/patients')
|
||||
},
|
||||
{
|
||||
label: '→ Melissa Agenda (M1.3-B)',
|
||||
icon: 'pi pi-calendar',
|
||||
command: () => goto('/melissa/agenda')
|
||||
},
|
||||
{
|
||||
label: '→ Melissa Pacientes (M1.3-B)',
|
||||
icon: 'pi pi-users',
|
||||
command: () => goto('/melissa/pacientes')
|
||||
}
|
||||
]);
|
||||
|
||||
return { devExtrasModel };
|
||||
}
|
||||
Reference in New Issue
Block a user