feat(sysadmin): Part 4 — QR code section in SiteDetailPage
- Install qrcode.react in sysadmin_panel - Add QR Codes section above Remote Managers with two codes side by side: Menu QR (https://yourdomain.com/menu/{site_id}) and Order QR (https://yourdomain.com/menu/{site_id}/order) - Each card shows the URL as copyable text and a Download PNG button - Uses site.site_id as the slug (no slug field exists on the Site model) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
10
sysadmin_panel/package-lock.json
generated
10
sysadmin_panel/package-lock.json
generated
@@ -9,6 +9,7 @@
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"axios": "^1.7.9",
|
||||
"qrcode.react": "^4.2.0",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-hot-toast": "^2.4.1",
|
||||
@@ -2472,6 +2473,15 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/qrcode.react": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/qrcode.react/-/qrcode.react-4.2.0.tgz",
|
||||
"integrity": "sha512-QpgqWi8rD9DsS9EP3z7BT+5lY5SFhsqGjpgW5DY/i3mK4M9DTBNz3ErMi8BWYEfI3L0d8GIbGmcdFAS1uIRGjA==",
|
||||
"license": "ISC",
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/queue-microtask": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.7.9",
|
||||
"qrcode.react": "^4.2.0",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-hot-toast": "^2.4.1",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState, useEffect, useCallback } from 'react'
|
||||
import { useParams, useNavigate } from 'react-router-dom'
|
||||
import toast from 'react-hot-toast'
|
||||
import { QRCodeCanvas } from 'qrcode.react'
|
||||
import client, { getManagersBySite, addManagerToSite, removeManagerSiteAccess } from '../api/client'
|
||||
import LicenseStatus from '../components/LicenseStatus'
|
||||
import ConfirmModal from '../components/ConfirmModal'
|
||||
@@ -322,6 +323,49 @@ export default function SiteDetailPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* QR Codes */}
|
||||
{(() => {
|
||||
const slug = site.site_id
|
||||
const menuUrl = `https://yourdomain.com/menu/${slug}`
|
||||
const orderUrl = `https://yourdomain.com/menu/${slug}/order`
|
||||
|
||||
function handleDownload(canvasId, filename) {
|
||||
const canvas = document.getElementById(canvasId)
|
||||
if (!canvas) return
|
||||
const url = canvas.toDataURL('image/png')
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = filename
|
||||
a.click()
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="bg-gray-900 border border-gray-700 rounded-xl p-4 mt-4">
|
||||
<h2 className="text-xs font-semibold text-gray-500 uppercase tracking-wider mb-4">QR Codes</h2>
|
||||
<div className="flex flex-wrap gap-8">
|
||||
{[
|
||||
{ id: `qr-menu-${site.id}`, url: menuUrl, label: 'Menu QR Code', file: `menu-qr-${slug}.png` },
|
||||
{ id: `qr-order-${site.id}`, url: orderUrl, label: 'Order QR Code', file: `order-qr-${slug}.png` },
|
||||
].map(({ id, url, label, file }) => (
|
||||
<div key={id} className="flex flex-col items-center gap-3">
|
||||
<p className="text-xs font-medium text-gray-400">{label}</p>
|
||||
<div className="bg-white p-3 rounded-xl">
|
||||
<QRCodeCanvas id={id} value={url} size={180} includeMargin={false} />
|
||||
</div>
|
||||
<p className="text-xs text-gray-600 font-mono break-all max-w-[220px] text-center">{url}</p>
|
||||
<button
|
||||
onClick={() => handleDownload(id, file)}
|
||||
className="text-xs text-cyan-400 hover:text-cyan-300 transition-colors"
|
||||
>
|
||||
Download PNG
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})()}
|
||||
|
||||
{/* Remote Managers */}
|
||||
<div className="bg-gray-900 border border-gray-700 rounded-xl p-4 mt-4">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
|
||||
Reference in New Issue
Block a user