import type { Metadata } from "next"; import Link from "next/link"; import { notFound } from "next/navigation"; import { ArrowRight, Check, Lock, RefreshCw } from "lucide-react"; import Breadcrumbs, { type BreadcrumbItem } from "@/components/Breadcrumbs"; import SeoJsonLd from "@/components/SeoJsonLd"; import { getComparisonPage } from "@/lib/comparison-pages"; import type { ComparisonPage } from "@/lib/pseo-page-types"; import { isPublishedComparisonSlug, publishedComparisonPages, } 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 publishedComparisonPages.map((page) => ({ slug: page.slug })); } function getPublishedPage(slug: string): ComparisonPage { if (!isPublishedComparisonSlug(slug)) { notFound(); } const page = getComparisonPage(slug); if (!page) { notFound(); } return page; } function titleFor(page: ComparisonPage) { if (page.slug === "dynamic-vs-static-qr-codes") { return "Dynamic or Static QR Codes: Which to Choose for Your Campaign"; } if (page.slug === "free-vs-paid-qr-code-generator") { return "Free vs Paid QR Code Generator"; } return page.title; } function descriptionFor(page: ComparisonPage) { if (page.slug === "dynamic-vs-static-qr-codes") { return "Decide between dynamic and static QR codes for your next campaign: a buyer-focused comparison of reprint risk, tracking, and cost before you commit to print."; } if (page.slug === "free-vs-paid-qr-code-generator") { return "See when a free QR generator is enough and when paid dynamic QR features, tracking, branding, and reprint savings are worth it."; } return page.description; } function intentLabel(intentStage: ComparisonPage["intentStage"]) { if (intentStage === "bottom") return "Commercial investigation"; if (intentStage === "middle") return "Comparison research"; return "Educational comparison"; } 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 comparisonItemListSchema(page: ComparisonPage) { return { "@context": "https://schema.org", "@type": "ItemList", "@id": `${SITE_URL}${page.canonicalPath}#comparison`, name: `${page.primaryEntity} compared with ${page.secondaryEntity}`, numberOfItems: page.scorecard.length, itemListElement: page.scorecard.map((row, index) => ({ "@type": "ListItem", position: index + 1, name: row.topic, description: `${page.primaryEntity}: ${row.qrMaster}. ${page.secondaryEntity}: ${row.alternative}.`, })), }; } function breadcrumbsFor(page: ComparisonPage): BreadcrumbItem[] { return [ { name: "Home", url: "/" }, { name: page.title, url: page.canonicalPath }, ]; } function DynamicFlowVisual() { return (
Printed QR

The physical code stays in place.

Current destination

The URL can change after print.

); } export default function ComparisonPageRoute({ params }: PageProps) { const page = getPublishedPage(params.slug); const title = titleFor(page); const description = descriptionFor(page); const breadcrumbs = breadcrumbsFor(page); const canonical = `${SITE_URL}${page.canonicalPath}`; const structuredData = [ articleSchema({ headline: title, description, datePublished: LAST_MODIFIED, dateModified: LAST_MODIFIED, author: "QR Master", url: canonical, image: `${SITE_URL}/og-image.png`, }), faqPageSchema(page.faq), breadcrumbSchema(breadcrumbs), comparisonItemListSchema(page), ]; return ( <>

{intentLabel(page.intentStage)}

{title}

{page.quickAnswer}

{page.primaryCta.label} {page.secondaryCta.label}

The short answer

{page.intro} {page.quickAnswer}

{page.scorecard.map((row) => ( ))}
Comparison of {page.primaryEntity} and {page.secondaryEntity}
Decision point {page.secondaryEntity} {page.primaryEntity}
{row.topic} {row.alternative} {row.qrMaster}

Which option should you choose?

Use this page as a buying decision, not as a feature glossary. The right answer depends on whether the printed asset must survive a future destination change.

Migration steps

If this comparison changes your decision, move the highest-risk printed assets first. That keeps the work focused on real reprint and tracking value.

    {page.migrationSteps.map((step, index) => (
  1. {index + 1}

    {step}

  2. ))}

Related QR Master workflows

These links connect the comparison to creation, analytics, pricing, and operational guidance.

{page.relatedLinks.map((link) => (

{link.title}

{link.description}

Open page ))}

Common questions

{page.faq.map((item) => (
{item.question} +

{item.answer}

))}
); }