import type { Metadata } from "next";
import Link from "next/link";
import { notFound } from "next/navigation";
import { ArrowRight, CheckCircle2, ClipboardCheck, Gauge, RefreshCw } from "lucide-react";
import Breadcrumbs, { type BreadcrumbItem } from "@/components/Breadcrumbs";
import SeoJsonLd from "@/components/SeoJsonLd";
import { getGuidePage } from "@/lib/guide-pages";
import type { GuidePage } from "@/lib/pseo-page-types";
import {
isPublishedGuideSlug,
publishedGuidePages,
} from "@/lib/pseo-published-pages";
import { articleSchema, breadcrumbSchema, faqPageSchema } from "@/lib/schema";
const SITE_URL = "https://www.qrmaster.net";
const LAST_MODIFIED = "2026-06-22";
type PageProps = {
params: {
slug: string;
};
};
export const dynamicParams = false;
export function generateStaticParams() {
return publishedGuidePages.map((page) => ({ slug: page.slug }));
}
function getPublishedPage(slug: string): GuidePage {
if (!isPublishedGuideSlug(slug)) {
notFound();
}
const page = getGuidePage(slug);
if (!page) {
notFound();
}
return page;
}
function titleFor(page: GuidePage) {
if (page.slug === "dynamic-qr-code-best-practices") {
return "Dynamic QR Code Best Practices";
}
return page.title;
}
function descriptionFor(page: GuidePage) {
if (page.slug === "dynamic-qr-code-best-practices") {
return "Plan dynamic QR codes with better naming, tracking, print testing, privacy checks, and update workflows before campaigns go live.";
}
return page.description;
}
export function generateMetadata({ params }: PageProps): Metadata {
const page = getPublishedPage(params.slug);
const title = titleFor(page);
const description = descriptionFor(page);
const canonical = `${SITE_URL}${page.canonicalPath}`;
return {
title: {
absolute: title,
},
description,
alternates: {
canonical,
languages: {
"x-default": canonical,
en: canonical,
},
},
robots: {
index: true,
follow: true,
},
icons: {
icon: [
{ url: "/favicon.svg", type: "image/svg+xml" },
{ url: "/favicon.ico", sizes: "16x16 32x32", type: "image/x-icon" },
],
shortcut: "/favicon.ico",
apple: "/logo.svg",
},
openGraph: {
title,
description,
url: canonical,
type: "article",
images: ["/og-image.png"],
},
twitter: {
title,
description,
},
};
}
function breadcrumbsFor(page: GuidePage): BreadcrumbItem[] {
return [
{ name: "Home", url: "/" },
{ name: page.title, url: page.canonicalPath },
];
}
function howToStructuredData(page: GuidePage) {
return {
"@context": "https://schema.org",
"@type": "HowTo",
"@id": `${SITE_URL}${page.canonicalPath}#howto`,
name: titleFor(page),
description: descriptionFor(page),
datePublished: LAST_MODIFIED,
dateModified: LAST_MODIFIED,
totalTime: "PT15M",
author: {
"@type": "Organization",
name: "QR Master",
url: SITE_URL,
},
step: page.howToSteps.map((step, index) => ({
"@type": "HowToStep",
position: index + 1,
name: `Step ${index + 1}`,
text: step,
})),
};
}
function PracticeRail() {
const items = [
{
label: "Before print",
detail: "Name the QR by campaign, surface, and destination risk.",
icon: ClipboardCheck,
},
{
label: "During launch",
detail: "Test the printed asset on real devices and final material.",
icon: Gauge,
},
{
label: "After launch",
detail: "Review scan context before changing or reprinting assets.",
icon: RefreshCw,
},
];
return (
Operating rhythm
{items.map((item) => {
const Icon = item.icon;
return (
{item.label}
{item.detail}
);
})}
);
}
export default function GuidePageRoute({ params }: PageProps) {
const page = getPublishedPage(params.slug);
const title = titleFor(page);
const description = descriptionFor(page);
const canonical = `${SITE_URL}${page.canonicalPath}`;
const breadcrumbs = breadcrumbsFor(page);
const structuredData = [
articleSchema({
headline: title,
description,
datePublished: LAST_MODIFIED,
dateModified: LAST_MODIFIED,
author: "QR Master",
url: canonical,
image: `${SITE_URL}/og-image.png`,
}),
howToStructuredData(page),
faqPageSchema(page.faq),
breadcrumbSchema(breadcrumbs),
];
return (
<>
Dynamic QR operating guide
{title}
{page.quickAnswer}
{page.primaryCta.label}
{page.secondaryCta.label}
The working principle
{page.intro} A dynamic QR code is strongest when the team treats
the printed asset, the destination, and the reporting convention
as one workflow.
{page.keyTakeaways.map((item) => (
))}
Dynamic QR setup sequence
Start with naming and placement. Tracking data only becomes
useful when the scan can be traced back to a real campaign,
surface, or operational context.
{page.howToSteps.map((step, index) => (
0{index + 1}
{step}
))}
{page.checklist && (
{page.checklist.title}
Use this before the QR code reaches print. Most expensive QR
mistakes are workflow mistakes, not image-generation mistakes.
{page.checklist.items.map((item) => (
{item}
))}
)}
Pages to pair with this guide
These companion pages cover the buying decision, tracking
setup, and the product workflow behind dynamic QR codes.
{page.relatedLinks.map((link) => (
{link.title}
{link.description}
Open page
))}
Common questions
{page.faq.map((item) => (
{item.question}
+
{item.answer}
))}
>
);
}