diff --git a/Product_Scope.md b/Product_Scope.md index f085c7d..cbfd54f 100644 --- a/Product_Scope.md +++ b/Product_Scope.md @@ -50,10 +50,10 @@ The platform operates on a tiered structure, utilizing a robust downgrade logic | Feature / Capability | Guest / Free | Free Trial (14-Day) | Pro / Enterprise Paid | | :--- | :--- | :--- | :--- | | **Static QR Codes** | Unlimited | Unlimited | Unlimited | -| **Dynamic QR Codes** | Up to 5 | Unlimited | Unlimited | -| **Scan Interstitial Ads** | Yes (Ad-supported) | No Ads | No Ads | +| **Dynamic QR Codes** | Up to 5 | Up to 1 | Unlimited | +| **Scan Interstitial Ads** | Yes (Ad-supported) | Yes (Ad-supported) | No Ads | | **Custom Domains** | CK-QR domain only | Custom subdomains | Custom domain / White-label | -| **Export Formats** | PNG, JPEG | PNG, JPEG, SVG, PDF | All + Bulk zip export | +| **Export Formats** | PNG, JPEG | PNG, JPEG | All + Bulk zip export | | **File Storage Limit** | 5 MB per upload | 20 MB per upload | 100 MB - 1 GB+ per upload | **Trial Expiration Logic:** diff --git a/client/src/app/dashboard/create/page.tsx b/client/src/app/dashboard/create/page.tsx index d0759ee..b0b083b 100644 --- a/client/src/app/dashboard/create/page.tsx +++ b/client/src/app/dashboard/create/page.tsx @@ -15,6 +15,7 @@ export default function CreateQRPage() { const [customSlug, setCustomSlug] = useState(''); const [randomSlug, setRandomSlug] = useState(''); const [isGenerating, setIsGenerating] = useState(false); + const [userRole, setUserRole] = useState('free'); const baseUrl = typeof window !== 'undefined' ? (process.env.NEXT_PUBLIC_APP_URL || 'https://qr.houseofwebsites.ai') : 'https://qr.houseofwebsites.ai'; const [qrOptions, setQrOptions] = useState({ @@ -55,6 +56,13 @@ export default function CreateQRPage() { } else { setQrOptions(prev => ({ ...prev, data: destinationUrl })); } + + // Fetch user role + api.get('/auth/me').then(res => { + if (res.data?.user?.role) { + setUserRole(res.data.user.role); + } + }).catch(() => {}); }, [baseUrl]); // Keep QR data in sync with type and destinationUrl @@ -124,9 +132,15 @@ export default function CreateQRPage() { diff --git a/client/src/app/page.tsx b/client/src/app/page.tsx index cad062e..158366b 100644 --- a/client/src/app/page.tsx +++ b/client/src/app/page.tsx @@ -1,31 +1,13 @@ import Image from "next/image"; import Link from "next/link"; +import HomeNavbar from "@/components/HomeNavbar"; +import GuestQRGenerator from "@/components/GuestQRGenerator"; export default function Home() { return (
- {/* Navigation */} - + {/* Hero Section with Parallax */}
+ {/* Guest Static QR Generator Section */} +
+
+ +
+
+ + {/* Trust & Scale Metrics (Data Section) */}
diff --git a/client/src/components/GuestQRGenerator.tsx b/client/src/components/GuestQRGenerator.tsx new file mode 100644 index 0000000..1d86109 --- /dev/null +++ b/client/src/components/GuestQRGenerator.tsx @@ -0,0 +1,103 @@ +'use client'; +import React, { useState } from 'react'; +import dynamic from 'next/dynamic'; +import Link from 'next/link'; + +// Load LivePreview dynamically since it depends on browser APIs +const LivePreview = dynamic(() => import('@/components/qr-editor/LivePreview'), { ssr: false }); + +export default function GuestQRGenerator() { + const [url, setUrl] = useState('https://ck-qr.com'); + + const defaultOptions = { + width: 300, + height: 300, + type: 'svg' as const, + data: url || 'https://ck-qr.com', + margin: 10, + qrOptions: { + typeNumber: 0 as const, + mode: 'Byte' as const, + errorCorrectionLevel: 'Q' as const + }, + imageOptions: { + hideBackgroundDots: true, + imageSize: 0.4, + margin: 5 + }, + dotsOptions: { + color: '#4f46e5', + type: 'rounded' as const + }, + backgroundOptions: { + color: '#ffffff', + }, + cornersSquareOptions: { + color: '#4f46e5', + type: 'extra-rounded' as const + } + }; + + const handleDownload = async () => { + try { + const QRCodeStyling = (await import('qr-code-styling')).default; + const qrCode = new QRCodeStyling(defaultOptions); + qrCode.download({ name: 'Guest-Static-QR', extension: 'png' }); + } catch (err) { + console.error('Download failed', err); + } + }; + + return ( +
+
+
+ +
+
+

Try it now, for free.

+

+ Enter a destination URL below to instantly generate a basic static QR code. No signup required. +

+ +
+ setUrl(e.target.value)} + placeholder="https://yourwebsite.com" + className="w-full bg-gray-950 border border-gray-700 text-white rounded-xl px-4 py-4 focus:outline-none focus:ring-2 focus:ring-indigo-500 transition-all font-medium" + /> +
+ +
+ + + Track Scans (Free Trial) + + +
+ +

+ Static QR codes cannot be edited later and do not track scan analytics. + Upgrade to track. +

+
+ +
+
+ +
+
+
+
+ ); +} diff --git a/client/src/components/HomeNavbar.tsx b/client/src/components/HomeNavbar.tsx new file mode 100644 index 0000000..14567e5 --- /dev/null +++ b/client/src/components/HomeNavbar.tsx @@ -0,0 +1,59 @@ +'use client'; +import React, { useEffect, useState } from 'react'; +import Link from 'next/link'; +import api from '@/lib/api'; + +export default function HomeNavbar() { + const [user, setUser] = useState<{ email: string; role: string } | null>(null); + + useEffect(() => { + // Check if user is logged in + const checkAuth = async () => { + try { + const res = await api.get('/auth/me'); + if (res.data?.user) { + setUser(res.data.user); + } + } catch (err) { + // Not logged in or error + } + }; + checkAuth(); + }, []); + + return ( + + ); +}