diff --git a/frontend/index.html b/frontend/index.html index 86cf656..8972ca6 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -3,12 +3,7 @@ - - - - - - + PriceFlow diff --git a/frontend/public/apple-touch-icon.png b/frontend/public/apple-touch-icon.png index 8aceb70..313ffb6 100644 Binary files a/frontend/public/apple-touch-icon.png and b/frontend/public/apple-touch-icon.png differ diff --git a/frontend/public/favicon.png b/frontend/public/favicon.png new file mode 100644 index 0000000..313ffb6 Binary files /dev/null and b/frontend/public/favicon.png differ diff --git a/frontend/public/logo.png b/frontend/public/logo.png index 431e3fc..d0d0fba 100644 Binary files a/frontend/public/logo.png and b/frontend/public/logo.png differ diff --git a/frontend/src/components/layout/Layout.jsx b/frontend/src/components/layout/Layout.jsx index b30360c..46c4dbe 100644 --- a/frontend/src/components/layout/Layout.jsx +++ b/frontend/src/components/layout/Layout.jsx @@ -37,7 +37,7 @@ const Layout = ({ children, theme, toggleTheme }) => {
- PriceFlow Logo + PriceFlow Logo PriceFlow @@ -166,7 +166,7 @@ const Layout = ({ children, theme, toggleTheme }) => { - PriceFlow Logo + PriceFlow Logo PriceFlow
diff --git a/frontend/src/pages/Settings.jsx b/frontend/src/pages/Settings.jsx index dab5ea8..9fa1b99 100644 --- a/frontend/src/pages/Settings.jsx +++ b/frontend/src/pages/Settings.jsx @@ -173,17 +173,43 @@ export default function Settings() { const handleProfileSubmit = async (e) => { e.preventDefault(); try { + let finalAppriseUrl = newProfile.apprise_url; + + // Construct Apprise URL based on provider + if (newProfile.provider === 'discord' && newProfile.discord_webhook) { + // Parse Discord Webhook: https://discord.com/api/webhooks/{id}/{token} -> discord://{id}/{token} + const match = newProfile.discord_webhook.match(/webhooks\/(\d+)\/(.+)/); + if (match) { + finalAppriseUrl = `discord://${match[1]}/${match[2]}`; + } else { + toast.error('Invalid Discord Webhook URL'); + return; + } + } else if (newProfile.provider === 'telegram' && newProfile.telegram_token && newProfile.telegram_chat_id) { + // Construct Telegram URL: tgram://{token}/{chat_id} + finalAppriseUrl = `tgram://${newProfile.telegram_token}/${newProfile.telegram_chat_id}`; + } + + const profileData = { + ...newProfile, + apprise_url: finalAppriseUrl + }; + if (editingProfileId) { - await axios.put(`${API_URL}/notification-profiles/${editingProfileId}`, newProfile); + await axios.put(`${API_URL}/notification-profiles/${editingProfileId}`, profileData); toast.success('Profile updated'); } else { - await axios.post(`${API_URL}/notification-profiles`, newProfile); + await axios.post(`${API_URL}/notification-profiles`, profileData); toast.success('Profile created'); } setNewProfile({ name: '', apprise_url: '', + discord_webhook: '', + telegram_token: '', + telegram_chat_id: '', + provider: 'custom', check_interval_minutes: 60, notify_on_price_drop: true, notify_on_target_price: true, @@ -198,9 +224,36 @@ export default function Settings() { }; const editProfile = (profile) => { + let provider = 'custom'; + let discord_webhook = ''; + let telegram_token = ''; + let telegram_chat_id = ''; + + // Deconstruct Apprise URL + if (profile.apprise_url.startsWith('discord://')) { + provider = 'discord'; + // discord://{id}/{token} -> https://discord.com/api/webhooks/{id}/{token} + const parts = profile.apprise_url.replace('discord://', '').split('/'); + if (parts.length >= 2) { + discord_webhook = `https://discord.com/api/webhooks/${parts[0]}/${parts[1]}`; + } + } else if (profile.apprise_url.startsWith('tgram://')) { + provider = 'telegram'; + // tgram://{token}/{chat_id} + const parts = profile.apprise_url.replace('tgram://', '').split('/'); + if (parts.length >= 2) { + telegram_token = parts[0]; + telegram_chat_id = parts[1]; + } + } + setNewProfile({ name: profile.name, apprise_url: profile.apprise_url, + provider, + discord_webhook, + telegram_token, + telegram_chat_id, check_interval_minutes: profile.check_interval_minutes, notify_on_price_drop: profile.notify_on_price_drop, notify_on_target_price: profile.notify_on_target_price, @@ -639,36 +692,87 @@ export default function Settings() { setNewProfile({ ...newProfile, name: e.target.value })} placeholder="e.g., Email Alerts" />
-
- - setNewProfile({ ...newProfile, apprise_url: e.target.value })} - placeholder="mailto://user:pass@gmail.com" - className="font-mono text-sm" - /> -
-

Exemples d'URLs Apprise :

-
-

• mailto://user:pass@gmail.com - Email

-

• tgram://bottoken/ChatID - Telegram

-

• discord://webhook_id/webhook_token - Discord

-

• slack://tokenA/tokenB/tokenC - Slack

-

• ntfy://topic - Ntfy

-

• gotify://hostname/token - Gotify

-
-

- - 📚 Documentation complète Apprise - -

+
+
+ +
+ + {(!newProfile.provider || newProfile.provider === 'custom') && ( +
+ + setNewProfile({ ...newProfile, apprise_url: e.target.value })} + placeholder="mailto://user:pass@gmail.com" + className="font-mono text-sm" + /> +

+ See Apprise documentation for supported services. +

+
+ )} + + {newProfile.provider === 'discord' && ( +
+ + setNewProfile({ ...newProfile, discord_webhook: e.target.value })} + placeholder="https://discord.com/api/webhooks/..." + className="font-mono text-sm" + /> +

+ Paste the full Webhook URL from Discord Server Settings > Integrations > Webhooks. +

+
+ )} + + {newProfile.provider === 'telegram' && ( +
+
+ + setNewProfile({ ...newProfile, telegram_token: e.target.value })} + placeholder="123456789:ABCdef..." + className="font-mono text-sm" + /> +
+
+ + setNewProfile({ ...newProfile, telegram_chat_id: e.target.value })} + placeholder="-100123456789" + className="font-mono text-sm" + /> +
+
+ )}