← back to Dear Bubbe Nextjs
components/ShareModal.tsx
272 lines
'use client'
import { useState, useEffect } from 'react'
interface ShareModalProps {
isOpen: boolean
onClose: () => void
messageToShare: string
}
export default function ShareModal({ isOpen, onClose, messageToShare }: ShareModalProps) {
const [copied, setCopied] = useState(false)
const [activeButton, setActiveButton] = useState<string | null>(null)
useEffect(() => {
if (isOpen) {
document.body.style.overflow = 'hidden'
} else {
document.body.style.overflow = 'unset'
}
return () => {
document.body.style.overflow = 'unset'
}
}, [isOpen])
if (!isOpen) return null
// Format message for sharing (remove any HTML or special characters)
const cleanMessage = messageToShare.replace(/<[^>]*>/g, '')
// Truncate for social media if too long
const twitterMessage = cleanMessage.length > 280 ? cleanMessage.substring(0, 277) + '...' : cleanMessage
// Add hashtag
const shareText = `${cleanMessage}\n\n#DearBubbe #BubbeAdvice #JewishGrandma`
const shortShareText = `${twitterMessage}\n\n#DearBubbe`
const handleCopyText = async () => {
try {
await navigator.clipboard.writeText(shareText)
setCopied(true)
setActiveButton('copy')
setTimeout(() => {
setCopied(false)
setActiveButton(null)
}, 2000)
} catch (err) {
console.error('Failed to copy text:', err)
}
}
const handleShare = (platform: string, action: () => void) => {
setActiveButton(platform)
action()
setTimeout(() => setActiveButton(null), 1000)
}
const handleShareToX = () => {
const url = `https://twitter.com/intent/tweet?text=${encodeURIComponent(shortShareText)}`
window.open(url, '_blank')
}
const handleShareToFacebook = () => {
const url = `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent('http://45.61.58.125:3011')}"e=${encodeURIComponent(shareText)}`
window.open(url, '_blank')
}
const handleShareToTikTok = () => {
// TikTok doesn't have direct share API - open app/website
window.open('https://www.tiktok.com/upload', '_blank')
// Copy text for user to paste
handleCopyText()
}
const handleShareToInstagram = () => {
// Instagram doesn't allow direct text sharing via web - copy text
handleCopyText()
// Open Instagram
window.open('https://www.instagram.com', '_blank')
}
const handleEmailShare = () => {
const subject = '👵 Bubbe gave me advice!'
const body = `Check out what Bubbe said:\n\n${shareText}\n\n❤️ Get your own advice from Bubbe at: http://45.61.58.125:3011`
const mailtoUrl = `mailto:?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`
window.location.href = mailtoUrl
}
const handleWhatsAppShare = () => {
const url = `https://wa.me/?text=${encodeURIComponent(shareText + '\n\n👵 Talk to Bubbe: http://45.61.58.125:3011')}`
window.open(url, '_blank')
}
return (
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 animate-in fade-in duration-300">
{/* Backdrop with blur */}
<div
className="absolute inset-0 bg-gradient-to-br from-amber-900/40 via-orange-900/30 to-red-900/40 backdrop-blur-xl"
onClick={onClose}
/>
{/* Modal */}
<div className="relative bg-gradient-to-br from-white via-amber-50 to-orange-50 rounded-3xl max-w-md w-full p-8 shadow-[0_20px_60px_rgba(0,0,0,0.3)] border border-amber-200/50 animate-in slide-in-from-bottom-5 duration-400">
{/* Decorative circles */}
<div className="absolute -top-10 -right-10 w-32 h-32 bg-gradient-to-br from-amber-300 to-orange-400 rounded-full opacity-20 blur-2xl" />
<div className="absolute -bottom-10 -left-10 w-40 h-40 bg-gradient-to-br from-orange-300 to-red-400 rounded-full opacity-20 blur-2xl" />
{/* Header */}
<div className="relative flex justify-between items-start mb-6">
<div>
<h2 className="text-3xl font-bold bg-gradient-to-r from-amber-600 to-orange-600 bg-clip-text text-transparent">
Share Bubbe's Wisdom
</h2>
<p className="text-sm text-amber-700 mt-1 font-medium">Spread the chutzpah! 💫</p>
</div>
<button
onClick={onClose}
className="group relative p-2 rounded-full bg-white/80 hover:bg-white shadow-lg transition-all duration-300 hover:scale-110"
>
<svg className="w-5 h-5 text-gray-600 group-hover:text-red-500 transition-colors" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
{/* Message Preview */}
<div className="relative mb-8">
<div className="absolute inset-0 bg-gradient-to-br from-amber-100 to-orange-100 rounded-2xl blur-xl opacity-50" />
<div className="relative bg-gradient-to-br from-white/90 to-amber-50/90 rounded-2xl p-5 max-h-36 overflow-y-auto shadow-inner border border-amber-200/30">
<div className="absolute top-2 left-2 text-6xl opacity-10">💬</div>
<p className="text-sm text-gray-800 font-medium leading-relaxed relative z-10">
{cleanMessage}
</p>
</div>
</div>
{/* Share Options Grid */}
<div className="grid grid-cols-3 gap-3 mb-6">
{/* Copy Text */}
<button
onClick={handleCopyText}
className={`group relative overflow-hidden flex flex-col items-center p-4 rounded-2xl transition-all duration-300 transform hover:scale-105 ${
activeButton === 'copy'
? 'bg-gradient-to-br from-green-400 to-green-500 shadow-lg shadow-green-500/30'
: 'bg-gradient-to-br from-gray-100 to-gray-200 hover:from-gray-200 hover:to-gray-300 shadow-md'
}`}
>
<div className="absolute inset-0 bg-gradient-to-t from-white/0 to-white/20 opacity-0 group-hover:opacity-100 transition-opacity" />
<svg className={`w-7 h-7 mb-2 transition-colors ${activeButton === 'copy' ? 'text-white' : 'text-gray-700'}`} fill="none" stroke="currentColor" viewBox="0 0 24 24">
{copied ? (
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
) : (
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3" />
)}
</svg>
<span className={`text-xs font-bold ${activeButton === 'copy' ? 'text-white' : 'text-gray-700'}`}>
{copied ? 'Copied!' : 'Copy'}
</span>
</button>
{/* X (Twitter) */}
<button
onClick={() => handleShare('x', handleShareToX)}
className={`group relative overflow-hidden flex flex-col items-center p-4 rounded-2xl transition-all duration-300 transform hover:scale-105 ${
activeButton === 'x'
? 'bg-black shadow-lg shadow-black/30'
: 'bg-gradient-to-br from-gray-800 to-black hover:from-black hover:to-gray-800 shadow-md'
}`}
>
<div className="absolute inset-0 bg-gradient-to-t from-white/0 to-white/10 opacity-0 group-hover:opacity-100 transition-opacity" />
<svg className="w-7 h-7 mb-2 text-white" viewBox="0 0 24 24" fill="currentColor">
<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/>
</svg>
<span className="text-xs text-white font-bold">X</span>
</button>
{/* Facebook */}
<button
onClick={() => handleShare('facebook', handleShareToFacebook)}
className={`group relative overflow-hidden flex flex-col items-center p-4 rounded-2xl transition-all duration-300 transform hover:scale-105 ${
activeButton === 'facebook'
? 'bg-gradient-to-br from-blue-500 to-blue-700 shadow-lg shadow-blue-500/30'
: 'bg-gradient-to-br from-blue-500 to-blue-600 hover:from-blue-600 hover:to-blue-700 shadow-md'
}`}
>
<div className="absolute inset-0 bg-gradient-to-t from-white/0 to-white/20 opacity-0 group-hover:opacity-100 transition-opacity" />
<svg className="w-7 h-7 mb-2 text-white" fill="currentColor" viewBox="0 0 24 24">
<path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/>
</svg>
<span className="text-xs text-white font-bold">Facebook</span>
</button>
{/* TikTok */}
<button
onClick={() => handleShare('tiktok', handleShareToTikTok)}
className={`group relative overflow-hidden flex flex-col items-center p-4 rounded-2xl transition-all duration-300 transform hover:scale-105 ${
activeButton === 'tiktok'
? 'bg-gradient-to-br from-pink-500 via-purple-500 to-indigo-500 shadow-lg shadow-purple-500/30'
: 'bg-gradient-to-br from-pink-400 via-purple-500 to-indigo-500 hover:from-pink-500 hover:to-indigo-600 shadow-md'
}`}
>
<div className="absolute inset-0 bg-gradient-to-t from-white/0 to-white/20 opacity-0 group-hover:opacity-100 transition-opacity" />
<svg className="w-7 h-7 mb-2 text-white" fill="currentColor" viewBox="0 0 24 24">
<path d="M12.525.02c1.31-.02 2.61-.01 3.91-.02.08 1.53.63 3.09 1.75 4.17 1.12 1.11 2.7 1.62 4.24 1.79v4.03c-1.44-.05-2.89-.35-4.2-.97-.57-.26-1.1-.59-1.62-.93-.01 2.92.01 5.84-.02 8.75-.08 1.4-.54 2.79-1.35 3.94-1.31 1.92-3.58 3.17-5.91 3.21-1.43.08-2.86-.31-4.08-1.03-2.02-1.19-3.44-3.37-3.65-5.71-.02-.5-.03-1-.01-1.49.18-1.9 1.12-3.72 2.58-4.96 1.66-1.44 3.98-2.13 6.15-1.72.02 1.48-.04 2.96-.04 4.44-.99-.32-2.15-.23-3.02.37-.63.41-1.11 1.04-1.36 1.75-.21.51-.15 1.07-.14 1.61.24 1.64 1.82 3.02 3.5 2.87 1.12-.01 2.19-.66 2.77-1.61.19-.33.4-.67.41-1.06.1-1.79.06-3.57.07-5.36.01-4.03-.01-8.05.02-12.07z"/>
</svg>
<span className="text-xs text-white font-bold">TikTok</span>
</button>
{/* Instagram */}
<button
onClick={() => handleShare('instagram', handleShareToInstagram)}
className={`group relative overflow-hidden flex flex-col items-center p-4 rounded-2xl transition-all duration-300 transform hover:scale-105 ${
activeButton === 'instagram'
? 'bg-gradient-to-br from-purple-500 via-pink-500 to-yellow-500 shadow-lg shadow-pink-500/30'
: 'bg-gradient-to-br from-purple-400 via-pink-500 to-orange-400 hover:from-purple-500 hover:to-orange-500 shadow-md'
}`}
>
<div className="absolute inset-0 bg-gradient-to-t from-white/0 to-white/20 opacity-0 group-hover:opacity-100 transition-opacity" />
<svg className="w-7 h-7 mb-2 text-white" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zM5.838 12a6.162 6.162 0 1112.324 0 6.162 6.162 0 01-12.324 0zM12 16a4 4 0 110-8 4 4 0 010 8zm4.965-10.405a1.44 1.44 0 112.881.001 1.44 1.44 0 01-2.881-.001z"/>
</svg>
<span className="text-xs text-white font-bold">Instagram</span>
</button>
{/* Email */}
<button
onClick={() => handleShare('email', handleEmailShare)}
className={`group relative overflow-hidden flex flex-col items-center p-4 rounded-2xl transition-all duration-300 transform hover:scale-105 ${
activeButton === 'email'
? 'bg-gradient-to-br from-indigo-500 to-purple-600 shadow-lg shadow-indigo-500/30'
: 'bg-gradient-to-br from-indigo-400 to-purple-500 hover:from-indigo-500 hover:to-purple-600 shadow-md'
}`}
>
<div className="absolute inset-0 bg-gradient-to-t from-white/0 to-white/20 opacity-0 group-hover:opacity-100 transition-opacity" />
<svg className="w-7 h-7 mb-2 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
<span className="text-xs text-white font-bold">Email</span>
</button>
</div>
{/* WhatsApp Button - Full Width with gradient */}
<button
onClick={() => handleShare('whatsapp', handleWhatsAppShare)}
className={`group relative overflow-hidden w-full flex items-center justify-center p-4 rounded-2xl transition-all duration-300 transform hover:scale-[1.02] ${
activeButton === 'whatsapp'
? 'bg-gradient-to-r from-green-500 to-green-600 shadow-lg shadow-green-500/30'
: 'bg-gradient-to-r from-green-400 to-green-500 hover:from-green-500 hover:to-green-600 shadow-md'
}`}
>
<div className="absolute inset-0 bg-gradient-to-t from-white/0 to-white/20 opacity-0 group-hover:opacity-100 transition-opacity" />
<svg className="w-6 h-6 mr-3 text-white" fill="currentColor" viewBox="0 0 24 24">
<path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.149-.67.149-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.074-.297-.149-1.255-.462-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.297-.347.446-.521.151-.172.2-.296.3-.495.099-.198.05-.372-.025-.521-.075-.148-.669-1.611-.916-2.206-.242-.579-.487-.501-.669-.51l-.57-.01c-.198 0-.52.074-.792.372s-1.04 1.016-1.04 2.479 1.065 2.876 1.213 3.074c.149.198 2.095 3.2 5.076 4.487.709.306 1.263.489 1.694.626.712.226 1.36.194 1.872.118.571-.085 1.758-.719 2.006-1.413.248-.695.248-1.29.173-1.414-.074-.123-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413Z"/>
</svg>
<span className="text-white font-bold">Share on WhatsApp</span>
</button>
{/* Footer Note with animation */}
<div className="mt-6 text-center">
<p className={`text-xs font-medium transition-all duration-500 ${
copied
? 'text-green-600 scale-105'
: 'text-amber-600'
}`}>
{copied ? '✨ Text copied! Ready to paste!' : "👵 Share Bubbe's wisdom with the world!"}
</p>
</div>
</div>
</div>
)
}