Popup free generatoren
This commit is contained in:
@@ -11,6 +11,7 @@ import { showToast } from '@/components/ui/Toast';
|
|||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { toPng, toSvg, toBlob } from 'html-to-image';
|
import { toPng, toSvg, toBlob } from 'html-to-image';
|
||||||
import { trackEvent } from '@/components/PostHogProvider';
|
import { trackEvent } from '@/components/PostHogProvider';
|
||||||
|
import PostDownloadPopup, { shouldShowDownloadPopup } from '@/components/marketing/PostDownloadPopup';
|
||||||
|
|
||||||
// Brand Colors
|
// Brand Colors
|
||||||
const BRAND = {
|
const BRAND = {
|
||||||
@@ -54,6 +55,7 @@ export default function BarcodeGeneratorClient() {
|
|||||||
const [lineColor, setLineColor] = useState('#000000');
|
const [lineColor, setLineColor] = useState('#000000');
|
||||||
const [frameType, setFrameType] = useState('none');
|
const [frameType, setFrameType] = useState('none');
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
const [showPopup, setShowPopup] = useState(false);
|
||||||
|
|
||||||
const barcodeRef = useRef<HTMLDivElement>(null);
|
const barcodeRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
@@ -109,6 +111,7 @@ export default function BarcodeGeneratorClient() {
|
|||||||
document.body.removeChild(link);
|
document.body.removeChild(link);
|
||||||
|
|
||||||
showToast(`Barcode downloaded as ${extension.toUpperCase()}`, 'success');
|
showToast(`Barcode downloaded as ${extension.toUpperCase()}`, 'success');
|
||||||
|
if (shouldShowDownloadPopup()) setShowPopup(true);
|
||||||
trackEvent('barcode_downloaded', {
|
trackEvent('barcode_downloaded', {
|
||||||
format: format,
|
format: format,
|
||||||
extension: extension,
|
extension: extension,
|
||||||
@@ -118,7 +121,6 @@ export default function BarcodeGeneratorClient() {
|
|||||||
console.error('Download failed', err);
|
console.error('Download failed', err);
|
||||||
showToast('Download failed', 'error');
|
showToast('Download failed', 'error');
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const copyBarcode = async () => {
|
const copyBarcode = async () => {
|
||||||
if (!barcodeRef.current) return;
|
if (!barcodeRef.current) return;
|
||||||
@@ -160,6 +162,8 @@ export default function BarcodeGeneratorClient() {
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<PostDownloadPopup open={showPopup} onClose={() => setShowPopup(false)} />
|
||||||
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
||||||
|
|
||||||
{/* Main Generator Card */}
|
{/* Main Generator Card */}
|
||||||
@@ -453,5 +457,6 @@ export default function BarcodeGeneratorClient() {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
import { Button } from '@/components/ui/Button';
|
import { Button } from '@/components/ui/Button';
|
||||||
import { Input } from '@/components/ui/Input';
|
import { Input } from '@/components/ui/Input';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import PostDownloadPopup, { shouldShowDownloadPopup } from '@/components/marketing/PostDownloadPopup';
|
||||||
|
|
||||||
// Brand Colors
|
// Brand Colors
|
||||||
const BRAND = {
|
const BRAND = {
|
||||||
@@ -45,6 +46,7 @@ export default function PhoneGenerator() {
|
|||||||
const [phone, setPhone] = useState('');
|
const [phone, setPhone] = useState('');
|
||||||
const [qrColor, setQrColor] = useState(BRAND.richBlue);
|
const [qrColor, setQrColor] = useState(BRAND.richBlue);
|
||||||
const [frameType, setFrameType] = useState('none');
|
const [frameType, setFrameType] = useState('none');
|
||||||
|
const [showPopup, setShowPopup] = useState(false);
|
||||||
|
|
||||||
const qrRef = useRef<HTMLDivElement>(null);
|
const qrRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
@@ -74,6 +76,7 @@ export default function PhoneGenerator() {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Download failed', err);
|
console.error('Download failed', err);
|
||||||
}
|
}
|
||||||
|
if (shouldShowDownloadPopup()) setShowPopup(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFrameLabel = () => {
|
const getFrameLabel = () => {
|
||||||
@@ -82,6 +85,8 @@ export default function PhoneGenerator() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<PostDownloadPopup open={showPopup} onClose={() => setShowPopup(false)} />
|
||||||
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
||||||
|
|
||||||
{/* Main Generator Card */}
|
{/* Main Generator Card */}
|
||||||
@@ -243,5 +248,6 @@ export default function PhoneGenerator() {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { Input } from '@/components/ui/Input';
|
|||||||
import { Select } from '@/components/ui/Select';
|
import { Select } from '@/components/ui/Select';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import AdBanner from '@/components/ads/AdBanner';
|
import AdBanner from '@/components/ads/AdBanner';
|
||||||
|
import PostDownloadPopup, { shouldShowDownloadPopup } from '@/components/marketing/PostDownloadPopup';
|
||||||
|
|
||||||
// Brand Colors
|
// Brand Colors
|
||||||
const BRAND = {
|
const BRAND = {
|
||||||
@@ -58,6 +59,7 @@ export default function CryptoGenerator() {
|
|||||||
const [qrMode, setQrMode] = useState<'universal' | 'wallet'>('universal');
|
const [qrMode, setQrMode] = useState<'universal' | 'wallet'>('universal');
|
||||||
const [qrColor, setQrColor] = useState('#F7931A');
|
const [qrColor, setQrColor] = useState('#F7931A');
|
||||||
const [frameType, setFrameType] = useState('none');
|
const [frameType, setFrameType] = useState('none');
|
||||||
|
const [showPopup, setShowPopup] = useState(false);
|
||||||
|
|
||||||
const qrRef = useRef<HTMLDivElement>(null);
|
const qrRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
@@ -123,6 +125,7 @@ export default function CryptoGenerator() {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Download failed', err);
|
console.error('Download failed', err);
|
||||||
}
|
}
|
||||||
|
if (shouldShowDownloadPopup()) setShowPopup(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFrameLabel = () => {
|
const getFrameLabel = () => {
|
||||||
@@ -131,6 +134,8 @@ export default function CryptoGenerator() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<PostDownloadPopup open={showPopup} onClose={() => setShowPopup(false)} />
|
||||||
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
||||||
|
|
||||||
{/* Main Generator Card */}
|
{/* Main Generator Card */}
|
||||||
@@ -370,5 +375,6 @@ export default function CryptoGenerator() {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
import { Button } from '@/components/ui/Button';
|
import { Button } from '@/components/ui/Button';
|
||||||
import { Input } from '@/components/ui/Input';
|
import { Input } from '@/components/ui/Input';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import PostDownloadPopup, { shouldShowDownloadPopup } from '@/components/marketing/PostDownloadPopup';
|
||||||
|
|
||||||
// Brand Colors
|
// Brand Colors
|
||||||
const BRAND = {
|
const BRAND = {
|
||||||
@@ -43,6 +44,7 @@ const FRAME_OPTIONS = [
|
|||||||
|
|
||||||
export default function EmailGenerator() {
|
export default function EmailGenerator() {
|
||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
|
const [showPopup, setShowPopup] = useState(false);
|
||||||
email: '',
|
email: '',
|
||||||
subject: '',
|
subject: '',
|
||||||
body: ''
|
body: ''
|
||||||
@@ -88,6 +90,7 @@ export default function EmailGenerator() {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Download failed', err);
|
console.error('Download failed', err);
|
||||||
}
|
}
|
||||||
|
if (shouldShowDownloadPopup()) setShowPopup(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFrameLabel = () => {
|
const getFrameLabel = () => {
|
||||||
@@ -100,6 +103,8 @@ export default function EmailGenerator() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<PostDownloadPopup open={showPopup} onClose={() => setShowPopup(false)} />
|
||||||
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
||||||
|
|
||||||
{/* Main Generator Card */}
|
{/* Main Generator Card */}
|
||||||
@@ -292,5 +297,6 @@ export default function EmailGenerator() {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
import { Button } from '@/components/ui/Button';
|
import { Button } from '@/components/ui/Button';
|
||||||
import { Input } from '@/components/ui/Input';
|
import { Input } from '@/components/ui/Input';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import PostDownloadPopup, { shouldShowDownloadPopup } from '@/components/marketing/PostDownloadPopup';
|
||||||
|
|
||||||
// Brand Colors
|
// Brand Colors
|
||||||
const BRAND = {
|
const BRAND = {
|
||||||
@@ -51,6 +52,7 @@ export default function EventGenerator() {
|
|||||||
|
|
||||||
const [qrColor, setQrColor] = useState(BRAND.primary);
|
const [qrColor, setQrColor] = useState(BRAND.primary);
|
||||||
const [frameType, setFrameType] = useState('none');
|
const [frameType, setFrameType] = useState('none');
|
||||||
|
const [showPopup, setShowPopup] = useState(false);
|
||||||
|
|
||||||
const qrRef = useRef<HTMLDivElement>(null);
|
const qrRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
@@ -102,6 +104,7 @@ export default function EventGenerator() {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Download failed', err);
|
console.error('Download failed', err);
|
||||||
}
|
}
|
||||||
|
if (shouldShowDownloadPopup()) setShowPopup(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFrameLabel = () => {
|
const getFrameLabel = () => {
|
||||||
@@ -110,6 +113,8 @@ export default function EventGenerator() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<PostDownloadPopup open={showPopup} onClose={() => setShowPopup(false)} />
|
||||||
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
||||||
|
|
||||||
{/* Main Generator Card */}
|
{/* Main Generator Card */}
|
||||||
@@ -326,5 +331,6 @@ export default function EventGenerator() {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
import { Button } from '@/components/ui/Button';
|
import { Button } from '@/components/ui/Button';
|
||||||
import { Input } from '@/components/ui/Input';
|
import { Input } from '@/components/ui/Input';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import PostDownloadPopup, { shouldShowDownloadPopup } from '@/components/marketing/PostDownloadPopup';
|
||||||
|
|
||||||
// Brand Colors
|
// Brand Colors
|
||||||
const BRAND = {
|
const BRAND = {
|
||||||
@@ -46,6 +47,7 @@ export default function FacebookGenerator() {
|
|||||||
const [url, setUrl] = useState('');
|
const [url, setUrl] = useState('');
|
||||||
const [qrColor, setQrColor] = useState('#1877F2'); // Default to FB Blue
|
const [qrColor, setQrColor] = useState('#1877F2'); // Default to FB Blue
|
||||||
const [frameType, setFrameType] = useState('none');
|
const [frameType, setFrameType] = useState('none');
|
||||||
|
const [showPopup, setShowPopup] = useState(false);
|
||||||
|
|
||||||
const qrRef = useRef<HTMLDivElement>(null);
|
const qrRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
@@ -73,6 +75,7 @@ export default function FacebookGenerator() {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Download failed', err);
|
console.error('Download failed', err);
|
||||||
}
|
}
|
||||||
|
if (shouldShowDownloadPopup()) setShowPopup(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFrameLabel = () => {
|
const getFrameLabel = () => {
|
||||||
@@ -81,6 +84,8 @@ export default function FacebookGenerator() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<PostDownloadPopup open={showPopup} onClose={() => setShowPopup(false)} />
|
||||||
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
||||||
|
|
||||||
{/* Main Generator Card */}
|
{/* Main Generator Card */}
|
||||||
@@ -243,5 +248,6 @@ export default function FacebookGenerator() {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
import { Button } from '@/components/ui/Button';
|
import { Button } from '@/components/ui/Button';
|
||||||
import { Input } from '@/components/ui/Input';
|
import { Input } from '@/components/ui/Input';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import PostDownloadPopup, { shouldShowDownloadPopup } from '@/components/marketing/PostDownloadPopup';
|
||||||
|
|
||||||
// Brand Colors
|
// Brand Colors
|
||||||
const BRAND = {
|
const BRAND = {
|
||||||
@@ -46,6 +47,7 @@ export default function GeolocationGenerator() {
|
|||||||
const [longitude, setLongitude] = useState('');
|
const [longitude, setLongitude] = useState('');
|
||||||
const [qrColor, setQrColor] = useState(BRAND.primary);
|
const [qrColor, setQrColor] = useState(BRAND.primary);
|
||||||
const [frameType, setFrameType] = useState('none');
|
const [frameType, setFrameType] = useState('none');
|
||||||
|
const [showPopup, setShowPopup] = useState(false);
|
||||||
|
|
||||||
const qrRef = useRef<HTMLDivElement>(null);
|
const qrRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
@@ -76,6 +78,7 @@ export default function GeolocationGenerator() {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Download failed', err);
|
console.error('Download failed', err);
|
||||||
}
|
}
|
||||||
|
if (shouldShowDownloadPopup()) setShowPopup(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFrameLabel = () => {
|
const getFrameLabel = () => {
|
||||||
@@ -101,6 +104,8 @@ export default function GeolocationGenerator() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<PostDownloadPopup open={showPopup} onClose={() => setShowPopup(false)} />
|
||||||
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
||||||
|
|
||||||
{/* Main Generator Card */}
|
{/* Main Generator Card */}
|
||||||
@@ -288,5 +293,6 @@ export default function GeolocationGenerator() {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { toPng } from 'html-to-image';
|
|||||||
import { Star, Download, AlertCircle } from 'lucide-react';
|
import { Star, Download, AlertCircle } from 'lucide-react';
|
||||||
import { Button } from '@/components/ui/Button';
|
import { Button } from '@/components/ui/Button';
|
||||||
import { Input } from '@/components/ui/Input';
|
import { Input } from '@/components/ui/Input';
|
||||||
|
import PostDownloadPopup, { shouldShowDownloadPopup } from '@/components/marketing/PostDownloadPopup';
|
||||||
|
|
||||||
const QR_COLORS = [
|
const QR_COLORS = [
|
||||||
{ name: 'Google Blue', value: '#1A73E8' },
|
{ name: 'Google Blue', value: '#1A73E8' },
|
||||||
@@ -41,6 +42,7 @@ export default function GoogleReviewGenerator() {
|
|||||||
const [qrColor, setQrColor] = useState('#1A73E8');
|
const [qrColor, setQrColor] = useState('#1A73E8');
|
||||||
const [frameType, setFrameType] = useState('review');
|
const [frameType, setFrameType] = useState('review');
|
||||||
const [error, setError] = useState('');
|
const [error, setError] = useState('');
|
||||||
|
const [showPopup, setShowPopup] = useState(false);
|
||||||
|
|
||||||
const qrRef = useRef<HTMLDivElement>(null);
|
const qrRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
@@ -76,12 +78,15 @@ export default function GoogleReviewGenerator() {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Download failed', err);
|
console.error('Download failed', err);
|
||||||
}
|
}
|
||||||
|
if (shouldShowDownloadPopup()) setShowPopup(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const frameLabel = FRAME_OPTIONS.find(f => f.id === frameType && f.id !== 'none')?.label ?? null;
|
const frameLabel = FRAME_OPTIONS.find(f => f.id === frameType && f.id !== 'none')?.label ?? null;
|
||||||
const isReady = reviewUrl && !error && isValidGoogleReviewLink(reviewUrl);
|
const isReady = reviewUrl && !error && isValidGoogleReviewLink(reviewUrl);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<PostDownloadPopup open={showPopup} onClose={() => setShowPopup(false)} />
|
||||||
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
||||||
<div className="bg-white rounded-3xl shadow-2xl shadow-slate-900/10 overflow-hidden border border-slate-100">
|
<div className="bg-white rounded-3xl shadow-2xl shadow-slate-900/10 overflow-hidden border border-slate-100">
|
||||||
<div className="grid lg:grid-cols-2">
|
<div className="grid lg:grid-cols-2">
|
||||||
@@ -209,5 +214,6 @@ export default function GoogleReviewGenerator() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
import { Button } from '@/components/ui/Button';
|
import { Button } from '@/components/ui/Button';
|
||||||
import { Input } from '@/components/ui/Input';
|
import { Input } from '@/components/ui/Input';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import PostDownloadPopup, { shouldShowDownloadPopup } from '@/components/marketing/PostDownloadPopup';
|
||||||
|
|
||||||
// Brand Colors
|
// Brand Colors
|
||||||
const BRAND = {
|
const BRAND = {
|
||||||
@@ -45,6 +46,7 @@ export default function InstagramGenerator() {
|
|||||||
const [username, setUsername] = useState('');
|
const [username, setUsername] = useState('');
|
||||||
const [qrColor, setQrColor] = useState('#E1306C');
|
const [qrColor, setQrColor] = useState('#E1306C');
|
||||||
const [frameType, setFrameType] = useState('none');
|
const [frameType, setFrameType] = useState('none');
|
||||||
|
const [showPopup, setShowPopup] = useState(false);
|
||||||
|
|
||||||
const qrRef = useRef<HTMLDivElement>(null);
|
const qrRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
@@ -78,6 +80,7 @@ export default function InstagramGenerator() {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Download failed', err);
|
console.error('Download failed', err);
|
||||||
}
|
}
|
||||||
|
if (shouldShowDownloadPopup()) setShowPopup(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFrameLabel = () => {
|
const getFrameLabel = () => {
|
||||||
@@ -86,6 +89,8 @@ export default function InstagramGenerator() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<PostDownloadPopup open={showPopup} onClose={() => setShowPopup(false)} />
|
||||||
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
||||||
|
|
||||||
{/* Main Generator Card */}
|
{/* Main Generator Card */}
|
||||||
@@ -248,5 +253,6 @@ export default function InstagramGenerator() {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { Button } from '@/components/ui/Button';
|
|||||||
import { Input } from '@/components/ui/Input';
|
import { Input } from '@/components/ui/Input';
|
||||||
import { Select } from '@/components/ui/Select';
|
import { Select } from '@/components/ui/Select';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import PostDownloadPopup, { shouldShowDownloadPopup } from '@/components/marketing/PostDownloadPopup';
|
||||||
|
|
||||||
// Brand Colors - PayPal Blue
|
// Brand Colors - PayPal Blue
|
||||||
const BRAND = {
|
const BRAND = {
|
||||||
@@ -64,6 +65,7 @@ export default function PayPalGenerator() {
|
|||||||
const [currency, setCurrency] = useState('EUR');
|
const [currency, setCurrency] = useState('EUR');
|
||||||
const [qrColor, setQrColor] = useState(BRAND.primary);
|
const [qrColor, setQrColor] = useState(BRAND.primary);
|
||||||
const [frameType, setFrameType] = useState('none');
|
const [frameType, setFrameType] = useState('none');
|
||||||
|
const [showPopup, setShowPopup] = useState(false);
|
||||||
|
|
||||||
const qrRef = useRef<HTMLDivElement>(null);
|
const qrRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
@@ -114,6 +116,7 @@ export default function PayPalGenerator() {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Download failed', err);
|
console.error('Download failed', err);
|
||||||
}
|
}
|
||||||
|
if (shouldShowDownloadPopup()) setShowPopup(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFrameLabel = () => {
|
const getFrameLabel = () => {
|
||||||
@@ -122,6 +125,8 @@ export default function PayPalGenerator() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<PostDownloadPopup open={showPopup} onClose={() => setShowPopup(false)} />
|
||||||
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
||||||
|
|
||||||
{/* Main Generator Card */}
|
{/* Main Generator Card */}
|
||||||
@@ -338,5 +343,6 @@ export default function PayPalGenerator() {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
import { Button } from '@/components/ui/Button';
|
import { Button } from '@/components/ui/Button';
|
||||||
import { Input } from '@/components/ui/Input';
|
import { Input } from '@/components/ui/Input';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import PostDownloadPopup, { shouldShowDownloadPopup } from '@/components/marketing/PostDownloadPopup';
|
||||||
|
|
||||||
// Brand Colors
|
// Brand Colors
|
||||||
const BRAND = {
|
const BRAND = {
|
||||||
@@ -46,6 +47,7 @@ export default function SMSGenerator() {
|
|||||||
const [message, setMessage] = useState('');
|
const [message, setMessage] = useState('');
|
||||||
const [qrColor, setQrColor] = useState(BRAND.primary);
|
const [qrColor, setQrColor] = useState(BRAND.primary);
|
||||||
const [frameType, setFrameType] = useState('none');
|
const [frameType, setFrameType] = useState('none');
|
||||||
|
const [showPopup, setShowPopup] = useState(false);
|
||||||
|
|
||||||
const qrRef = useRef<HTMLDivElement>(null);
|
const qrRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
@@ -76,6 +78,7 @@ export default function SMSGenerator() {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Download failed', err);
|
console.error('Download failed', err);
|
||||||
}
|
}
|
||||||
|
if (shouldShowDownloadPopup()) setShowPopup(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFrameLabel = () => {
|
const getFrameLabel = () => {
|
||||||
@@ -84,6 +87,8 @@ export default function SMSGenerator() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<PostDownloadPopup open={showPopup} onClose={() => setShowPopup(false)} />
|
||||||
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
||||||
|
|
||||||
{/* Main Generator Card */}
|
{/* Main Generator Card */}
|
||||||
@@ -262,5 +267,6 @@ export default function SMSGenerator() {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
import { Button } from '@/components/ui/Button';
|
import { Button } from '@/components/ui/Button';
|
||||||
import { Input } from '@/components/ui/Input';
|
import { Input } from '@/components/ui/Input';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import PostDownloadPopup, { shouldShowDownloadPopup } from '@/components/marketing/PostDownloadPopup';
|
||||||
|
|
||||||
// Brand Colors - Microsoft Teams Purple
|
// Brand Colors - Microsoft Teams Purple
|
||||||
const BRAND = {
|
const BRAND = {
|
||||||
@@ -53,6 +54,7 @@ export default function TeamsGenerator() {
|
|||||||
const [userEmail, setUserEmail] = useState('');
|
const [userEmail, setUserEmail] = useState('');
|
||||||
const [qrColor, setQrColor] = useState(BRAND.primary);
|
const [qrColor, setQrColor] = useState(BRAND.primary);
|
||||||
const [frameType, setFrameType] = useState('none');
|
const [frameType, setFrameType] = useState('none');
|
||||||
|
const [showPopup, setShowPopup] = useState(false);
|
||||||
|
|
||||||
const qrRef = useRef<HTMLDivElement>(null);
|
const qrRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
@@ -96,6 +98,7 @@ export default function TeamsGenerator() {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Download failed', err);
|
console.error('Download failed', err);
|
||||||
}
|
}
|
||||||
|
if (shouldShowDownloadPopup()) setShowPopup(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFrameLabel = () => {
|
const getFrameLabel = () => {
|
||||||
@@ -104,6 +107,8 @@ export default function TeamsGenerator() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<PostDownloadPopup open={showPopup} onClose={() => setShowPopup(false)} />
|
||||||
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
||||||
|
|
||||||
{/* Main Generator Card */}
|
{/* Main Generator Card */}
|
||||||
@@ -314,5 +319,6 @@ export default function TeamsGenerator() {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { Button } from '@/components/ui/Button';
|
import { Button } from '@/components/ui/Button';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import PostDownloadPopup, { shouldShowDownloadPopup } from '@/components/marketing/PostDownloadPopup';
|
||||||
|
|
||||||
// Brand Colors
|
// Brand Colors
|
||||||
const BRAND = {
|
const BRAND = {
|
||||||
@@ -45,6 +46,7 @@ export default function TextGenerator() {
|
|||||||
const [text, setText] = useState('');
|
const [text, setText] = useState('');
|
||||||
const [qrColor, setQrColor] = useState(BRAND.richBlue);
|
const [qrColor, setQrColor] = useState(BRAND.richBlue);
|
||||||
const [frameType, setFrameType] = useState('none');
|
const [frameType, setFrameType] = useState('none');
|
||||||
|
const [showPopup, setShowPopup] = useState(false);
|
||||||
|
|
||||||
const qrRef = useRef<HTMLDivElement>(null);
|
const qrRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
@@ -72,6 +74,7 @@ export default function TextGenerator() {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Download failed', err);
|
console.error('Download failed', err);
|
||||||
}
|
}
|
||||||
|
if (shouldShowDownloadPopup()) setShowPopup(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFrameLabel = () => {
|
const getFrameLabel = () => {
|
||||||
@@ -80,6 +83,8 @@ export default function TextGenerator() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<PostDownloadPopup open={showPopup} onClose={() => setShowPopup(false)} />
|
||||||
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
||||||
|
|
||||||
{/* Main Generator Card */}
|
{/* Main Generator Card */}
|
||||||
@@ -241,5 +246,6 @@ export default function TextGenerator() {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
import { Button } from '@/components/ui/Button';
|
import { Button } from '@/components/ui/Button';
|
||||||
import { Input } from '@/components/ui/Input';
|
import { Input } from '@/components/ui/Input';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import PostDownloadPopup, { shouldShowDownloadPopup } from '@/components/marketing/PostDownloadPopup';
|
||||||
|
|
||||||
// Brand Colors
|
// Brand Colors
|
||||||
const BRAND = {
|
const BRAND = {
|
||||||
@@ -45,6 +46,7 @@ export default function TiktokGenerator() {
|
|||||||
const [username, setUsername] = useState('');
|
const [username, setUsername] = useState('');
|
||||||
const [qrColor, setQrColor] = useState('#000000');
|
const [qrColor, setQrColor] = useState('#000000');
|
||||||
const [frameType, setFrameType] = useState('none');
|
const [frameType, setFrameType] = useState('none');
|
||||||
|
const [showPopup, setShowPopup] = useState(false);
|
||||||
|
|
||||||
const qrRef = useRef<HTMLDivElement>(null);
|
const qrRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
@@ -78,6 +80,7 @@ export default function TiktokGenerator() {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Download failed', err);
|
console.error('Download failed', err);
|
||||||
}
|
}
|
||||||
|
if (shouldShowDownloadPopup()) setShowPopup(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFrameLabel = () => {
|
const getFrameLabel = () => {
|
||||||
@@ -86,6 +89,8 @@ export default function TiktokGenerator() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<PostDownloadPopup open={showPopup} onClose={() => setShowPopup(false)} />
|
||||||
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
||||||
|
|
||||||
{/* Main Generator Card */}
|
{/* Main Generator Card */}
|
||||||
@@ -248,5 +253,6 @@ export default function TiktokGenerator() {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
import { Button } from '@/components/ui/Button';
|
import { Button } from '@/components/ui/Button';
|
||||||
import { Input } from '@/components/ui/Input';
|
import { Input } from '@/components/ui/Input';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import PostDownloadPopup, { shouldShowDownloadPopup } from '@/components/marketing/PostDownloadPopup';
|
||||||
|
|
||||||
// Brand Colors
|
// Brand Colors
|
||||||
const BRAND = {
|
const BRAND = {
|
||||||
@@ -45,6 +46,7 @@ export default function TwitterGenerator() {
|
|||||||
const [username, setUsername] = useState('');
|
const [username, setUsername] = useState('');
|
||||||
const [qrColor, setQrColor] = useState('#000000');
|
const [qrColor, setQrColor] = useState('#000000');
|
||||||
const [frameType, setFrameType] = useState('none');
|
const [frameType, setFrameType] = useState('none');
|
||||||
|
const [showPopup, setShowPopup] = useState(false);
|
||||||
|
|
||||||
const qrRef = useRef<HTMLDivElement>(null);
|
const qrRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
@@ -78,6 +80,7 @@ export default function TwitterGenerator() {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Download failed', err);
|
console.error('Download failed', err);
|
||||||
}
|
}
|
||||||
|
if (shouldShowDownloadPopup()) setShowPopup(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFrameLabel = () => {
|
const getFrameLabel = () => {
|
||||||
@@ -86,6 +89,8 @@ export default function TwitterGenerator() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<PostDownloadPopup open={showPopup} onClose={() => setShowPopup(false)} />
|
||||||
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
||||||
|
|
||||||
{/* Main Generator Card */}
|
{/* Main Generator Card */}
|
||||||
@@ -248,5 +253,6 @@ export default function TwitterGenerator() {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
import { Button } from '@/components/ui/Button';
|
import { Button } from '@/components/ui/Button';
|
||||||
import { Input } from '@/components/ui/Input';
|
import { Input } from '@/components/ui/Input';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import PostDownloadPopup, { shouldShowDownloadPopup } from '@/components/marketing/PostDownloadPopup';
|
||||||
|
|
||||||
// Brand Colors
|
// Brand Colors
|
||||||
const BRAND = {
|
const BRAND = {
|
||||||
@@ -46,6 +47,7 @@ export default function URLGenerator() {
|
|||||||
const [url, setUrl] = useState('');
|
const [url, setUrl] = useState('');
|
||||||
const [qrColor, setQrColor] = useState(BRAND.primary);
|
const [qrColor, setQrColor] = useState(BRAND.primary);
|
||||||
const [frameType, setFrameType] = useState('none');
|
const [frameType, setFrameType] = useState('none');
|
||||||
|
const [showPopup, setShowPopup] = useState(false);
|
||||||
|
|
||||||
const qrRef = useRef<HTMLDivElement>(null);
|
const qrRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
@@ -72,6 +74,7 @@ export default function URLGenerator() {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Download failed', err);
|
console.error('Download failed', err);
|
||||||
}
|
}
|
||||||
|
if (shouldShowDownloadPopup()) setShowPopup(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFrameLabel = () => {
|
const getFrameLabel = () => {
|
||||||
@@ -80,6 +83,8 @@ export default function URLGenerator() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<PostDownloadPopup open={showPopup} onClose={() => setShowPopup(false)} />
|
||||||
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
||||||
|
|
||||||
{/* Main Generator Card */}
|
{/* Main Generator Card */}
|
||||||
@@ -241,5 +246,6 @@ export default function URLGenerator() {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import {
|
|||||||
import { Button } from '@/components/ui/Button';
|
import { Button } from '@/components/ui/Button';
|
||||||
import { Input } from '@/components/ui/Input';
|
import { Input } from '@/components/ui/Input';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import PostDownloadPopup, { shouldShowDownloadPopup } from '@/components/marketing/PostDownloadPopup';
|
||||||
|
|
||||||
// Brand Colors
|
// Brand Colors
|
||||||
const BRAND = {
|
const BRAND = {
|
||||||
@@ -63,6 +64,7 @@ export default function VCardGenerator() {
|
|||||||
|
|
||||||
const [qrColor, setQrColor] = useState(BRAND.primary);
|
const [qrColor, setQrColor] = useState(BRAND.primary);
|
||||||
const [frameType, setFrameType] = useState('none');
|
const [frameType, setFrameType] = useState('none');
|
||||||
|
const [showPopup, setShowPopup] = useState(false);
|
||||||
|
|
||||||
const qrRef = useRef<HTMLDivElement>(null);
|
const qrRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
@@ -108,6 +110,7 @@ export default function VCardGenerator() {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Download failed', err);
|
console.error('Download failed', err);
|
||||||
}
|
}
|
||||||
|
if (shouldShowDownloadPopup()) setShowPopup(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFrameLabel = () => {
|
const getFrameLabel = () => {
|
||||||
@@ -116,6 +119,8 @@ export default function VCardGenerator() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<PostDownloadPopup open={showPopup} onClose={() => setShowPopup(false)} />
|
||||||
<div className="w-full max-w-6xl mx-auto px-4 md:px-6">
|
<div className="w-full max-w-6xl mx-auto px-4 md:px-6">
|
||||||
|
|
||||||
{/* Main Generator Card */}
|
{/* Main Generator Card */}
|
||||||
@@ -344,5 +349,6 @@ export default function VCardGenerator() {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { Button } from '@/components/ui/Button';
|
|||||||
import { Input } from '@/components/ui/Input';
|
import { Input } from '@/components/ui/Input';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { Textarea } from '@/components/ui/Textarea';
|
import { Textarea } from '@/components/ui/Textarea';
|
||||||
|
import PostDownloadPopup, { shouldShowDownloadPopup } from '@/components/marketing/PostDownloadPopup';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -49,6 +50,7 @@ export default function WhatsappGenerator() {
|
|||||||
const [message, setMessage] = useState('');
|
const [message, setMessage] = useState('');
|
||||||
const [qrColor, setQrColor] = useState('#25D366');
|
const [qrColor, setQrColor] = useState('#25D366');
|
||||||
const [frameType, setFrameType] = useState('none');
|
const [frameType, setFrameType] = useState('none');
|
||||||
|
const [showPopup, setShowPopup] = useState(false);
|
||||||
|
|
||||||
const qrRef = useRef<HTMLDivElement>(null);
|
const qrRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
@@ -83,6 +85,7 @@ export default function WhatsappGenerator() {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Download failed', err);
|
console.error('Download failed', err);
|
||||||
}
|
}
|
||||||
|
if (shouldShowDownloadPopup()) setShowPopup(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFrameLabel = () => {
|
const getFrameLabel = () => {
|
||||||
@@ -91,6 +94,8 @@ export default function WhatsappGenerator() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<PostDownloadPopup open={showPopup} onClose={() => setShowPopup(false)} />
|
||||||
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
||||||
|
|
||||||
{/* Main Generator Card */}
|
{/* Main Generator Card */}
|
||||||
@@ -263,5 +268,6 @@ export default function WhatsappGenerator() {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { Button } from '@/components/ui/Button';
|
|||||||
import { Input } from '@/components/ui/Input';
|
import { Input } from '@/components/ui/Input';
|
||||||
import { Select } from '@/components/ui/Select';
|
import { Select } from '@/components/ui/Select';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import PostDownloadPopup, { shouldShowDownloadPopup } from '@/components/marketing/PostDownloadPopup';
|
||||||
|
|
||||||
// Brand Colors
|
// Brand Colors
|
||||||
const BRAND = {
|
const BRAND = {
|
||||||
@@ -55,6 +56,7 @@ export default function WiFiGenerator() {
|
|||||||
// Customization
|
// Customization
|
||||||
const [qrColor, setQrColor] = useState(BRAND.primary);
|
const [qrColor, setQrColor] = useState(BRAND.primary);
|
||||||
const [frameType, setFrameType] = useState('none');
|
const [frameType, setFrameType] = useState('none');
|
||||||
|
const [showPopup, setShowPopup] = useState(false);
|
||||||
|
|
||||||
const qrRef = useRef<HTMLDivElement>(null);
|
const qrRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
@@ -84,6 +86,7 @@ export default function WiFiGenerator() {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Download failed', err);
|
console.error('Download failed', err);
|
||||||
}
|
}
|
||||||
|
if (shouldShowDownloadPopup()) setShowPopup(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFrameLabel = () => {
|
const getFrameLabel = () => {
|
||||||
@@ -92,6 +95,8 @@ export default function WiFiGenerator() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<PostDownloadPopup open={showPopup} onClose={() => setShowPopup(false)} />
|
||||||
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
||||||
|
|
||||||
{/* Main Generator Card */}
|
{/* Main Generator Card */}
|
||||||
@@ -303,5 +308,6 @@ export default function WiFiGenerator() {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
import { Button } from '@/components/ui/Button';
|
import { Button } from '@/components/ui/Button';
|
||||||
import { Input } from '@/components/ui/Input';
|
import { Input } from '@/components/ui/Input';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import PostDownloadPopup, { shouldShowDownloadPopup } from '@/components/marketing/PostDownloadPopup';
|
||||||
|
|
||||||
// Brand Colors
|
// Brand Colors
|
||||||
const BRAND = {
|
const BRAND = {
|
||||||
@@ -44,6 +45,7 @@ export default function YoutubeGenerator() {
|
|||||||
const [url, setUrl] = useState('');
|
const [url, setUrl] = useState('');
|
||||||
const [qrColor, setQrColor] = useState('#FF0000');
|
const [qrColor, setQrColor] = useState('#FF0000');
|
||||||
const [frameType, setFrameType] = useState('none');
|
const [frameType, setFrameType] = useState('none');
|
||||||
|
const [showPopup, setShowPopup] = useState(false);
|
||||||
|
|
||||||
const qrRef = useRef<HTMLDivElement>(null);
|
const qrRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
@@ -71,6 +73,7 @@ export default function YoutubeGenerator() {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Download failed', err);
|
console.error('Download failed', err);
|
||||||
}
|
}
|
||||||
|
if (shouldShowDownloadPopup()) setShowPopup(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFrameLabel = () => {
|
const getFrameLabel = () => {
|
||||||
@@ -79,6 +82,8 @@ export default function YoutubeGenerator() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<PostDownloadPopup open={showPopup} onClose={() => setShowPopup(false)} />
|
||||||
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
||||||
|
|
||||||
{/* Main Generator Card */}
|
{/* Main Generator Card */}
|
||||||
@@ -241,5 +246,6 @@ export default function YoutubeGenerator() {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
import { Button } from '@/components/ui/Button';
|
import { Button } from '@/components/ui/Button';
|
||||||
import { Input } from '@/components/ui/Input';
|
import { Input } from '@/components/ui/Input';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import PostDownloadPopup, { shouldShowDownloadPopup } from '@/components/marketing/PostDownloadPopup';
|
||||||
|
|
||||||
// Brand Colors - Zoom Blue
|
// Brand Colors - Zoom Blue
|
||||||
const BRAND = {
|
const BRAND = {
|
||||||
@@ -46,6 +47,7 @@ export default function ZoomGenerator() {
|
|||||||
const [useDirectLink, setUseDirectLink] = useState(false); // Default to web URL for compatibility
|
const [useDirectLink, setUseDirectLink] = useState(false); // Default to web URL for compatibility
|
||||||
const [qrColor, setQrColor] = useState(BRAND.primary);
|
const [qrColor, setQrColor] = useState(BRAND.primary);
|
||||||
const [frameType, setFrameType] = useState('none');
|
const [frameType, setFrameType] = useState('none');
|
||||||
|
const [showPopup, setShowPopup] = useState(false);
|
||||||
|
|
||||||
const qrRef = useRef<HTMLDivElement>(null);
|
const qrRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
@@ -103,6 +105,7 @@ export default function ZoomGenerator() {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Download failed', err);
|
console.error('Download failed', err);
|
||||||
}
|
}
|
||||||
|
if (shouldShowDownloadPopup()) setShowPopup(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFrameLabel = () => {
|
const getFrameLabel = () => {
|
||||||
@@ -111,6 +114,8 @@ export default function ZoomGenerator() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<PostDownloadPopup open={showPopup} onClose={() => setShowPopup(false)} />
|
||||||
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
|
||||||
|
|
||||||
{/* Main Generator Card */}
|
{/* Main Generator Card */}
|
||||||
@@ -298,5 +303,6 @@ export default function ZoomGenerator() {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
99
src/components/marketing/PostDownloadPopup.tsx
Normal file
99
src/components/marketing/PostDownloadPopup.tsx
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import React, { useEffect, useRef } from 'react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { X, Zap, BarChart2, RefreshCw, Palette } from 'lucide-react';
|
||||||
|
import { Button } from '@/components/ui/Button';
|
||||||
|
|
||||||
|
interface PostDownloadPopupProps {
|
||||||
|
open: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const BENEFITS = [
|
||||||
|
{ icon: RefreshCw, text: 'Edit the link anytime — QR stays the same' },
|
||||||
|
{ icon: BarChart2, text: 'See who scans, when & where' },
|
||||||
|
{ icon: Palette, text: 'Custom colors, logo & frames' },
|
||||||
|
{ icon: Zap, text: 'Free plan included — upgrade anytime for more' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const LS_KEY = 'qrm_download_popup_seen';
|
||||||
|
|
||||||
|
export function shouldShowDownloadPopup(): boolean {
|
||||||
|
try { return !localStorage.getItem(LS_KEY); } catch { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
export function markDownloadPopupSeen(): void {
|
||||||
|
try { localStorage.setItem(LS_KEY, '1'); } catch { /* ignore */ }
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function PostDownloadPopup({ open, onClose }: PostDownloadPopupProps) {
|
||||||
|
const overlayRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!open) return;
|
||||||
|
markDownloadPopupSeen();
|
||||||
|
const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); };
|
||||||
|
document.addEventListener('keydown', onKey);
|
||||||
|
return () => document.removeEventListener('keydown', onKey);
|
||||||
|
}, [open, onClose]);
|
||||||
|
|
||||||
|
if (!open) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={overlayRef}
|
||||||
|
className="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||||
|
style={{ backgroundColor: 'rgba(15, 23, 42, 0.6)', backdropFilter: 'blur(4px)' }}
|
||||||
|
onClick={(e) => { if (e.target === overlayRef.current) onClose(); }}
|
||||||
|
>
|
||||||
|
<div className="bg-white rounded-3xl shadow-2xl w-full max-w-md overflow-hidden animate-in fade-in zoom-in-95 duration-200">
|
||||||
|
|
||||||
|
{/* Header */}
|
||||||
|
<div className="relative bg-gradient-to-br from-[#4F46E5] to-[#7C3AED] p-6 text-white text-center">
|
||||||
|
<button
|
||||||
|
onClick={onClose}
|
||||||
|
className="absolute top-4 right-4 text-white/70 hover:text-white transition-colors"
|
||||||
|
aria-label="Close"
|
||||||
|
>
|
||||||
|
<X className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
|
<div className="w-12 h-12 bg-white/20 rounded-2xl flex items-center justify-center mx-auto mb-3">
|
||||||
|
<Zap className="w-6 h-6 text-white" />
|
||||||
|
</div>
|
||||||
|
<h2 className="text-xl font-bold">Your QR code is downloading!</h2>
|
||||||
|
<p className="text-white/80 text-sm mt-1">
|
||||||
|
Want to make it smarter — for free?
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Benefits */}
|
||||||
|
<div className="p-6 space-y-3">
|
||||||
|
{BENEFITS.map(({ icon: Icon, text }) => (
|
||||||
|
<div key={text} className="flex items-center gap-3">
|
||||||
|
<div className="w-8 h-8 rounded-xl bg-indigo-50 flex items-center justify-center shrink-0">
|
||||||
|
<Icon className="w-4 h-4 text-[#4F46E5]" />
|
||||||
|
</div>
|
||||||
|
<span className="text-sm text-slate-700">{text}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* CTAs */}
|
||||||
|
<div className="px-6 pb-6 space-y-3">
|
||||||
|
<Link href="/signup" onClick={onClose} className="block">
|
||||||
|
<Button className="w-full bg-[#4F46E5] hover:bg-[#4338CA] text-white h-12 text-base font-semibold shadow-lg">
|
||||||
|
Create Free Account
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
<button
|
||||||
|
onClick={onClose}
|
||||||
|
className="w-full text-sm text-slate-400 hover:text-slate-600 transition-colors py-1"
|
||||||
|
>
|
||||||
|
No thanks, keep it static
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user