File size: 5,067 Bytes
78b3b2b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import React, { useMemo, useState } from 'react';
import { parseCsv } from '../../utils/index.ts';

import type { CsvRow } from '../../types/index.ts';

interface UploadCsvModalProps {
  isOpen: boolean;
  onClose: () => void;
  onAnalyze: (file: File) => Promise<void>;
  isAnalyzing: boolean;
}

const UploadCsvModal = ({
  isOpen,
  onClose,
  onAnalyze,
  isAnalyzing
}: UploadCsvModalProps) => {
  const [selectedFile, setSelectedFile] = useState<File | null>(null);
  const [rows, setRows] = useState<CsvRow[]>([]);
  const [error, setError] = useState<string | null>(null);

  const fileName = useMemo(
    () => selectedFile?.name ?? 'Select a CSV file with arguments',
    [selectedFile]
  );

  const handleFileChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0] ?? null;
    setSelectedFile(file);
    setError(null);
    setRows([]);

    if (!file) {
      return;
    }

    // Parse CSV
    try {
      const content = await file.text();
      const parsed = parseCsv(content);

      setRows(parsed.rows);

      if (parsed.rows.length === 0) {
        setError('No data found in the CSV file.');
      }
    } catch (err) {
      setError(
        err instanceof Error ? err.message : 'Unable to read the CSV file.'
      );
      setRows([]);
    }
  };

  const handleAnalyze = async () => {
    if (!selectedFile) {
      setError('Please choose a CSV file to analyze.');
      return;
    }

    if (rows.length === 0) {
      setError('No data found in the CSV file.');
      return;
    }

    await onAnalyze(selectedFile);
  };

  if (!isOpen) return null;

  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/50 dark:bg-black/70">
      <div
        className="relative w-full max-w-2xl max-h-[90vh] overflow-hidden rounded-xl border border-slate-200 dark:border-zinc-700 bg-white dark:bg-zinc-900 shadow-xl"
        onClick={(e) => e.stopPropagation()}
      >
        <div className="flex items-center justify-between border-b border-slate-200 dark:border-zinc-700 px-6 py-4">
          <h2 className="text-lg font-semibold text-slate-800 dark:text-white">
            Analyze New Arguments
          </h2>
          <button
            onClick={onClose}
            className="text-slate-500 dark:text-zinc-400 hover:text-slate-700 dark:hover:text-zinc-200 transition-colors"
            aria-label="Close"
          >
            <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
              <path fillRule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clipRule="evenodd" />
            </svg>
          </button>
        </div>

        <div className="p-6 space-y-6 overflow-y-auto max-h-[calc(90vh-140px)]">
          <div className="flex flex-col gap-3">
            <label className="text-sm font-medium text-slate-700 dark:text-zinc-300">
              Upload a CSV file
            </label>

            <div className="flex flex-wrap items-center justify-between gap-3">
              <label className="flex w-full max-w-xl cursor-pointer items-center justify-between rounded-full border border-slate-300 dark:border-zinc-600 bg-slate-50 dark:bg-zinc-800 px-5 py-3 transition hover:border-slate-400 dark:hover:border-zinc-500">
                <span className="truncate text-sm font-semibold text-slate-500 dark:text-zinc-400">
                  {fileName}
                </span>
                <input
                  type="file"
                  accept=".csv,text/csv"
                  className="hidden"
                  onChange={handleFileChange}
                />
              </label>

              <div className="flex w-full justify-center">
                <button
                  type="button"
                  onClick={handleAnalyze}
                  disabled={!selectedFile || rows.length === 0 || isAnalyzing}
                  className="rounded-md bg-blue-600 dark:bg-blue-500 px-4 py-2 text-sm font-semibold text-white transition hover:bg-blue-700 dark:hover:bg-blue-600 disabled:cursor-not-allowed disabled:opacity-60"
                >
                  {isAnalyzing ? 'Analyzing...' : 'Analyze'}
                </button>
              </div>
            </div>
            {error && <p className="text-sm text-red-600 dark:text-red-400">{error}</p>}
          </div>

          {isAnalyzing && (
            <div className="flex items-center justify-center py-8">
              <div className="flex flex-col items-center">
                <div className="h-10 w-10 animate-spin rounded-full border-4 border-blue-600 border-t-transparent"></div>
                <p className="mt-3 text-sm text-slate-600 dark:text-zinc-400">Analyzing arguments...</p>
              </div>
            </div>
          )}
        </div>
      </div>
    </div>
  );
};

export default UploadCsvModal;