feat(03-01): enhance InlineEditCell with pencil icon hover affordance and save/error callbacks
- Add Pencil icon in display mode (opacity-0, group-hover:opacity-100) - Add onSaveSuccess optional callback fired after successful save - Add onSaveError optional callback fired + value reverted on save failure - Wrap onSave in try/catch in handleBlur
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
|
import { Pencil } from 'lucide-react'
|
||||||
import { TableCell } from '@/components/ui/table'
|
import { TableCell } from '@/components/ui/table'
|
||||||
import { Input } from '@/components/ui/input'
|
import { Input } from '@/components/ui/input'
|
||||||
import { formatCurrency } from '@/lib/format'
|
import { formatCurrency } from '@/lib/format'
|
||||||
@@ -8,10 +9,12 @@ interface InlineEditCellProps {
|
|||||||
value: number
|
value: number
|
||||||
currency: string
|
currency: string
|
||||||
onSave: (value: number) => Promise<void>
|
onSave: (value: number) => Promise<void>
|
||||||
|
onSaveSuccess?: () => void
|
||||||
|
onSaveError?: () => void
|
||||||
className?: string
|
className?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export function InlineEditCell({ value, currency, onSave, className }: InlineEditCellProps) {
|
export function InlineEditCell({ value, currency, onSave, onSaveSuccess, onSaveError, className }: InlineEditCellProps) {
|
||||||
const [editing, setEditing] = useState(false)
|
const [editing, setEditing] = useState(false)
|
||||||
const [inputValue, setInputValue] = useState(String(value))
|
const [inputValue, setInputValue] = useState(String(value))
|
||||||
|
|
||||||
@@ -23,7 +26,13 @@ export function InlineEditCell({ value, currency, onSave, className }: InlineEdi
|
|||||||
const handleBlur = async () => {
|
const handleBlur = async () => {
|
||||||
const num = parseFloat(inputValue)
|
const num = parseFloat(inputValue)
|
||||||
if (!isNaN(num) && num !== value) {
|
if (!isNaN(num) && num !== value) {
|
||||||
await onSave(num)
|
try {
|
||||||
|
await onSave(num)
|
||||||
|
onSaveSuccess?.()
|
||||||
|
} catch {
|
||||||
|
setInputValue(String(value))
|
||||||
|
onSaveError?.()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
setEditing(false)
|
setEditing(false)
|
||||||
}
|
}
|
||||||
@@ -49,10 +58,14 @@ export function InlineEditCell({ value, currency, onSave, className }: InlineEdi
|
|||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<span
|
<span
|
||||||
className="cursor-pointer rounded px-2 py-1 hover:bg-muted"
|
className="group flex cursor-pointer items-center justify-end gap-1 rounded px-2 py-1 hover:bg-muted"
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
>
|
>
|
||||||
{formatCurrency(value, currency)}
|
{formatCurrency(value, currency)}
|
||||||
|
<Pencil
|
||||||
|
data-testid="pencil-icon"
|
||||||
|
className="size-3 opacity-0 transition-opacity duration-150 group-hover:opacity-100 text-muted-foreground"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|||||||
Reference in New Issue
Block a user