modifs complete
This commit is contained in:
117
app/api/add-credits-single/route.ts
Normal file
117
app/api/add-credits-single/route.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { getDatabase } from "@/lib/db/mongodb";
|
||||
import { ObjectId } from "mongodb";
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const { userId } = await request.json();
|
||||
|
||||
if (!userId) {
|
||||
return NextResponse.json(
|
||||
{ success: false, error: "userId est requis" },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
const db = await getDatabase();
|
||||
const CREDITS_TO_ADD = 3000000; // 3 millions de tokens
|
||||
|
||||
// Vérifier que l'utilisateur existe
|
||||
let userObjectId: ObjectId;
|
||||
try {
|
||||
userObjectId = new ObjectId(userId);
|
||||
} catch {
|
||||
return NextResponse.json(
|
||||
{ success: false, error: "ID utilisateur invalide" },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
const user = await db.collection("users").findOne({ _id: userObjectId });
|
||||
|
||||
if (!user) {
|
||||
return NextResponse.json(
|
||||
{ success: false, error: "Utilisateur non trouvé" },
|
||||
{ status: 404 }
|
||||
);
|
||||
}
|
||||
|
||||
console.log(
|
||||
`🎯 Ajout de ${CREDITS_TO_ADD.toLocaleString()} crédits à: ${user.email || user.name}`
|
||||
);
|
||||
|
||||
// Chercher la balance existante - essayer avec ObjectId ET string
|
||||
let existingBalance = await db
|
||||
.collection("balances")
|
||||
.findOne({ user: userObjectId });
|
||||
|
||||
// Si pas trouvé avec ObjectId, essayer avec string
|
||||
if (!existingBalance) {
|
||||
existingBalance = await db
|
||||
.collection("balances")
|
||||
.findOne({ user: userId });
|
||||
}
|
||||
|
||||
console.log(`📊 Balance existante trouvée: ${existingBalance ? "OUI" : "NON"}`);
|
||||
if (existingBalance) {
|
||||
console.log(`📊 Balance ID: ${existingBalance._id}, Crédits actuels: ${existingBalance.tokenCredits}`);
|
||||
}
|
||||
|
||||
let newBalance: number;
|
||||
|
||||
if (existingBalance) {
|
||||
// Mettre à jour la balance existante avec $inc pour être sûr
|
||||
const currentCredits = existingBalance.tokenCredits || 0;
|
||||
newBalance = currentCredits + CREDITS_TO_ADD;
|
||||
|
||||
const updateResult = await db.collection("balances").updateOne(
|
||||
{ _id: existingBalance._id },
|
||||
{
|
||||
$inc: { tokenCredits: CREDITS_TO_ADD },
|
||||
$set: { lastRefill: new Date() },
|
||||
}
|
||||
);
|
||||
|
||||
console.log(`✅ Update result: matchedCount=${updateResult.matchedCount}, modifiedCount=${updateResult.modifiedCount}`);
|
||||
console.log(
|
||||
`✅ Balance mise à jour: ${currentCredits.toLocaleString()} → ${newBalance.toLocaleString()}`
|
||||
);
|
||||
} else {
|
||||
// Créer une nouvelle balance
|
||||
newBalance = CREDITS_TO_ADD;
|
||||
|
||||
const insertResult = await db.collection("balances").insertOne({
|
||||
user: userObjectId,
|
||||
tokenCredits: newBalance,
|
||||
autoRefillEnabled: false,
|
||||
lastRefill: new Date(),
|
||||
refillAmount: 0,
|
||||
refillIntervalUnit: "month",
|
||||
refillIntervalValue: 1,
|
||||
__v: 0,
|
||||
});
|
||||
|
||||
console.log(`🆕 Nouvelle balance créée: ${insertResult.insertedId} avec ${newBalance.toLocaleString()} crédits`);
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: `${CREDITS_TO_ADD.toLocaleString()} crédits ajoutés à ${user.email || user.name}`,
|
||||
newBalance,
|
||||
user: {
|
||||
id: user._id.toString(),
|
||||
name: user.name,
|
||||
email: user.email,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Erreur lors de l'ajout des crédits:", error);
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
error: "Erreur serveur lors de l'ajout des crédits",
|
||||
},
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -55,29 +55,76 @@ export async function GET(
|
||||
if (collection === "users") {
|
||||
const email = searchParams.get("email");
|
||||
const id = searchParams.get("id");
|
||||
const search = searchParams.get("search"); // ✅ AJOUTER cette ligne
|
||||
const search = searchParams.get("search");
|
||||
const referent = searchParams.get("referent");
|
||||
|
||||
if (email) {
|
||||
filter.email = email.toLowerCase();
|
||||
} else if (id) {
|
||||
// Vérifier si l'ID est un ObjectId valide
|
||||
if (ObjectId.isValid(id)) {
|
||||
filter._id = new ObjectId(id);
|
||||
} else {
|
||||
// Si l'ID n'est pas valide, retourner une erreur
|
||||
return NextResponse.json(
|
||||
{ error: "ID utilisateur invalide" },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
} else if (search) {
|
||||
// ✅ AJOUTER ce bloc
|
||||
// Recherche partielle sur nom et email
|
||||
filter.$or = [
|
||||
{ name: { $regex: search, $options: "i" } },
|
||||
{ email: { $regex: search, $options: "i" } },
|
||||
];
|
||||
}
|
||||
|
||||
// Filtre par référent (peut être combiné avec search)
|
||||
if (referent) {
|
||||
filter.referent = referent;
|
||||
}
|
||||
}
|
||||
|
||||
// Gestion spéciale pour conversations - recherche par nom/email d'utilisateur
|
||||
if (collection === "conversations") {
|
||||
const search = searchParams.get("search");
|
||||
const userId = searchParams.get("userId");
|
||||
|
||||
if (userId) {
|
||||
// Recherche directe par userId (stocké comme string dans conversations)
|
||||
filter.user = userId;
|
||||
} else if (search && search.trim()) {
|
||||
// Normaliser la recherche (enlever accents pour recherche insensible aux accents)
|
||||
const normalizedSearch = search
|
||||
.normalize("NFD")
|
||||
.replace(/[\u0300-\u036f]/g, "");
|
||||
|
||||
const db = await getDatabase();
|
||||
|
||||
// Recherche users avec nom/email/username (insensible casse + accents)
|
||||
const matchingUsers = await db
|
||||
.collection("users")
|
||||
.find({
|
||||
$or: [
|
||||
{ name: { $regex: normalizedSearch, $options: "i" } },
|
||||
{ email: { $regex: normalizedSearch, $options: "i" } },
|
||||
{ username: { $regex: normalizedSearch, $options: "i" } },
|
||||
],
|
||||
})
|
||||
.project({ _id: 1 })
|
||||
.toArray();
|
||||
|
||||
if (matchingUsers.length > 0) {
|
||||
// IMPORTANT: Convertir en strings car user dans conversations est stocké comme string
|
||||
const userIds = matchingUsers.map((u) => u._id.toString());
|
||||
filter.user = { $in: userIds };
|
||||
} else {
|
||||
return NextResponse.json({
|
||||
data: [],
|
||||
total: 0,
|
||||
page,
|
||||
limit,
|
||||
totalPages: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const db = await getDatabase();
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { Metadata } from "next";
|
||||
import { Geist, Geist_Mono } from "next/font/google";
|
||||
import "./globals.css";
|
||||
import { Sidebar } from "@/components/layout/sidebar";
|
||||
import { QueryProvider } from "@/components/providers/query-provider";
|
||||
|
||||
const geistSans = Geist({
|
||||
variable: "--font-geist-sans",
|
||||
@@ -28,12 +29,14 @@ export default function RootLayout({
|
||||
<body
|
||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
||||
>
|
||||
<div className="flex h-screen">
|
||||
<Sidebar />
|
||||
<main className="flex-1 overflow-auto">
|
||||
<div className="container mx-auto p-6">{children}</div>
|
||||
</main>
|
||||
</div>
|
||||
<QueryProvider>
|
||||
<div className="flex h-screen">
|
||||
<Sidebar />
|
||||
<main className="flex-1 overflow-auto">
|
||||
<div className="container mx-auto p-6">{children}</div>
|
||||
</main>
|
||||
</div>
|
||||
</QueryProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Badge } from "@/components/ui/badge";
|
||||
import { Database, Server, Settings } from "lucide-react";
|
||||
|
||||
import AddCredits from "@/components/dashboard/add-credits";
|
||||
import AddCreditsSingleUser from "@/components/dashboard/add-credits-single-user";
|
||||
import UserManagement from "@/components/dashboard/user-management";
|
||||
|
||||
export default function SettingsPage() {
|
||||
@@ -79,8 +80,11 @@ export default function SettingsPage() {
|
||||
Gestion des Crédits
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<AddCredits />
|
||||
<CardContent className="space-y-6">
|
||||
<AddCreditsSingleUser />
|
||||
<div className="border-t pt-6">
|
||||
<AddCredits />
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user