feat(admin-procedimentos): num_faces (dentística) e num_raizes (endodontia) + oculta ARCO
- Dropdown 1-5 de faces visível quando especialidade é Dentística - Dropdown 1-5 de raízes visível quando especialidade é Endodontia - Opção ARCO COMPLETO oculta nos dois casos (não se aplica) - Select de especialidade agora controlado — reseta num_faces/num_raizes ao trocar - DB: ALTER TABLE procedimentos ADD COLUMN num_faces INTEGER, num_raizes INTEGER (executado) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -242,6 +242,8 @@ export interface Procedimento {
|
||||
codigoInterno?: string;
|
||||
descricao?: string;
|
||||
descricao_mobile?: string;
|
||||
num_faces?: number;
|
||||
num_raizes?: number;
|
||||
especialidadeId: string;
|
||||
especialidadeNome: string;
|
||||
valorParticular: number;
|
||||
|
||||
@@ -463,6 +463,8 @@ export const ProcedimentosView: React.FC = () => {
|
||||
valorParticular: parseFloat(data.valorParticular),
|
||||
tipo_regiao: editingProcedimento?.tipo_regiao || 'GERAL',
|
||||
exige_face: editingProcedimento?.tipo_regiao === 'DENTE' ? !!editingProcedimento?.exige_face : false,
|
||||
num_faces: editingProcedimento?.num_faces || undefined,
|
||||
num_raizes: editingProcedimento?.num_raizes || undefined,
|
||||
valoresPlanos: planValues.map(pv => ({
|
||||
planoId: pv.planoId!,
|
||||
planoNome: planos?.find(p => p.id === pv.planoId)?.nome || '',
|
||||
@@ -523,6 +525,12 @@ export const ProcedimentosView: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const normEsp = (s: string) => s.normalize('NFD').replace(/[̀-ͯ]/g, '').toLowerCase();
|
||||
const procEspNome = normEsp(especialidades?.find(e => e.id === editingProcedimento?.especialidadeId)?.nome || '');
|
||||
const isDentistica = procEspNome.includes('dentistic');
|
||||
const isEndodontia = procEspNome.includes('endodont');
|
||||
const hideArco = isDentistica || isEndodontia;
|
||||
|
||||
return (
|
||||
<AdminSection title="PROCEDIMENTOS E VALORES" buttonLabel="NOVO PROCEDIMENTO" onButtonClick={() => { setEditingProcedimento({}); setIsModalOpen(true); }}>
|
||||
<div className="bg-white border border-gray-200 rounded-xl shadow-sm overflow-hidden">
|
||||
@@ -654,7 +662,24 @@ export const ProcedimentosView: React.FC = () => {
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="text-xs font-bold text-gray-500 uppercase">ESPECIALIDADE</label>
|
||||
<select name="especialidadeId" defaultValue={editingProcedimento?.especialidadeId} className="w-full border border-gray-300 rounded-lg p-2 bg-white uppercase-select" required>
|
||||
<select
|
||||
name="especialidadeId"
|
||||
value={editingProcedimento?.especialidadeId || ''}
|
||||
onChange={(e) => {
|
||||
const espId = e.target.value;
|
||||
const espNorm = normEsp(especialidades?.find(es => es.id === espId)?.nome || '');
|
||||
const willHide = espNorm.includes('dentistic') || espNorm.includes('endodont');
|
||||
setEditingProcedimento(prev => ({
|
||||
...prev,
|
||||
especialidadeId: espId,
|
||||
tipo_regiao: (willHide && prev?.tipo_regiao === 'ARCO') ? 'DENTE' : prev?.tipo_regiao,
|
||||
num_faces: undefined,
|
||||
num_raizes: undefined,
|
||||
}));
|
||||
}}
|
||||
className="w-full border border-gray-300 rounded-lg p-2 bg-white uppercase-select"
|
||||
required
|
||||
>
|
||||
<option value="">SELECIONE UMA ESPECIALIDADE</option>
|
||||
{especialidades?.map(e => <option key={e.id} value={e.id}>{e.nome}</option>)}
|
||||
</select>
|
||||
@@ -672,11 +697,11 @@ export const ProcedimentosView: React.FC = () => {
|
||||
|
||||
<div className="space-y-3">
|
||||
<label className="text-xs font-bold text-gray-700 uppercase">EXIGÊNCIA DE REGIÃO NO LANÇAMENTO</label>
|
||||
<div className="grid grid-cols-3 gap-2">
|
||||
<div className={`grid gap-2 ${hideArco ? 'grid-cols-2' : 'grid-cols-3'}`}>
|
||||
{[
|
||||
{ id: 'GERAL', label: 'PROCED. GERAL', desc: 'SEM ODONTOGRAMA' },
|
||||
{ id: 'DENTE', label: 'DENTE ESPECÍFICO', desc: 'LIBERA NÚMEROS' },
|
||||
{ id: 'ARCO', label: 'ARCO COMPLETO', desc: 'LIBERA AI / AS' }
|
||||
...(!hideArco ? [{ id: 'ARCO', label: 'ARCO COMPLETO', desc: 'LIBERA AI / AS' }] : [])
|
||||
].map((opt) => (
|
||||
<label
|
||||
key={opt.id}
|
||||
@@ -721,6 +746,42 @@ export const ProcedimentosView: React.FC = () => {
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isDentistica && (
|
||||
<div className="pt-2 animate-in slide-in-from-top-2 duration-200">
|
||||
<label className="text-[10px] font-black text-blue-700 uppercase tracking-widest mb-1.5 block">
|
||||
Nº de Faces (Dentística)
|
||||
</label>
|
||||
<select
|
||||
value={editingProcedimento?.num_faces || ''}
|
||||
onChange={(e) => setEditingProcedimento(prev => ({ ...prev, num_faces: e.target.value ? parseInt(e.target.value) : undefined }))}
|
||||
className="w-full border border-blue-200 rounded-lg p-2.5 bg-white text-sm font-bold text-gray-700 focus:border-blue-500 outline-none"
|
||||
>
|
||||
<option value="">NÃO DEFINIDO</option>
|
||||
{[1, 2, 3, 4, 5].map(n => (
|
||||
<option key={n} value={n}>{n} {n === 1 ? 'face' : 'faces'}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isEndodontia && (
|
||||
<div className="pt-2 animate-in slide-in-from-top-2 duration-200">
|
||||
<label className="text-[10px] font-black text-blue-700 uppercase tracking-widest mb-1.5 block">
|
||||
Nº de Raízes (Endodontia)
|
||||
</label>
|
||||
<select
|
||||
value={editingProcedimento?.num_raizes || ''}
|
||||
onChange={(e) => setEditingProcedimento(prev => ({ ...prev, num_raizes: e.target.value ? parseInt(e.target.value) : undefined }))}
|
||||
className="w-full border border-blue-200 rounded-lg p-2.5 bg-white text-sm font-bold text-gray-700 focus:border-blue-500 outline-none"
|
||||
>
|
||||
<option value="">NÃO DEFINIDO</option>
|
||||
{[1, 2, 3, 4, 5].map(n => (
|
||||
<option key={n} value={n}>{n} {n === 1 ? 'raiz' : 'raízes'}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="pt-4">
|
||||
|
||||
Reference in New Issue
Block a user