Spaces:
Sleeping
Sleeping
| import React, { useState, useEffect } from "react"; | |
| import { motion, AnimatePresence } from "framer-motion"; | |
| import { X, Copy, Check, Loader2 } from "lucide-react"; | |
| import { Button } from "@/components/ui/button"; | |
| import { Input } from "@/components/ui/input"; | |
| export default function ShareLinkModal({ isOpen, onClose, shareLink, isLoading }) { | |
| const [copied, setCopied] = useState(false); | |
| useEffect(() => { | |
| if (!isOpen) { | |
| setCopied(false); | |
| } | |
| }, [isOpen]); | |
| const handleCopy = async () => { | |
| if (!shareLink) return; | |
| try { | |
| await navigator.clipboard.writeText(shareLink); | |
| setCopied(true); | |
| setTimeout(() => setCopied(false), 2000); | |
| } catch (err) { | |
| // Fallback for older browsers | |
| const textArea = document.createElement("textarea"); | |
| textArea.value = shareLink; | |
| textArea.style.position = "fixed"; | |
| textArea.style.opacity = "0"; | |
| document.body.appendChild(textArea); | |
| textArea.select(); | |
| try { | |
| document.execCommand("copy"); | |
| setCopied(true); | |
| setTimeout(() => setCopied(false), 2000); | |
| } catch (fallbackErr) { | |
| console.error("Failed to copy:", fallbackErr); | |
| } | |
| document.body.removeChild(textArea); | |
| } | |
| }; | |
| if (!isOpen) return null; | |
| return ( | |
| <AnimatePresence> | |
| <div className="fixed inset-0 z-50 flex items-center justify-center"> | |
| {/* Backdrop */} | |
| <motion.div | |
| initial={{ opacity: 0 }} | |
| animate={{ opacity: 1 }} | |
| exit={{ opacity: 0 }} | |
| className="absolute inset-0 bg-black/50 backdrop-blur-sm" | |
| onClick={onClose} | |
| /> | |
| {/* Modal */} | |
| <motion.div | |
| initial={{ opacity: 0, scale: 0.95, y: 20 }} | |
| animate={{ opacity: 1, scale: 1, y: 0 }} | |
| exit={{ opacity: 0, scale: 0.95, y: 20 }} | |
| className="relative z-10 w-full max-w-md mx-4 bg-white rounded-2xl shadow-2xl overflow-hidden" | |
| onClick={(e) => e.stopPropagation()} | |
| > | |
| {/* Header */} | |
| <div className="px-6 py-4 border-b border-slate-200 flex items-center justify-between"> | |
| <h2 className="text-xl font-semibold text-slate-900">Copy Share Link</h2> | |
| <button | |
| onClick={onClose} | |
| disabled={isLoading} | |
| className="p-2 rounded-lg hover:bg-slate-100 transition-colors disabled:opacity-50 disabled:cursor-not-allowed" | |
| > | |
| <X className="h-5 w-5 text-slate-500" /> | |
| </button> | |
| </div> | |
| {/* Content */} | |
| <div className="px-6 py-6"> | |
| {isLoading ? ( | |
| <div className="text-center py-8"> | |
| <Loader2 className="h-8 w-8 mx-auto mb-4 text-indigo-600 animate-spin" /> | |
| <p className="text-sm text-slate-600">Generating share link...</p> | |
| </div> | |
| ) : shareLink ? ( | |
| <div className="space-y-4"> | |
| <div> | |
| <label className="block text-sm font-medium text-slate-700 mb-2"> | |
| Share Link | |
| </label> | |
| <div className="flex gap-2"> | |
| <Input | |
| type="text" | |
| value={shareLink} | |
| readOnly | |
| className="flex-1 h-12 rounded-xl border-slate-200 bg-slate-50 text-sm font-mono" | |
| /> | |
| <Button | |
| onClick={handleCopy} | |
| 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" | |
| > | |
| {copied ? ( | |
| <> | |
| <Check className="h-4 w-4 mr-2" /> | |
| Copied! | |
| </> | |
| ) : ( | |
| <> | |
| <Copy className="h-4 w-4 mr-2" /> | |
| Copy | |
| </> | |
| )} | |
| </Button> | |
| </div> | |
| </div> | |
| <p className="text-xs text-slate-500"> | |
| Share this link with anyone you want to give access to this extraction. They'll need to sign in to view it. | |
| </p> | |
| </div> | |
| ) : ( | |
| <div className="text-center py-8"> | |
| <p className="text-sm text-slate-600">No share link available</p> | |
| </div> | |
| )} | |
| <div className="pt-4 mt-6 border-t border-slate-200"> | |
| <Button | |
| type="button" | |
| variant="outline" | |
| onClick={onClose} | |
| disabled={isLoading} | |
| className="w-full h-11 rounded-xl" | |
| > | |
| Close | |
| </Button> | |
| </div> | |
| </div> | |
| </motion.div> | |
| </div> | |
| </AnimatePresence> | |
| ); | |
| } | |