feat(01-02): implement InlineEditCell shared component
- Shared TableCell with display/edit mode toggle - Calls onSave(number) on blur or Enter key - Skips save when value unchanged or NaN - Accepts className for amount coloring
This commit is contained in:
60
frontend/src/components/InlineEditCell.tsx
Normal file
60
frontend/src/components/InlineEditCell.tsx
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import { useState } from 'react'
|
||||||
|
import { TableCell } from '@/components/ui/table'
|
||||||
|
import { Input } from '@/components/ui/input'
|
||||||
|
import { formatCurrency } from '@/lib/format'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
|
interface InlineEditCellProps {
|
||||||
|
value: number
|
||||||
|
currency: string
|
||||||
|
onSave: (value: number) => Promise<void>
|
||||||
|
className?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function InlineEditCell({ value, currency, onSave, className }: InlineEditCellProps) {
|
||||||
|
const [editing, setEditing] = useState(false)
|
||||||
|
const [inputValue, setInputValue] = useState(String(value))
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
setInputValue(String(value))
|
||||||
|
setEditing(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleBlur = async () => {
|
||||||
|
const num = parseFloat(inputValue)
|
||||||
|
if (!isNaN(num) && num !== value) {
|
||||||
|
await onSave(num)
|
||||||
|
}
|
||||||
|
setEditing(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
handleBlur()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableCell className={cn('text-right', className)}>
|
||||||
|
{editing ? (
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
step="0.01"
|
||||||
|
value={inputValue}
|
||||||
|
onChange={(e) => setInputValue(e.target.value)}
|
||||||
|
onBlur={handleBlur}
|
||||||
|
onKeyDown={handleKeyDown}
|
||||||
|
className="ml-auto w-28 text-right"
|
||||||
|
autoFocus
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<span
|
||||||
|
className="cursor-pointer rounded px-2 py-1 hover:bg-muted"
|
||||||
|
onClick={handleClick}
|
||||||
|
>
|
||||||
|
{formatCurrency(value, currency)}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user