Untitled
unknown
plain_text
2 months ago
11 kB
4
Indexable
import React, { useState, useEffect } from 'react'; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@/components/ui/alert-dialog"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Switch } from "@/components/ui/switch"; import { CheckCircle, Copy, Eye, EyeOff, Link, Lock, Share2, ExternalLink, X, Check, Loader2 } from "lucide-react"; import { toast } from "sonner"; interface ShareDialogProps { open: boolean; onOpenChange: (open: boolean) => void; favoriteCount: number; clientId: string; handleCreateSharedLink: (password: string, requirePassword: boolean) => Promise<string>; } export function ShareDialog({ open, onOpenChange, favoriteCount, clientId, handleCreateSharedLink }: ShareDialogProps) { const [password, setPassword] = useState(""); const [requirePassword, setRequirePassword] = useState(true); const [shareLink, setShareLink] = useState(""); const [isLoading, setIsLoading] = useState(false); const [showPassword, setShowPassword] = useState(false); const [showConfirmation, setShowConfirmation] = useState(false); const [copyIconState, setCopyIconState] = useState<'copy' | 'success' | 'error'>('copy'); const [processingLink, setProcessingLink] = useState(false); // Reset copy icon state after animation useEffect(() => { if (copyIconState !== 'copy') { const timer = setTimeout(() => { setCopyIconState('copy'); }, 2000); return () => clearTimeout(timer); } }, [copyIconState]); const resetState = () => { setPassword(""); setRequirePassword(true); setShareLink(""); setShowPassword(false); setShowConfirmation(false); setIsLoading(false); setCopyIconState('copy'); setProcessingLink(false); }; const handleClose = () => { resetState(); onOpenChange(false); }; const handleCreate = async () => { setShowConfirmation(true); }; const handleConfirm = async () => { try { setIsLoading(true); setShowConfirmation(false); setProcessingLink(true); // Show the processing overlay const link = await handleCreateSharedLink(password, requirePassword); setShareLink(link); } catch (error) { console.error("Error creating shared link:", error); toast.error("Fehler beim Erstellen des Links."); } finally { setIsLoading(false); setProcessingLink(false); // Hide the processing overlay } }; const copyToClipboard = () => { navigator.clipboard.writeText(shareLink) .then(() => { toast.success("Link in die Zwischenablage kopiert!"); setCopyIconState('success'); }) .catch(() => { toast.error("Fehler beim Kopieren des Links."); setCopyIconState('error'); }); }; const openLinkInNewTab = () => { window.open(shareLink, '_blank'); }; return ( <> {/* Confirmation Dialog */} <AlertDialog open={showConfirmation} onOpenChange={setShowConfirmation}> <AlertDialogContent className="bg-zinc-900 border-zinc-800 text-zinc-100"> <AlertDialogHeader> <AlertDialogTitle className="flex items-center gap-2"> <Share2 className="h-5 w-5 text-blue-500" /> Favoriten teilen bestätigen </AlertDialogTitle> <AlertDialogDescription className="text-zinc-400"> Sie teilen {favoriteCount} {favoriteCount === 1 ? 'Bild' : 'Bilder'} {requirePassword ? ( <> mit Passwortschutz: <span className="font-medium text-zinc-300">{password}</span></> ) : ( <> ohne Passwortschutz</> )} </AlertDialogDescription> </AlertDialogHeader> <AlertDialogFooter> <AlertDialogCancel className="bg-zinc-800 text-zinc-300 hover:bg-zinc-700 hover:text-zinc-100 border-zinc-700"> Abbrechen </AlertDialogCancel> <AlertDialogAction className="bg-blue-600 hover:bg-blue-700 text-white border-0" onClick={handleConfirm} disabled={isLoading} > {isLoading ? ( <> <Loader2 className="mr-2 h-4 w-4 animate-spin" /> Wird erstellt... </> ) : ( "Link erstellen" )} </AlertDialogAction> </AlertDialogFooter> </AlertDialogContent> </AlertDialog> {/* Main Share Dialog */} <Dialog open={open} onOpenChange={handleClose}> <DialogContent className="bg-zinc-900 border-zinc-800 text-zinc-100 sm:max-w-md"> <DialogHeader> <DialogTitle className="flex items-center gap-2"> <Share2 className="h-5 w-5 text-blue-500" /> Favoriten teilen </DialogTitle> <DialogDescription className="text-zinc-400"> Erstellen Sie einen Link, um Ihre {favoriteCount} ausgewählten Bilder zu teilen. </DialogDescription> </DialogHeader> {/* Processing Link Overlay */} {processingLink && ( <div className="absolute inset-0 bg-zinc-900/90 backdrop-blur-sm flex flex-col items-center justify-center z-50 rounded-md"> <div className="bg-indigo-500/10 p-4 rounded-full mb-4"> <Loader2 className="h-8 w-8 text-indigo-400 animate-spin" /> </div> <h3 className="text-lg font-medium mb-2 text-zinc-200">Link wird erstellt</h3> <p className="text-zinc-400 text-center max-w-xs"> Bitte warten Sie, während Ihr persönlicher Link generiert wird... </p> </div> )} {shareLink ? ( <div className="space-y-4 py-2"> <div className="bg-zinc-800/50 p-3 rounded-md flex items-center gap-2 border border-zinc-700"> <CheckCircle className="h-5 w-5 text-green-500 flex-shrink-0" /> <p className="text-sm text-zinc-300"> Link wurde erfolgreich erstellt! </p> </div> <div className="flex items-center space-x-2"> <div className="bg-zinc-800 flex-1 rounded-md flex items-center overflow-hidden"> <div className="bg-zinc-900/50 p-3"> <Link className="h-5 w-5 text-zinc-400" /> </div> <input className="flex-1 bg-transparent border-0 text-sm px-3 py-2 focus:outline-none text-zinc-300" value={shareLink} readOnly /> </div> <Button type="button" size="icon" onClick={copyToClipboard} className={`transition-colors duration-300 ${ copyIconState === 'success' ? 'bg-green-600 hover:bg-green-700' : copyIconState === 'error' ? 'bg-red-600 hover:bg-red-700' : 'bg-blue-600 hover:bg-blue-700' } text-white`} > {copyIconState === 'copy' && <Copy className="h-4 w-4" />} {copyIconState === 'success' && <Check className="h-4 w-4" />} {copyIconState === 'error' && <X className="h-4 w-4" />} </Button> </div> <Button type="button" onClick={openLinkInNewTab} className="w-full bg-zinc-800 hover:bg-zinc-700 text-zinc-300 flex items-center justify-center gap-2" > <ExternalLink className="h-4 w-4" /> Link in neuem Tab öffnen </Button> <div className="pt-2"> <Button onClick={handleClose} className="w-full" > Schließen </Button> </div> </div> ) : ( <div className="space-y-4 py-2"> <div className="space-y-4"> <div className="flex items-center justify-between"> <Label htmlFor="require-password" className="text-zinc-300 flex items-center gap-2"> <Lock className="h-4 w-4 text-zinc-400" /> Passwortschutz </Label> <Switch id="require-password" checked={requirePassword} onCheckedChange={setRequirePassword} /> </div> {requirePassword && ( <div className="space-y-2"> <Label htmlFor="password" className="text-zinc-300"> Passwort für den geteilten Link </Label> <div className="relative"> <Input id="password" type={showPassword ? "text" : "password"} value={password} onChange={(e) => setPassword(e.target.value)} placeholder="Passwort eingeben" className="bg-zinc-800 border-zinc-700 pr-10" /> <button type="button" onClick={() => setShowPassword(!showPassword)} className="absolute right-3 top-2.5 text-zinc-400 hover:text-zinc-300" > {showPassword ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />} </button> </div> </div> )} <div className="pt-2"> <Button onClick={handleCreate} disabled={requirePassword && !password} className="w-full bg-gradient-to-r from-indigo-500 to-blue-500 hover:from-indigo-600 hover:to-blue-600 text-white border-0" > Link erstellen </Button> </div> </div> </div> )} </DialogContent> </Dialog> </> ); }
Editor is loading...
Leave a Comment