1+ import { useState } from "react" ;
2+ import type { EventData } from "../types/events" ;
3+
4+ interface ExportImportModalProps {
5+ isOpen : boolean ;
6+ onClose : ( ) => void ;
7+ events : EventData [ ] ;
8+ onImportEvents : ( events : EventData [ ] ) => void ;
9+ mode : "export" | "import" ;
10+ }
11+
12+ export function ExportImportModal ( {
13+ isOpen,
14+ onClose,
15+ events,
16+ onImportEvents,
17+ mode,
18+ } : ExportImportModalProps ) {
19+ const [ importText , setImportText ] = useState ( "" ) ;
20+ const [ copySuccess , setCopySuccess ] = useState ( false ) ;
21+
22+ const exportJson = JSON . stringify ( events , null , 2 ) ;
23+
24+ const handleCopy = async ( ) => {
25+ try {
26+ await navigator . clipboard . writeText ( exportJson ) ;
27+ setCopySuccess ( true ) ;
28+ setTimeout ( ( ) => setCopySuccess ( false ) , 2000 ) ;
29+ } catch ( err ) {
30+ console . error ( "Failed to copy text: " , err ) ;
31+ }
32+ } ;
33+
34+ const handleImport = ( ) => {
35+ try {
36+ const importedEvents = JSON . parse ( importText ) ;
37+ if ( Array . isArray ( importedEvents ) ) {
38+ onImportEvents ( importedEvents ) ;
39+ onClose ( ) ;
40+ setImportText ( "" ) ;
41+ } else {
42+ alert ( "Invalid format: Expected an array of events" ) ;
43+ }
44+ } catch {
45+ alert ( "Error parsing JSON data" ) ;
46+ }
47+ } ;
48+
49+ if ( ! isOpen ) return null ;
50+
51+ return (
52+ < div className = "fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50" >
53+ < div className = "bg-bg border border-sub rounded-lg p-6 max-w-2xl w-full mx-4 max-h-[80vh] flex flex-col" >
54+ < div className = "flex justify-between items-center mb-4" >
55+ < h2 className = "text-xl font-bold text-main" >
56+ { mode === "export" ? "Export Events" : "Import Events" }
57+ </ h2 >
58+ < button
59+ onClick = { onClose }
60+ className = "text-sub hover:text-text transition-colors"
61+ >
62+ ✕
63+ </ button >
64+ </ div >
65+
66+ { mode === "export" ? (
67+ < div className = "flex flex-col flex-1" >
68+ < div className = "flex justify-between items-center mb-2" >
69+ < p className = "text-text" >
70+ Copy the JSON data below ({ events . length } events):
71+ </ p >
72+ < button
73+ onClick = { handleCopy }
74+ className = "px-3 py-1 bg-main text-bg rounded hover:bg-main/80 transition-colors"
75+ >
76+ { copySuccess ? "Copied!" : "Copy" }
77+ </ button >
78+ </ div >
79+ < textarea
80+ value = { exportJson }
81+ readOnly
82+ className = "flex-1 bg-bg border border-sub rounded p-3 text-text font-mono text-sm resize-none"
83+ style = { { minHeight : "300px" } }
84+ />
85+ </ div >
86+ ) : (
87+ < div className = "flex flex-col flex-1" >
88+ < p className = "text-text mb-2" > Paste the JSON data below:</ p >
89+ < textarea
90+ value = { importText }
91+ onChange = { ( e ) => setImportText ( e . target . value ) }
92+ placeholder = "Paste exported JSON data here..."
93+ className = "flex-1 bg-bg border border-sub rounded p-3 text-text font-mono text-sm resize-none"
94+ style = { { minHeight : "300px" } }
95+ />
96+ < div className = "flex justify-end gap-2 mt-4" >
97+ < button
98+ onClick = { onClose }
99+ className = "px-4 py-2 bg-sub/20 hover:bg-sub/30 text-text rounded transition-colors"
100+ >
101+ Cancel
102+ </ button >
103+ < button
104+ onClick = { handleImport }
105+ disabled = { ! importText . trim ( ) }
106+ className = "px-4 py-2 bg-main text-bg rounded hover:bg-main/80 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
107+ >
108+ Import
109+ </ button >
110+ </ div >
111+ </ div >
112+ ) }
113+ </ div >
114+ </ div >
115+ ) ;
116+ }
0 commit comments