feat: Add edit button and modal for battery groups
Users can now edit battery group counts and notes via an edit button on each battery card. The edit modal allows updating available count, charging count, and notes. Changes: - Create EditBatteryModal component - Add edit button (pencil icon) to BatteryCard - Uses existing PATCH /api/batteries/[id] endpoint 🤖 Generated with [Qoder][https://qoder.com]
This commit is contained in:
parent
febdc8beab
commit
9d59024fed
|
|
@ -9,7 +9,8 @@ import { Input } from '@/components/ui/Input';
|
|||
import { Select } from '@/components/ui/Select';
|
||||
import { useToast } from '@/components/ui/Toast';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { Battery, BatteryCharging, Monitor, Trash2, ArrowRight } from 'lucide-react';
|
||||
import { Battery, BatteryCharging, Monitor, Trash2, ArrowRight, Pencil } from 'lucide-react';
|
||||
import { EditBatteryModal } from './EditBatteryModal';
|
||||
|
||||
interface Device {
|
||||
id: number;
|
||||
|
|
@ -36,6 +37,7 @@ export function BatteryCard({ battery, devices }: BatteryCardProps) {
|
|||
const router = useRouter();
|
||||
const { showToast } = useToast();
|
||||
const [actionModal, setActionModal] = useState<'charge' | 'available' | 'assign' | 'delete' | null>(null);
|
||||
const [showEditModal, setShowEditModal] = useState(false);
|
||||
const [count, setCount] = useState('1');
|
||||
const [deviceId, setDeviceId] = useState('');
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
|
@ -148,6 +150,14 @@ export function BatteryCard({ battery, devices }: BatteryCardProps) {
|
|||
</h3>
|
||||
<p className="text-sm text-slate-500">Total: {total} batteries</p>
|
||||
</div>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => setShowEditModal(true)}
|
||||
className="text-slate-400 hover:text-slate-600"
|
||||
>
|
||||
<Pencil className="w-4 h-4" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
|
|
@ -356,6 +366,13 @@ export function BatteryCard({ battery, devices }: BatteryCardProps) {
|
|||
</p>
|
||||
)}
|
||||
</Modal>
|
||||
|
||||
{/* Edit Modal */}
|
||||
<EditBatteryModal
|
||||
isOpen={showEditModal}
|
||||
onClose={() => setShowEditModal(false)}
|
||||
battery={battery}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,137 @@
|
|||
'use client';
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Button } from '@/components/ui/Button';
|
||||
import { Input } from '@/components/ui/Input';
|
||||
import { Modal } from '@/components/ui/Modal';
|
||||
import { useToast } from '@/components/ui/Toast';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
interface BatteryGroup {
|
||||
id: number;
|
||||
brandName: string;
|
||||
typeName: string;
|
||||
chemistryName: string;
|
||||
availableCount: number;
|
||||
chargingCount: number;
|
||||
inUseCount: number;
|
||||
notes: string | null;
|
||||
}
|
||||
|
||||
interface EditBatteryModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
battery: BatteryGroup | null;
|
||||
}
|
||||
|
||||
export function EditBatteryModal({ isOpen, onClose, battery }: EditBatteryModalProps) {
|
||||
const router = useRouter();
|
||||
const { showToast } = useToast();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [formData, setFormData] = useState({
|
||||
availableCount: '0',
|
||||
chargingCount: '0',
|
||||
notes: '',
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (battery) {
|
||||
setFormData({
|
||||
availableCount: battery.availableCount.toString(),
|
||||
chargingCount: battery.chargingCount.toString(),
|
||||
notes: battery.notes || '',
|
||||
});
|
||||
}
|
||||
}, [battery]);
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
if (!battery) return;
|
||||
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
const res = await fetch(`/api/batteries/${battery.id}`, {
|
||||
method: 'PATCH',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
availableCount: parseInt(formData.availableCount) || 0,
|
||||
chargingCount: parseInt(formData.chargingCount) || 0,
|
||||
notes: formData.notes || null,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
const error = await res.json();
|
||||
throw new Error(error.error || 'Failed to update battery');
|
||||
}
|
||||
|
||||
showToast('success', 'Battery group updated');
|
||||
onClose();
|
||||
router.refresh();
|
||||
} catch (error) {
|
||||
showToast('error', error instanceof Error ? error.message : 'Failed to update battery');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (!battery) return null;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
onClose={onClose}
|
||||
title="Edit Battery Group"
|
||||
footer={
|
||||
<div className="flex justify-end gap-3">
|
||||
<Button variant="secondary" onClick={onClose} disabled={loading}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button onClick={handleSubmit} disabled={loading}>
|
||||
{loading ? 'Saving...' : 'Save Changes'}
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
<div className="bg-slate-50 rounded-lg p-3 mb-4">
|
||||
<p className="text-sm text-slate-600">
|
||||
<span className="font-medium text-slate-900">
|
||||
{battery.brandName} {battery.typeName} ({battery.chemistryName})
|
||||
</span>
|
||||
</p>
|
||||
{battery.inUseCount > 0 && (
|
||||
<p className="text-xs text-slate-500 mt-1">
|
||||
{battery.inUseCount} currently in use (managed via device assignments)
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<Input
|
||||
label="Available Count"
|
||||
type="number"
|
||||
min="0"
|
||||
value={formData.availableCount}
|
||||
onChange={(e) => setFormData({ ...formData, availableCount: e.target.value })}
|
||||
/>
|
||||
<Input
|
||||
label="Charging Count"
|
||||
type="number"
|
||||
min="0"
|
||||
value={formData.chargingCount}
|
||||
onChange={(e) => setFormData({ ...formData, chargingCount: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Input
|
||||
label="Notes (optional)"
|
||||
value={formData.notes}
|
||||
onChange={(e) => setFormData({ ...formData, notes: e.target.value })}
|
||||
placeholder="Any additional notes..."
|
||||
/>
|
||||
</form>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in New Issue