Seth0330 commited on
Commit
1a97c17
·
verified ·
1 Parent(s): c0fd8f6

Create ShareLinkModal.jsx

Browse files
frontend/src/components/ShareLinkModal.jsx ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useState, useEffect } from "react";
2
+ import { motion, AnimatePresence } from "framer-motion";
3
+ import { X, Copy, Check, Loader2 } from "lucide-react";
4
+ import { Button } from "@/components/ui/button";
5
+ import { Input } from "@/components/ui/input";
6
+
7
+ export default function ShareLinkModal({ isOpen, onClose, shareLink, isLoading }) {
8
+ const [copied, setCopied] = useState(false);
9
+
10
+ useEffect(() => {
11
+ if (!isOpen) {
12
+ setCopied(false);
13
+ }
14
+ }, [isOpen]);
15
+
16
+ const handleCopy = async () => {
17
+ if (!shareLink) return;
18
+
19
+ try {
20
+ await navigator.clipboard.writeText(shareLink);
21
+ setCopied(true);
22
+ setTimeout(() => setCopied(false), 2000);
23
+ } catch (err) {
24
+ // Fallback for older browsers
25
+ const textArea = document.createElement("textarea");
26
+ textArea.value = shareLink;
27
+ textArea.style.position = "fixed";
28
+ textArea.style.opacity = "0";
29
+ document.body.appendChild(textArea);
30
+ textArea.select();
31
+ try {
32
+ document.execCommand("copy");
33
+ setCopied(true);
34
+ setTimeout(() => setCopied(false), 2000);
35
+ } catch (fallbackErr) {
36
+ console.error("Failed to copy:", fallbackErr);
37
+ }
38
+ document.body.removeChild(textArea);
39
+ }
40
+ };
41
+
42
+ if (!isOpen) return null;
43
+
44
+ return (
45
+ <AnimatePresence>
46
+ <div className="fixed inset-0 z-50 flex items-center justify-center">
47
+ {/* Backdrop */}
48
+ <motion.div
49
+ initial={{ opacity: 0 }}
50
+ animate={{ opacity: 1 }}
51
+ exit={{ opacity: 0 }}
52
+ className="absolute inset-0 bg-black/50 backdrop-blur-sm"
53
+ onClick={onClose}
54
+ />
55
+
56
+ {/* Modal */}
57
+ <motion.div
58
+ initial={{ opacity: 0, scale: 0.95, y: 20 }}
59
+ animate={{ opacity: 1, scale: 1, y: 0 }}
60
+ exit={{ opacity: 0, scale: 0.95, y: 20 }}
61
+ className="relative z-10 w-full max-w-md mx-4 bg-white rounded-2xl shadow-2xl overflow-hidden"
62
+ onClick={(e) => e.stopPropagation()}
63
+ >
64
+ {/* Header */}
65
+ <div className="px-6 py-4 border-b border-slate-200 flex items-center justify-between">
66
+ <h2 className="text-xl font-semibold text-slate-900">Copy Share Link</h2>
67
+ <button
68
+ onClick={onClose}
69
+ disabled={isLoading}
70
+ className="p-2 rounded-lg hover:bg-slate-100 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
71
+ >
72
+ <X className="h-5 w-5 text-slate-500" />
73
+ </button>
74
+ </div>
75
+
76
+ {/* Content */}
77
+ <div className="px-6 py-6">
78
+ {isLoading ? (
79
+ <div className="text-center py-8">
80
+ <Loader2 className="h-8 w-8 mx-auto mb-4 text-indigo-600 animate-spin" />
81
+ <p className="text-sm text-slate-600">Generating share link...</p>
82
+ </div>
83
+ ) : shareLink ? (
84
+ <div className="space-y-4">
85
+ <div>
86
+ <label className="block text-sm font-medium text-slate-700 mb-2">
87
+ Share Link
88
+ </label>
89
+ <div className="flex gap-2">
90
+ <Input
91
+ type="text"
92
+ value={shareLink}
93
+ readOnly
94
+ className="flex-1 h-12 rounded-xl border-slate-200 bg-slate-50 text-sm font-mono"
95
+ />
96
+ <Button
97
+ onClick={handleCopy}
98
+ className="h-12 px-4 rounded-xl bg-gradient-to-r from-indigo-600 to-violet-600 hover:from-indigo-700 hover:to-violet-700"
99
+ >
100
+ {copied ? (
101
+ <>
102
+ <Check className="h-4 w-4 mr-2" />
103
+ Copied!
104
+ </>
105
+ ) : (
106
+ <>
107
+ <Copy className="h-4 w-4 mr-2" />
108
+ Copy
109
+ </>
110
+ )}
111
+ </Button>
112
+ </div>
113
+ </div>
114
+ <p className="text-xs text-slate-500">
115
+ Share this link with anyone you want to give access to this extraction. They'll need to sign in to view it.
116
+ </p>
117
+ </div>
118
+ ) : (
119
+ <div className="text-center py-8">
120
+ <p className="text-sm text-slate-600">No share link available</p>
121
+ </div>
122
+ )}
123
+
124
+ <div className="pt-4 mt-6 border-t border-slate-200">
125
+ <Button
126
+ type="button"
127
+ variant="outline"
128
+ onClick={onClose}
129
+ disabled={isLoading}
130
+ className="w-full h-11 rounded-xl"
131
+ >
132
+ Close
133
+ </Button>
134
+ </div>
135
+ </div>
136
+ </motion.div>
137
+ </div>
138
+ </AnimatePresence>
139
+ );
140
+ }
141
+