mirror of
https://github.com/clucraft/PriceGhost.git
synced 2026-04-27 17:56:25 +02:00
Add target price alerts, historical low indicator, bulk actions, and dashboard summary
Features: - Target price alerts: Set a specific price target and get notified when reached - Historical low indicator: Badge showing when current price is at/near all-time low - Bulk actions: Select multiple products to delete at once - Dashboard summary: Shows total products, items at lowest price, at target, biggest drops Backend changes: - Add target_price column to products table - Add target_price notification type with Telegram/Discord support - Include min_price in product queries for historical low detection - Update scheduler to check target price conditions Frontend changes: - Add target price input to ProductDetail notification settings - Show target price badge on product cards - Add "Lowest Price" and "Near Low" badges to product cards - Add bulk selection mode with checkboxes - Add dashboard summary cards at top of product list Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
2acc47c21c
commit
a85e22d8bc
9 changed files with 454 additions and 5 deletions
|
|
@ -24,6 +24,7 @@ export default function ProductDetail() {
|
|||
const [error, setError] = useState('');
|
||||
const [notificationSettings, setNotificationSettings] = useState<NotificationSettings | null>(null);
|
||||
const [priceDropThreshold, setPriceDropThreshold] = useState<string>('');
|
||||
const [targetPrice, setTargetPrice] = useState<string>('');
|
||||
const [notifyBackInStock, setNotifyBackInStock] = useState(false);
|
||||
|
||||
const REFRESH_INTERVALS = [
|
||||
|
|
@ -50,6 +51,9 @@ export default function ProductDetail() {
|
|||
if (productRes.data.price_drop_threshold !== null && productRes.data.price_drop_threshold !== undefined) {
|
||||
setPriceDropThreshold(productRes.data.price_drop_threshold.toString());
|
||||
}
|
||||
if (productRes.data.target_price !== null && productRes.data.target_price !== undefined) {
|
||||
setTargetPrice(productRes.data.target_price.toString());
|
||||
}
|
||||
setNotifyBackInStock(productRes.data.notify_back_in_stock || false);
|
||||
} catch {
|
||||
setError('Failed to load product details');
|
||||
|
|
@ -121,13 +125,16 @@ export default function ProductDetail() {
|
|||
setIsSavingNotifications(true);
|
||||
try {
|
||||
const threshold = priceDropThreshold ? parseFloat(priceDropThreshold) : null;
|
||||
const target = targetPrice ? parseFloat(targetPrice) : null;
|
||||
await productsApi.update(productId, {
|
||||
price_drop_threshold: threshold,
|
||||
target_price: target,
|
||||
notify_back_in_stock: notifyBackInStock,
|
||||
});
|
||||
setProduct({
|
||||
...product,
|
||||
price_drop_threshold: threshold,
|
||||
target_price: target,
|
||||
notify_back_in_stock: notifyBackInStock,
|
||||
});
|
||||
} catch {
|
||||
|
|
@ -678,6 +685,23 @@ export default function ProductDetail() {
|
|||
</span>
|
||||
</div>
|
||||
|
||||
<div className="notification-form-group">
|
||||
<label>Target Price</label>
|
||||
<input
|
||||
type="number"
|
||||
min="0"
|
||||
step="0.01"
|
||||
value={targetPrice}
|
||||
onChange={(e) => setTargetPrice(e.target.value)}
|
||||
placeholder="Enter target price (e.g., 49.99)"
|
||||
/>
|
||||
<span className="hint">
|
||||
Notify when price drops to or below this amount ({product.currency || 'USD'})
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="notification-form-row">
|
||||
<div className="notification-form-group">
|
||||
<label>Back in Stock Alert</label>
|
||||
<label className="notification-checkbox-group">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue