import React, { useState, useEffect } from "react"; import axios from "../../../lib/axios_instance"; import { Form, Row, Col, Button, Spinner, Alert } from "react-bootstrap"; import InformationLineIcon from "remixicon-react/InformationLineIcon"; import { Tooltip } from "@mui/material"; import PropTypes from 'prop-types'; import Table from '@mui/material/Table'; import TableBody from '@mui/material/TableBody'; import TableCell from '@mui/material/TableCell'; import TableContainer from '@mui/material/TableContainer'; import TableHead from '@mui/material/TableHead'; import TableRow from '@mui/material/TableRow'; import { Trans } from "react-i18next"; import Loading from "../general/loading"; import ErrorBoundary from "../general/ErrorBoundary"; const token = localStorage.getItem('token'); // Modification du composant WebhookRow pour passer l'objet webhook complet function WebhookRow(props) { const { webhook, onEdit, onTest } = props; return ( *': { borderBottom: 'unset' } }}> {webhook.name} {webhook.url} {webhook.webhook_type || 'generic'} {webhook.trigger_type} {webhook.enabled ? : }
); } WebhookRow.propTypes = { webhook: PropTypes.shape({ id: PropTypes.string.isRequired, name: PropTypes.string.isRequired, url: PropTypes.string.isRequired, webhook_type: PropTypes.string, trigger_type: PropTypes.string.isRequired, enabled: PropTypes.bool.isRequired }).isRequired, onEdit: PropTypes.func.isRequired, onTest: PropTypes.func.isRequired }; function WebhooksSettings() { const [webhooks, setWebhooks] = useState([]); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [error, setError] = useState(null); const [success, setSuccess] = useState(false); const [currentWebhook, setCurrentWebhook] = useState({ name: 'Monthly Report of Most watched movies and series', url: '', enabled: false, trigger_type: 'scheduled', schedule: '0 9 1 * *', method: 'POST', webhook_type: 'discord' }); const [eventWebhooks, setEventWebhooks] = useState({ playback_started: { exists: false, enabled: false }, playback_ended: { exists: false, enabled: false }, media_recently_added: { exists: false, enabled: false } }); useEffect(() => { const fetchWebhooks = async () => { try { const response = await axios.get('/webhooks', { headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json", }, }); if (response.data !== webhooks) { setWebhooks(response.data); await loadEventWebhooks(); } if (loading) { setLoading(false); } } catch (err) { console.error("Error loading webhooks:", err); if (loading) { setLoading(false); } } }; fetchWebhooks(); const intervalId = setInterval(fetchWebhooks, 1000 * 10); return () => clearInterval(intervalId); }, [webhooks.length]); const handleInputChange = (e) => { const { name, value } = e.target; setCurrentWebhook(prev => ({ ...prev, [name]: value })); }; const handleToggleEnabled = () => { setCurrentWebhook(prev => ({ ...prev, enabled: !prev.enabled })); }; const handleFormSubmit = async (e) => { e.preventDefault(); try { setSaving(true); setError(null); setSuccess(false); if (!currentWebhook.url) { setError("Webhook URL is required"); setSaving(false); return; } if (currentWebhook.trigger_type === 'event' && !currentWebhook.event_type) { setError("Event type is required for an event based webhook"); setSaving(false); return; } let response; if (currentWebhook.id) { response = await axios.put(`/webhooks/${currentWebhook.id}`, currentWebhook, { headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json", } }); } else { response = await axios.post('/webhooks', currentWebhook, { headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json", } }); } const webhooksResponse = await axios.get('/webhooks', { headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json", }, }); setWebhooks(webhooksResponse.data); await loadEventWebhooks(); setCurrentWebhook({ name: 'New Webhook', url: '', enabled: false, trigger_type: 'scheduled', schedule: '0 9 1 * *', method: 'POST', webhook_type: 'discord' }); setSuccess("Webhook saved successfully!"); setSaving(false); } catch (err) { setError("Error while saving webhook " + (err.response?.data?.error || err.message)); setSaving(false); } }; const handleEdit = (webhook) => { setCurrentWebhook(webhook); }; const handleTest = async (webhook) => { if (!webhook || !webhook.id) { setError("Impossible to test the webhook: no webhook provided"); setLoading(false); return; } try { setLoading(true); setError(null); let endpoint = `/webhooks/${webhook.id}/test`; if (webhook.trigger_type === 'scheduled' && webhook.schedule && webhook.schedule.includes('1 * *')) { endpoint = `/webhooks/${webhook.id}/trigger-monthly`; } await axios.post(endpoint, {}, { headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json", } }); setSuccess(`Webhook ${webhook.name} test triggered successfully!`); setLoading(false); } catch (err) { setError("Error during the test of the webhook: " + (err.response?.data?.message || err.message)); setLoading(false); } }; const getEventWebhookStatus = (eventType) => { return eventWebhooks[eventType]?.enabled || false; }; const loadEventWebhooks = async () => { try { const eventTypes = ['playback_started', 'playback_ended', 'media_recently_added']; const status = {}; eventTypes.forEach(eventType => { const matchingWebhooks = webhooks.filter( webhook => webhook.trigger_type === 'event' && webhook.event_type === eventType ); status[eventType] = { exists: matchingWebhooks.length > 0, enabled: matchingWebhooks.some(webhook => webhook.enabled) }; }); setEventWebhooks(status); } catch (error) { console.error('Error loading event webhook status:', error); } }; const toggleEventWebhook = async (eventType) => { try { setLoading(true); setError(null); const isCurrentlyEnabled = getEventWebhookStatus(eventType); const matchingWebhooks = webhooks.filter( webhook => webhook.trigger_type === 'event' && webhook.event_type === eventType ); if (matchingWebhooks.length === 0 && !isCurrentlyEnabled) { const newWebhook = { name: `Notification - ${getEventDisplayName(eventType)}`, url: '', enabled: true, trigger_type: 'event', event_type: eventType, method: 'POST', webhook_type: 'discord' }; setCurrentWebhook(newWebhook); setLoading(false); return; } for (const webhook of matchingWebhooks) { await axios.put(`/webhooks/${webhook.id}`, { ...webhook, enabled: !isCurrentlyEnabled }, { headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json", } } ); } setEventWebhooks(prev => ({ ...prev, [eventType]: { ...prev[eventType], enabled: !isCurrentlyEnabled } })); const response = await axios.get('/webhooks', { headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json", }, }); setWebhooks(response.data); setLoading(false); setSuccess(`Webhook for ${getEventDisplayName(eventType)} ${!isCurrentlyEnabled ? 'enabled' : 'disabled'} with success!`); } catch (error) { setError("Error while editing webhook: " + (error.response?.data?.error || error.message)); setLoading(false); } }; const getEventDisplayName = (eventType) => { switch(eventType) { case 'playback_started': return 'Playback started'; case 'playback_ended': return 'Playback ended'; case 'media_recently_added': return 'New media added'; default: return eventType; } }; if (loading && !webhooks.length) { return ; } return (

{" "} }>

{error && setError(null)} dismissible>{error}} {success && setSuccess(false)} dismissible> {typeof success === 'string' ? success : } }
} checked={currentWebhook.enabled} onChange={handleToggleEnabled} />
{/* Ajout de la section pour les webhooks événementiels */}

}>

toggleEventWebhook('playback_started')} />

Send a webhook notification when a user starts watching a media

toggleEventWebhook('playback_ended')} />

Send a webhook notification when a user finishes watching a media

toggleEventWebhook('media_recently_added')} />

Send a webhook notification when new media is added to the library

{webhooks.map((webhook) => ( ))} {webhooks.length === 0 && ( )}
); } export default WebhooksSettings;