comma split

This commit is contained in:
Andreas Knuth 2026-01-25 16:16:11 -06:00
parent 6fdf8f6436
commit be855415d5
1 changed files with 64 additions and 23 deletions

View File

@ -2,38 +2,68 @@ import React, { useState } from 'react';
import { FiSlash, FiPlus, FiTrash2, FiShield } from 'react-icons/fi'; import { FiSlash, FiPlus, FiTrash2, FiShield } from 'react-icons/fi';
const BlockedSenders = ({ rule, onUpdate }) => { const BlockedSenders = ({ rule, onUpdate }) => {
// 'rule' ist hier das Objekt { email_address, blocked_patterns: [] }
const [patterns, setPatterns] = useState(rule?.blocked_patterns || []); const [patterns, setPatterns] = useState(rule?.blocked_patterns || []);
const [newPattern, setNewPattern] = useState(''); const [newPattern, setNewPattern] = useState('');
const [inputError, setInputError] = useState(''); const [inputError, setInputError] = useState('');
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const validatePattern = (pattern) => { const validatePattern = (pattern) => {
// Einfache Validierung: Muss mindestens 3 Zeichen haben und darf nicht leer sein. // Einfache Validierung: Mindestens 3 Zeichen. Wildcards * sind erlaubt.
// Wildcards * sind erlaubt.
return pattern.length >= 3; return pattern.length >= 3;
}; };
const handleAddPattern = () => { const handleAddPattern = () => {
const trimmedPattern = newPattern.trim(); if (!newPattern.trim()) {
if (!trimmedPattern) { setInputError('Please enter a pattern');
setInputError('Pattern is required');
return; return;
} }
if (!validatePattern(trimmedPattern)) { // NEU: Splitten am Komma, bereinigen und leere Einträge filtern
setInputError('Pattern too short or invalid'); 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; return;
} }
if (patterns.includes(trimmedPattern)) { // State aktualisieren
setInputError('This pattern is already in the list'); setPatterns([...patterns, ...validNewPatterns]);
return;
}
setPatterns([...patterns, trimmedPattern]);
setNewPattern(''); 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) => { const handleRemovePattern = (patternToRemove) => {
@ -64,7 +94,7 @@ const BlockedSenders = ({ rule, onUpdate }) => {
{/* Add Pattern Form */} {/* Add Pattern Form */}
<div> <div>
<label htmlFor="block-pattern" className="block text-sm font-semibold text-gray-700 mb-2"> <label htmlFor="block-pattern" className="block text-sm font-semibold text-gray-700 mb-2">
Block Sender Pattern Block Sender Pattern(s)
</label> </label>
<div className="flex gap-2"> <div className="flex gap-2">
<div className="flex-1"> <div className="flex-1">
@ -74,14 +104,17 @@ const BlockedSenders = ({ rule, onUpdate }) => {
value={newPattern} value={newPattern}
onChange={(e) => { onChange={(e) => {
setNewPattern(e.target.value); setNewPattern(e.target.value);
setInputError(''); // Fehler nur löschen, wenn User tippt und keine Erfolgsmeldung angezeigt wird
if (!inputError.startsWith('Added')) setInputError('');
}} }}
onKeyPress={handleKeyPress} onKeyPress={handleKeyPress}
placeholder="spam@*.com, *@badsite.org" placeholder="spam@*.com, *@badsite.org (comma separated)"
className={`input-field ${inputError ? 'border-red-500 focus:ring-red-500' : ''}`} className={`input-field ${inputError && !inputError.startsWith('Added') ? 'border-red-500 focus:ring-red-500' : ''}`}
/> />
{inputError && ( {inputError && (
<p className="mt-1 text-sm text-red-600">{inputError}</p> <p className={`mt-1 text-sm ${inputError.startsWith('Added') ? 'text-green-600' : 'text-red-600'}`}>
{inputError}
</p>
)} )}
</div> </div>
<button <button
@ -93,7 +126,7 @@ const BlockedSenders = ({ rule, onUpdate }) => {
</button> </button>
</div> </div>
<p className="mt-2 text-xs text-gray-500"> <p className="mt-2 text-xs text-gray-500">
Supports wildcards (*). Examples: <code>marketing@spam.com</code>, <code>*@phishing.net</code> Paste a comma-separated list to add multiple entries at once. Supports wildcards (*).
</p> </p>
</div> </div>
@ -103,6 +136,14 @@ const BlockedSenders = ({ rule, onUpdate }) => {
<label className="block text-sm font-semibold text-gray-700"> <label className="block text-sm font-semibold text-gray-700">
Blocked Patterns ({patterns.length}) Blocked Patterns ({patterns.length})
</label> </label>
{patterns.length > 0 && (
<button
onClick={() => setPatterns([])}
className="text-xs text-red-600 hover:text-red-800 hover:underline"
>
Clear all
</button>
)}
</div> </div>
{patterns.length === 0 ? ( {patterns.length === 0 ? (
@ -112,10 +153,10 @@ const BlockedSenders = ({ rule, onUpdate }) => {
<p className="text-sm text-gray-500 mt-1">Add a pattern above to block incoming emails</p> <p className="text-sm text-gray-500 mt-1">Add a pattern above to block incoming emails</p>
</div> </div>
) : ( ) : (
<div className="space-y-2"> <div className="space-y-2 max-h-[400px] overflow-y-auto pr-2 custom-scrollbar">
{patterns.map((pattern, index) => ( {patterns.map((pattern, index) => (
<div <div
key={index} key={`${pattern}-${index}`}
className="flex items-center justify-between p-4 bg-white border border-gray-200 rounded-lg hover:border-red-300 transition-colors group" className="flex items-center justify-between p-4 bg-white border border-gray-200 rounded-lg hover:border-red-300 transition-colors group"
> >
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">