MelissaPaciente Fase 3: Tab Perfil completa (6 sections stacked + anchors)
EXTENSAO: src/features/patients/utils/patientFormatters.js - +5 formatters: pickField (compartilhado), onlyDigits, fmtCPF (000.000.000-00), fmtRG (passthrough), fmtPhoneMobile ((XX) 9XXXX-XXXX), fmtGender (Masculino/Feminino/Nao-binario/Outro), fmtMarital (Solteiro/Casado/ Divorciado/Viuvo/Uniao estavel). MELISSAPACIENTE.VUE — script - 30+ field computeds usando pickField (cobre snake_case + camelCase): birthValue, telefone/Alternativo, email/Alternativo, genero, estadoCivil, naturalidade, ondeNosConheceu, encaminhadoPor, observacoes, notasInternas + 8 campos de endereco + 5 dados adicionais + 4 responsavel. - groupNames/groupLabel/groupCountLabel pra bloco Origem. - scrollToProfileSection(key): liga sidebar sub-nav -> scrollIntoView do anchor #mpa-perfil-XXX. Em mobile fecha o drawer. MELISSAPACIENTE.VUE — Tab Perfil reescrita Diferente do PatientProntuario legacy que usa PrimeVue Accordion (1 painel aberto por vez), o Melissa nativo mostra os 6 cards stacked com scroll suave do sidebar sub-nav. Mais legivel em desktop, mais rapido de escanear. - 1. Informacoes Pessoais: 2-col com Dados de cadastro (nome/data nasc com idade inline/genero/estado civil/CPF/RG/naturalidade) + Contato + Origem (grupos/tags chips/onde nos conheceu/encaminhado por). tel: e mailto: links onde ha valor. Observacoes full-width quando preenchido. - 2. Endereco: grid 2-col com 8 fields. - 3. Dados Adicionais: grid 2-col com escolaridade/profissao/parente/grau/ tel parente. - 4. Responsavel: 1-col com nome/CPF/tel + observacao block textual. - 5. Anotacoes Internas: card com hint lock + textblock min-height. - 6. Sessoes: lista compacta scrollable (max-height 360px) com titulo/ data/duracao/modalidade chips + tag status. CSS: ~250L novos pros componentes (mpa-fields/field-row/field-grid-2/ field-block/sess/sess-list). Pattern visual Melissa: cards com label uppercase, separadores horizontais sutis, links primary, monospace pra CPF/RG/CEP. ESLint: 0 errors da minha mudanca. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -40,6 +40,82 @@ export function dash(v) {
|
||||
return s || '—';
|
||||
}
|
||||
|
||||
/**
|
||||
* Pega a primeira chave nao vazia de um objeto (snake_case ou camelCase).
|
||||
* Usado pra resolver discrepancias de schema (ex: 'data_nascimento' vs 'birth_date').
|
||||
*/
|
||||
export function pickField(obj, keys = []) {
|
||||
for (const k of keys) {
|
||||
const v = obj?.[k];
|
||||
if (v !== null && v !== undefined && String(v).trim()) return v;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function onlyDigits(v) {
|
||||
return String(v ?? '').replace(/\D/g, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Formata CPF: 00000000000 -> 000.000.000-00
|
||||
*/
|
||||
export function fmtCPF(v) {
|
||||
const d = onlyDigits(v);
|
||||
if (!d) return '—';
|
||||
if (d.length !== 11) return d;
|
||||
return `${d.slice(0, 3)}.${d.slice(3, 6)}.${d.slice(6, 9)}-${d.slice(9)}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formata RG (genericamente — varia por estado):
|
||||
* 00.000.000-0 / 0000000000 → mantem digitos com pontos a cada 3 a partir da direita.
|
||||
*/
|
||||
export function fmtRG(v) {
|
||||
const s = String(v ?? '').trim();
|
||||
if (!s) return '—';
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formata telefone celular pt-br: (XX) 9XXXX-XXXX ou (XX) XXXX-XXXX.
|
||||
*/
|
||||
export function fmtPhoneMobile(v) {
|
||||
const d = onlyDigits(v);
|
||||
if (!d) return '—';
|
||||
if (d.length === 11) return `(${d.slice(0, 2)}) ${d.slice(2, 7)}-${d.slice(7, 11)}`;
|
||||
if (d.length === 10) return `(${d.slice(0, 2)}) ${d.slice(2, 6)}-${d.slice(6, 10)}`;
|
||||
return d;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mapeia variantes de genero pra label legivel.
|
||||
*/
|
||||
export function fmtGender(v) {
|
||||
const s = String(v ?? '').trim();
|
||||
if (!s) return '—';
|
||||
const x = s.toLowerCase();
|
||||
if (['m', 'masc', 'masculino', 'male', 'man', 'homem'].includes(x)) return 'Masculino';
|
||||
if (['f', 'fem', 'feminino', 'female', 'woman', 'mulher'].includes(x)) return 'Feminino';
|
||||
if (['nb', 'nao-binario', 'não-binário', 'nonbinary', 'non-binary'].includes(x)) return 'Não-binário';
|
||||
if (['outro', 'other'].includes(x)) return 'Outro';
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mapeia variantes de estado civil pra label pt-br.
|
||||
*/
|
||||
export function fmtMarital(v) {
|
||||
const s = String(v ?? '').trim();
|
||||
if (!s) return '—';
|
||||
const x = s.toLowerCase();
|
||||
if (['solteiro', 'solteira', 'single'].includes(x)) return 'Solteiro(a)';
|
||||
if (['casado', 'casada', 'married'].includes(x)) return 'Casado(a)';
|
||||
if (['divorciado', 'divorciada', 'divorced'].includes(x)) return 'Divorciado(a)';
|
||||
if (['viuvo', 'viúva', 'viuvo(a)', 'widowed'].includes(x)) return 'Viúvo(a)';
|
||||
if (['uniao estavel', 'união estável', 'civil union'].includes(x)) return 'União estável';
|
||||
return s;
|
||||
}
|
||||
|
||||
export function fmtDateBR(v) {
|
||||
const d = parseDateLoose(v);
|
||||
if (!d) return v ? dash(v) : '—';
|
||||
|
||||
Reference in New Issue
Block a user