mirror of
https://github.com/R0m1k3/Priceflow.git
synced 2026-10-19 13:18:12 +02:00
Merge pull request #57 from R0m1k3/antigravity
feat: Implement dashboard page for item management and add/edit item …
This commit is contained in:
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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in new issue
Block a user