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:
1 parent
55eebde0ba
commit
ab37b477df
106 files changed
+15261
-301
No files matched your search
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* Queries de itens unificados
|
||||
* Busca itens da tabela unificada items (PostgreSQL)
|
||||
*/
|
||||
|
||||
import { query } from "../index";
|
||||
|
||||
export interface UnifiedItem {
|
||||
item_id: number;
|
||||
source_table_id: number;
|
||||
source_table_name: string;
|
||||
item_name: string;
|
||||
category: string;
|
||||
image_local_path: string | null;
|
||||
image_url: string | null;
|
||||
rarity: string | null;
|
||||
level: number | null;
|
||||
weight: number | null;
|
||||
slots: number | null;
|
||||
skill: string | null;
|
||||
metadata: any; // JSONB
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Busca item por ID unificado
|
||||
*/
|
||||
export async function getItemByIdUnified(itemId: number): Promise<UnifiedItem | null> {
|
||||
try {
|
||||
const result = await query<UnifiedItem>(
|
||||
`
|
||||
SELECT
|
||||
item_id,
|
||||
source_table_id,
|
||||
source_table_name,
|
||||
item_name,
|
||||
category,
|
||||
image_local_path,
|
||||
image_url,
|
||||
rarity,
|
||||
level,
|
||||
weight,
|
||||
slots,
|
||||
skill,
|
||||
metadata,
|
||||
created_at,
|
||||
updated_at
|
||||
FROM items
|
||||
WHERE item_id = $1
|
||||
`,
|
||||
[itemId]
|
||||
);
|
||||
|
||||
if (result.rows.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return result.rows[0];
|
||||
} catch (error: any) {
|
||||
// Se a tabela não existe (código 42P01), retornar null silenciosamente
|
||||
// Isso permite fallback para SQLite sem poluir logs
|
||||
if (error?.code === "42P01") {
|
||||
return null;
|
||||
}
|
||||
// Para outros erros, re-lançar
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Busca item por nome (case-insensitive)
|
||||
*/
|
||||
export async function getItemByNameUnified(itemName: string): Promise<UnifiedItem | null> {
|
||||
try {
|
||||
const result = await query<UnifiedItem>(
|
||||
`
|
||||
SELECT
|
||||
item_id,
|
||||
source_table_id,
|
||||
source_table_name,
|
||||
item_name,
|
||||
category,
|
||||
image_local_path,
|
||||
image_url,
|
||||
rarity,
|
||||
level,
|
||||
weight,
|
||||
slots,
|
||||
skill,
|
||||
metadata,
|
||||
created_at,
|
||||
updated_at
|
||||
FROM items
|
||||
WHERE LOWER(item_name) = LOWER($1)
|
||||
LIMIT 1
|
||||
`,
|
||||
[itemName]
|
||||
);
|
||||
|
||||
if (result.rows.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return result.rows[0];
|
||||
} catch (error: any) {
|
||||
// Se a tabela não existe (código 42P01), retornar null silenciosamente
|
||||
if (error?.code === "42P01") {
|
||||
return null;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Valida se um item existe na tabela unificada
|
||||
*/
|
||||
export async function itemExists(itemId: number): Promise<boolean> {
|
||||
try {
|
||||
const result = await query<{ exists: boolean }>(
|
||||
`
|
||||
SELECT EXISTS(
|
||||
SELECT 1 FROM items WHERE item_id = $1
|
||||
) as exists
|
||||
`,
|
||||
[itemId]
|
||||
);
|
||||
|
||||
return result.rows[0]?.exists || false;
|
||||
} catch (error: any) {
|
||||
// Se a tabela não existe (código 42P01), retornar false silenciosamente
|
||||
if (error?.code === "42P01") {
|
||||
return false;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user