mirror of
https://github.com/clucraft/PriceGhost.git
synced 2026-05-09 15:52:41 +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
|
|
@ -3,11 +3,12 @@ import axios from 'axios';
|
|||
export interface NotificationPayload {
|
||||
productName: string;
|
||||
productUrl: string;
|
||||
type: 'price_drop' | 'back_in_stock';
|
||||
type: 'price_drop' | 'back_in_stock' | 'target_price';
|
||||
oldPrice?: number;
|
||||
newPrice?: number;
|
||||
currency?: string;
|
||||
threshold?: number;
|
||||
targetPrice?: number;
|
||||
}
|
||||
|
||||
function formatMessage(payload: NotificationPayload): string {
|
||||
|
|
@ -27,6 +28,16 @@ function formatMessage(payload: NotificationPayload): string {
|
|||
`🔗 ${payload.productUrl}`;
|
||||
}
|
||||
|
||||
if (payload.type === 'target_price') {
|
||||
const newPriceStr = payload.newPrice ? `${currencySymbol}${payload.newPrice.toFixed(2)}` : 'N/A';
|
||||
const targetPriceStr = payload.targetPrice ? `${currencySymbol}${payload.targetPrice.toFixed(2)}` : 'N/A';
|
||||
|
||||
return `🎯 Target Price Reached!\n\n` +
|
||||
`📦 ${payload.productName}\n\n` +
|
||||
`💰 Price is now ${newPriceStr} (your target: ${targetPriceStr})\n\n` +
|
||||
`🔗 ${payload.productUrl}`;
|
||||
}
|
||||
|
||||
if (payload.type === 'back_in_stock') {
|
||||
const priceStr = payload.newPrice ? ` at ${currencySymbol}${payload.newPrice.toFixed(2)}` : '';
|
||||
return `🎉 Back in Stock!\n\n` +
|
||||
|
|
@ -85,6 +96,21 @@ export async function sendDiscordNotification(
|
|||
url: payload.productUrl,
|
||||
timestamp: new Date().toISOString(),
|
||||
};
|
||||
} else if (payload.type === 'target_price') {
|
||||
const newPriceStr = payload.newPrice ? `${currencySymbol}${payload.newPrice.toFixed(2)}` : 'N/A';
|
||||
const targetPriceStr = payload.targetPrice ? `${currencySymbol}${payload.targetPrice.toFixed(2)}` : 'N/A';
|
||||
|
||||
embed = {
|
||||
title: '🎯 Target Price Reached!',
|
||||
description: payload.productName,
|
||||
color: 0xf59e0b, // Amber
|
||||
fields: [
|
||||
{ name: 'Current Price', value: newPriceStr, inline: true },
|
||||
{ name: 'Your Target', value: targetPriceStr, inline: true },
|
||||
],
|
||||
url: payload.productUrl,
|
||||
timestamp: new Date().toISOString(),
|
||||
};
|
||||
} else {
|
||||
const priceStr = payload.newPrice ? `${currencySymbol}${payload.newPrice.toFixed(2)}` : 'Check link';
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue