mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-20 05:41:47 +00:00
47671d52e0
FE6: split the oversized page and panel components into thin layout shells plus colocated use<Component> hooks, .constants.ts, .helpers.ts (with tests) and presentational sub-components, following the established 'logic in a hook, render in slices' pattern. Behaviour, markup, classes and effect order are unchanged. Largest reductions: PackingListPanel 1598->42, FileManager 1055->36, AdminPage 1525->167, BudgetPanel 1266->146, JourneyDetailPage 2822->547, PlacesSidebar 945->66, CollabChat 861->106, CollabNotes 1417->532. DayPlanSidebar's drag-and-drop render body was left intact (ref-identity sensitive) and only its toolbar/modals/constants were extracted.
27 lines
1.2 KiB
TypeScript
27 lines
1.2 KiB
TypeScript
import { useState, useEffect } from 'react'
|
|
|
|
export function QuantityInput({ value, onSave }: { value: number; onSave: (qty: number) => void }) {
|
|
const [local, setLocal] = useState(String(value))
|
|
useEffect(() => setLocal(String(value)), [value])
|
|
|
|
const commit = () => {
|
|
const qty = Math.max(1, Math.min(999, Number(local) || 1))
|
|
setLocal(String(qty))
|
|
if (qty !== value) onSave(qty)
|
|
}
|
|
|
|
return (
|
|
<div style={{ display: 'flex', alignItems: 'center', gap: 2, border: '1px solid var(--border-primary)', borderRadius: 8, padding: '3px 6px', background: 'transparent', flexShrink: 0 }}>
|
|
<input
|
|
type="text" inputMode="numeric"
|
|
value={local}
|
|
onChange={e => setLocal(e.target.value.replace(/\D/g, ''))}
|
|
onBlur={commit}
|
|
onKeyDown={e => { if (e.key === 'Enter') { commit(); (e.target as HTMLInputElement).blur() } }}
|
|
style={{ width: 24, border: 'none', outline: 'none', background: 'transparent', fontSize: 12, textAlign: 'right', fontFamily: 'inherit', color: 'var(--text-secondary)', padding: 0 }}
|
|
/>
|
|
<span style={{ fontSize: 10, color: 'var(--text-faint)', fontWeight: 500 }}>x</span>
|
|
</div>
|
|
)
|
|
}
|