feat: add static vs dynamic QR code toggle to the create page
This commit is contained in:
@@ -11,6 +11,7 @@ export default function CreateQRPage() {
|
||||
const router = useRouter();
|
||||
const [destinationUrl, setDestinationUrl] = useState('https://ck-qr.com');
|
||||
const [qrName, setQrName] = useState('');
|
||||
const [qrType, setQrType] = useState<'dynamic' | 'static'>('dynamic');
|
||||
const [customSlug, setCustomSlug] = useState('');
|
||||
const [randomSlug, setRandomSlug] = useState('');
|
||||
const [isGenerating, setIsGenerating] = useState(false);
|
||||
@@ -49,9 +50,22 @@ export default function CreateQRPage() {
|
||||
React.useEffect(() => {
|
||||
const generated = Math.random().toString(36).substring(2, 8);
|
||||
setRandomSlug(generated);
|
||||
setQrOptions(prev => ({ ...prev, data: `${baseUrl}/l/${generated}` }));
|
||||
if (qrType === 'dynamic') {
|
||||
setQrOptions(prev => ({ ...prev, data: `${baseUrl}/l/${generated}` }));
|
||||
} else {
|
||||
setQrOptions(prev => ({ ...prev, data: destinationUrl }));
|
||||
}
|
||||
}, [baseUrl]);
|
||||
|
||||
// Keep QR data in sync with type and destinationUrl
|
||||
React.useEffect(() => {
|
||||
if (qrType === 'static') {
|
||||
setQrOptions(prev => ({ ...prev, data: destinationUrl }));
|
||||
} else {
|
||||
setQrOptions(prev => ({ ...prev, data: `${baseUrl}/l/${customSlug || randomSlug}` }));
|
||||
}
|
||||
}, [qrType, destinationUrl]);
|
||||
|
||||
// Keep QR data in sync with custom slug
|
||||
const handleSlugChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const val = e.target.value.replace(/[^a-zA-Z0-9-_]/g, '');
|
||||
@@ -65,8 +79,8 @@ export default function CreateQRPage() {
|
||||
// Generate Dynamic QR via API
|
||||
const response = await api.post('/qr/generate', {
|
||||
name: qrName,
|
||||
customSlug: customSlug || randomSlug, // Pass the previewed slug so the backend uses it!
|
||||
type: 'dynamic',
|
||||
customSlug: qrType === 'dynamic' ? (customSlug || randomSlug) : undefined, // Pass the previewed slug so the backend uses it!
|
||||
type: qrType,
|
||||
dataType: 'URL',
|
||||
destinationUrl: destinationUrl,
|
||||
designData: qrOptions
|
||||
@@ -134,6 +148,34 @@ export default function CreateQRPage() {
|
||||
<h2 className="text-xl font-bold text-gray-800 border-b pb-4 mb-6">QR Content</h2>
|
||||
<div className="flex flex-col gap-6">
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">QR Type</label>
|
||||
<div className="flex gap-4">
|
||||
<label className="flex items-center gap-2 cursor-pointer">
|
||||
<input
|
||||
type="radio"
|
||||
name="qrType"
|
||||
value="dynamic"
|
||||
checked={qrType === 'dynamic'}
|
||||
onChange={() => setQrType('dynamic')}
|
||||
className="text-indigo-600 focus:ring-indigo-500"
|
||||
/>
|
||||
<span className="text-gray-900 font-medium">Dynamic (Trackable & Editable)</span>
|
||||
</label>
|
||||
<label className="flex items-center gap-2 cursor-pointer">
|
||||
<input
|
||||
type="radio"
|
||||
name="qrType"
|
||||
value="static"
|
||||
checked={qrType === 'static'}
|
||||
onChange={() => setQrType('static')}
|
||||
className="text-indigo-600 focus:ring-indigo-500"
|
||||
/>
|
||||
<span className="text-gray-900 font-medium">Static (Permanent)</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">Internal Name</label>
|
||||
<input
|
||||
@@ -154,25 +196,32 @@ export default function CreateQRPage() {
|
||||
placeholder="https://your-website.com"
|
||||
className="w-full border-gray-300 rounded-lg shadow-sm p-3 border focus:ring-indigo-500 focus:border-indigo-500 text-gray-900 bg-white"
|
||||
/>
|
||||
<p className="text-xs text-gray-500 mt-2">This is a dynamic QR. You can change this URL later without reprinting the code.</p>
|
||||
{qrType === 'dynamic' && (
|
||||
<p className="text-xs text-gray-500 mt-2">This is a dynamic QR. You can change this URL later without reprinting the code.</p>
|
||||
)}
|
||||
{qrType === 'static' && (
|
||||
<p className="text-xs text-gray-500 mt-2">This URL is embedded directly into the code and cannot be changed later.</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">Custom Short Link (Optional)</label>
|
||||
<div className="flex flex-col sm:flex-row shadow-sm rounded-lg overflow-hidden border border-gray-300 focus-within:ring-2 focus-within:ring-indigo-500">
|
||||
<span className="inline-flex items-center px-4 bg-gray-50 text-gray-500 border-r border-gray-300 text-sm whitespace-nowrap">
|
||||
{(process.env.NEXT_PUBLIC_APP_URL || 'https://qr.houseofwebsites.ai').replace(/^https?:\/\//, '')}/l/
|
||||
</span>
|
||||
<input
|
||||
type="text"
|
||||
value={customSlug}
|
||||
onChange={handleSlugChange}
|
||||
placeholder={randomSlug || "my-promo"}
|
||||
className="flex-1 w-full p-3 focus:outline-none text-gray-900 bg-white"
|
||||
/>
|
||||
{qrType === 'dynamic' && (
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">Custom Short Link (Optional)</label>
|
||||
<div className="flex flex-col sm:flex-row shadow-sm rounded-lg overflow-hidden border border-gray-300 focus-within:ring-2 focus-within:ring-indigo-500">
|
||||
<span className="inline-flex items-center px-4 bg-gray-50 text-gray-500 border-r border-gray-300 text-sm whitespace-nowrap">
|
||||
{(process.env.NEXT_PUBLIC_APP_URL || 'https://qr.houseofwebsites.ai').replace(/^https?:\/\//, '')}/l/
|
||||
</span>
|
||||
<input
|
||||
type="text"
|
||||
value={customSlug}
|
||||
onChange={handleSlugChange}
|
||||
placeholder={randomSlug || "my-promo"}
|
||||
className="flex-1 w-full p-3 focus:outline-none text-gray-900 bg-white"
|
||||
/>
|
||||
</div>
|
||||
<p className="text-xs text-gray-500 mt-2">Leave blank to auto-generate a random link.</p>
|
||||
</div>
|
||||
<p className="text-xs text-gray-500 mt-2">Leave blank to auto-generate a random link.</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user