Winner selection

This commit is contained in:
EdiFarcas
2025-05-06 17:05:35 +03:00
parent ce143da08c
commit de05090b85
3 changed files with 191 additions and 32 deletions
+65 -32
View File
@@ -2,6 +2,7 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { giveawaysFind } from "./GiveawayManagementCardServer"; import { giveawaysFind } from "./GiveawayManagementCardServer";
import Modal from "./ModalGiveawayWinner";
interface Giveaway { interface Giveaway {
id: string; id: string;
@@ -16,6 +17,13 @@ interface Giveaway {
const GiveawayManagementCards: React.FC = () => { const GiveawayManagementCards: React.FC = () => {
const [activeGiveaways, setActiveGiveaways] = useState<Giveaway[]>([]); const [activeGiveaways, setActiveGiveaways] = useState<Giveaway[]>([]);
const [finishedGiveaways, setFinishedGiveaways] = useState<Giveaway[]>([]); const [finishedGiveaways, setFinishedGiveaways] = useState<Giveaway[]>([]);
const [isModalOpen, setIsModalOpen] = useState(false);
const [selectedGiveaway, setSelectedGiveaway] = useState<{
id: string;
title: string;
prize: string;
value: number;
} | null>(null);
const fetchGiveaways = async () => { const fetchGiveaways = async () => {
try { try {
@@ -40,19 +48,30 @@ const GiveawayManagementCards: React.FC = () => {
} }
}; };
const handleSelectWinner = async (giveawayId: string) => {
alert(`Selecting winner for giveaway ID: ${giveawayId}`);
};
useEffect(() => { useEffect(() => {
fetchGiveaways(); fetchGiveaways();
}, []); }, []);
const handleSelectWinner = (giveawayId: string, giveawayTitle: string, giveawayPrize: string, giveawayValue: number) => {
setSelectedGiveaway({
id: giveawayId,
title: giveawayTitle,
prize: giveawayPrize,
value: giveawayValue,
}); // Set the selected giveaway
setIsModalOpen(true); // Open the modal
};
const handleCloseModal = () => {
setIsModalOpen(false); // Close the modal
setSelectedGiveaway(null); // Clear the selected giveaway
};
return ( return (
<div className="space-y-10"> <div className="space-y-10">
{/* Finished Giveaways Section */} {/* Finished Giveaways Section */}
<div className="bg-white border border-gray-200 p-6 rounded-2xl shadow-lg"> <div className="bg-white border border-gray-200 p-6 rounded-2xl shadow-lg">
<h2 className="text-2xl font-semibold text-gray-700 mb-4">🏁 Finished Giveaways</h2> <h2 className="text-2xl font-semibold text-gray-700 mb-4">🏁 Finished Giveaways</h2>
<div className="space-y-4"> <div className="space-y-4">
{finishedGiveaways.map((giveaway) => ( {finishedGiveaways.map((giveaway) => (
@@ -61,47 +80,61 @@ const GiveawayManagementCards: React.FC = () => {
className="p-4 border border-gray-200 rounded-lg bg-gray-50 hover:bg-gray-100 transition relative" className="p-4 border border-gray-200 rounded-lg bg-gray-50 hover:bg-gray-100 transition relative"
> >
<div> <div>
<h3 className="text-lg font-bold text-gray-800">{giveaway.title}</h3> <h3 className="text-lg font-bold text-gray-800">{giveaway.title}</h3>
<p className="text-gray-600">{giveaway.description}</p> <p className="text-gray-600">{giveaway.description}</p>
<p className="text-gray-600 mt-2">Prize: {giveaway.prize}</p> <p className="text-gray-600 mt-2">Prize: {giveaway.prize}</p>
<p className="text-gray-600 mt-2">Value: {giveaway.value} coins</p> <p className="text-gray-600 mt-2">Value: {giveaway.value} coins</p>
<p className="text-gray-600 mt-2"> <p className="text-gray-600 mt-2">
Ended At: {giveaway.endsAt ? new Date(giveaway.endsAt).toLocaleString() : "N/A"} Ended At: {giveaway.endsAt ? new Date(giveaway.endsAt).toLocaleString() : "N/A"}
</p> </p>
</div> </div>
<button <button
onClick={() => handleSelectWinner(giveaway.id)} onClick={() => handleSelectWinner(giveaway.id, giveaway.title, giveaway.prize, giveaway.value)}
className="bg-blue-500 text-white px-4 py-2 rounded-lg hover:bg-blue-600 transition absolute bottom-4 right-4" className="bg-blue-500 text-white px-4 py-2 rounded-lg hover:bg-blue-600 transition absolute bottom-4 right-4"
style={{ position: "absolute", bottom: "10px", right: "10px" }} style={{ position: "absolute", bottom: "10px", right: "10px" }}
> >
Select Winner Select Winner
</button> </button>
</div> </div>
))} ))}
</div> </div>
</div> </div>
{/* Active Giveaways Section */} {/* Active Giveaways Section */}
<div className="bg-white border border-blue-200 p-6 rounded-2xl shadow-lg"> <div className="bg-white border border-blue-200 p-6 rounded-2xl shadow-lg">
<h2 className="text-2xl font-semibold text-blue-700 mb-4">🎉 Active Giveaways</h2> <h2 className="text-2xl font-semibold text-blue-700 mb-4">🎉 Active Giveaways</h2>
<div className="space-y-4"> <div className="space-y-4">
{activeGiveaways.map((giveaway) => ( {activeGiveaways.map((giveaway) => (
<div <div
key={giveaway.id} key={giveaway.id}
className="p-4 border border-blue-200 rounded-lg bg-blue-50 hover:bg-blue-100 transition" className="p-4 border border-blue-200 rounded-lg bg-blue-50 hover:bg-blue-100 transition"
> >
<h3 className="text-lg font-bold text-blue-800">{giveaway.title}</h3> <h3 className="text-lg font-bold text-blue-800">{giveaway.title}</h3>
<p className="text-gray-600">{giveaway.description}</p> <p className="text-gray-600">{giveaway.description}</p>
<p className="text-gray-600 mt-2">Prize: {giveaway.prize}</p> <p className="text-gray-600 mt-2">Prize: {giveaway.prize}</p>
<p className="text-gray-600 mt-2">Value: {giveaway.value} coins</p> <p className="text-gray-600 mt-2">Value: {giveaway.value} coins</p>
<p className="text-gray-600 mt-2"> <p className="text-gray-600 mt-2">
Ends At: {giveaway.endsAt ? new Date(giveaway.endsAt).toLocaleString() : "N/A"} Ends At: {giveaway.endsAt ? new Date(giveaway.endsAt).toLocaleString() : "N/A"}
</p> </p>
</div>
))}
</div> </div>
))}
</div>
</div> </div>
{/* Modal */}
{isModalOpen && (
<Modal
isOpen={isModalOpen}
onClose={handleCloseModal}
title="Select Giveaway Winner"
giveawayId={selectedGiveaway?.id || null}
giveawayTitle={selectedGiveaway?.title || ""}
giveawayPrize={selectedGiveaway?.prize || ""}
giveawayValue={selectedGiveaway?.value || 0}
>
<p>Here you can select the winner for the giveaway.</p>
</Modal>
)}
</div> </div>
); );
}; };
+80
View File
@@ -0,0 +1,80 @@
import React from "react"
import { selectWinner } from "./SelectWinerServer"
interface ModalProps {
isOpen: boolean;
onClose: () => void;
title: string;
children: React.ReactNode;
giveawayId: string | null;
giveawayTitle: string | null;
giveawayPrize: string | null;
giveawayValue: number | null;
}
const Modal: React.FC<ModalProps> = ({
isOpen,
onClose,
title,
children,
giveawayId,
giveawayTitle,
giveawayPrize,
giveawayValue,
}) => {
if (!isOpen) return null;
const handleSelectWinner = () => {
if (giveawayId) {
selectWinner(giveawayId)
.then((winner) => {
alert(`Winner selected: ${winner.youtubeHandle}`);
})
.catch((error) => {
console.error("Error selecting winner:", error);
alert("Failed to select a winner or no entries in the Giveaway. Please try again.");
});
} else {
alert("No giveaway ID provided.");
}
};
return (
<div className="fixed inset-0 bg-opacity-60 flex justify-center items-center z-50 backdrop-blur-md">
<div className="bg-white p-8 rounded-xl shadow-2xl w-96 relative">
<h2 className="text-2xl font-semibold mb-6 text-center text-gray-800">{title}</h2>
{giveawayTitle && (
<p className="text-lg font-medium text-gray-700 mb-2">
<strong>Giveaway Title:</strong> {giveawayTitle}
</p>
)}
{giveawayPrize && (
<p className="text-lg font-medium text-gray-700 mb-2">
<strong>Prize:</strong> {giveawayPrize}
</p>
)}
{giveawayValue !== null && (
<p className="text-lg font-medium text-gray-700 mb-4">
<strong>Value:</strong> {giveawayValue} coins
</p>
)}
<div className="text-gray-700">{children}</div>
<button
className="mt-4 w-full bg-green-600 text-white py-2 px-4 rounded-lg hover:bg-green-700 transition duration-200"
onClick={handleSelectWinner}
>
Select Winner
</button>
<button
className="mt-6 w-full bg-blue-600 text-white py-2 px-4 rounded-lg hover:bg-blue-700 transition duration-200"
onClick={onClose}
>
Close
</button>
</div>
</div>
);
};
export default Modal;
+46
View File
@@ -0,0 +1,46 @@
"use server";
import { db } from "@/lib/db";
async function selectWinner(giveawayId: string) {
try {
const giveaway = await db.giveaway.findUnique({
where: { id: giveawayId },
include: { entries: true },
});
if (!giveaway) {
throw new Error("Giveaway not found");
}
if (giveaway.entries.length === 0) {
throw new Error("No entries in this giveaway");
}
const randomIndex = Math.floor(Math.random() * giveaway.entries.length);
const winnerEntry = giveaway.entries[randomIndex];
const user = await db.user.findUnique({
where: { id: winnerEntry.userId },
select: { youtubeHandle: true },
});
if (!user || !user.youtubeHandle) {
throw new Error("Winner's YouTube handle not found");
}
const winner = {
entry: winnerEntry,
youtubeHandle: user.youtubeHandle,
};
// Here you can add logic to notify the winner, e.g., send an email or a message
return winner;
} catch (error) {
console.error("Error selecting winner:", error);
throw new Error("Failed to select winner");
}
}
export { selectWinner };