mirror of
https://github.com/EdiFarcas/Giveaway-app.git
synced 2026-06-22 05:00:55 +03:00
Winner selection
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { giveawaysFind } from "./GiveawayManagementCardServer";
|
||||
import Modal from "./ModalGiveawayWinner";
|
||||
|
||||
interface Giveaway {
|
||||
id: string;
|
||||
@@ -16,6 +17,13 @@ interface Giveaway {
|
||||
const GiveawayManagementCards: React.FC = () => {
|
||||
const [activeGiveaways, setActiveGiveaways] = 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 () => {
|
||||
try {
|
||||
@@ -40,19 +48,30 @@ const GiveawayManagementCards: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectWinner = async (giveawayId: string) => {
|
||||
alert(`Selecting winner for giveaway ID: ${giveawayId}`);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
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 (
|
||||
<div className="space-y-10">
|
||||
|
||||
{/* 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>
|
||||
<div className="space-y-4">
|
||||
{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"
|
||||
>
|
||||
<div>
|
||||
<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 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">
|
||||
<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 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">
|
||||
Ended At: {giveaway.endsAt ? new Date(giveaway.endsAt).toLocaleString() : "N/A"}
|
||||
</p>
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => handleSelectWinner(giveaway.id)}
|
||||
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" }}
|
||||
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"
|
||||
style={{ position: "absolute", bottom: "10px", right: "10px" }}
|
||||
>
|
||||
Select Winner
|
||||
Select Winner
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Active Giveaways Section */}
|
||||
<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>
|
||||
<div className="space-y-4">
|
||||
{activeGiveaways.map((giveaway) => (
|
||||
<div
|
||||
key={giveaway.id}
|
||||
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>
|
||||
<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">Value: {giveaway.value} coins</p>
|
||||
<p className="text-gray-600 mt-2">
|
||||
Ends At: {giveaway.endsAt ? new Date(giveaway.endsAt).toLocaleString() : "N/A"}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
<h2 className="text-2xl font-semibold text-blue-700 mb-4">🎉 Active Giveaways</h2>
|
||||
<div className="space-y-4">
|
||||
{activeGiveaways.map((giveaway) => (
|
||||
<div
|
||||
key={giveaway.id}
|
||||
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>
|
||||
<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">Value: {giveaway.value} coins</p>
|
||||
<p className="text-gray-600 mt-2">
|
||||
Ends At: {giveaway.endsAt ? new Date(giveaway.endsAt).toLocaleString() : "N/A"}
|
||||
</p>
|
||||
</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>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
@@ -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 };
|
||||
Reference in New Issue
Block a user