From 9e2524a5e7e97c259f31dd8197be278d96d4a2c4 Mon Sep 17 00:00:00 2001 From: LognDH Date: Thu, 19 Mar 2026 00:59:26 +0700 Subject: [PATCH] Add QR code to match --- .../events/[id]/stages/[stageId]/page.tsx | 68 ++++++++++++++++++- next.config.ts | 3 + 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/app/[locale]/admin/events/[id]/stages/[stageId]/page.tsx b/app/[locale]/admin/events/[id]/stages/[stageId]/page.tsx index b66e16f..02d77f3 100644 --- a/app/[locale]/admin/events/[id]/stages/[stageId]/page.tsx +++ b/app/[locale]/admin/events/[id]/stages/[stageId]/page.tsx @@ -1,6 +1,7 @@ 'use client'; -import { useState } from 'react'; +import { useState, useEffect } from 'react'; +import QRCode from 'qrcode'; import { useParams, useRouter } from 'next/navigation'; import { useQueryClient } from '@tanstack/react-query'; import { @@ -19,6 +20,9 @@ import { RefreshCw, Eye, EyeOff, + QrCode, + Copy, + Check, } from 'lucide-react'; import { toast } from 'sonner'; @@ -85,8 +89,21 @@ const MATCH_STATUS_CONFIG: Record CANCELLED: { className: 'bg-gray-500 text-white', label: 'Cancelled' }, }; -function MatchRow({ match, statusConfig }: { match: any; statusConfig: Record }) { +function MatchRow({ match, statusConfig, eventId }: { match: any; statusConfig: Record; eventId: string }) { const [showScore, setShowScore] = useState(false); + const [showQrDialog, setShowQrDialog] = useState(false); + const [qrImage, setQrImage] = useState(''); + const [copied, setCopied] = useState(false); + + const refereeUrl = `${process.env.REFEREE_UI_URL || 'https://dev-trongtai.5sport.vn'}/vi/events/${eventId}/matches/${match.id}`; + + useEffect(() => { + if (showQrDialog) { + QRCode.toDataURL(refereeUrl, { width: 256, margin: 2 }) + .then(setQrImage) + .catch(console.error); + } + }, [showQrDialog, refereeUrl]); const { data: scoresData, isFetching: isFetchingScores, refetch } = useMatchScoreControllerFindAll( match.id, @@ -105,6 +122,7 @@ function MatchRow({ match, statusConfig }: { match: any; statusConfig: Record
@@ -175,6 +193,15 @@ function MatchRow({ match, statusConfig }: { match: any; statusConfig: Record
+
+ + + + + Referee QR Code + +
+

+ {match.name} +

+ {qrImage ? ( + Referee QR Code + ) : ( +
+ +
+ )} +
+ +

{refereeUrl}

+
+
+
+
+ ); } @@ -510,7 +572,7 @@ export default function StageDetailPage() { {roundMatches .sort((a: any, b: any) => (a.matchNumber || 0) - (b.matchNumber || 0)) .map((match: any) => ( - + ))} diff --git a/next.config.ts b/next.config.ts index 9629e3b..85f9057 100644 --- a/next.config.ts +++ b/next.config.ts @@ -5,6 +5,9 @@ const withNextIntl = createNextIntlPlugin('./i18n.ts'); const nextConfig: NextConfig = { output: 'standalone', + env: { + REFEREE_UI_URL: process.env.REFEREE_UI_URL, + }, async rewrites() { return [ {