File size: 4,089 Bytes
4083225
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import { useEffect, useRef, useState } from "react";
import { X } from "lucide-react";
import "./TopicSelector.css";
import { DEFAULT_NEWS_TIMEFRAME, NEWS_TIMEFRAMES } from "../constants/timeframes.js";

const SUGGESTIONS = [
  "Russia–Ukraine war",
  "Israel–Gaza conflict",
  "Sahel coups",
  "South China Sea disputes",
  "Climate negotiations at COP",
  "Migration across the Mediterranean",
];

export default function TopicSelector({ initialQuery, onSubmit, onCancel }) {
  const [topic, setTopic] = useState(initialQuery?.topic ?? "");
  const [newsTimeframe, setNewsTimeframe] = useState(
    initialQuery?.newsTimeframe ?? DEFAULT_NEWS_TIMEFRAME
  );
  const inputRef = useRef(null);

  useEffect(() => {
    inputRef.current?.focus();
  }, []);

  useEffect(() => {
    setTopic(initialQuery?.topic ?? "");
    setNewsTimeframe(initialQuery?.newsTimeframe ?? DEFAULT_NEWS_TIMEFRAME);
  }, [initialQuery]);

  useEffect(() => {
    function onKey(e) {
      if (e.key === "Escape" && onCancel) onCancel();
    }
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [onCancel]);

  const canSubmit = topic.trim().length > 0;

  function submit(e) {
    e?.preventDefault();
    if (!canSubmit) return;
    onSubmit({
      topic: topic.trim(),
      newsTimeframe,
    });
  }

  return (
    <div className="modal" role="dialog" aria-modal="true" aria-label="Define a topic">
      <div className="modal__backdrop" onClick={onCancel} />
      <form className="modal__panel" onSubmit={submit}>
        <header className="modal__header">
          <div>
            <div className="label">Define a topic</div>
            <h2 className="modal__title">Open an investigation</h2>
          </div>
          {onCancel && (
            <button
              type="button"
              className="ghost modal__close"
              aria-label="Close"
              onClick={onCancel}
            >
              <X size={16} strokeWidth={1.5} />
            </button>
          )}
        </header>

        <div className="modal__body">
          <label className="field">
            <span className="label">Topic / query</span>
            <input
              ref={inputRef}
              type="text"
              value={topic}
              onChange={(e) => setTopic(e.target.value)}
              placeholder="e.g. Russia–Ukraine war, Gaza ceasefire negotiations…"
            />
          </label>

          <label className="field">
            <span className="label">News timeframe</span>
            <select
              value={newsTimeframe}
              onChange={(e) => setNewsTimeframe(e.target.value)}
            >
              {NEWS_TIMEFRAMES.map((item) => (
                <option key={item.value} value={item.value}>
                  {item.label}
                </option>
              ))}
            </select>
          </label>

          <div className="suggestions">
            <div className="label">Suggested investigations</div>
            <div className="suggestions__chips">
              {SUGGESTIONS.map((s) => (
                <button
                  key={s}
                  type="button"
                  className="chip"
                  onClick={() => setTopic(s)}
                >
                  {s}
                </button>
              ))}
            </div>
          </div>
        </div>

        <footer className="modal__footer">
          <p className="modal__hint">
            FrameVis will compile coverage from international wires, national
            press, and partisan outlets — then surface where their narratives
            diverge.
          </p>
          <div className="modal__actions">
            {onCancel && (
              <button type="button" onClick={onCancel}>
                Cancel
              </button>
            )}
            <button type="submit" className="primary" disabled={!canSubmit}>
              Open investigation
            </button>
          </div>
        </footer>
      </form>
    </div>
  );
}