diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 166617c..5297503 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -8,7 +8,9 @@ "Bash(git add:*)", "Bash(git commit:*)", "Bash(git push)", - "Bash(npm install:*)" + "Bash(npm install:*)", + "Bash(node debug-search.js:*)", + "Bash(node update-referent.js:*)" ], "deny": [], "ask": [] diff --git a/app/api/add-credits-single/route.ts b/app/api/add-credits-single/route.ts new file mode 100644 index 0000000..312d179 --- /dev/null +++ b/app/api/add-credits-single/route.ts @@ -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 } + ); + } +} diff --git a/app/api/collections/[collection]/route.ts b/app/api/collections/[collection]/route.ts index 797a3c0..7a5217e 100644 --- a/app/api/collections/[collection]/route.ts +++ b/app/api/collections/[collection]/route.ts @@ -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(); diff --git a/app/layout.tsx b/app/layout.tsx index 1c2be10..7f743c3 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -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({
-