diff --git a/frontend/src/components/BlockedSenders.jsx b/frontend/src/components/BlockedSenders.jsx index 5fa6625..82d9517 100644 --- a/frontend/src/components/BlockedSenders.jsx +++ b/frontend/src/components/BlockedSenders.jsx @@ -2,38 +2,68 @@ import React, { useState } from 'react'; import { FiSlash, FiPlus, FiTrash2, FiShield } from 'react-icons/fi'; const BlockedSenders = ({ rule, onUpdate }) => { - // 'rule' ist hier das Objekt { email_address, blocked_patterns: [] } const [patterns, setPatterns] = useState(rule?.blocked_patterns || []); const [newPattern, setNewPattern] = useState(''); const [inputError, setInputError] = useState(''); const [isLoading, setIsLoading] = useState(false); const validatePattern = (pattern) => { - // Einfache Validierung: Muss mindestens 3 Zeichen haben und darf nicht leer sein. - // Wildcards * sind erlaubt. + // Einfache Validierung: Mindestens 3 Zeichen. Wildcards * sind erlaubt. return pattern.length >= 3; }; const handleAddPattern = () => { - const trimmedPattern = newPattern.trim(); - if (!trimmedPattern) { - setInputError('Pattern is required'); + if (!newPattern.trim()) { + setInputError('Please enter a pattern'); return; } - if (!validatePattern(trimmedPattern)) { - setInputError('Pattern too short or invalid'); + // NEU: Splitten am Komma, bereinigen und leere Einträge filtern + const potentialPatterns = newPattern + .split(',') + .map(p => p.trim()) + .filter(p => p.length > 0); + + const validNewPatterns = []; + let duplicateCount = 0; + let invalidCount = 0; + + potentialPatterns.forEach(pattern => { + // Validierung prüfen + if (!validatePattern(pattern)) { + invalidCount++; + return; + } + + // Duplikate prüfen (sowohl in bestehender Liste als auch in der neuen Charge) + if (patterns.includes(pattern) || validNewPatterns.includes(pattern)) { + duplicateCount++; + return; + } + + validNewPatterns.push(pattern); + }); + + // Fehlerbehandlung: Wenn gar nichts hinzugefügt werden kann + if (validNewPatterns.length === 0) { + if (invalidCount > 0 && potentialPatterns.length === invalidCount) { + setInputError('All entered patterns were invalid (too short).'); + } else if (duplicateCount > 0) { + setInputError('All entered patterns are already in the list.'); + } return; } - if (patterns.includes(trimmedPattern)) { - setInputError('This pattern is already in the list'); - return; - } - - setPatterns([...patterns, trimmedPattern]); + // State aktualisieren + setPatterns([...patterns, ...validNewPatterns]); setNewPattern(''); - setInputError(''); + + // Optional: Feedback bei teilweisem Erfolg + if (invalidCount > 0 || duplicateCount > 0) { + setInputError(`Added ${validNewPatterns.length} patterns. (${invalidCount} invalid, ${duplicateCount} duplicates skipped)`); + } else { + setInputError(''); + } }; const handleRemovePattern = (patternToRemove) => { @@ -64,7 +94,7 @@ const BlockedSenders = ({ rule, onUpdate }) => { {/* Add Pattern Form */}
@@ -74,14 +104,17 @@ const BlockedSenders = ({ rule, onUpdate }) => { value={newPattern} onChange={(e) => { setNewPattern(e.target.value); - setInputError(''); + // Fehler nur löschen, wenn User tippt und keine Erfolgsmeldung angezeigt wird + if (!inputError.startsWith('Added')) setInputError(''); }} onKeyPress={handleKeyPress} - placeholder="spam@*.com, *@badsite.org" - className={`input-field ${inputError ? 'border-red-500 focus:ring-red-500' : ''}`} + placeholder="spam@*.com, *@badsite.org (comma separated)" + className={`input-field ${inputError && !inputError.startsWith('Added') ? 'border-red-500 focus:ring-red-500' : ''}`} /> {inputError && ( -

{inputError}

+

+ {inputError} +

)}

- Supports wildcards (*). Examples: marketing@spam.com, *@phishing.net + Paste a comma-separated list to add multiple entries at once. Supports wildcards (*).

@@ -103,6 +136,14 @@ const BlockedSenders = ({ rule, onUpdate }) => { + {patterns.length > 0 && ( + + )} {patterns.length === 0 ? ( @@ -112,10 +153,10 @@ const BlockedSenders = ({ rule, onUpdate }) => {

Add a pattern above to block incoming emails

) : ( -
+
{patterns.map((pattern, index) => (