[32788f42] Implement Feature 3: Nachfass-E-Mails (Reminder Analysis) with CSV export for Supermailer
This commit is contained in:
@@ -38,6 +38,9 @@ function App() {
|
||||
const [eventTypes, setEventTypes] = useState<any[]>([]);
|
||||
const [selectedEventType, setSelectedEventType] = useState<string>("");
|
||||
const [isListGenerating, setIsListGenerating] = useState(false);
|
||||
const [reminderTaskId, setReminderTaskId] = useState<string | null>(null);
|
||||
const [reminderProgress, setReminderProgress] = useState<string>('');
|
||||
const [isReminderRunning, setIsReminderRunning] = useState(false);
|
||||
|
||||
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://192.168.178.6:8002';
|
||||
|
||||
@@ -138,6 +141,32 @@ function App() {
|
||||
};
|
||||
}, [statsTaskId, isStatsRunning]);
|
||||
|
||||
useEffect(() => {
|
||||
let interval: any;
|
||||
if (reminderTaskId && isReminderRunning) {
|
||||
interval = setInterval(async () => {
|
||||
try {
|
||||
const res = await fetch(`${API_BASE_URL}/api/tasks/${reminderTaskId}`);
|
||||
if (!res.ok) throw new Error('Task Status Request failed');
|
||||
const data = await res.json();
|
||||
setReminderProgress(data.progress || 'Verarbeite...');
|
||||
if (data.status === 'completed') {
|
||||
setIsReminderRunning(false);
|
||||
// Auto-trigger download or show button? The user wants a CSV.
|
||||
// Let's keep the task ID so we can show a download button.
|
||||
} else if (data.status === 'error') {
|
||||
setError(data.progress || 'Ein Fehler ist aufgetreten.');
|
||||
setIsReminderRunning(false);
|
||||
setReminderTaskId(null);
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error("Polling Error:", err);
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
return () => { if (interval) clearInterval(interval); };
|
||||
}, [reminderTaskId, isReminderRunning]);
|
||||
|
||||
const handleGeneratePdf = async (job: Job) => {
|
||||
setProcessingJobId(job.id);
|
||||
setError(null);
|
||||
@@ -237,6 +266,32 @@ function App() {
|
||||
setIsListGenerating(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleStartReminderAnalysis = async (job: Job) => {
|
||||
setIsReminderRunning(true);
|
||||
setReminderProgress('Starte Analyse...');
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/api/jobs/${job.id}/reminder-analysis?account_type=${activeTab}`, {
|
||||
method: 'POST'
|
||||
});
|
||||
if (!response.ok) throw new Error('Konnte Analyse nicht starten.');
|
||||
const data = await response.json();
|
||||
setReminderTaskId(data.task_id);
|
||||
} catch (err: any) {
|
||||
setError(err.message);
|
||||
setIsReminderRunning(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDownloadReminderCsv = async (taskId: string) => {
|
||||
try {
|
||||
window.open(`${API_BASE_URL}/api/tasks/${taskId}/download-csv`, '_blank');
|
||||
} catch (err: any) {
|
||||
setError("Download fehlgeschlagen.");
|
||||
}
|
||||
};
|
||||
const currentJobs = jobsCache[activeTab];
|
||||
|
||||
return (
|
||||
@@ -521,20 +576,43 @@ function App() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* Tool 3: Follow-up Emails */}
|
||||
|
||||
{/* Tool 3: Follow-up Emails */}
|
||||
<div className="bg-white border border-gray-200 rounded-xl p-5 hover:border-amber-300 transition-colors shadow-sm">
|
||||
<div className="flex items-start justify-between mb-2">
|
||||
<div className="p-2 bg-amber-50 rounded-lg text-amber-600 text-xl">✉️</div>
|
||||
<span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-100 text-gray-600">Demnächst</span>
|
||||
<span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-amber-100 text-amber-700">Aktiv</span>
|
||||
</div>
|
||||
<h5 className="font-bold text-gray-900 mb-1">Nachfass-Mails (Supermailer)</h5>
|
||||
<p className="text-sm text-gray-500 mb-4 line-clamp-2">Analysiert das Kaufverhalten und generiert eine fertige CSV-Liste für den Supermailer.</p>
|
||||
<button className="w-full px-4 py-2 bg-gray-100 text-gray-500 text-sm font-medium rounded-lg cursor-not-allowed">
|
||||
Analyse starten (Dauert lange)
|
||||
</button>
|
||||
|
||||
{isReminderRunning ? (
|
||||
<div className="w-full bg-gray-100 p-3 rounded-lg text-sm text-gray-700 flex flex-col gap-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<svg className="animate-spin h-4 w-4 text-amber-600" viewBox="0 0 24 24" fill="none"><circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" /><path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" /></svg>
|
||||
<span className="font-medium text-amber-700">Analyse läuft...</span>
|
||||
</div>
|
||||
<p className="text-xs break-words">{reminderProgress}</p>
|
||||
</div>
|
||||
) : reminderTaskId ? (
|
||||
<button
|
||||
onClick={() => handleDownloadReminderCsv(reminderTaskId)}
|
||||
className="w-full px-4 py-2 bg-emerald-600 text-white text-sm font-medium rounded-lg hover:bg-emerald-700 transition-colors shadow-sm flex items-center justify-center gap-2"
|
||||
>
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16v1a2 2 0 002 2h12a2 2 0 002-2v-1m-4-4l-4 4m0 0l-4-4m4 4V4" /></svg>
|
||||
CSV herunterladen
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
onClick={() => handleStartReminderAnalysis(selectedJob)}
|
||||
disabled={processingJobId !== null || isReminderRunning || isStatsRunning}
|
||||
className="w-full px-4 py-2 bg-amber-600 text-white text-sm font-medium rounded-lg hover:bg-amber-700 disabled:opacity-50 transition-colors shadow-sm"
|
||||
>
|
||||
Analyse starten (Dauert lange)
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Tool 4: Statistics */}
|
||||
{/* Tool 4: Statistics */}
|
||||
<div className="bg-white border border-gray-200 rounded-xl p-5 hover:border-purple-300 transition-colors shadow-sm">
|
||||
<div className="flex items-start justify-between mb-2">
|
||||
<div className="p-2 bg-purple-50 rounded-lg text-purple-600 text-xl">📊</div>
|
||||
|
||||
Reference in New Issue
Block a user