Used the network service class for network requests.
This commit is contained in:
1 parent
845b7692bc
commit
9aa0041022
5 files changed
+131
-76
No files matched your search
+16
-67
@@ -1,6 +1,5 @@
|
||||
import { useState, useMemo } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import {
|
||||
Dialog,
|
||||
@@ -10,11 +9,13 @@ import {
|
||||
Typography,
|
||||
Box,
|
||||
Tabs,
|
||||
Tab
|
||||
Tab,
|
||||
CircularProgress
|
||||
} from "@mui/material";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import TabPanel from "./TabPanel";
|
||||
import TabComponent from "./TabComponent";
|
||||
import useNotifications from "../Hooks/useNotification";
|
||||
|
||||
const NotificationIntegrationModal = ({
|
||||
open,
|
||||
@@ -28,6 +29,8 @@ const NotificationIntegrationModal = ({
|
||||
const theme = useTheme();
|
||||
const [tabValue, setTabValue] = useState(0);
|
||||
|
||||
const { loading, sendTestNotification } = useNotifications();
|
||||
|
||||
// Define notification types
|
||||
const DEFAULT_NOTIFICATION_TYPES = [
|
||||
{
|
||||
@@ -144,74 +147,18 @@ const NotificationIntegrationModal = ({
|
||||
return `${typeId}${fieldId.charAt(0).toUpperCase() + fieldId.slice(1)}`;
|
||||
};
|
||||
|
||||
// Prepare request payload based on notification type
|
||||
let payload = { platform: type };
|
||||
// Prepare config object based on notification type
|
||||
const config = {};
|
||||
|
||||
switch(type) {
|
||||
case 'slack':
|
||||
payload.webhookUrl = integrations[getFieldKey('slack', 'webhook')];
|
||||
if (!payload.webhookUrl) {
|
||||
toast.error('Please enter a Slack webhook URL first.');
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'discord':
|
||||
payload.webhookUrl = integrations[getFieldKey('discord', 'webhook')];
|
||||
if (!payload.webhookUrl) {
|
||||
toast.error('Please enter a Discord webhook URL first.');
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'telegram':
|
||||
payload.botToken = integrations[getFieldKey('telegram', 'token')];
|
||||
payload.chatId = integrations[getFieldKey('telegram', 'chatId')];
|
||||
if (!payload.botToken || !payload.chatId) {
|
||||
toast.error('Please enter both Telegram bot token and chat ID.');
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'webhook':
|
||||
payload.webhookUrl = integrations[getFieldKey('webhook', 'url')];
|
||||
payload.platform = 'slack'; // Use slack as platform for webhooks
|
||||
if (!payload.webhookUrl) {
|
||||
toast.error('Please enter a webhook URL first.');
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
toast.error('This notification type cannot be tested.');
|
||||
return;
|
||||
}
|
||||
// Add each field value to the config object
|
||||
notificationType.fields.forEach(field => {
|
||||
const fieldKey = getFieldKey(type, field.id);
|
||||
config[field.id] = integrations[fieldKey];
|
||||
});
|
||||
|
||||
try {
|
||||
const apiUrl = `${import.meta.env.VITE_APP_API_BASE_URL || 'http://localhost:5000'}/api/v1/notifications/test-webhook`;
|
||||
|
||||
|
||||
const response = await fetch(apiUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (response.ok && data.success) {
|
||||
toast.success('Test notification sent successfully!');
|
||||
} else {
|
||||
throw new Error(data.msg || 'Failed to send test notification');
|
||||
}
|
||||
} catch (error) {
|
||||
toast.error(`Failed to send test notification: ${error.message}`);
|
||||
}
|
||||
await sendTestNotification(type, config);
|
||||
};
|
||||
|
||||
|
||||
const handleSave = () => {
|
||||
//notifications array for selected integrations
|
||||
const notifications = [...(monitor?.notifications || [])];
|
||||
@@ -318,6 +265,7 @@ const NotificationIntegrationModal = ({
|
||||
handleIntegrationChange={handleIntegrationChange}
|
||||
handleInputChange={handleInputChange}
|
||||
handleTestNotification={handleTestNotification}
|
||||
isLoading={loading}
|
||||
/>
|
||||
</TabPanel>
|
||||
))}
|
||||
@@ -335,13 +283,14 @@ const NotificationIntegrationModal = ({
|
||||
variant="contained"
|
||||
color="accent"
|
||||
onClick={handleSave}
|
||||
disabled={loading}
|
||||
sx={{
|
||||
width: 'auto',
|
||||
minWidth: theme.spacing(60),
|
||||
px: theme.spacing(8)
|
||||
}}
|
||||
>
|
||||
{t('common.save', 'Save')}
|
||||
{loading ? <CircularProgress size={24} color="inherit" /> : t('common.save', 'Save')}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
+12
-6
@@ -2,19 +2,21 @@ import React from "react";
|
||||
import {
|
||||
Typography,
|
||||
Box,
|
||||
Button
|
||||
Button,
|
||||
CircularProgress
|
||||
} from "@mui/material";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import TextInput from "../../../src/Components/Inputs/TextInput";
|
||||
import Checkbox from "../../../src/Components/Inputs/Checkbox";
|
||||
import TextInput from "../../../Components/Inputs/TextInput";
|
||||
import Checkbox from "../../../Components/Inputs/Checkbox";
|
||||
|
||||
const TabComponent = ({
|
||||
type,
|
||||
integrations,
|
||||
handleIntegrationChange,
|
||||
handleInputChange,
|
||||
handleTestNotification
|
||||
handleTestNotification,
|
||||
isLoading
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
@@ -55,6 +57,7 @@ const TabComponent = ({
|
||||
label={t('notifications.enableNotifications', { platform: type.label })}
|
||||
isChecked={integrations[type.id]}
|
||||
onChange={(e) => handleIntegrationChange(type.id, e.target.checked)}
|
||||
disabled={isLoading}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
@@ -77,7 +80,7 @@ const TabComponent = ({
|
||||
placeholder={field.placeholder}
|
||||
value={integrations[fieldKey]}
|
||||
onChange={(e) => handleInputChange(fieldKey, e.target.value)}
|
||||
disabled={!integrations[type.id]}
|
||||
disabled={!integrations[type.id] || isLoading}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
@@ -88,8 +91,11 @@ const TabComponent = ({
|
||||
variant="text"
|
||||
color="info"
|
||||
onClick={() => handleTestNotification(type.id)}
|
||||
disabled={!integrations[type.id] || !areAllFieldsFilled()}
|
||||
disabled={!integrations[type.id] || !areAllFieldsFilled() || isLoading}
|
||||
>
|
||||
{isLoading ? (
|
||||
<CircularProgress size={16} color="inherit" sx={{ mr: 1 }} />
|
||||
) : null}
|
||||
{t('notifications.testNotification')}
|
||||
</Button>
|
||||
</Box>
|
||||
File renamed without changes.
@@ -0,0 +1,100 @@
|
||||
import { useState } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { networkService } from '../../../Utils/NetworkService';
|
||||
|
||||
/**
|
||||
* Custom hook for notification-related operations
|
||||
*/
|
||||
const useNotifications = () => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState(null);
|
||||
const { t } = useTranslation();
|
||||
|
||||
/**
|
||||
* Send a test notification
|
||||
* @param {string} type - The notification type (slack, discord, telegram, webhook)
|
||||
* @param {object} config - Configuration object with necessary params
|
||||
*/
|
||||
const sendTestNotification = async (type, config) => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
// Validation based on notification type
|
||||
let payload = { platform: type };
|
||||
let isValid = true;
|
||||
let errorMessage = '';
|
||||
|
||||
switch(type) {
|
||||
case 'slack':
|
||||
payload.webhookUrl = config.webhook;
|
||||
if (!payload.webhookUrl) {
|
||||
isValid = false;
|
||||
errorMessage = t('notifications.slack.webhookRequired', 'Please enter a Slack webhook URL first.');
|
||||
}
|
||||
break;
|
||||
|
||||
case 'discord':
|
||||
payload.webhookUrl = config.webhook;
|
||||
if (!payload.webhookUrl) {
|
||||
isValid = false;
|
||||
errorMessage = t('notifications.discord.webhookRequired', 'Please enter a Discord webhook URL first.');
|
||||
}
|
||||
break;
|
||||
|
||||
case 'telegram':
|
||||
payload.botToken = config.token;
|
||||
payload.chatId = config.chatId;
|
||||
if (!payload.botToken || !payload.chatId) {
|
||||
isValid = false;
|
||||
errorMessage = t('notifications.telegram.fieldsRequired', 'Please enter both Telegram bot token and chat ID.');
|
||||
}
|
||||
break;
|
||||
|
||||
case 'webhook':
|
||||
payload.webhookUrl = config.url;
|
||||
payload.platform = 'slack'; // Use slack as platform for webhooks
|
||||
if (!payload.webhookUrl) {
|
||||
isValid = false;
|
||||
errorMessage = t('notifications.webhook.urlRequired', 'Please enter a webhook URL first.');
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
isValid = false;
|
||||
errorMessage = t('notifications.unsupportedType', 'This notification type cannot be tested.');
|
||||
}
|
||||
|
||||
// If validation fails, show error and return
|
||||
if (!isValid) {
|
||||
toast.error(errorMessage);
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Use your existing NetworkService to make the API call
|
||||
const response = await networkService.axiosInstance.post('/notifications/test-webhook', payload);
|
||||
|
||||
if (response.data.success) {
|
||||
toast.success(t('notifications.testSuccess', 'Test notification sent successfully!'));
|
||||
} else {
|
||||
throw new Error(response.data.msg || t('notifications.testFailed', 'Failed to send test notification'));
|
||||
}
|
||||
} catch (error) {
|
||||
const errorMsg = error.response?.data?.msg || error.message || t('notifications.networkError', 'Network error occurred');
|
||||
toast.error(`${t('notifications.testFailed', 'Failed to send test notification')}: ${errorMsg}`);
|
||||
setError(errorMsg);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
loading,
|
||||
error,
|
||||
sendTestNotification
|
||||
};
|
||||
};
|
||||
|
||||
export default useNotifications;
|
||||
Reference in new issue
Block a user