All files / lib/awareness/collective/components ExportCenter.tsx

86.53% Statements 90/104
20% Branches 1/5
11.11% Functions 1/9
86.53% Lines 90/104

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 1881x   1x               1x   1x 1x           1x 1x       1x 1x     1x 3x 3x 3x   3x 3x         3x         3x         3x 3x   3x 3x   3x   3x 3x 3x 3x         3x 3x 3x 3x 3x     3x 3x     3x 3x     3x 3x 3x 3x           3x 3x 3x 3x 3x     3x 3x 3x 3x           3x 3x       3x 3x   3x     3x 3x 3x 3x 3x 3x   3x 3x 3x       3x 3x 3x 3x 3x   3x 3x 3x       3x 3x 3x       3x             3x 3x     3x 3x 3x 3x     3x 3x       3x               3x 3x 3x 3x 3x 3x       3x  
"use client";
 
/**
 * @file ExportCenter.tsx
 * مركز تصدير وتحليل شامل
 * يدعم:
 *  - Snapshot يدوي + تشغيل/إيقاف Auto Snapshot
 *  - Export Evolution Logs (CSV / JSON)
 *  - Export 📌 Pinned Insights (CSV / PDF)
 *  - HUD Animated AI Panel (Phase 006.9.R)
 */
 
import React, { useState } from "react";
import {
  getEvolutionLogs,
  logSnapshot,
  startAutoSnapshot,
  stopAutoSnapshot,
} from "@/lib/evolution/history.collector";
import { download, toCSV, toJSON } from "@/lib/evolution/exporters/report";
import {
  downloadCSV as downloadPinnedCSV,
  downloadPDF as downloadPinnedPDF,
} from "@/lib/awareness/collective/analysis/exporter";
import { getPinnedInsights } from "@/lib/evolution/history.pins";
import { HUDLayerManager } from "./HUDLayerManager"; // ✅
import type { Insight } from "../analysis/insight";
 
export const ExportCenter: React.FC = () => {
  const [showAI, setShowAI] = useState(false);
  const [showVoice, setShowVoice] = useState(false);
  const [initialInsight, setInitialInsight] = useState<Insight | null>(null);
 
  // === Evolution Logs ===
  const handleExportCSV = () => {
    const csv = toCSV(getEvolutionLogs());
    download(`evolution_logs_${Date.now()}.csv`, csv, "text/csv");
  };
 
  const handleExportJSON = () => {
    const json = toJSON(getEvolutionLogs());
    download(`evolution_logs_${Date.now()}.json`, json, "application/json");
  };
 
  const handleManualSnapshot = () => {
    logSnapshot({ notes: "manual:snapshot" });
    location.reload();
  };
 
  // === Annotated Insights ===
  const pinned = getPinnedInsights();
 
  const avgConfidence =
    pinned.length > 0
      ? pinned.reduce((s, p) => s + (p.confidence || 0), 0) / pinned.length
      : 0;
 
  return (
    <>
      <div className="relative rounded-2xl border border-[hsl(var(--border))/50] bg-[hsl(var(--card))/80] p-5 shadow-[inset_0_0_25px_rgba(0,0,0,0.3)] overflow-hidden">
        <h3 className="text-[hsl(var(--primary))] font-semibold mb-3">
          Export Center
        </h3>
 
        {/* === Snapshot Controls === */}
        <div className="flex flex-wrap gap-2 mb-3">
          <button
            onClick={handleManualSnapshot}
            className="px-3 py-1.5 rounded-md border border-[hsl(var(--border))/60] hover:bg-[hsl(var(--muted))/30] text-sm transition"
          >
            📸 Snapshot Now
          </button>
          <button
            onClick={() =>
              startAutoSnapshot({ intervalSec: 60, confidenceDelta: 0.05 })
            }
            className="px-3 py-1.5 rounded-md border border-[hsl(var(--border))/60] hover:bg-[hsl(var(--muted))/30] text-sm transition"
          >
            ▶ Auto-Snapshot: Start
          </button>
          <button
            onClick={() => stopAutoSnapshot()}
            className="px-3 py-1.5 rounded-md border border-[hsl(var(--border))/60] hover:bg-[hsl(var(--muted))/30] text-sm transition"
          >
            ⏹ Auto-Snapshot: Stop
          </button>
        </div>
 
        {/* === Logs Export === */}
        <div className="flex flex-wrap gap-2 mb-4">
          <button
            onClick={handleExportCSV}
            className="px-3 py-1.5 rounded-md border border-[hsl(var(--border))/60] hover:bg-[hsl(var(--muted))/30] text-sm transition"
          >
            ⬇ Export Logs (CSV)
          </button>
          <button
            onClick={handleExportJSON}
            className="px-3 py-1.5 rounded-md border border-[hsl(var(--border))/60] hover:bg-[hsl(var(--muted))/30] text-sm transition"
          >
            ⬇ Export Logs (JSON)
          </button>
        </div>
 
        {/* === Insights Export === */}
        <div className="border-t border-[hsl(var(--border))/30] pt-3 mt-2">
          <h4 className="text-[hsl(var(--primary))] text-sm font-semibold mb-2">
            📌 Annotated Insights
          </h4>
 
          <p className="text-xs text-[hsl(var(--muted-foreground))] mb-3">
            {pinned.length > 0
              ? `You have ${pinned.length} pinned insights ready for export.`
              : "No pinned insights yet — select and pin insights from the chart."}
          </p>
 
          <div className="flex flex-wrap gap-2">
            <button
              onClick={downloadPinnedCSV}
              disabled={!pinned.length}
              className={`px-3 py-1.5 rounded-md border border-[hsl(var(--border))/60] text-sm transition ${
                pinned.length
                  ? "hover:bg-[hsl(var(--muted))/30]"
                  : "opacity-50 cursor-not-allowed"
              }`}
            >
              ⬇ Export Insights (CSV)
            </button>
 
            <button
              onClick={downloadPinnedPDF}
              disabled={!pinned.length}
              className={`px-3 py-1.5 rounded-md border border-[hsl(var(--border))/60] text-sm transition ${
                pinned.length
                  ? "hover:bg-[hsl(var(--muted))/30]"
                  : "opacity-50 cursor-not-allowed"
              }`}
            >
              🧾 Export Insights (PDF)
            </button>
 
            <button
              onClick={() => setShowAI(true)}
              className="px-4 py-2 rounded-md border border-[hsl(var(--border))/60]
                         bg-[hsl(var(--background))/60] hover:bg-[hsl(var(--muted))/30]
                         text-sm text-cyan-300 font-semibold shadow-[0_0_12px_rgba(0,255,255,0.25)]
                         transition-all duration-300 hover:scale-[1.03]"
            >
              🤖 Generate AI Summary
            </button>
          </div>
        </div>
 
        {/* === Insight Memory Bar === */}
        <div className="mt-6 border-t border-[hsl(var(--border))/40] pt-3">
          <h5 className="text-xs text-[hsl(var(--muted-foreground))] mb-1">
            System Confidence Memory
          </h5>
          <div className="h-2 w-full rounded-full bg-[hsl(var(--muted))/20] overflow-hidden">
            <div
              className="h-full bg-gradient-to-r from-teal-400 to-cyan-300 transition-all duration-500"
              style={{ width: `${avgConfidence * 100}%` }}
            ></div>
          </div>
          <p className="text-[10px] text-right mt-1 text-cyan-400/80">
            {(avgConfidence * 100).toFixed(1)}% Predictive Trust
          </p>
        </div>
 
        <p className="text-xs text-[hsl(var(--muted-foreground))] mt-3 leading-relaxed">
          Snapshots and pins are stored safely in localStorage (client-side).
          All exports follow the Jemy-dev OS HUD theme.
          Switchable to IndexedDB or remote sync in future builds.
        </p>
      </div>
 
      {/* 🔮 Mount unified HUD overlay */}
      <HUDLayerManager
        showAI={showAI}
        showVoice={showVoice}
        onCloseAI={() => setShowAI(false)}
        onCloseVoice={() => setShowVoice(false)}
        initialInsight={initialInsight}
      />
    </>
  );
};