io
This commit is contained in:
@@ -52,9 +52,9 @@ export async function POST(_: NextRequest, { params }: { params: Promise<{ id: s
|
||||
});
|
||||
|
||||
const stat = await db.playerMatchStat.upsert({
|
||||
where: { playerId_matchId: { playerId, matchId: params.id } },
|
||||
where: { playerId_matchId: { playerId, matchId: id } },
|
||||
update: { goals, assists, yellowCards, redCards, minutesPlayed, cleanSheet, penaltySaved, penaltyMissed, ownGoals, isMotm, extraTimeBonus, points },
|
||||
create: { playerId, matchId: params.id, goals, assists, yellowCards, redCards, minutesPlayed, cleanSheet, penaltySaved, penaltyMissed, ownGoals, isMotm, extraTimeBonus, points },
|
||||
create: { playerId, matchId: id, goals, assists, yellowCards, redCards, minutesPlayed, cleanSheet, penaltySaved, penaltyMissed, ownGoals, isMotm, extraTimeBonus, points },
|
||||
});
|
||||
|
||||
// آپدیت totalPoints بازیکن
|
||||
|
||||
30
app/api/admin/players/[id]/card-tier/route.ts
Normal file
30
app/api/admin/players/[id]/card-tier/route.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
|
||||
const validTiers = new Set(["GOLD", "SILVER", "BRONZE"]);
|
||||
|
||||
export async function PATCH(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || (session.user as any).role !== "ADMIN") {
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
}
|
||||
|
||||
const { id } = await params;
|
||||
const { cardTier } = await req.json();
|
||||
|
||||
if (!validTiers.has(cardTier)) {
|
||||
return NextResponse.json({ error: "Invalid card tier" }, { status: 400 });
|
||||
}
|
||||
|
||||
const updated = await db.player.update({
|
||||
where: { id },
|
||||
data: {
|
||||
cardTier,
|
||||
isGoldenCardEligible: cardTier === "GOLD",
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json(updated);
|
||||
}
|
||||
24
app/api/admin/players/[id]/golden-toggle/route.ts
Normal file
24
app/api/admin/players/[id]/golden-toggle/route.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
|
||||
// PATCH /api/admin/players/[id]/golden-toggle
|
||||
export async function PATCH(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || (session.user as any).role !== "ADMIN") {
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
}
|
||||
|
||||
const { id } = await params;
|
||||
|
||||
const player = await db.player.findUnique({ where: { id } });
|
||||
if (!player) return NextResponse.json({ error: "Player not found" }, { status: 404 });
|
||||
|
||||
const updated = await db.player.update({
|
||||
where: { id },
|
||||
data: { isGoldenCardEligible: !player.isGoldenCardEligible },
|
||||
});
|
||||
|
||||
return NextResponse.json({ isGoldenCardEligible: updated.isGoldenCardEligible });
|
||||
}
|
||||
105
app/api/admin/quiz/[id]/lottery/route.ts
Normal file
105
app/api/admin/quiz/[id]/lottery/route.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
import { CARD_TIER_LABELS, resolveQuizRewardTier } from "@/lib/cardTier";
|
||||
|
||||
function shuffleArray<T>(items: T[]) {
|
||||
return [...items].sort(() => Math.random() - 0.5);
|
||||
}
|
||||
|
||||
// POST /api/admin/quiz/[id]/lottery - run reward distribution for a quiz
|
||||
export async function POST(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || (session.user as any).role !== "ADMIN") {
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
}
|
||||
|
||||
const { id } = await params;
|
||||
|
||||
const quiz = await db.dailyQuiz.findUnique({
|
||||
where: { id },
|
||||
include: { questions: true },
|
||||
});
|
||||
|
||||
if (!quiz) return NextResponse.json({ error: "Quiz not found" }, { status: 404 });
|
||||
if (quiz.isProcessed) {
|
||||
return NextResponse.json({ error: "قرعه کشی قبلا انجام شده" }, { status: 400 });
|
||||
}
|
||||
|
||||
const submissions = await db.quizSubmission.findMany({
|
||||
where: { quizId: id },
|
||||
include: { user: true },
|
||||
});
|
||||
|
||||
const tierLimits = {
|
||||
GOLD: quiz.goldWinnersCount,
|
||||
SILVER: quiz.silverWinnersCount,
|
||||
BRONZE: quiz.bronzeWinnersCount,
|
||||
} as const;
|
||||
|
||||
const candidatesByTier = {
|
||||
GOLD: submissions.filter((submission) => resolveQuizRewardTier(quiz, submission.correctAnswers) === "GOLD"),
|
||||
SILVER: submissions.filter((submission) => resolveQuizRewardTier(quiz, submission.correctAnswers) === "SILVER"),
|
||||
BRONZE: submissions.filter((submission) => resolveQuizRewardTier(quiz, submission.correctAnswers) === "BRONZE"),
|
||||
};
|
||||
|
||||
const rewardQueue = (["GOLD", "SILVER", "BRONZE"] as const).flatMap((cardTier) =>
|
||||
shuffleArray(candidatesByTier[cardTier])
|
||||
.slice(0, Math.max(tierLimits[cardTier], 0))
|
||||
.map((submission) => ({ submission, cardTier }))
|
||||
);
|
||||
|
||||
if (rewardQueue.length === 0) {
|
||||
await db.dailyQuiz.update({ where: { id }, data: { isProcessed: true } });
|
||||
return NextResponse.json({ winners: [], message: "هیچ شرکت کننده ای واجد دریافت کارت نبود" });
|
||||
}
|
||||
|
||||
const players = await db.player.findMany({
|
||||
where: {
|
||||
isActive: true,
|
||||
cardTier: { in: ["GOLD", "SILVER", "BRONZE"] },
|
||||
},
|
||||
include: { country: true },
|
||||
});
|
||||
|
||||
const playersByTier = {
|
||||
GOLD: players.filter((player) => player.cardTier === "GOLD"),
|
||||
SILVER: players.filter((player) => player.cardTier === "SILVER"),
|
||||
BRONZE: players.filter((player) => player.cardTier === "BRONZE"),
|
||||
};
|
||||
|
||||
for (const tier of ["GOLD", "SILVER", "BRONZE"] as const) {
|
||||
if (rewardQueue.some((item) => item.cardTier === tier) && playersByTier[tier].length === 0) {
|
||||
return NextResponse.json(
|
||||
{ error: `برای کارت ${CARD_TIER_LABELS[tier]} هیچ بازیکن فعالی تعریف نشده است` },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const createdCards = await db.$transaction(
|
||||
rewardQueue.map(({ submission, cardTier }) => {
|
||||
const tierPlayers = playersByTier[cardTier];
|
||||
const randomPlayer = tierPlayers[Math.floor(Math.random() * tierPlayers.length)];
|
||||
|
||||
return db.goldenCard.create({
|
||||
data: {
|
||||
userId: submission.userId,
|
||||
quizId: id,
|
||||
playerId: randomPlayer.id,
|
||||
cardTier,
|
||||
status: "SEALED",
|
||||
},
|
||||
include: {
|
||||
user: { select: { id: true, name: true, email: true } },
|
||||
player: { include: { country: true } },
|
||||
},
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
await db.dailyQuiz.update({ where: { id }, data: { isProcessed: true } });
|
||||
|
||||
return NextResponse.json({ winners: createdCards });
|
||||
}
|
||||
191
app/api/admin/quiz/[id]/route.ts
Normal file
191
app/api/admin/quiz/[id]/route.ts
Normal file
@@ -0,0 +1,191 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
import { Prisma } from "@prisma/client";
|
||||
|
||||
async function requireAdmin() {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || (session.user as any).role !== "ADMIN") {
|
||||
return null;
|
||||
}
|
||||
return session;
|
||||
}
|
||||
|
||||
function calculateResult(answers: number[], questions: Array<{ correctAnswer: number }>) {
|
||||
let correct = 0;
|
||||
questions.forEach((question, index) => {
|
||||
if (answers[index] === question.correctAnswer) {
|
||||
correct += 1;
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
correct,
|
||||
score: questions.length > 0 ? Math.round((correct / questions.length) * 100) : 0,
|
||||
};
|
||||
}
|
||||
|
||||
function validateTierConfig(input: {
|
||||
goldWinnersCount: number;
|
||||
silverWinnersCount: number;
|
||||
bronzeWinnersCount: number;
|
||||
goldMinCorrect: number | null;
|
||||
silverMinCorrect: number | null;
|
||||
bronzeMinCorrect: number | null;
|
||||
}) {
|
||||
if (input.goldWinnersCount < 0 || input.silverWinnersCount < 0 || input.bronzeWinnersCount < 0) {
|
||||
return "Winner counts cannot be negative";
|
||||
}
|
||||
|
||||
if (input.goldWinnersCount + input.silverWinnersCount + input.bronzeWinnersCount <= 0) {
|
||||
return "At least one winner must be configured";
|
||||
}
|
||||
|
||||
if (input.goldWinnersCount > 0 && input.goldMinCorrect == null) {
|
||||
return "Gold minimum correct answers is required";
|
||||
}
|
||||
|
||||
if (input.silverWinnersCount > 0 && input.silverMinCorrect == null) {
|
||||
return "Silver minimum correct answers is required";
|
||||
}
|
||||
|
||||
if (input.bronzeWinnersCount > 0 && input.bronzeMinCorrect == null) {
|
||||
return "Bronze minimum correct answers is required";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function PUT(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
try {
|
||||
const session = await requireAdmin();
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const { id } = await params;
|
||||
const {
|
||||
date,
|
||||
windowStart,
|
||||
windowEnd,
|
||||
goldWinnersCount,
|
||||
silverWinnersCount,
|
||||
bronzeWinnersCount,
|
||||
goldMinCorrect,
|
||||
silverMinCorrect,
|
||||
bronzeMinCorrect,
|
||||
questions,
|
||||
} = await req.json();
|
||||
|
||||
const parsedInput = {
|
||||
goldWinnersCount: Number(goldWinnersCount),
|
||||
silverWinnersCount: Number(silverWinnersCount),
|
||||
bronzeWinnersCount: Number(bronzeWinnersCount),
|
||||
goldMinCorrect: goldMinCorrect == null ? null : Number(goldMinCorrect),
|
||||
silverMinCorrect: silverMinCorrect == null ? null : Number(silverMinCorrect),
|
||||
bronzeMinCorrect: bronzeMinCorrect == null ? null : Number(bronzeMinCorrect),
|
||||
};
|
||||
|
||||
const validationError = validateTierConfig(parsedInput);
|
||||
if (validationError) {
|
||||
return NextResponse.json({ error: validationError }, { status: 400 });
|
||||
}
|
||||
|
||||
if (!Array.isArray(questions) || questions.length === 0) {
|
||||
return NextResponse.json({ error: "At least one question is required" }, { status: 400 });
|
||||
}
|
||||
|
||||
const quiz = await db.dailyQuiz.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
submissions: {
|
||||
select: { id: true, answers: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!quiz) return NextResponse.json({ error: "Quiz not found" }, { status: 404 });
|
||||
if (quiz.isProcessed) {
|
||||
return NextResponse.json({ error: "Quiz can no longer be edited after lottery processing" }, { status: 400 });
|
||||
}
|
||||
|
||||
const normalizedQuestions = questions.map((q: any, index: number) => ({
|
||||
questionText: q.questionText,
|
||||
options: q.options,
|
||||
correctAnswer: Number(q.correctAnswer),
|
||||
order: index,
|
||||
}));
|
||||
|
||||
const updatedQuiz = await db.$transaction(async (tx) => {
|
||||
await tx.quizQuestion.deleteMany({ where: { quizId: id } });
|
||||
|
||||
const updated = await tx.dailyQuiz.update({
|
||||
where: { id },
|
||||
data: {
|
||||
date: new Date(`${date}T00:00:00.000Z`),
|
||||
windowStart: new Date(windowStart),
|
||||
windowEnd: new Date(windowEnd),
|
||||
goldWinnersCount: parsedInput.goldWinnersCount,
|
||||
silverWinnersCount: parsedInput.silverWinnersCount,
|
||||
bronzeWinnersCount: parsedInput.bronzeWinnersCount,
|
||||
goldMinCorrect: parsedInput.goldMinCorrect,
|
||||
silverMinCorrect: parsedInput.silverMinCorrect,
|
||||
bronzeMinCorrect: parsedInput.bronzeMinCorrect,
|
||||
questions: {
|
||||
create: normalizedQuestions,
|
||||
},
|
||||
},
|
||||
include: {
|
||||
questions: { orderBy: { order: "asc" } },
|
||||
},
|
||||
});
|
||||
|
||||
for (const submission of quiz.submissions) {
|
||||
const result = calculateResult(submission.answers, normalizedQuestions);
|
||||
await tx.quizSubmission.update({
|
||||
where: { id: submission.id },
|
||||
data: {
|
||||
score: result.score,
|
||||
correctAnswers: result.correct,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return updated;
|
||||
});
|
||||
|
||||
return NextResponse.json(updatedQuiz);
|
||||
} catch (error) {
|
||||
console.error("Failed to update quiz", error);
|
||||
|
||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
if (error.code === "P2002") {
|
||||
return NextResponse.json({ error: "Quiz date already exists" }, { status: 409 });
|
||||
}
|
||||
}
|
||||
|
||||
return NextResponse.json({ error: "Failed to update quiz" }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
export async function DELETE(_: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const session = await requireAdmin();
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const { id } = await params;
|
||||
|
||||
const quiz = await db.dailyQuiz.findUnique({
|
||||
where: { id },
|
||||
select: {
|
||||
id: true,
|
||||
isProcessed: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!quiz) return NextResponse.json({ error: "Quiz not found" }, { status: 404 });
|
||||
if (quiz.isProcessed) {
|
||||
return NextResponse.json({ error: "Quiz can no longer be deleted after lottery processing" }, { status: 400 });
|
||||
}
|
||||
|
||||
await db.dailyQuiz.delete({ where: { id } });
|
||||
return NextResponse.json({ success: true });
|
||||
}
|
||||
132
app/api/admin/quiz/route.ts
Normal file
132
app/api/admin/quiz/route.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
import { Prisma } from "@prisma/client";
|
||||
|
||||
async function adminOnly(req: NextRequest) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || (session.user as any).role !== "ADMIN") return null;
|
||||
return session;
|
||||
}
|
||||
|
||||
function validateTierConfig(input: {
|
||||
goldWinnersCount: number;
|
||||
silverWinnersCount: number;
|
||||
bronzeWinnersCount: number;
|
||||
goldMinCorrect: number | null;
|
||||
silverMinCorrect: number | null;
|
||||
bronzeMinCorrect: number | null;
|
||||
}) {
|
||||
if (input.goldWinnersCount < 0 || input.silverWinnersCount < 0 || input.bronzeWinnersCount < 0) {
|
||||
return "Winner counts cannot be negative";
|
||||
}
|
||||
|
||||
if (input.goldWinnersCount + input.silverWinnersCount + input.bronzeWinnersCount <= 0) {
|
||||
return "At least one winner must be configured";
|
||||
}
|
||||
|
||||
if (input.goldWinnersCount > 0 && input.goldMinCorrect == null) {
|
||||
return "Gold minimum correct answers is required";
|
||||
}
|
||||
|
||||
if (input.silverWinnersCount > 0 && input.silverMinCorrect == null) {
|
||||
return "Silver minimum correct answers is required";
|
||||
}
|
||||
|
||||
if (input.bronzeWinnersCount > 0 && input.bronzeMinCorrect == null) {
|
||||
return "Bronze minimum correct answers is required";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// GET /api/admin/quiz - list all quizzes
|
||||
export async function GET(req: NextRequest) {
|
||||
const session = await adminOnly(req);
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const quizzes = await db.dailyQuiz.findMany({
|
||||
orderBy: { date: "desc" },
|
||||
include: {
|
||||
questions: { orderBy: { order: "asc" } },
|
||||
_count: { select: { submissions: true } },
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json(quizzes);
|
||||
}
|
||||
|
||||
// POST /api/admin/quiz - create quiz
|
||||
export async function POST(req: NextRequest) {
|
||||
try {
|
||||
const session = await adminOnly(req);
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const {
|
||||
date,
|
||||
windowStart,
|
||||
windowEnd,
|
||||
goldWinnersCount,
|
||||
silverWinnersCount,
|
||||
bronzeWinnersCount,
|
||||
goldMinCorrect,
|
||||
silverMinCorrect,
|
||||
bronzeMinCorrect,
|
||||
questions,
|
||||
} = await req.json();
|
||||
|
||||
const parsedInput = {
|
||||
goldWinnersCount: Number(goldWinnersCount),
|
||||
silverWinnersCount: Number(silverWinnersCount),
|
||||
bronzeWinnersCount: Number(bronzeWinnersCount),
|
||||
goldMinCorrect: goldMinCorrect == null ? null : Number(goldMinCorrect),
|
||||
silverMinCorrect: silverMinCorrect == null ? null : Number(silverMinCorrect),
|
||||
bronzeMinCorrect: bronzeMinCorrect == null ? null : Number(bronzeMinCorrect),
|
||||
};
|
||||
|
||||
const validationError = validateTierConfig(parsedInput);
|
||||
if (validationError) {
|
||||
return NextResponse.json({ error: validationError }, { status: 400 });
|
||||
}
|
||||
|
||||
if (!Array.isArray(questions) || questions.length === 0) {
|
||||
return NextResponse.json({ error: "At least one question is required" }, { status: 400 });
|
||||
}
|
||||
|
||||
const quiz = await db.dailyQuiz.create({
|
||||
data: {
|
||||
date: new Date(`${date}T00:00:00.000Z`),
|
||||
windowStart: new Date(windowStart),
|
||||
windowEnd: new Date(windowEnd),
|
||||
goldWinnersCount: parsedInput.goldWinnersCount,
|
||||
silverWinnersCount: parsedInput.silverWinnersCount,
|
||||
bronzeWinnersCount: parsedInput.bronzeWinnersCount,
|
||||
goldMinCorrect: parsedInput.goldMinCorrect,
|
||||
silverMinCorrect: parsedInput.silverMinCorrect,
|
||||
bronzeMinCorrect: parsedInput.bronzeMinCorrect,
|
||||
questions: {
|
||||
create: questions.map((q: any, i: number) => ({
|
||||
questionText: q.questionText,
|
||||
options: q.options,
|
||||
correctAnswer: Number(q.correctAnswer),
|
||||
order: i,
|
||||
})),
|
||||
},
|
||||
},
|
||||
include: { questions: true },
|
||||
});
|
||||
|
||||
return NextResponse.json(quiz, { status: 201 });
|
||||
} catch (error) {
|
||||
console.error("Failed to create quiz", error);
|
||||
|
||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
if (error.code === "P2002") {
|
||||
return NextResponse.json({ error: "Quiz date already exists" }, { status: 409 });
|
||||
}
|
||||
}
|
||||
|
||||
return NextResponse.json({ error: "Failed to create quiz" }, { status: 500 });
|
||||
}
|
||||
}
|
||||
@@ -3,14 +3,15 @@ import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
|
||||
export async function PUT(req: NextRequest, { params }: { params: { id: string } }) {
|
||||
export async function PUT(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const { id } = await params;
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || (session.user as any).role !== "ADMIN")
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const { status } = await req.json();
|
||||
const team = await db.team.update({
|
||||
where: { id: params.id },
|
||||
where: { id },
|
||||
data: { status },
|
||||
});
|
||||
return NextResponse.json(team);
|
||||
|
||||
@@ -3,7 +3,8 @@ import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
|
||||
export async function POST(_: NextRequest, { params }: { params: { id: string } }) {
|
||||
export async function POST(_: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const { id } = await params;
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || (session.user as any).role !== "ADMIN")
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
@@ -11,6 +12,6 @@ export async function POST(_: NextRequest, { params }: { params: { id: string }
|
||||
// غیرفعال کردن همه
|
||||
await db.gameweek.updateMany({ data: { isActive: false } });
|
||||
// فعال کردن این هفته
|
||||
const gw = await db.gameweek.update({ where: { id: params.id }, data: { isActive: true } });
|
||||
const gw = await db.gameweek.update({ where: { id }, data: { isActive: true } });
|
||||
return NextResponse.json(gw);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,11 @@ export async function POST(req: NextRequest) {
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const body = await req.json();
|
||||
const gw = await db.gameweek.create({ data: body });
|
||||
const gw = await db.gameweek.create({
|
||||
data: {
|
||||
...body,
|
||||
deadline: new Date(body.deadline),
|
||||
},
|
||||
});
|
||||
return NextResponse.json(gw, { status: 201 });
|
||||
}
|
||||
|
||||
173
app/api/golden-cards/[id]/add-to-team/route.ts
Normal file
173
app/api/golden-cards/[id]/add-to-team/route.ts
Normal file
@@ -0,0 +1,173 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
import {
|
||||
getAutoPlacement,
|
||||
getPositionLabel,
|
||||
SPECIAL_CARD_TEAM_LIMIT,
|
||||
} from "@/lib/specialCards";
|
||||
|
||||
export async function POST(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const userId = (session.user as any).id;
|
||||
const { id } = await params;
|
||||
const { replacePlayerId } = await req.json().catch(() => ({}));
|
||||
|
||||
const team = await db.team.findUnique({
|
||||
where: { userId },
|
||||
include: {
|
||||
players: {
|
||||
include: {
|
||||
player: true,
|
||||
goldenCard: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
if (!team) return NextResponse.json({ error: "ابتدا تیم بساز" }, { status: 400 });
|
||||
|
||||
const card = await db.goldenCard.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
player: { include: { country: true } },
|
||||
teamPlayer: true,
|
||||
},
|
||||
});
|
||||
if (!card) return NextResponse.json({ error: "کارت ویژه پیدا نشد" }, { status: 404 });
|
||||
if (card.userId !== userId) return NextResponse.json({ error: "Forbidden" }, { status: 403 });
|
||||
if (card.status !== "OPENED") return NextResponse.json({ error: "ابتدا کارت را باز کنید" }, { status: 400 });
|
||||
if (card.state === "SOLD") return NextResponse.json({ error: "این کارت فروخته شده است" }, { status: 400 });
|
||||
if (card.state === "IN_TEAM") return NextResponse.json({ error: "این کارت همین حالا در تیم است" }, { status: 400 });
|
||||
|
||||
const existingSpecialCount = team.players.filter((item) => item.goldenCardId).length;
|
||||
const sameCountry = team.players.filter((item) => item.player.countryId === card.player.countryId).length;
|
||||
const existingPlayer = team.players.find((item) => item.playerId === card.playerId);
|
||||
|
||||
if (!existingPlayer && sameCountry >= 3) {
|
||||
return NextResponse.json({ error: "حداکثر 3 بازیکن از یک تیم ملی" }, { status: 400 });
|
||||
}
|
||||
|
||||
if (existingPlayer) {
|
||||
if (existingPlayer.goldenCardId) {
|
||||
return NextResponse.json({ error: "نسخه ویژه این بازیکن در تیم شما وجود دارد" }, { status: 400 });
|
||||
}
|
||||
if (existingSpecialCount >= SPECIAL_CARD_TEAM_LIMIT) {
|
||||
return NextResponse.json({ error: "ظرفیت 3 کارت ویژه تیم پر است" }, { status: 400 });
|
||||
}
|
||||
|
||||
const updatedTeamPlayer = await db.$transaction(async (tx) => {
|
||||
const updatedPlayer = await tx.teamPlayer.update({
|
||||
where: { teamId_playerId: { teamId: team.id, playerId: existingPlayer.playerId } },
|
||||
data: { goldenCardId: card.id },
|
||||
});
|
||||
|
||||
await tx.goldenCard.update({
|
||||
where: { id: card.id },
|
||||
data: { state: "IN_TEAM" },
|
||||
});
|
||||
|
||||
return updatedPlayer;
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
action: "converted_existing",
|
||||
placement: existingPlayer.isBench ? "ذخیره" : "فیکس",
|
||||
teamPlayer: updatedTeamPlayer,
|
||||
card: { ...card, state: "IN_TEAM" },
|
||||
message: "بازیکن موجود تیم شما به نسخه ویژه تبدیل شد",
|
||||
});
|
||||
}
|
||||
|
||||
const autoPlacement = getAutoPlacement(team.formation, team.players as any, card.player.position);
|
||||
|
||||
if (!replacePlayerId && !autoPlacement) {
|
||||
const candidates = team.players
|
||||
.filter((item) => item.player.position === card.player.position)
|
||||
.map((item) => ({
|
||||
playerId: item.playerId,
|
||||
name: item.player.name,
|
||||
isBench: item.isBench,
|
||||
isSpecial: Boolean(item.goldenCardId),
|
||||
}));
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: `پست ${getPositionLabel(card.player.position)} در ترکیب اصلی و ذخیره پر است`,
|
||||
needsReplacement: true,
|
||||
candidates,
|
||||
},
|
||||
{ status: 409 }
|
||||
);
|
||||
}
|
||||
|
||||
const replacingPlayer = replacePlayerId
|
||||
? team.players.find((item) => item.playerId === replacePlayerId)
|
||||
: null;
|
||||
|
||||
if (replacePlayerId && (!replacingPlayer || replacingPlayer.player.position !== card.player.position)) {
|
||||
return NextResponse.json({ error: "بازیکن انتخابشده برای تعویض معتبر نیست" }, { status: 400 });
|
||||
}
|
||||
|
||||
const nextSpecialCount = existingSpecialCount + 1 - (replacingPlayer?.goldenCardId ? 1 : 0);
|
||||
if (nextSpecialCount > SPECIAL_CARD_TEAM_LIMIT) {
|
||||
return NextResponse.json({ error: "ظرفیت 3 کارت ویژه تیم پر است" }, { status: 400 });
|
||||
}
|
||||
|
||||
if (!replacingPlayer && team.players.length >= 15) {
|
||||
return NextResponse.json({ error: "تیم پر است" }, { status: 400 });
|
||||
}
|
||||
|
||||
const result = await db.$transaction(async (tx) => {
|
||||
if (replacingPlayer) {
|
||||
await tx.teamPlayer.delete({
|
||||
where: { teamId_playerId: { teamId: team.id, playerId: replacingPlayer.playerId } },
|
||||
});
|
||||
|
||||
if (replacingPlayer.goldenCardId) {
|
||||
await tx.goldenCard.update({
|
||||
where: { id: replacingPlayer.goldenCardId },
|
||||
data: { state: "IN_INVENTORY" },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const teamPlayer = await tx.teamPlayer.create({
|
||||
data: {
|
||||
teamId: team.id,
|
||||
playerId: card.playerId,
|
||||
goldenCardId: card.id,
|
||||
isBench: replacingPlayer ? replacingPlayer.isBench : autoPlacement!.isBench,
|
||||
},
|
||||
});
|
||||
|
||||
await tx.goldenCard.update({
|
||||
where: { id: card.id },
|
||||
data: { state: "IN_TEAM" },
|
||||
});
|
||||
|
||||
return teamPlayer;
|
||||
});
|
||||
|
||||
const placement = replacingPlayer
|
||||
? replacingPlayer.isBench
|
||||
? "ذخیره"
|
||||
: "فیکس"
|
||||
: autoPlacement!.placementLabel;
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
action: replacingPlayer ? "replaced" : "added",
|
||||
placement,
|
||||
replacedPlayerId: replacingPlayer?.playerId ?? null,
|
||||
replacedGoldenCardId: replacingPlayer?.goldenCardId ?? null,
|
||||
card: { ...card, state: "IN_TEAM" },
|
||||
teamPlayer: result,
|
||||
message: replacingPlayer
|
||||
? "بازیکن ویژه جایگزین بازیکن انتخابشده شد"
|
||||
: `بازیکن ویژه به صورت خودکار در ${placement} قرار گرفت`,
|
||||
});
|
||||
}
|
||||
26
app/api/golden-cards/[id]/reveal/route.ts
Normal file
26
app/api/golden-cards/[id]/reveal/route.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
|
||||
// POST /api/golden-cards/[id]/reveal
|
||||
export async function POST(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const userId = (session.user as any).id;
|
||||
const { id } = await params;
|
||||
|
||||
const card = await db.goldenCard.findUnique({ where: { id } });
|
||||
if (!card) return NextResponse.json({ error: "Card not found" }, { status: 404 });
|
||||
if (card.userId !== userId) return NextResponse.json({ error: "Forbidden" }, { status: 403 });
|
||||
if (card.status === "OPENED") return NextResponse.json({ error: "کارت قبلاً باز شده" }, { status: 400 });
|
||||
|
||||
const updated = await db.goldenCard.update({
|
||||
where: { id },
|
||||
data: { status: "OPENED", openedAt: new Date() },
|
||||
include: { player: { include: { country: true } } },
|
||||
});
|
||||
|
||||
return NextResponse.json(updated);
|
||||
}
|
||||
52
app/api/golden-cards/[id]/sell/route.ts
Normal file
52
app/api/golden-cards/[id]/sell/route.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
import { getSpecialCardSalePrice } from "@/lib/specialCards";
|
||||
|
||||
export async function POST(_: Request, { params }: { params: Promise<{ id: string }> }) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const userId = (session.user as any).id;
|
||||
const { id } = await params;
|
||||
|
||||
const card = await db.goldenCard.findUnique({
|
||||
where: { id },
|
||||
include: { player: true, teamPlayer: true },
|
||||
});
|
||||
|
||||
if (!card) return NextResponse.json({ error: "کارت ویژه پیدا نشد" }, { status: 404 });
|
||||
if (card.userId !== userId) return NextResponse.json({ error: "Forbidden" }, { status: 403 });
|
||||
if (card.status !== "OPENED") return NextResponse.json({ error: "ابتدا کارت را باز کنید" }, { status: 400 });
|
||||
if (card.state === "SOLD") return NextResponse.json({ error: "این کارت قبلاً فروخته شده" }, { status: 400 });
|
||||
|
||||
const team = await db.team.findUnique({ where: { userId } });
|
||||
if (!team) return NextResponse.json({ error: "تیم پیدا نشد" }, { status: 404 });
|
||||
|
||||
const addedBudget = getSpecialCardSalePrice(card.player.price);
|
||||
|
||||
await db.$transaction(async (tx) => {
|
||||
if (card.teamPlayer) {
|
||||
await tx.teamPlayer.delete({
|
||||
where: { teamId_playerId: { teamId: card.teamPlayer.teamId, playerId: card.teamPlayer.playerId } },
|
||||
});
|
||||
}
|
||||
|
||||
await tx.goldenCard.update({
|
||||
where: { id },
|
||||
data: { state: "SOLD" },
|
||||
});
|
||||
|
||||
await tx.team.update({
|
||||
where: { id: team.id },
|
||||
data: { budget: { increment: addedBudget } },
|
||||
});
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
addedBudget,
|
||||
cardId: id,
|
||||
});
|
||||
}
|
||||
22
app/api/golden-cards/route.ts
Normal file
22
app/api/golden-cards/route.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
|
||||
// GET /api/golden-cards - get current user's golden cards
|
||||
export async function GET() {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const userId = (session.user as any).id;
|
||||
|
||||
const cards = await db.goldenCard.findMany({
|
||||
where: { userId },
|
||||
include: {
|
||||
player: { include: { country: true } },
|
||||
},
|
||||
orderBy: { acquiredDate: "desc" },
|
||||
});
|
||||
|
||||
return NextResponse.json(cards);
|
||||
}
|
||||
@@ -20,7 +20,13 @@ export async function PUT(req: NextRequest, { params }: { params: Promise<{ id:
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const body = await req.json();
|
||||
const match = await db.match.update({ where: { id }, data: body });
|
||||
const match = await db.match.update({
|
||||
where: { id },
|
||||
data: {
|
||||
...body,
|
||||
matchDate: new Date(body.matchDate),
|
||||
},
|
||||
});
|
||||
return NextResponse.json(match);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,10 @@ import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
import { calculatePoints } from "@/lib/points";
|
||||
import { calculateMatchPoints } from "@/lib/points";
|
||||
|
||||
export async function POST(req: NextRequest, { params }: { params: { id: string } }) {
|
||||
export async function POST(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const { id } = await params;
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || (session.user as any).role !== "ADMIN")
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
@@ -25,12 +26,25 @@ export async function POST(req: NextRequest, { params }: { params: { id: string
|
||||
const player = await db.player.findUnique({ where: { id: stat.playerId } });
|
||||
if (!player) continue;
|
||||
|
||||
const points = calculatePoints({ position: player.position, ...stat });
|
||||
const points = await calculateMatchPoints({
|
||||
position: player.position,
|
||||
goals: stat.goals,
|
||||
assists: stat.assists,
|
||||
yellowCards: stat.yellowCards,
|
||||
redCards: stat.redCards,
|
||||
minutesPlayed: stat.minutesPlayed,
|
||||
cleanSheet: stat.cleanSheet,
|
||||
penaltySaved: 0,
|
||||
penaltyMissed: 0,
|
||||
ownGoals: 0,
|
||||
isMotm: false,
|
||||
extraTimeBonus: 0,
|
||||
});
|
||||
|
||||
const record = await db.playerMatchStat.upsert({
|
||||
where: { playerId_matchId: { playerId: stat.playerId, matchId: params.id } },
|
||||
where: { playerId_matchId: { playerId: stat.playerId, matchId: id } },
|
||||
update: { ...stat, points },
|
||||
create: { ...stat, matchId: params.id, points },
|
||||
create: { ...stat, matchId: id, points },
|
||||
});
|
||||
|
||||
// آپدیت امتیاز کل بازیکن
|
||||
|
||||
@@ -22,7 +22,10 @@ export async function POST(req: NextRequest) {
|
||||
|
||||
const body = await req.json();
|
||||
const match = await db.match.create({
|
||||
data: body,
|
||||
data: {
|
||||
...body,
|
||||
matchDate: new Date(body.matchDate),
|
||||
},
|
||||
include: { homeTeam: true, awayTeam: true },
|
||||
});
|
||||
return NextResponse.json(match, { status: 201 });
|
||||
|
||||
11
app/api/openapi/route.ts
Normal file
11
app/api/openapi/route.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { openApiSpec } from "@/lib/openapi";
|
||||
|
||||
export async function GET() {
|
||||
return NextResponse.json(openApiSpec, {
|
||||
headers: {
|
||||
"Cache-Control": "no-store",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -13,7 +13,11 @@ export async function PUT(req: NextRequest, { params }: { params: Promise<{ id:
|
||||
const body = await req.json();
|
||||
const player = await db.player.update({
|
||||
where: { id },
|
||||
data: body,
|
||||
data: {
|
||||
...body,
|
||||
cardTier: body.cardTier ?? undefined,
|
||||
isGoldenCardEligible: body.cardTier ? body.cardTier === "GOLD" : undefined,
|
||||
},
|
||||
});
|
||||
return NextResponse.json(player);
|
||||
}
|
||||
|
||||
@@ -27,6 +27,12 @@ export async function POST(req: NextRequest) {
|
||||
}
|
||||
|
||||
const body = await req.json();
|
||||
const player = await db.player.create({ data: body });
|
||||
const player = await db.player.create({
|
||||
data: {
|
||||
...body,
|
||||
cardTier: body.cardTier ?? "BRONZE",
|
||||
isGoldenCardEligible: (body.cardTier ?? "BRONZE") === "GOLD",
|
||||
},
|
||||
});
|
||||
return NextResponse.json(player, { status: 201 });
|
||||
}
|
||||
|
||||
24
app/api/quiz/my-results/route.ts
Normal file
24
app/api/quiz/my-results/route.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
|
||||
// GET /api/quiz/my-results
|
||||
export async function GET() {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const userId = (session.user as any).id;
|
||||
|
||||
const submissions = await db.quizSubmission.findMany({
|
||||
where: { userId },
|
||||
include: {
|
||||
quiz: {
|
||||
include: { questions: { orderBy: { order: "asc" } } },
|
||||
},
|
||||
},
|
||||
orderBy: { submittedAt: "desc" },
|
||||
});
|
||||
|
||||
return NextResponse.json(submissions);
|
||||
}
|
||||
31
app/api/quiz/route.ts
Normal file
31
app/api/quiz/route.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
|
||||
// GET /api/quiz - get today's active quiz
|
||||
export async function GET() {
|
||||
const now = new Date();
|
||||
const todayStart = new Date(now);
|
||||
todayStart.setHours(0, 0, 0, 0);
|
||||
const todayEnd = new Date(now);
|
||||
todayEnd.setHours(23, 59, 59, 999);
|
||||
|
||||
const quiz = await db.dailyQuiz.findFirst({
|
||||
where: { date: { gte: todayStart, lte: todayEnd } },
|
||||
include: {
|
||||
questions: {
|
||||
orderBy: { order: "asc" },
|
||||
select: {
|
||||
id: true,
|
||||
questionText: true,
|
||||
options: true,
|
||||
order: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!quiz) return NextResponse.json(null);
|
||||
|
||||
const isActive = !quiz.isProcessed && now >= quiz.windowStart && now <= quiz.windowEnd;
|
||||
return NextResponse.json({ ...quiz, isActive });
|
||||
}
|
||||
61
app/api/quiz/submit/route.ts
Normal file
61
app/api/quiz/submit/route.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
import { CARD_TIER_LABELS, resolveQuizRewardTier } from "@/lib/cardTier";
|
||||
|
||||
// POST /api/quiz/submit
|
||||
export async function POST(req: NextRequest) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const userId = (session.user as any).id;
|
||||
const { quizId, answers } = await req.json();
|
||||
|
||||
if (!quizId || !Array.isArray(answers)) {
|
||||
return NextResponse.json({ error: "Invalid payload" }, { status: 400 });
|
||||
}
|
||||
|
||||
const quiz = await db.dailyQuiz.findUnique({
|
||||
where: { id: quizId },
|
||||
include: { questions: { orderBy: { order: "asc" } } },
|
||||
});
|
||||
|
||||
if (!quiz) return NextResponse.json({ error: "Quiz not found" }, { status: 404 });
|
||||
if (quiz.isProcessed) {
|
||||
return NextResponse.json({ error: "این کوییز بعد از قرعهکشی بسته شده است" }, { status: 400 });
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
if (now < quiz.windowStart || now > quiz.windowEnd) {
|
||||
return NextResponse.json({ error: "خارج از بازه زمانی مجاز" }, { status: 400 });
|
||||
}
|
||||
|
||||
const existing = await db.quizSubmission.findUnique({
|
||||
where: { userId_quizId: { userId, quizId } },
|
||||
});
|
||||
if (existing) return NextResponse.json({ error: "قبلاً شرکت کردهاید" }, { status: 400 });
|
||||
|
||||
let correct = 0;
|
||||
quiz.questions.forEach((q, i) => {
|
||||
if (answers[i] === q.correctAnswer) correct++;
|
||||
});
|
||||
|
||||
const score = quiz.questions.length > 0
|
||||
? Math.round((correct / quiz.questions.length) * 100)
|
||||
: 0;
|
||||
const rewardTier = resolveQuizRewardTier(quiz, correct);
|
||||
|
||||
const submission = await db.quizSubmission.create({
|
||||
data: { userId, quizId, answers, correctAnswers: correct, score },
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
score,
|
||||
correct,
|
||||
total: quiz.questions.length,
|
||||
rewardTier,
|
||||
rewardTierLabel: rewardTier ? CARD_TIER_LABELS[rewardTier] : null,
|
||||
submission,
|
||||
});
|
||||
}
|
||||
@@ -3,7 +3,6 @@ import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
|
||||
// اضافه کردن بازیکن به تیم
|
||||
export async function POST(req: NextRequest) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
@@ -13,7 +12,7 @@ export async function POST(req: NextRequest) {
|
||||
|
||||
const team = await db.team.findUnique({
|
||||
where: { userId },
|
||||
include: { players: { include: { player: true } } },
|
||||
include: { players: { include: { player: true, goldenCard: true } } },
|
||||
});
|
||||
|
||||
if (!team) return NextResponse.json({ error: "ابتدا تیم بساز" }, { status: 400 });
|
||||
@@ -21,32 +20,34 @@ export async function POST(req: NextRequest) {
|
||||
const player = await db.player.findUnique({ where: { id: playerId } });
|
||||
if (!player) return NextResponse.json({ error: "بازیکن پیدا نشد" }, { status: 404 });
|
||||
|
||||
// چک بودجه
|
||||
const spent = team.players.reduce((s, tp) => s + tp.player.price, 0);
|
||||
if (spent + player.price > team.budget)
|
||||
const spent = team.players
|
||||
.filter((item) => !item.goldenCardId)
|
||||
.reduce((sum, item) => sum + item.player.price, 0);
|
||||
if (spent + player.price > team.budget) {
|
||||
return NextResponse.json({ error: "بودجه کافی نیست" }, { status: 400 });
|
||||
}
|
||||
|
||||
// چک تعداد (۱۵ نفر: ۱۱ اصلی + ۴ ذخیره)
|
||||
if (team.players.length >= 15)
|
||||
return NextResponse.json({ error: "تیم پر است (حداکثر ۱۵ بازیکن)" }, { status: 400 });
|
||||
if (team.players.length >= 15) {
|
||||
return NextResponse.json({ error: "تیم پر است (حداکثر 15 بازیکن)" }, { status: 400 });
|
||||
}
|
||||
|
||||
// چک تکراری
|
||||
const exists = team.players.find((tp) => tp.playerId === playerId);
|
||||
if (exists) return NextResponse.json({ error: "این بازیکن قبلاً انتخاب شده" }, { status: 400 });
|
||||
const exists = team.players.find((item) => item.playerId === playerId);
|
||||
if (exists) {
|
||||
return NextResponse.json({ error: "این بازیکن قبلاً انتخاب شده" }, { status: 400 });
|
||||
}
|
||||
|
||||
// چک حداکثر ۳ بازیکن از یک تیم ملی
|
||||
const sameCountry = team.players.filter((tp) => tp.player.countryId === player.countryId).length;
|
||||
if (sameCountry >= 3)
|
||||
return NextResponse.json({ error: "حداکثر ۳ بازیکن از یک تیم ملی" }, { status: 400 });
|
||||
const sameCountry = team.players.filter((item) => item.player.countryId === player.countryId).length;
|
||||
if (sameCountry >= 3) {
|
||||
return NextResponse.json({ error: "حداکثر 3 بازیکن از یک تیم ملی" }, { status: 400 });
|
||||
}
|
||||
|
||||
const tp = await db.teamPlayer.create({
|
||||
const teamPlayer = await db.teamPlayer.create({
|
||||
data: { teamId: team.id, playerId, isBench: isBench ?? false },
|
||||
});
|
||||
|
||||
return NextResponse.json(tp, { status: 201 });
|
||||
return NextResponse.json(teamPlayer, { status: 201 });
|
||||
}
|
||||
|
||||
// حذف بازیکن از تیم
|
||||
export async function DELETE(req: NextRequest) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
@@ -54,11 +55,26 @@ export async function DELETE(req: NextRequest) {
|
||||
const { playerId } = await req.json();
|
||||
const userId = (session.user as any).id;
|
||||
|
||||
const team = await db.team.findUnique({ where: { userId } });
|
||||
const team = await db.team.findUnique({
|
||||
where: { userId },
|
||||
include: { players: true },
|
||||
});
|
||||
if (!team) return NextResponse.json({ error: "تیم پیدا نشد" }, { status: 404 });
|
||||
|
||||
await db.teamPlayer.delete({
|
||||
where: { teamId_playerId: { teamId: team.id, playerId } },
|
||||
const teamPlayer = team.players.find((item) => item.playerId === playerId);
|
||||
if (!teamPlayer) return NextResponse.json({ error: "بازیکن در تیم نیست" }, { status: 404 });
|
||||
|
||||
await db.$transaction(async (tx) => {
|
||||
await tx.teamPlayer.delete({
|
||||
where: { teamId_playerId: { teamId: team.id, playerId } },
|
||||
});
|
||||
|
||||
if (teamPlayer.goldenCardId) {
|
||||
await tx.goldenCard.update({
|
||||
where: { id: teamPlayer.goldenCardId },
|
||||
data: { state: "IN_INVENTORY" },
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return NextResponse.json({ success: true });
|
||||
|
||||
Reference in New Issue
Block a user