Used the network service class for network requests.

This commit is contained in:
Skorpios committed 2025-03-11 18:37:14 -07:00
1 parent 845b7692bc
commit 9aa0041022
5 files changed
+131 -76

No files matched your search

@@ -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>
@@ -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>
@@ -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;