272 lines
10 KiB
React
272 lines
10 KiB
React
import React, { useState, useEffect } from "react"
|
||
import { motion, AnimatePresence } from "framer-motion"
|
||
|
||
/**
|
||
* JokerApprovalModal - Gamemaster felület a Joker kártya feladatok jóváhagyására
|
||
*
|
||
* @param {Object} props
|
||
* @param {boolean} props.isOpen - Modal megjelenítése
|
||
* @param {Function} props.onClose - Modal bezárása
|
||
* @param {Object} props.jokerRequest - Joker kártya adatok
|
||
* @param {Function} props.onApprove - Jóváhagyás callback
|
||
* @param {Function} props.onReject - Elutasítás callback
|
||
* @param {string} props.playerName - Játékos neve
|
||
* @param {string} props.playerEmoji - Játékos emoji
|
||
* @param {number} props.timeLimit - Időkorlát másodpercben (default: 120)
|
||
*/
|
||
const JokerApprovalModal = ({
|
||
isOpen,
|
||
onClose,
|
||
jokerRequest,
|
||
onApprove,
|
||
onReject,
|
||
playerName,
|
||
playerEmoji = "🎭",
|
||
timeLimit = 120
|
||
}) => {
|
||
const [isProcessing, setIsProcessing] = useState(false)
|
||
const [timeLeft, setTimeLeft] = useState(timeLimit)
|
||
|
||
// Timer countdown
|
||
useEffect(() => {
|
||
if (!isOpen) return
|
||
|
||
setTimeLeft(timeLimit)
|
||
const timer = setInterval(() => {
|
||
setTimeLeft(prev => {
|
||
if (prev <= 1) {
|
||
clearInterval(timer)
|
||
handleTimeout()
|
||
return 0
|
||
}
|
||
return prev - 1
|
||
})
|
||
}, 1000)
|
||
|
||
return () => clearInterval(timer)
|
||
}, [isOpen, timeLimit])
|
||
|
||
const handleTimeout = () => {
|
||
// Auto-reject on timeout
|
||
if (onReject && !isProcessing) {
|
||
handleReject()
|
||
}
|
||
}
|
||
|
||
const formatTime = (seconds) => {
|
||
const mins = Math.floor(seconds / 60)
|
||
const secs = seconds % 60
|
||
return `${mins}:${secs.toString().padStart(2, '0')}`
|
||
}
|
||
|
||
const getTimeColor = () => {
|
||
if (timeLeft > 60) return "text-green-400"
|
||
if (timeLeft > 30) return "text-yellow-400"
|
||
return "text-red-400 animate-pulse"
|
||
}
|
||
|
||
const handleApprove = async () => {
|
||
setIsProcessing(true)
|
||
try {
|
||
await onApprove(jokerRequest)
|
||
onClose()
|
||
} catch (error) {
|
||
console.error("Jóváhagyási hiba:", error)
|
||
} finally {
|
||
setIsProcessing(false)
|
||
}
|
||
}
|
||
|
||
const handleReject = async () => {
|
||
setIsProcessing(true)
|
||
try {
|
||
await onReject(jokerRequest)
|
||
onClose()
|
||
} catch (error) {
|
||
console.error("Elutasítási hiba:", error)
|
||
} finally {
|
||
setIsProcessing(false)
|
||
}
|
||
}
|
||
|
||
if (!isOpen) return null
|
||
|
||
return (
|
||
<AnimatePresence>
|
||
{isOpen && (
|
||
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
|
||
{/* Backdrop */}
|
||
<motion.div
|
||
initial={{ opacity: 0 }}
|
||
animate={{ opacity: 1 }}
|
||
exit={{ opacity: 0 }}
|
||
className="absolute inset-0 bg-black/70 backdrop-blur-sm"
|
||
onClick={onClose}
|
||
/>
|
||
|
||
{/* Modal Content */}
|
||
<motion.div
|
||
initial={{ scale: 0.9, opacity: 0, y: 20 }}
|
||
animate={{ scale: 1, opacity: 1, y: 0 }}
|
||
exit={{ scale: 0.9, opacity: 0, y: 20 }}
|
||
transition={{ type: "spring", duration: 0.5 }}
|
||
className="relative bg-gradient-to-br from-gray-900 via-gray-800 to-gray-900 rounded-2xl shadow-2xl border-2 border-purple-500/30 max-w-2xl w-full overflow-hidden"
|
||
>
|
||
{/* Header with Joker theme */}
|
||
<div className="bg-gradient-to-r from-purple-600 via-pink-600 to-purple-600 p-6 relative overflow-hidden">
|
||
<div className="absolute inset-0 bg-gradient-to-r from-transparent via-white/10 to-transparent animate-pulse" />
|
||
<div className="relative flex items-center justify-between">
|
||
<div className="flex items-center gap-3">
|
||
<div className="text-5xl animate-bounce">🃏</div>
|
||
<div>
|
||
<h2 className="text-2xl font-bold text-white">Joker Kártya Feladat</h2>
|
||
<p className="text-purple-100 text-sm">Gamemaster jóváhagyás szükséges</p>
|
||
</div>
|
||
</div>
|
||
<div className="flex items-center gap-3">
|
||
{/* Timer */}
|
||
<div className="bg-black/30 rounded-lg px-4 py-2">
|
||
<div className={`text-2xl font-bold ${getTimeColor()}`}>
|
||
⏱️ {formatTime(timeLeft)}
|
||
</div>
|
||
</div>
|
||
<button
|
||
onClick={onClose}
|
||
className="text-white/80 hover:text-white transition-colors text-2xl"
|
||
disabled={isProcessing}
|
||
>
|
||
✕
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Content */}
|
||
<div className="p-6 space-y-6">
|
||
{/* Player Info */}
|
||
<div className="bg-gray-800/50 rounded-xl p-4 border border-gray-700">
|
||
<div className="flex items-center gap-3">
|
||
<div className="text-4xl">{playerEmoji}</div>
|
||
<div>
|
||
<p className="text-gray-400 text-sm">Játékos</p>
|
||
<p className="text-white font-semibold text-lg">{playerName}</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Joker Card Details */}
|
||
<div className="bg-gradient-to-br from-purple-900/30 to-pink-900/30 rounded-xl p-5 border border-purple-500/30">
|
||
<div className="flex items-start gap-3 mb-3">
|
||
<div className="text-3xl">🎯</div>
|
||
<div className="flex-1">
|
||
<h3 className="text-purple-300 font-semibold mb-2">Feladat címe</h3>
|
||
<p className="text-white text-lg font-medium">
|
||
{jokerRequest?.cardTitle || "Joker Kártya Feladat"}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="flex items-start gap-3">
|
||
<div className="text-2xl">📝</div>
|
||
<div className="flex-1">
|
||
<h3 className="text-purple-300 font-semibold mb-2">Feladat leírása</h3>
|
||
<p className="text-gray-300 leading-relaxed">
|
||
{jokerRequest?.cardDescription || "A játékosnak teljesítenie kell a Joker kártya feladatát."}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Points Info */}
|
||
{jokerRequest?.points && (
|
||
<div className="mt-4 pt-4 border-t border-purple-500/20">
|
||
<div className="flex items-center gap-2">
|
||
<span className="text-2xl">⭐</span>
|
||
<span className="text-yellow-400 font-bold text-lg">
|
||
{jokerRequest.points} pont
|
||
</span>
|
||
<span className="text-gray-400 text-sm">járható érte</span>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
{/* Player's Claim (Optional - ha később hozzáadod) */}
|
||
{jokerRequest?.playerMessage && (
|
||
<div className="bg-blue-900/20 rounded-xl p-4 border border-blue-500/30">
|
||
<div className="flex items-start gap-3">
|
||
<div className="text-2xl">💬</div>
|
||
<div className="flex-1">
|
||
<h3 className="text-blue-300 font-semibold mb-2">Játékos üzenete</h3>
|
||
<p className="text-gray-300 italic">"{jokerRequest.playerMessage}"</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{/* Instructions */}
|
||
<div className="bg-yellow-900/20 rounded-xl p-4 border border-yellow-500/30">
|
||
<div className="flex items-start gap-3">
|
||
<div className="text-2xl">ℹ️</div>
|
||
<div className="flex-1">
|
||
<p className="text-yellow-200 text-sm">
|
||
<strong>Gamemaster döntés:</strong> Nézd meg, hogy a játékos teljesítette-e a feladatot,
|
||
majd hagyd jóvá vagy utasítsd el.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Action Buttons */}
|
||
<div className="flex gap-4 pt-2">
|
||
<button
|
||
onClick={handleReject}
|
||
disabled={isProcessing}
|
||
className="flex-1 bg-gradient-to-r from-red-600 to-red-700 hover:from-red-500 hover:to-red-600
|
||
text-white font-bold py-4 px-6 rounded-xl shadow-lg
|
||
transform transition-all duration-200 hover:scale-105 active:scale-95
|
||
disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:scale-100
|
||
border border-red-500/50"
|
||
>
|
||
<div className="flex items-center justify-center gap-2">
|
||
<span className="text-2xl">❌</span>
|
||
<span className="text-lg">Elutasítás</span>
|
||
</div>
|
||
<div className="text-xs text-red-200 mt-1">Nem teljesítette</div>
|
||
</button>
|
||
|
||
<button
|
||
onClick={handleApprove}
|
||
disabled={isProcessing}
|
||
className="flex-1 bg-gradient-to-r from-green-600 to-green-700 hover:from-green-500 hover:to-green-600
|
||
text-white font-bold py-4 px-6 rounded-xl shadow-lg
|
||
transform transition-all duration-200 hover:scale-105 active:scale-95
|
||
disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:scale-100
|
||
border border-green-500/50"
|
||
>
|
||
<div className="flex items-center justify-center gap-2">
|
||
<span className="text-2xl">✅</span>
|
||
<span className="text-lg">Jóváhagyás</span>
|
||
</div>
|
||
<div className="text-xs text-green-200 mt-1">Sikeresen teljesítette</div>
|
||
</button>
|
||
</div>
|
||
|
||
{/* Processing indicator */}
|
||
{isProcessing && (
|
||
<div className="text-center py-2">
|
||
<div className="inline-flex items-center gap-2 text-purple-400">
|
||
<div className="animate-spin text-2xl">⚙️</div>
|
||
<span>Feldolgozás...</span>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
</motion.div>
|
||
</div>
|
||
)}
|
||
</AnimatePresence>
|
||
)
|
||
}
|
||
|
||
export default JokerApprovalModal
|