| | 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) { |
| | |
| | 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> |
| | ); |
| | } |
| |
|