mirror of
https://github.com/EdiFarcas/Giveaway-app.git
synced 2026-06-28 23:00:55 +03:00
Giveaway MAnagement Upadate 1
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import handleUpdateCoins from "./AdminServer";
|
import handleUpdateCoins from "./AdminServer";
|
||||||
//import GiveawayManagement from "./GiveawayManagementCards";
|
import GiveawayManagement from "./GiveawayManagementCards";
|
||||||
|
|
||||||
interface AdminClientProps {
|
interface AdminClientProps {
|
||||||
email: string;
|
email: string;
|
||||||
@@ -20,6 +20,7 @@ export default function AdminClient({ email }: AdminClientProps) {
|
|||||||
});
|
});
|
||||||
const [youtube_url, setYoutubeUrl] = useState("");
|
const [youtube_url, setYoutubeUrl] = useState("");
|
||||||
const [coin_value, setCoinValue] = useState(0);
|
const [coin_value, setCoinValue] = useState(0);
|
||||||
|
const [showGiveawayManagement, setShowGiveawayManagement] = useState(false);
|
||||||
|
|
||||||
const handleCreateGiveaway = async () => {
|
const handleCreateGiveaway = async () => {
|
||||||
const response = await fetch("/api/admin/create-giveaway", {
|
const response = await fetch("/api/admin/create-giveaway", {
|
||||||
@@ -38,87 +39,97 @@ export default function AdminClient({ email }: AdminClientProps) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gradient-to-br from-yellow-50 to-pink-100 text-black py-12 px-4 sm:px-6 lg:px-8">
|
<div className="min-h-screen bg-gradient-to-br from-yellow-50 to-pink-100 text-black py-12 px-4 sm:px-6 lg:px-8">
|
||||||
<div className="max-w-3xl mx-auto space-y-10">
|
<div className="max-w-3xl mx-auto space-y-10">
|
||||||
<h1 className="text-4xl font-bold text-pink-700">Admin Dashboard</h1>
|
<h1 className="text-4xl font-bold text-pink-700">Admin Dashboard</h1>
|
||||||
<p className="text-lg text-gray-700">Welcome, <span className="font-medium">{email}</span>!</p>
|
<p className="text-lg text-gray-700">Welcome, <span className="font-medium">{email}</span>!</p>
|
||||||
|
|
||||||
{/* Create Giveaway Form */}
|
|
||||||
<div className="bg-white border border-pink-200 p-6 rounded-2xl shadow-lg">
|
|
||||||
<h2 className="text-2xl font-semibold text-pink-700 mb-4">🎁 Create Giveaway</h2>
|
|
||||||
<div className="space-y-3">
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
placeholder="Giveaway Title"
|
|
||||||
value={giveaway.title}
|
|
||||||
onChange={(e) => setGiveaway({ ...giveaway, title: e.target.value })}
|
|
||||||
className="w-full p-3 border border-pink-200 rounded-lg bg-white text-gray-700 focus:outline-none focus:ring-2 focus:ring-pink-400"
|
|
||||||
/>
|
|
||||||
<textarea
|
|
||||||
placeholder="Description"
|
|
||||||
value={giveaway.description}
|
|
||||||
onChange={(e) => setGiveaway({ ...giveaway, description: e.target.value })}
|
|
||||||
className="w-full p-3 border border-pink-200 rounded-lg bg-white text-gray-700 focus:outline-none focus:ring-2 focus:ring-pink-400"
|
|
||||||
/>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
placeholder="Prize"
|
|
||||||
value={giveaway.prize}
|
|
||||||
onChange={(e) => setGiveaway({ ...giveaway, prize: e.target.value })}
|
|
||||||
className="w-full p-3 border border-pink-200 rounded-lg bg-white text-gray-700 focus:outline-none focus:ring-2 focus:ring-pink-400"
|
|
||||||
/>
|
|
||||||
<input
|
|
||||||
type="number"
|
|
||||||
placeholder="Value in Coins"
|
|
||||||
value={giveaway.value || ""}
|
|
||||||
onChange={(e) => setGiveaway({ ...giveaway, value: Number(e.target.value) })}
|
|
||||||
className="w-full p-3 border border-pink-200 rounded-lg bg-white text-gray-700 focus:outline-none focus:ring-2 focus:ring-pink-400"
|
|
||||||
/>
|
|
||||||
<input
|
|
||||||
type="datetime-local"
|
|
||||||
placeholder="Ends At"
|
|
||||||
value={giveaway.endsAt ? new Date(giveaway.endsAt).toISOString().slice(0, 16) : ""}
|
|
||||||
onChange={(e) => setGiveaway({ ...giveaway, endsAt: Date.parse(e.target.value) })}
|
|
||||||
className="w-full p-3 border border-pink-200 rounded-lg bg-white text-gray-700 focus:outline-none focus:ring-2 focus:ring-pink-400"
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
onClick={handleCreateGiveaway}
|
|
||||||
className="w-full bg-gradient-to-r from-pink-500 to-yellow-400 text-white font-semibold py-3 rounded-lg hover:brightness-110 transition-all shadow"
|
|
||||||
>
|
|
||||||
🚀 Create Giveaway
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Update User Coins Form */}
|
|
||||||
<div className="bg-white border border-green-200 p-6 rounded-2xl shadow-lg">
|
|
||||||
<h2 className="text-2xl font-semibold text-green-700 mb-4">💸 Update User Coins</h2>
|
|
||||||
<div className="space-y-3">
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
placeholder="YouTube Video URL"
|
|
||||||
value={youtube_url}
|
|
||||||
onChange={(e) => setYoutubeUrl(e.target.value)}
|
|
||||||
className="w-full p-3 border border-green-200 rounded-lg bg-white text-gray-700 focus:outline-none focus:ring-2 focus:ring-green-400"
|
|
||||||
/>
|
|
||||||
<input
|
|
||||||
type="number"
|
|
||||||
placeholder="Coins to Add"
|
|
||||||
value={coin_value || ""}
|
|
||||||
onChange={(e) => setCoinValue(Number(e.target.value))}
|
|
||||||
className="w-full p-3 border border-green-200 rounded-lg bg-white text-gray-700 focus:outline-none focus:ring-2 focus:ring-green-400"
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
onClick={() => handleUpdateCoins(youtube_url, coin_value)}
|
|
||||||
className="w-full bg-gradient-to-r from-green-500 to-lime-400 text-white font-semibold py-3 rounded-lg hover:brightness-110 transition-all shadow"
|
|
||||||
>
|
|
||||||
✅ Update Coins
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* <GiveawayManagement/> */}
|
{/* Create Giveaway Form */}
|
||||||
|
<div className="bg-white border border-pink-200 p-6 rounded-2xl shadow-lg">
|
||||||
|
<h2 className="text-2xl font-semibold text-pink-700 mb-4">🎁 Create Giveaway</h2>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Giveaway Title"
|
||||||
|
value={giveaway.title}
|
||||||
|
onChange={(e) => setGiveaway({ ...giveaway, title: e.target.value })}
|
||||||
|
className="w-full p-3 border border-pink-200 rounded-lg bg-white text-gray-700 focus:outline-none focus:ring-2 focus:ring-pink-400"
|
||||||
|
/>
|
||||||
|
<textarea
|
||||||
|
placeholder="Description"
|
||||||
|
value={giveaway.description}
|
||||||
|
onChange={(e) => setGiveaway({ ...giveaway, description: e.target.value })}
|
||||||
|
className="w-full p-3 border border-pink-200 rounded-lg bg-white text-gray-700 focus:outline-none focus:ring-2 focus:ring-pink-400"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Prize"
|
||||||
|
value={giveaway.prize}
|
||||||
|
onChange={(e) => setGiveaway({ ...giveaway, prize: e.target.value })}
|
||||||
|
className="w-full p-3 border border-pink-200 rounded-lg bg-white text-gray-700 focus:outline-none focus:ring-2 focus:ring-pink-400"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
placeholder="Value in Coins"
|
||||||
|
value={giveaway.value || ""}
|
||||||
|
onChange={(e) => setGiveaway({ ...giveaway, value: Number(e.target.value) })}
|
||||||
|
className="w-full p-3 border border-pink-200 rounded-lg bg-white text-gray-700 focus:outline-none focus:ring-2 focus:ring-pink-400"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="datetime-local"
|
||||||
|
placeholder="Ends At"
|
||||||
|
value={giveaway.endsAt ? new Date(giveaway.endsAt).toISOString().slice(0, 16) : ""}
|
||||||
|
onChange={(e) => setGiveaway({ ...giveaway, endsAt: Date.parse(e.target.value) })}
|
||||||
|
className="w-full p-3 border border-pink-200 rounded-lg bg-white text-gray-700 focus:outline-none focus:ring-2 focus:ring-pink-400"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
onClick={handleCreateGiveaway}
|
||||||
|
className="w-full bg-gradient-to-r from-pink-500 to-yellow-400 text-white font-semibold py-3 rounded-lg hover:brightness-110 transition-all shadow"
|
||||||
|
>
|
||||||
|
🚀 Create Giveaway
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Update User Coins Form */}
|
||||||
|
<div className="bg-white border border-green-200 p-6 rounded-2xl shadow-lg">
|
||||||
|
<h2 className="text-2xl font-semibold text-green-700 mb-4">💸 Update User Coins</h2>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="YouTube Video URL"
|
||||||
|
value={youtube_url}
|
||||||
|
onChange={(e) => setYoutubeUrl(e.target.value)}
|
||||||
|
className="w-full p-3 border border-green-200 rounded-lg bg-white text-gray-700 focus:outline-none focus:ring-2 focus:ring-green-400"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
placeholder="Coins to Add"
|
||||||
|
value={coin_value || ""}
|
||||||
|
onChange={(e) => setCoinValue(Number(e.target.value))}
|
||||||
|
className="w-full p-3 border border-green-200 rounded-lg bg-white text-gray-700 focus:outline-none focus:ring-2 focus:ring-green-400"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
onClick={() => handleUpdateCoins(youtube_url, coin_value)}
|
||||||
|
className="w-full bg-gradient-to-r from-green-500 to-lime-400 text-white font-semibold py-3 rounded-lg hover:brightness-110 transition-all shadow"
|
||||||
|
>
|
||||||
|
✅ Update Coins
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Toggle Giveaway Management */}
|
||||||
|
<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">🎮 Giveaway Management</h2>
|
||||||
|
<button
|
||||||
|
onClick={() => setShowGiveawayManagement((prev) => !prev)}
|
||||||
|
className="w-full bg-gradient-to-r from-blue-500 to-indigo-400 text-white font-semibold py-3 rounded-lg hover:brightness-110 transition-all shadow"
|
||||||
|
>
|
||||||
|
{showGiveawayManagement ? "Hide Giveaway Management" : "Show Giveaway Management"}
|
||||||
|
</button>
|
||||||
|
{showGiveawayManagement && <GiveawayManagement />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
"use server";
|
||||||
|
|
||||||
|
import {db} from "@/lib/db";
|
||||||
|
|
||||||
|
export async function giveawaysFind() {
|
||||||
|
try {
|
||||||
|
const giveaways = await db.giveaway.findMany();
|
||||||
|
return giveaways;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching giveaways:", error);
|
||||||
|
throw new Error("Failed to fetch giveaways");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import { giveawaysFind } from "./GiveawayManagementCardServer";
|
||||||
|
|
||||||
|
interface Giveaway {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
prize: string;
|
||||||
|
value: number;
|
||||||
|
endsAt: string | null;
|
||||||
|
active: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const GiveawayManagementCards: React.FC = () => {
|
||||||
|
const [activeGiveaways, setActiveGiveaways] = useState<Giveaway[]>([]);
|
||||||
|
const [finishedGiveaways, setFinishedGiveaways] = useState<Giveaway[]>([]);
|
||||||
|
|
||||||
|
const fetchGiveaways = async () => {
|
||||||
|
try {
|
||||||
|
const giveawayList = await giveawaysFind();
|
||||||
|
const active = giveawayList
|
||||||
|
.filter((giveaway) => giveaway.endsAt && new Date(giveaway.endsAt) > new Date())
|
||||||
|
.map((giveaway) => ({
|
||||||
|
...giveaway,
|
||||||
|
endsAt: giveaway.endsAt ? giveaway.endsAt.toISOString() : null,
|
||||||
|
}));
|
||||||
|
const finished = giveawayList
|
||||||
|
.filter((giveaway) => !giveaway.endsAt || new Date(giveaway.endsAt) <= new Date())
|
||||||
|
.map((giveaway) => ({
|
||||||
|
...giveaway,
|
||||||
|
endsAt: giveaway.endsAt ? giveaway.endsAt.toISOString() : null,
|
||||||
|
}));
|
||||||
|
|
||||||
|
setActiveGiveaways(active);
|
||||||
|
setFinishedGiveaways(finished);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching giveaways:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelectWinner = async (giveawayId: string) => {
|
||||||
|
alert(`Selecting winner for giveaway ID: ${giveawayId}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchGiveaways();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-10">
|
||||||
|
|
||||||
|
{/* Finished Giveaways Section */}
|
||||||
|
<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) => (
|
||||||
|
<div
|
||||||
|
key={giveaway.id}
|
||||||
|
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">
|
||||||
|
Ended At: {giveaway.endsAt ? new Date(giveaway.endsAt).toLocaleString() : "N/A"}
|
||||||
|
</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" }}
|
||||||
|
>
|
||||||
|
Select Winner
|
||||||
|
</button>
|
||||||
|
</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>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default GiveawayManagementCards;
|
||||||
@@ -38,8 +38,12 @@ export default async function GiveawaysPage() {
|
|||||||
<div className="min-h-screen bg-gradient-to-br from-yellow-50 to-pink-100 py-12 px-4 sm:px-6 lg:px-8 font-sans">
|
<div className="min-h-screen bg-gradient-to-br from-yellow-50 to-pink-100 py-12 px-4 sm:px-6 lg:px-8 font-sans">
|
||||||
<div className="max-w-7xl mx-auto">
|
<div className="max-w-7xl mx-auto">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<h1 className="text-4xl sm:text-5xl font-bold mb-10 text-center bg-gradient-to-r from-pink-600 to-yellow-500 bg-clip-text text-transparent drop-shadow-md">
|
<h1 className="text-4xl sm:text-5xl font-bold mb-10 text-center drop-shadow-md">
|
||||||
🎁 Active Giveaways
|
🎁
|
||||||
|
{" "}
|
||||||
|
<span className="bg-gradient-to-r from-pink-600 to-yellow-500 bg-clip-text text-transparent">
|
||||||
|
Active Giveaways
|
||||||
|
</span>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
{/* Grid of Cards */}
|
{/* Grid of Cards */}
|
||||||
|
|||||||
+6
-2
@@ -13,8 +13,12 @@ export default function GiveawaySystem() {
|
|||||||
height={120}
|
height={120}
|
||||||
className="mx-auto mb-4 rounded-full border-4 border-pink-400 shadow-lg"
|
className="mx-auto mb-4 rounded-full border-4 border-pink-400 shadow-lg"
|
||||||
/>
|
/>
|
||||||
<h1 className="text-4xl sm:text-5xl font-bold mb-2 bg-gradient-to-r from-pink-600 to-yellow-500 bg-clip-text text-transparent drop-shadow">
|
<h1 className="text-4xl sm:text-5xl font-bold mb-2 drop-shadow">
|
||||||
🎁 TCG Love Giveaway System
|
🎁
|
||||||
|
{" "}
|
||||||
|
<span className="bg-gradient-to-r from-pink-600 to-yellow-500 bg-clip-text text-transparent">
|
||||||
|
TCG Love Giveaway System
|
||||||
|
</span>
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-lg text-gray-700">Join the fun — earn coins, win cool cards!</p>
|
<p className="text-lg text-gray-700">Join the fun — earn coins, win cool cards!</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user