feat(F-133): completed feature
This commit is contained in:
@@ -50,32 +50,17 @@ export function PriceStockSection({ productId }: { productId?: string }) {
|
||||
const [eanMsg, setEanMsg] = useState('');
|
||||
|
||||
// Peso y compra mínima (F-102)
|
||||
// Peso se gestiona en gramos (UI: dropdown + custom). Se convierte a kg al persistir.
|
||||
// Peso se gestiona en gramos. La UI es un <input type="number" list="…"> con
|
||||
// <datalist> que ofrece los presets como sugerencias pero permite cualquier
|
||||
// valor (custom) sin necesidad de un segundo campo (F-133). Se convierte a
|
||||
// kg al persistir.
|
||||
const WEIGHT_PRESETS_GR = [100, 150, 200, 250, 300, 350, 500, 740] as const;
|
||||
const [unitWeightGr, setUnitWeightGr] = useState('1');
|
||||
const [customWeightGr, setCustomWeightGr] = useState('');
|
||||
const [, setCustomWeightGr] = useState(''); // legacy, mantenida para no romper el handler
|
||||
const [minPurchaseQty, setMinPurchaseQty] = useState('1');
|
||||
const [savingProductMeta, setSavingProductMeta] = useState(false);
|
||||
const [metaMsg, setMetaMsg] = useState('');
|
||||
|
||||
// Determina si el valor actual coincide con un preset o si requiere custom.
|
||||
const weightIsCustom = !WEIGHT_PRESETS_GR.map(String).includes(unitWeightGr);
|
||||
const weightPresetValue = weightIsCustom ? 'custom' : unitWeightGr;
|
||||
|
||||
const onWeightPresetChange = (value: string) => {
|
||||
if (value === 'custom') {
|
||||
// Mantén el valor actual en customWeightGr para que el usuario no pierda lo escrito.
|
||||
setCustomWeightGr(unitWeightGr || '');
|
||||
// Marca custom sin asignar un valor concreto hasta que el usuario edite.
|
||||
if (!WEIGHT_PRESETS_GR.map(String).includes(unitWeightGr)) {
|
||||
setUnitWeightGr('');
|
||||
}
|
||||
} else {
|
||||
setUnitWeightGr(value);
|
||||
setCustomWeightGr('');
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
taxApi.list().then(({ items }) => setTaxRates(items.filter((r) => r.active))).catch(() => {});
|
||||
}, []);
|
||||
@@ -369,29 +354,30 @@ export function PriceStockSection({ productId }: { productId?: string }) {
|
||||
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<div>
|
||||
<label className="block text-xs font-semibold text-gray-600 mb-1">Peso unitario (Gr)</label>
|
||||
<select
|
||||
value={weightPresetValue}
|
||||
onChange={(e) => onWeightPresetChange(e.target.value)}
|
||||
{/* F-133: input único con datalist. El usuario puede escribir cualquier
|
||||
valor (custom) o elegir uno de los presets del desplegable nativo
|
||||
del navegador. Sin segundo campo separado, sin romper el grid. */}
|
||||
<input
|
||||
type="number"
|
||||
list="weight-presets-list"
|
||||
min={1}
|
||||
max={100000}
|
||||
value={unitWeightGr}
|
||||
onChange={(e) => {
|
||||
setUnitWeightGr(e.target.value);
|
||||
setCustomWeightGr('');
|
||||
}}
|
||||
onBlur={saveProductMeta}
|
||||
onKeyDown={(e) => { if (e.key === 'Enter') saveProductMeta(); }}
|
||||
disabled={savingProductMeta || pending}
|
||||
placeholder="Gramos"
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-xl text-sm focus:ring-2 focus:ring-[#2D6A4F] outline-none bg-white disabled:opacity-50"
|
||||
>
|
||||
/>
|
||||
<datalist id="weight-presets-list">
|
||||
{WEIGHT_PRESETS_GR.map(g => (
|
||||
<option key={g} value={String(g)}>{g} g</option>
|
||||
<option key={g} value={g} label={`${g} g`} />
|
||||
))}
|
||||
<option value="custom">Personalizado…</option>
|
||||
</select>
|
||||
{weightIsCustom && (
|
||||
<input
|
||||
type="text" inputMode="decimal" value={customWeightGr || unitWeightGr}
|
||||
onChange={(e) => { setCustomWeightGr(e.target.value); setUnitWeightGr(e.target.value); }}
|
||||
onBlur={saveProductMeta}
|
||||
onKeyDown={(e) => { if (e.key === 'Enter') saveProductMeta(); }}
|
||||
disabled={savingProductMeta || pending}
|
||||
placeholder="Gramos"
|
||||
className="mt-2 w-full px-3 py-2 border border-gray-300 rounded-xl text-sm focus:ring-2 focus:ring-[#2D6A4F] outline-none bg-white disabled:opacity-50"
|
||||
/>
|
||||
)}
|
||||
</datalist>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs font-semibold text-gray-600 mb-1">Compra mínima (uds.)</label>
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user