Merge branch 'feat/resenas-productos'
Build and Push Medusa / Escaneo de Secretos (Gitleaks) (push) Successful in 1m21s
Build and Push Medusa / Construir y publicar Medusa (push) Successful in 38m24s
Build and Push Frontend / Escaneo de Secretos (Gitleaks) (push) Successful in 49s
Build and Push Frontend / Construir y Subir Imagen (push) Failing after 33s
Build and Push Medusa / Escaneo de Secretos (Gitleaks) (push) Successful in 1m21s
Build and Push Medusa / Construir y publicar Medusa (push) Successful in 38m24s
Build and Push Frontend / Escaneo de Secretos (Gitleaks) (push) Successful in 49s
Build and Push Frontend / Construir y Subir Imagen (push) Failing after 33s
This commit is contained in:
commit
619228168d
28 files changed
+1276
-2
No files matched your search
@@ -0,0 +1,111 @@
|
||||
// Reseñas de productos + pedidos del cliente (Store API de Medusa, modulo
|
||||
// propio commerce-backend/src/modules/product-review). Server-side y sin
|
||||
// cache: las reseñas cambian al aprobarse en el admin y los pedidos son
|
||||
// estado de sesion.
|
||||
|
||||
function backendUrl(): string {
|
||||
const value = process.env.MEDUSA_BACKEND_URL;
|
||||
if (!value) throw new Error("MEDUSA_BACKEND_URL no está configurado.");
|
||||
return value.replace(/\/$/, "");
|
||||
}
|
||||
|
||||
async function medusaFetch<T>(path: string, init?: { method?: string; body?: unknown; token?: string }): Promise<T> {
|
||||
const publishableKey = process.env.MEDUSA_PUBLISHABLE_KEY;
|
||||
const response = await fetch(`${backendUrl()}${path}`, {
|
||||
method: init?.method ?? "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...(publishableKey ? { "x-publishable-api-key": publishableKey } : {}),
|
||||
...(init?.token ? { Authorization: `Bearer ${init.token}` } : {}),
|
||||
},
|
||||
body: init?.body ? JSON.stringify(init.body) : undefined,
|
||||
cache: "no-store",
|
||||
});
|
||||
const data = await response.json().catch(() => ({}));
|
||||
if (!response.ok) {
|
||||
const message = typeof data.message === "string" ? data.message : `Error ${response.status}`;
|
||||
throw Object.assign(new Error(message), { status: response.status });
|
||||
}
|
||||
return data as T;
|
||||
}
|
||||
|
||||
export interface PublicReview {
|
||||
id: string;
|
||||
author_name: string;
|
||||
rating: number;
|
||||
title: string | null;
|
||||
content: string;
|
||||
created_at: string;
|
||||
verified_purchase: boolean;
|
||||
}
|
||||
|
||||
export interface ReviewSummary {
|
||||
average: number;
|
||||
count: number;
|
||||
}
|
||||
|
||||
export interface MyReview {
|
||||
id: string;
|
||||
product_id: string;
|
||||
order_id: string;
|
||||
rating: number;
|
||||
status: "pending" | "approved" | "rejected";
|
||||
}
|
||||
|
||||
export interface CustomerOrder {
|
||||
id: string;
|
||||
displayId: number | null;
|
||||
createdAt: string;
|
||||
status: string;
|
||||
total: number | null;
|
||||
currency: string;
|
||||
items: { productId: string; title: string; thumbnail: string | null; handle: string | null; quantity: number }[];
|
||||
}
|
||||
|
||||
export function getProductReviews(productId: string) {
|
||||
return medusaFetch<{ reviews: PublicReview[]; average: number; count: number }>(`/store/reviews?product_id=${encodeURIComponent(productId)}`);
|
||||
}
|
||||
|
||||
export async function getReviewSummary(): Promise<Record<string, ReviewSummary>> {
|
||||
return (await medusaFetch<{ summary: Record<string, ReviewSummary> }>("/store/reviews/summary")).summary;
|
||||
}
|
||||
|
||||
export async function getMyReviews(token: string): Promise<MyReview[]> {
|
||||
return (await medusaFetch<{ reviews: MyReview[] }>("/store/reviews/me", { token })).reviews;
|
||||
}
|
||||
|
||||
export function createReview(token: string, body: { product_id: string; order_id: string; rating: number; title?: string; content: string }) {
|
||||
return medusaFetch<{ review: { id: string; status: string } }>("/store/reviews", { method: "POST", body, token });
|
||||
}
|
||||
|
||||
type MedusaOrder = {
|
||||
id: string;
|
||||
display_id?: number | null;
|
||||
created_at: string;
|
||||
status: string;
|
||||
total?: number | null;
|
||||
currency_code?: string | null;
|
||||
items?: { product_id?: string | null; product_title?: string | null; title?: string | null; thumbnail?: string | null; product_handle?: string | null; quantity?: number }[];
|
||||
};
|
||||
|
||||
export async function getMyOrders(token: string): Promise<CustomerOrder[]> {
|
||||
const fields = "id,display_id,created_at,status,total,currency_code,*items";
|
||||
const data = await medusaFetch<{ orders: MedusaOrder[] }>(`/store/orders?limit=50&order=-created_at&fields=${encodeURIComponent(fields)}`, { token });
|
||||
return data.orders.map((order) => ({
|
||||
id: order.id,
|
||||
displayId: order.display_id ?? null,
|
||||
createdAt: order.created_at,
|
||||
status: order.status,
|
||||
total: typeof order.total === "number" ? order.total : null,
|
||||
currency: (order.currency_code ?? "cop").toUpperCase(),
|
||||
items: (order.items ?? [])
|
||||
.filter((item) => item.product_id)
|
||||
.map((item) => ({
|
||||
productId: item.product_id as string,
|
||||
title: item.product_title || item.title || "Producto",
|
||||
thumbnail: item.thumbnail ?? null,
|
||||
handle: item.product_handle ?? null,
|
||||
quantity: item.quantity ?? 1,
|
||||
})),
|
||||
}));
|
||||
}
|
||||
Reference in new issue
Block a user