Merge pull request #57 from R0m1k3/antigravity

feat: Implement dashboard page for item management and add/edit item …
This commit is contained in:
LogiFlow authored and GitHub committed 2025-11-24 00:10:25 +01:00
commit be7c0a313e
2 files changed
+68 -7

No files matched your search

@@ -7,10 +7,11 @@ import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input'; import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label'; import { Label } from '@/components/ui/label';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { X } from 'lucide-react';
const API_URL = '/api'; const API_URL = '/api';
export function ItemModal({ item, onClose, onSaved, open }) { export function ItemModal({ item, onClose, onSaved, open, categories = [] }) {
const { t } = useTranslation(); const { t } = useTranslation();
const [formData, setFormData] = useState({ const [formData, setFormData] = useState({
url: '', url: '',
@@ -18,9 +19,11 @@ export function ItemModal({ item, onClose, onSaved, open }) {
target_price: '', target_price: '',
tags: '', tags: '',
description: '', description: '',
notification_channel_id: 'none' notification_channel_id: 'none',
category: ''
}); });
const [channels, setChannels] = useState([]); const [channels, setChannels] = useState([]);
const [showCustomInput, setShowCustomInput] = useState(false);
useEffect(() => { useEffect(() => {
const fetchChannels = async () => { const fetchChannels = async () => {
@@ -45,8 +48,10 @@ export function ItemModal({ item, onClose, onSaved, open }) {
target_price: item.target_price || '', target_price: item.target_price || '',
tags: item.tags || '', tags: item.tags || '',
description: item.description || '', description: item.description || '',
notification_channel_id: item.notification_channel_id ? item.notification_channel_id.toString() : 'none' notification_channel_id: item.notification_channel_id ? item.notification_channel_id.toString() : 'none',
category: item.category || ''
}); });
setShowCustomInput(!!item.category && !categories.includes(item.category));
} else { } else {
setFormData({ setFormData({
url: '', url: '',
@@ -54,10 +59,12 @@ export function ItemModal({ item, onClose, onSaved, open }) {
target_price: '', target_price: '',
tags: '', tags: '',
description: '', description: '',
notification_channel_id: 'none' notification_channel_id: 'none',
category: ''
}); });
setShowCustomInput(false);
} }
}, [item, open]); }, [item, open, categories]);
@@ -125,6 +132,58 @@ export function ItemModal({ item, onClose, onSaved, open }) {
/> />
</div> </div>
<div className="space-y-2">
<Label htmlFor="category">{t('itemModal.category') || 'Category'}</Label>
{showCustomInput ? (
<div className="flex gap-2">
<Input
id="custom_category"
placeholder="Enter new category"
value={formData.category}
onChange={e => setFormData({ ...formData, category: e.target.value })}
autoFocus
/>
<Button
type="button"
variant="ghost"
size="icon"
onClick={() => {
setShowCustomInput(false);
setFormData({ ...formData, category: '' });
}}
title="Select existing category"
>
<X className="h-4 w-4" />
</Button>
</div>
) : (
<Select
value={categories.includes(formData.category) ? formData.category : (formData.category ? '__custom__' : 'none')}
onValueChange={(val) => {
if (val === '__custom__') {
setShowCustomInput(true);
setFormData({ ...formData, category: '' });
} else if (val === 'none') {
setFormData({ ...formData, category: '' });
} else {
setFormData({ ...formData, category: val });
}
}}
>
<SelectTrigger className="w-full">
<SelectValue placeholder="Select a category" />
</SelectTrigger>
<SelectContent>
<SelectItem value="none">None</SelectItem>
{categories.map(cat => (
<SelectItem key={cat} value={cat}>{cat}</SelectItem>
))}
<SelectItem value="__custom__">Custom...</SelectItem>
</SelectContent>
</Select>
)}
</div>
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="channel">Notification Channel</Label> <Label htmlFor="channel">Notification Channel</Label>
<Select <Select
+4 -2
View File
@@ -178,14 +178,16 @@ export default function Dashboard() {
<ItemModal <ItemModal
open={showAddModal} open={showAddModal}
onClose={() => setShowAddModal(false)} onClose={() => setShowAddModal(false)}
onSaved={refreshItems} onSaved={() => { refreshItems(); loadCategories(); }}
categories={categories}
/> />
<ItemModal <ItemModal
open={!!editingItem} open={!!editingItem}
item={editingItem} item={editingItem}
onClose={() => setEditingItem(null)} onClose={() => setEditingItem(null)}
onSaved={refreshItems} onSaved={() => { refreshItems(); loadCategories(); }}
categories={categories}
/> />
<DeleteConfirmationModal <DeleteConfirmationModal