feat: Integrate join URL and QR code for player access
Adds a dynamic join URL and QR code displayed on the spectator view and host dashboard. This allows players to easily join the quiz session by scanning the QR code or navigating to the provided URL. The `joinUrl` is now managed within the `GameContext` and exposed to relevant components. The spectator view uses this URL to generate the QR code, while the host view displays it for easy access. This enhances the onboarding experience for new players and simplifies session management.
This commit is contained in:
+20
-3
@@ -3,13 +3,13 @@ import { useGame } from '../context/GameContext';
|
||||
import { GamePhase } from '../types';
|
||||
import type { Question } from '../types';
|
||||
import { Soundboard } from './Soundboard';
|
||||
import { Play, SkipForward, CheckCircle, XCircle, Users, Library, Sparkles, Plus, Trash2, Edit, ArrowLeft, Upload, RefreshCw, Image as ImageIcon, List, Trophy, RotateCcw } from 'lucide-react';
|
||||
import { Play, SkipForward, CheckCircle, XCircle, Users, Library, Sparkles, Plus, Trash2, Edit, ArrowLeft, Upload, RefreshCw, Image as ImageIcon, List, Trophy, RotateCcw, QrCode } from 'lucide-react';
|
||||
import { generateQuestions } from '../services/geminiService';
|
||||
|
||||
export const HostView: React.FC = () => {
|
||||
const {
|
||||
gameState, activeGameName, players, teams, buzzQueue, questions, games,
|
||||
approvePlayer, startGame, startCountdown, openBuzzers,
|
||||
gameState, activeGameName, players, teams, buzzQueue, questions, games, joinUrl,
|
||||
setJoinUrl, approvePlayer, startGame, startCountdown, openBuzzers,
|
||||
resolveBuzz, rectifyBuzz, skipQuestion, nextPhase, resetGame,
|
||||
createGame, updateGame, deleteGame, loadGameToLive
|
||||
} = useGame();
|
||||
@@ -189,6 +189,23 @@ export const HostView: React.FC = () => {
|
||||
{/* GAME CONTROL TAB */}
|
||||
{activeTab === 'GAME' && (
|
||||
<div className="max-w-4xl mx-auto">
|
||||
{/* Session Settings */}
|
||||
<div className="bg-white p-4 rounded-xl shadow-sm border border-slate-200 mb-6 flex items-center gap-4">
|
||||
<div className="bg-indigo-100 p-2 rounded-lg text-indigo-600">
|
||||
<QrCode size={20} />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<label className="block text-xs font-bold text-slate-500 uppercase">Player Join URL (for QR Code)</label>
|
||||
<input
|
||||
type="text"
|
||||
value={joinUrl}
|
||||
onChange={(e) => setJoinUrl(e.target.value)}
|
||||
className="w-full font-mono text-sm border-b border-slate-300 focus:border-indigo-600 outline-none bg-transparent py-1 text-slate-800"
|
||||
placeholder="https://..."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* LAST QUESTION WARNING */}
|
||||
{isLastQuestionPhase && !isGameOver && (
|
||||
<div className="bg-amber-100 border-l-4 border-amber-500 text-amber-700 p-4 mb-6 font-bold shadow-sm">
|
||||
|
||||
@@ -6,7 +6,7 @@ import { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer, Cell } from
|
||||
import { Trophy, Zap, Users } from 'lucide-react';
|
||||
|
||||
export const SpectatorView: React.FC = () => {
|
||||
const { gameState, questions, teams, players, buzzQueue } = useGame();
|
||||
const { gameState, questions, teams, players, buzzQueue, joinUrl } = useGame();
|
||||
const currentQ = questions[gameState.currentQuestionIndex];
|
||||
|
||||
// Helper to get formatted leaderboard data
|
||||
@@ -29,10 +29,11 @@ export const SpectatorView: React.FC = () => {
|
||||
<h1 className="text-6xl md:text-8xl font-black text-transparent bg-clip-text bg-gradient-to-r from-yellow-400 to-orange-500 mb-8">
|
||||
JOIN THE QUIZ
|
||||
</h1>
|
||||
<div className="bg-white p-4 inline-block rounded-xl mb-8">
|
||||
<img src="https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=https://quiz-app-demo.com" alt="QR Code" className="w-48 h-48" />
|
||||
<div className="bg-white p-4 inline-block rounded-xl mb-4">
|
||||
<img src={`https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${encodeURIComponent(joinUrl)}`} alt="QR Code" className="w-48 h-48" />
|
||||
</div>
|
||||
<p className="text-2xl text-slate-300 mb-8">Scan to Join</p>
|
||||
<p className="text-2xl text-slate-300 mb-2">Scan to Join</p>
|
||||
<p className="text-lg text-slate-500 font-mono mb-8">{joinUrl}</p>
|
||||
|
||||
<div className="flex flex-wrap justify-center gap-4 max-w-4xl mx-auto">
|
||||
{players.filter(p => p.isApproved).map(p => (
|
||||
|
||||
Reference in New Issue
Block a user