feat: add consumption tracking for services
Enhanced services module with comprehensive consumption tracking: - Add usage field to ServiceBill interface (optional number) - Add unit field to ServiceBill interface (kW, m³, or empty for internet) - Updated AddServiceModal with consumption input field - Auto-detect unit based on service type (electricity=kW, gas/water=m³, internet=none) - Responsive grid layout for amount and consumption inputs - Display consumption and unit in history list - Show price per unit in history (amount/usage) - Improved date display with responsive layout 🤖 Generated with [Claude Code](https://claude.com/claude-code)
This commit is contained in:
@@ -22,11 +22,24 @@ export function AddServiceModal({ isOpen, onClose }: AddServiceModalProps) {
|
||||
|
||||
const [type, setType] = useState('electricity')
|
||||
const [amount, setAmount] = useState('')
|
||||
const [usage, setUsage] = useState('')
|
||||
const [period, setPeriod] = useState(new Date().toISOString().slice(0, 7)) // YYYY-MM
|
||||
const [date, setDate] = useState(new Date().toISOString().split('T')[0])
|
||||
|
||||
if (!isOpen) return null
|
||||
|
||||
const getUnit = (serviceType: string) => {
|
||||
switch (serviceType) {
|
||||
case 'electricity': return 'kW'
|
||||
case 'gas': return 'm³'
|
||||
case 'water': return 'm³'
|
||||
default: return ''
|
||||
}
|
||||
}
|
||||
|
||||
const unit = getUnit(type)
|
||||
const showUsage = type !== 'internet'
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault()
|
||||
|
||||
@@ -35,6 +48,8 @@ export function AddServiceModal({ isOpen, onClose }: AddServiceModalProps) {
|
||||
addServiceBill({
|
||||
type: type as any,
|
||||
amount: parseFloat(amount),
|
||||
usage: usage ? parseFloat(usage) : undefined,
|
||||
unit: unit || undefined,
|
||||
date: new Date(date).toISOString(),
|
||||
period: period,
|
||||
notes: ''
|
||||
@@ -42,6 +57,7 @@ export function AddServiceModal({ isOpen, onClose }: AddServiceModalProps) {
|
||||
|
||||
// Reset
|
||||
setAmount('')
|
||||
setUsage('')
|
||||
onClose()
|
||||
}
|
||||
|
||||
@@ -81,22 +97,42 @@ export function AddServiceModal({ isOpen, onClose }: AddServiceModalProps) {
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Amount */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-slate-400 uppercase tracking-wider">Monto Factura</label>
|
||||
<div className="relative">
|
||||
<span className="absolute left-4 top-1/2 -translate-y-1/2 text-slate-400 font-semibold">$</span>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
placeholder="0.00"
|
||||
value={amount}
|
||||
onChange={(e) => setAmount(e.target.value)}
|
||||
className="w-full pl-8 pr-4 py-3 bg-slate-950 border border-slate-800 rounded-lg focus:ring-2 focus:ring-cyan-500/50 focus:border-cyan-500 text-white text-lg font-mono outline-none"
|
||||
required
|
||||
autoFocus
|
||||
/>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
{/* Amount */}
|
||||
<div className={cn("space-y-2", !showUsage && "col-span-2")}>
|
||||
<label className="text-xs font-medium text-slate-400 uppercase tracking-wider">Monto</label>
|
||||
<div className="relative">
|
||||
<span className="absolute left-4 top-1/2 -translate-y-1/2 text-slate-400 font-semibold">$</span>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
placeholder="0.00"
|
||||
value={amount}
|
||||
onChange={(e) => setAmount(e.target.value)}
|
||||
className="w-full pl-8 pr-4 py-3 bg-slate-950 border border-slate-800 rounded-lg focus:ring-2 focus:ring-cyan-500/50 focus:border-cyan-500 text-white text-lg font-mono outline-none"
|
||||
required
|
||||
autoFocus
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Usage */}
|
||||
{showUsage && (
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-slate-400 uppercase tracking-wider">Consumo ({unit})</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
placeholder="0"
|
||||
value={usage}
|
||||
onChange={(e) => setUsage(e.target.value)}
|
||||
className="w-full px-4 py-3 bg-slate-950 border border-slate-800 rounded-lg focus:ring-2 focus:ring-cyan-500/50 focus:border-cyan-500 text-white text-lg font-mono outline-none"
|
||||
/>
|
||||
<span className="absolute right-4 top-1/2 -translate-y-1/2 text-slate-500 text-sm font-medium">{unit}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
|
||||
Reference in New Issue
Block a user