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';
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;
}
if (patterns.includes(trimmedPattern)) {
setInputError('This pattern is already in the list');
// Duplikate prüfen (sowohl in bestehender Liste als auch in der neuen Charge)
if (patterns.includes(pattern) || validNewPatterns.includes(pattern)) {
duplicateCount++;
return;
}
setPatterns([...patterns, trimmedPattern]);
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;
}
// State aktualisieren
setPatterns([...patterns, ...validNewPatterns]);
setNewPattern('');
// 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 */}
<div>
<label htmlFor="block-pattern" className="block text-sm font-semibold text-gray-700 mb-2">
Block Sender Pattern
Block Sender Pattern(s)
</label>
<div className="flex gap-2">
<div className="flex-1">
@ -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 && (
<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>
<button
@ -93,7 +126,7 @@ const BlockedSenders = ({ rule, onUpdate }) => {
</button>
</div>
<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>
</div>
@ -103,6 +136,14 @@ const BlockedSenders = ({ rule, onUpdate }) => {
<label className="block text-sm font-semibold text-gray-700">
Blocked Patterns ({patterns.length})
</label>
{patterns.length > 0 && (
<button
onClick={() => setPatterns([])}
className="text-xs text-red-600 hover:text-red-800 hover:underline"
>
Clear all
</button>
)}
</div>
{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>
</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) => (
<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"
>
<div className="flex items-center gap-3">