diff --git a/client/src/pages/Alerts.jsx b/client/src/pages/Alerts.jsx
index d8654b8..7bb191c 100644
--- a/client/src/pages/Alerts.jsx
+++ b/client/src/pages/Alerts.jsx
@@ -462,7 +462,9 @@ const CreateAlertRuleModal = ({ onClose, onSave }) => {
device_ids: [],
drone_types: [],
min_rssi: '',
- max_rssi: ''
+ max_rssi: '',
+ sms_phone_number: '',
+ webhook_url: ''
});
const [saving, setSaving] = useState(false);
const [devices, setDevices] = useState([]);
@@ -502,6 +504,11 @@ const CreateAlertRuleModal = ({ onClose, onSave }) => {
if (!payload.max_rssi) delete payload.max_rssi;
if (!payload.device_ids || payload.device_ids.length === 0) payload.device_ids = null;
if (!payload.drone_types || payload.drone_types.length === 0) payload.drone_types = null;
+
+ // Only include webhook_url if webhook channel is selected
+ if (!payload.alert_channels || !payload.alert_channels.includes('webhook')) {
+ delete payload.webhook_url;
+ }
await api.post('/alerts/rules', payload);
onSave();
@@ -733,6 +740,46 @@ const CreateAlertRuleModal = ({ onClose, onSave }) => {
)}
+
+ {/* Conditional channel-specific fields */}
+ {formData.alert_channels.includes('sms') && (
+
+
+
+
+ Include country code (e.g., +1 for US)
+
+
+ )}
+
+ {formData.alert_channels.includes('webhook') && (
+
+
+
+
+ Must be a valid HTTPS URL
+
+
+ )}
diff --git a/server/routes/alert.js b/server/routes/alert.js
index 12e27a9..be5395a 100644
--- a/server/routes/alert.js
+++ b/server/routes/alert.js
@@ -18,7 +18,7 @@ const alertRuleSchema = Joi.object({
min_detections: Joi.number().integer().min(1).default(1),
cooldown_period: Joi.number().integer().min(0).default(600),
alert_channels: Joi.array().items(Joi.string().valid('sms', 'email', 'webhook')).default(['sms']),
- webhook_url: Joi.string().uri().optional(),
+ webhook_url: Joi.string().uri().allow('').optional(),
active_hours: Joi.object({
start: Joi.string().pattern(/^\d{2}:\d{2}$/).optional(),
end: Joi.string().pattern(/^\d{2}:\d{2}$/).optional()
@@ -66,6 +66,21 @@ router.get('/rules', authenticateToken, async (req, res) => {
// POST /api/alerts/rules - Create new alert rule
router.post('/rules', authenticateToken, validateRequest(alertRuleSchema), async (req, res) => {
try {
+ // Custom validation for webhook URL when webhook channel is selected
+ if (req.body.alert_channels && req.body.alert_channels.includes('webhook')) {
+ if (!req.body.webhook_url || req.body.webhook_url.trim() === '') {
+ return res.status(400).json({
+ success: false,
+ message: 'Validation error',
+ errors: [{
+ field: 'webhook_url',
+ message: 'Webhook URL is required when webhook channel is selected',
+ value: req.body.webhook_url || ''
+ }]
+ });
+ }
+ }
+
const alertRule = await AlertRule.create({
...req.body,
user_id: req.user.id