Skip to content

Commit 94e7f88

Browse files
committed
Formato de decimales del modal de precios + rotulo sin cortar
Merge normal, nunca squash.
2 parents d694e0e + 419d386 commit 94e7f88

2 files changed

Lines changed: 27 additions & 7 deletions

File tree

src/lib/format.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,19 @@ export function fmtMoney(x: unknown): string {
3434
return isNum(x) ? `${Number(x).toFixed(2).replace('.', ',')} €` : DASH
3535
}
3636

37+
/** Cifra en formato español SIN unidad: `15,90`. Ausente → '' (cadena vacía,
38+
* no '—'): esto se usa para SEMBRAR CAMPOS EDITABLES, y un guion dentro de un
39+
* input no es un valor, es basura que el usuario tiene que borrar.
40+
*
41+
* Existe porque faltaba el hueco evidente entre fmtNum (punto, para cálculo y
42+
* depuración) y fmtMoney/fmtPct (coma, pero con unidad pegada). Un input de
43+
* precio necesita justo lo de en medio: coma, dos decimales, sin símbolo.
44+
* Sembrar con String(n) daba "15.9" al lado de un "15,90 €" — dos formatos en
45+
* la misma pantalla, y el crudo era el del campo que se edita. */
46+
export function fmtNumEs(x: unknown, dp = 2): string {
47+
return isNum(x) ? Number(x).toFixed(dp).replace('.', ',') : ''
48+
}
49+
3750
/** Cantidad/gramaje del escandallo con `dp` decimales (punto). Ausente → '—'. */
3851
export function fmtQty(x: unknown, dp = 3): string {
3952
return isNum(x) ? Number(x).toFixed(dp) : DASH

src/modules/kitchen/components/EditPricesModal.tsx

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ import {
5858
import { updateMenuItem } from '@/modules/kitchen/services/menuItemService'
5959
import { useVisibleLocations } from '@/modules/multitenancy/hooks/useVisibleLocations'
6060
import { listSalesChannels } from '@/modules/kitchen/services/channelRateService'
61-
import { fmtNum } from '@/lib/format'
61+
import { fmtNumEs } from '@/lib/format'
6262

6363
interface EditPricesModalProps {
6464
menuItemId: string
@@ -150,7 +150,7 @@ export default function EditPricesModal({
150150
// saber a qué cae la cascada si se borra el override del local (regla de
151151
// Julio: el botón "Volver a..." tiene que nombrar el destino real).
152152
const [brandChannels, setBrandChannels] = useState<ChannelEconomics[]>([])
153-
const [defaultPrice, setDefaultPrice] = useState<string>(String(basePrice ?? 0))
153+
const [defaultPrice, setDefaultPrice] = useState<string>(fmtNumEs(basePrice ?? 0))
154154
const [prices, setPrices] = useState<Record<string, string>>({})
155155
const [avail, setAvail] = useState<Record<string, boolean>>({})
156156
const [live, setLive] = useState<ChannelEconomics[]>([])
@@ -196,7 +196,7 @@ export default function EditPricesModal({
196196
const a: Record<string, boolean> = {}
197197
for (const r of rows) {
198198
const seedFromThisScope = selectedLocationId ? r.isLocationOverride : r.priceSource === 'override'
199-
p[r.channelId] = seedFromThisScope ? String(r.price) : ''
199+
p[r.channelId] = seedFromThisScope ? fmtNumEs(r.price) : ''
200200
a[r.channelId] = r.isAvailable
201201
}
202202
setPrices(p)
@@ -217,7 +217,7 @@ export default function EditPricesModal({
217217
const m: Record<string, string> = {}
218218
for (const r of channels) {
219219
const own = selectedLocationId ? r.isLocationOverride : r.priceSource === 'override'
220-
m[r.channelId] = own ? String(r.price) : ''
220+
m[r.channelId] = own ? fmtNumEs(r.price) : ''
221221
}
222222
return m
223223
}, [channels, selectedLocationId])
@@ -532,7 +532,7 @@ export default function EditPricesModal({
532532
<input
533533
value={own}
534534
onChange={(e) => setPrices((p) => ({ ...p, [ch.channelId]: e.target.value }))}
535-
placeholder={inheritedAmount !== null ? fmtNum(inheritedAmount) : ''}
535+
placeholder={inheritedAmount !== null ? fmtNumEs(inheritedAmount) : ''}
536536
inputMode="decimal"
537537
aria-label={`Precio de ${ch.channelName}`}
538538
className={`w-[122px] px-2.5 py-1.5 text-right font-mono tabular-nums text-[13px] rounded-lg
@@ -596,8 +596,12 @@ export default function EditPricesModal({
596596
Modo dominante arriba (más pedidos en 30d), el resto
597597
en sub-líneas; un modo con 0 pedidos se atenúa y lo dice. */}
598598
<div className="text-right">
599+
{/* Sin truncate: "Reparto de plataforma" en mayúsculas no cabe
600+
en 106px y salía "REPARTO DE PLATA…". Un rótulo cortado no
601+
identifica el modo, que es justo para lo que está. Envuelve
602+
en dos líneas; el ancho de la columna manda sobre el alto. */}
599603
{modeLabel && (
600-
<div className="text-[9px] uppercase tracking-[.06em] text-tinta-45 truncate">{modeLabel}</div>
604+
<div className="text-[9px] uppercase tracking-[.06em] text-tinta-45 leading-[1.15]">{modeLabel}</div>
601605
)}
602606
<div className={`font-mono tabular-nums text-[16px] font-semibold leading-tight ${marginTone(lv, margin)}`}>
603607
{fmtEur(margin)}
@@ -610,7 +614,10 @@ export default function EditPricesModal({
610614
{otherLive.map((o) => (
611615
<div key={`${o.channelId}-${o.serviceType ?? 'none'}`}
612616
className={`flex items-baseline justify-between gap-2 text-[10.5px] ${o.ordersLast30d === 0 ? 'opacity-[.42]' : ''}`}>
613-
<span className="text-tinta-45 truncate">
617+
{/* Igual que el rótulo dominante: envuelve en vez de
618+
cortar. Se conserva el space-between de la maqueta —
619+
la cifra sigue a la derecha, en la primera línea. */}
620+
<span className="text-tinta-45 leading-[1.15] min-w-0">
614621
{o.serviceType ? (SERVICE_TYPE_LABEL[o.serviceType] ?? o.serviceType) : '—'}
615622
{o.ordersLast30d === 0 ? ' · 0 ped.' : ''}
616623
</span>

0 commit comments

Comments
 (0)