feat: implement market page with QueryProvider and dynamic listings

- wrap root layout with QueryProvider for React Query
- replace market UnderConstruction placeholder with MarketClient and real data fetching
- implement search, pagination, and sort via search params using getActiveListings
- add necessary client components and queries
- update dependencies (e.g., prisma, pkg-types)
This commit is contained in:
Evandro Fonseca Junior committed 2025-11-05 01:58:03 -03:00
1 parent 55eebde0ba
commit ab37b477df
106 files changed
+15261 -301

No files matched your search

+1 -1
View File
@@ -15,7 +15,7 @@ import {
getUserByEmail,
getUserByUsername,
updateLastLogin,
} from "@/lib/db/queries/users";
} from "@/lib/prisma/queries/users";
import { setSession } from "@/lib/redis/session";
import { randomUUID } from "crypto";
+2 -2
View File
@@ -1,8 +1,8 @@
import { NextRequest, NextResponse } from "next/server";
import { secureLogger } from "@/lib/secure-logger";
import { requireAuth } from "@/lib/auth/middleware";
import { getUserById } from "@/lib/db/queries/users";
import { getUserCharacters } from "@/lib/db/queries/characters";
import { getUserById } from "@/lib/prisma/queries/users";
import { getUserCharacters } from "@/lib/prisma/queries/characters";
export async function GET(request: NextRequest) {
try {
+67 -74
View File
@@ -14,14 +14,15 @@ import {
import {
getUserByEmail,
getUserByUsername,
} from "@/lib/db/queries/users";
} from "@/lib/prisma/queries/users";
import {
isServerActive,
incrementUsersForServers,
} from "@/lib/db/queries/servers";
} from "@/lib/prisma/queries/servers";
import { setSession } from "@/lib/redis/session";
import { randomUUID } from "crypto";
import { getPool } from "@/lib/db";
import { createUser } from "@/lib/prisma/queries/users";
import { createCharacter } from "@/lib/prisma/queries/characters";
export async function POST(request: NextRequest) {
try {
@@ -110,90 +111,82 @@ export async function POST(request: NextRequest) {
// Hash da senha
const passwordHash = await hashPassword(validatedData.password);
// Criar usuário e personagens em transação atômica
const pool = getPool();
const client = await pool.connect();
// Criar usuário e personagens em transação atômica usando Prisma
const { prisma } = await import("@/lib/prisma/app");
let newUser: { userId: number; username: string; email: string };
const createdCharacters: Array<{ characterName: string; serverName: string }> = [];
try {
await client.query("BEGIN");
// Usar transação Prisma
await prisma.$transaction(async (tx) => {
// Criar usuário
const user = await tx.user.create({
data: {
username: validatedData.username,
email: validatedData.email,
password_hash: passwordHash,
first_name: validatedData.firstName,
last_name: validatedData.lastName,
phone: validatedData.phone || null,
cpf: null, // CPF não é mais obrigatório
},
select: {
user_id: true,
username: true,
email: true,
},
});
// Criar usuário
const userResult = await client.query<{
user_id: number;
username: string;
email: string;
}>(
`
INSERT INTO users (username, email, password_hash, first_name, last_name, phone, cpf)
VALUES ($1, $2, $3, $4, $5, $6, $7)
RETURNING user_id, username, email
`,
[
validatedData.username,
validatedData.email,
passwordHash,
validatedData.firstName,
validatedData.lastName,
validatedData.phone || null,
null, // CPF não é mais obrigatório
]
);
newUser = {
userId: user.user_id,
username: user.username,
email: user.email,
};
newUser = {
userId: userResult.rows[0].user_id,
username: userResult.rows[0].username,
email: userResult.rows[0].email,
};
// Criar personagens (primeiro é main por padrão)
for (let i = 0; i < validatedData.servers.length; i++) {
const serverData = validatedData.servers[i];
const isMain = i === 0 || serverData.isMain === true;
// Criar personagens (primeiro é main por padrão)
for (let i = 0; i < validatedData.servers.length; i++) {
const serverData = validatedData.servers[i];
const isMain = i === 0 || serverData.isMain === true;
// Se este personagem será main e não é o primeiro, desmarcar outros
if (isMain && i > 0) {
await tx.userCharacter.updateMany({
where: { user_id: newUser.userId },
data: { is_main: false },
});
}
// Se este personagem será main e não é o primeiro, desmarcar outros
if (isMain && i > 0) {
await client.query(
`
UPDATE user_characters
SET is_main = FALSE
WHERE user_id = $1
`,
[newUser.userId]
);
// Inserir personagem
const character = await tx.userCharacter.create({
data: {
user_id: newUser.userId,
character_name: serverData.characterName,
server_name: serverData.serverName,
is_main: isMain,
},
});
createdCharacters.push({
characterName: character.character_name,
serverName: character.server_name,
});
}
// Inserir personagem
const charResult = await client.query<{
character_id: number;
character_name: string;
server_name: string;
}>(
`
INSERT INTO user_characters (user_id, character_name, server_name, is_main)
VALUES ($1, $2, $3, $4)
RETURNING character_id, character_name, server_name
`,
[newUser.userId, serverData.characterName, serverData.serverName, isMain]
);
createdCharacters.push({
characterName: charResult.rows[0].character_name,
serverName: charResult.rows[0].server_name,
// Incrementar total_users dos servidores (dentro da transação)
await tx.server.updateMany({
where: {
server_name: { in: uniqueServerNames },
},
data: {
total_users: { increment: 1 },
last_activity_at: new Date(),
},
});
}
// Incrementar total_users dos servidores
await incrementUsersForServers(uniqueServerNames);
await client.query("COMMIT");
});
} catch (error) {
await client.query("ROLLBACK");
// Prisma já faz rollback automático em caso de erro
throw error;
} finally {
client.release();
}
// Gerar tokens