feat(ui): dropdowns viram modal com busca (SearchSelect) na Avaliação/GTO e Nova OS
Mesmo padrão do seletor de protético, generalizado para os demais dropdowns: - Componente SearchSelect (modal genérico: trigger + busca + lista filtrável por rótulo/hint). - LancarGTO: Especialidade/Área, Produto/Prótese, Procedimento, Dentista e Convênio/Credenciada — todos os <select> convertidos (0 selects restantes). - Nova OS (ProteseView): Produto e Dentista convertidos. - Cotação (RFQ): input de busca na lista de laboratórios a convidar (continua multi-seleção). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,7 @@ import {
|
||||
} from 'lucide-react';
|
||||
import { PageHeader } from '../components/PageHeader.tsx';
|
||||
import { ProteticoPicker } from '../components/ProteticoPicker.tsx';
|
||||
import { SearchSelect } from '../components/SearchSelect.tsx';
|
||||
import { HybridBackend } from '../services/backend.ts';
|
||||
import { Paciente, Dentista, Procedimento, Especialidade } from '../types.ts';
|
||||
import { useToast } from '../contexts/ToastContext.tsx';
|
||||
@@ -457,10 +458,10 @@ export const LancarGTO: React.FC = () => {
|
||||
<Stethoscope size={20} strokeWidth={3} /> 02. Especialidade
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
<select
|
||||
<SearchSelect
|
||||
value={selectedEsp}
|
||||
onChange={(e) => {
|
||||
setSelectedEsp(e.target.value);
|
||||
onChange={(v) => {
|
||||
setSelectedEsp(v);
|
||||
setSelectedProc(null);
|
||||
setSelectedDentes([]);
|
||||
setSelectedArco(null);
|
||||
@@ -468,11 +469,9 @@ export const LancarGTO: React.FC = () => {
|
||||
setProtValor('');
|
||||
setProtObs('');
|
||||
}}
|
||||
className="w-full p-4 bg-gray-50 border-2 border-gray-100 rounded-2xl font-black text-gray-700 text-sm focus:border-teal-400 outline-none transition-all uppercase"
|
||||
>
|
||||
<option value="">ESCOLHA A ÁREA...</option>
|
||||
{especialidades.map(es => <option key={es.id} value={es.id}>{es.nome}</option>)}
|
||||
</select>
|
||||
options={especialidades.map(es => ({ value: es.id, label: es.nome }))}
|
||||
placeholder="ESCOLHA A ÁREA..." title="Especialidade"
|
||||
/>
|
||||
|
||||
{selectedEsp && isProtese && (
|
||||
<div className="space-y-3">
|
||||
@@ -484,18 +483,17 @@ export const LancarGTO: React.FC = () => {
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<select
|
||||
<SearchSelect
|
||||
value={selectedProdutoId}
|
||||
onChange={(e) => {
|
||||
setSelectedProdutoId(e.target.value);
|
||||
const pr = labProdutos.find(p => p.id === e.target.value);
|
||||
onChange={(v) => {
|
||||
setSelectedProdutoId(v);
|
||||
const pr = labProdutos.find(p => p.id === v);
|
||||
setProtValor(pr ? String(pr.preco ?? '') : '');
|
||||
}}
|
||||
options={labProdutos.map(p => ({ value: p.id, label: p.nome, hint: `R$ ${Number(p.preco || 0).toFixed(2)}` }))}
|
||||
placeholder="ESCOLHA A PRÓTESE..." title="Produto do laboratório"
|
||||
className="w-full p-4 bg-white border-2 border-teal-100 rounded-2xl font-black text-gray-800 text-sm shadow-inner uppercase"
|
||||
>
|
||||
<option value="">ESCOLHA A PRÓTESE...</option>
|
||||
{labProdutos.map(p => <option key={p.id} value={p.id}>{p.nome} — R$ {Number(p.preco || 0).toFixed(2)}</option>)}
|
||||
</select>
|
||||
/>
|
||||
|
||||
{selectedProduto && (
|
||||
<>
|
||||
@@ -543,21 +541,20 @@ export const LancarGTO: React.FC = () => {
|
||||
<p className="text-[10px] font-bold text-amber-500 uppercase mt-1">Cadastre em Procedimentos para usá-lo aqui</p>
|
||||
</div>
|
||||
) : (
|
||||
<select
|
||||
<SearchSelect
|
||||
value={selectedProc?.id || ''}
|
||||
onChange={(e) => {
|
||||
const pr = procedimentos.find(p => p.id === e.target.value);
|
||||
onChange={(v) => {
|
||||
const pr = procedimentos.find(p => p.id === v);
|
||||
setSelectedProc(pr || null);
|
||||
setSelectedDentes([]);
|
||||
setSelectedArco(null);
|
||||
setArcoFace('');
|
||||
setArcoObs('');
|
||||
}}
|
||||
options={filteredProcedimentos.map(p => ({ value: p.id, label: p.nome }))}
|
||||
placeholder="BUSCAR PROCEDIMENTO" title="Procedimento"
|
||||
className="w-full p-4 bg-white border-2 border-teal-100 rounded-2xl font-black text-gray-800 text-sm shadow-inner uppercase"
|
||||
>
|
||||
<option value="">BUSCAR PROCEDIMENTO</option>
|
||||
{filteredProcedimentos.map(p => <option key={p.id} value={p.id}>{p.nome}</option>)}
|
||||
</select>
|
||||
/>
|
||||
)}
|
||||
|
||||
{selectedProc && (
|
||||
@@ -588,28 +585,23 @@ export const LancarGTO: React.FC = () => {
|
||||
<div className="flex items-center gap-3 text-[#2d6a4f] font-black text-base uppercase tracking-wider">
|
||||
<Check size={20} strokeWidth={3} className="bg-green-100 p-1 rounded-full text-green-700" /> 03. Dentista Executor
|
||||
</div>
|
||||
<select
|
||||
<SearchSelect
|
||||
value={store.dentista?.id || ''}
|
||||
onChange={(e) => {
|
||||
const d = dentistas.find(d => d.id === e.target.value);
|
||||
store.setDentista(d || null);
|
||||
}}
|
||||
onChange={(v) => { const d = dentistas.find(d => d.id === v); store.setDentista(d || null); }}
|
||||
options={dentistas.map(d => ({ value: d.id, label: d.nome }))}
|
||||
placeholder="SELECIONE O PROFISSIONAL" title="Dentista executor"
|
||||
className="w-full p-4 bg-gray-50 border-2 border-gray-100 rounded-2xl font-black text-gray-800 text-sm focus:border-green-500 outline-none transition-all uppercase"
|
||||
>
|
||||
<option value="">SELECIONE O PROFISSIONAL</option>
|
||||
{dentistas.map(d => <option key={d.id} value={d.id}>{d.nome}</option>)}
|
||||
</select>
|
||||
/>
|
||||
|
||||
<div className="pt-1">
|
||||
<label className="text-[11px] font-black text-gray-400 uppercase tracking-widest mb-1.5 block">Convênio / Credenciada</label>
|
||||
<select
|
||||
<SearchSelect
|
||||
value={store.credenciada || ''}
|
||||
onChange={(e) => store.setCredenciada(e.target.value)}
|
||||
onChange={(v) => store.setCredenciada(v)}
|
||||
options={convenios.map(c => ({ value: c.id, label: c.nome }))}
|
||||
placeholder="SELECIONE O CONVÊNIO" title="Convênio / Credenciada"
|
||||
className="w-full p-4 bg-gray-50 border-2 border-gray-100 rounded-2xl font-black text-gray-800 text-sm focus:border-green-500 outline-none transition-all uppercase"
|
||||
>
|
||||
<option value="">SELECIONE O CONVÊNIO</option>
|
||||
{convenios.map(c => <option key={c.id} value={c.id}>{c.nome}</option>)}
|
||||
</select>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user