File size: 5,415 Bytes
e9d1895
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import {
  CheckCircle2, XCircle, Clock, Loader2, SkipForward, Send, Zap, Square, Eye,
} from "lucide-react";

const STATUS_CONFIG = {
  queued: { icon: Clock, color: "text-[var(--c-text-muted)]", bg: "bg-[var(--c-bg-subtle)]", border: "border-[var(--c-border)]", label: "Queued" },
  generating: { icon: Loader2, color: "text-indigo-500 dark:text-indigo-400", bg: "bg-indigo-500/5", border: "border-indigo-500/10", label: "Generating", spin: true },
  ready: { icon: Eye, color: "text-amber-600 dark:text-amber-300", bg: "bg-amber-500/10", border: "border-amber-500/20", label: "Ready" },
  sending: { icon: Loader2, color: "text-indigo-600 dark:text-indigo-300", bg: "bg-indigo-500/10", border: "border-indigo-500/20", label: "Sending", spin: true },
  sent: { icon: CheckCircle2, color: "text-emerald-700 dark:text-emerald-300", bg: "bg-emerald-500/10", border: "border-emerald-500/20", label: "Sent" },
  skipped: { icon: SkipForward, color: "text-[var(--c-text-muted)]", bg: "bg-[var(--c-bg-subtle)]", border: "border-[var(--c-border)]", label: "Skipped" },
  failed: { icon: XCircle, color: "text-red-500 dark:text-red-400", bg: "bg-red-500/5", border: "border-red-500/10", label: "Failed" },
};

export default function EmailQueue({ queue, currentIndex, stats, batchMode, autoRunning, onSelect, onApprove, onSkip, onAutoRun, onStopAuto }) {
  if (!queue || queue.length === 0) return null;

  const total = queue.length;
  const sent = stats?.sent || 0;
  const failed = stats?.failed || 0;
  const skipped = stats?.skipped || 0;
  const done = sent + failed + skipped;
  const progress = total > 0 ? (done / total) * 100 : 0;

  return (
    <div className="sticky bottom-0 bg-[var(--c-bg-primary)]/80 backdrop-blur-xl border-t border-[var(--c-border)] px-6 py-3 transition-colors duration-300 z-30">
      <div className="flex items-center justify-between mb-2">
        <div className="flex items-center gap-3 text-[11px]">
          <span className="font-bold text-[var(--c-text-primary)]">{sent}/{total}</span>
          <span className="text-[var(--c-text-muted)]">sent</span>
          {skipped > 0 && <span className="text-[var(--c-text-muted)]">{skipped} skipped</span>}
          {failed > 0 && <span className="text-red-500 dark:text-red-400 font-medium">{failed} failed</span>}
          {autoRunning && <span className="flex items-center gap-1 text-indigo-500 dark:text-indigo-400 font-medium"><Loader2 size={10} className="animate-spin" /> Running...</span>}
        </div>
        <div className="flex items-center gap-2">
          {batchMode === "auto" && !autoRunning && sent < total && (
            <button onClick={onAutoRun} className="flex items-center gap-1.5 px-4 py-1.5 bg-gradient-to-r from-emerald-600 to-teal-600 hover:from-emerald-500 hover:to-teal-500 text-white text-[11px] font-bold rounded-lg transition-all shadow-lg shadow-emerald-500/15">
              <Zap size={11} /> Auto-Send All
            </button>
          )}
          {autoRunning && (
            <button onClick={onStopAuto} className="flex items-center gap-1.5 px-4 py-1.5 bg-red-500/20 hover:bg-red-500/30 text-red-500 dark:text-red-400 border border-red-500/20 text-[11px] font-semibold rounded-lg transition-all">
              <Square size={11} /> Stop
            </button>
          )}
        </div>
      </div>

      <div className="w-full bg-gray-200 dark:bg-white/[0.04] rounded-full h-1 mb-3 overflow-hidden">
        <div className="bg-gradient-to-r from-emerald-400 to-teal-400 h-1 rounded-full transition-all duration-700 ease-out" style={{ width: `${progress}%` }} />
      </div>

      <div className="flex gap-1.5 overflow-x-auto pb-1">
        {queue.map((item, i) => {
          const config = STATUS_CONFIG[item.status] || STATUS_CONFIG.queued;
          const Icon = config.icon;
          const isActive = i === currentIndex;
          return (
            <div key={i} className="shrink-0 flex flex-col items-center gap-0.5">
              <button onClick={() => onSelect?.(i)}
                className={`flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-[11px] font-medium transition-all border ${isActive ? "bg-indigo-500/20 text-indigo-600 dark:text-indigo-300 border-indigo-500/30 shadow-lg shadow-indigo-500/10" : `${config.bg} ${config.color} ${config.border} hover:brightness-110`
                  }`}
                title={`${item.email} — ${config.label}${item.error ? ": " + item.error : ""}`}>
                <Icon size={11} className={config.spin ? "animate-spin" : ""} />
                <span className="max-w-[90px] truncate">{item.email?.split("@")[0] || item.input}</span>
              </button>
              {isActive && item.status === "ready" && batchMode === "manual" && (
                <div className="flex gap-1 mt-0.5">
                  <button onClick={() => onApprove?.(i)} className="flex items-center gap-0.5 px-2 py-0.5 bg-emerald-500 hover:bg-emerald-400 text-white rounded text-[9px] font-semibold transition-colors" title="Send"><Send size={8} /> Send</button>
                  <button onClick={() => onSkip?.(i)} className="px-2 py-0.5 bg-gray-100 dark:bg-white/5 text-gray-500 dark:text-[#5a5a72] hover:bg-gray-200 dark:hover:bg-white/10 rounded text-[9px] font-medium transition-colors" title="Skip">Skip</button>
                </div>
              )}
            </div>
          );
        })}
      </div>
    </div>
  );
}