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

This commit is contained in:
devops committed 2026-09-27 12:23:49 +00:00
commit 619228168d
28 files changed
+1276 -2

No files matched your search

@@ -0,0 +1,11 @@
import { getMyOrders } from "@/lib/headless/providers/medusa-reviews";
export async function GET(request: Request) {
const header = request.headers.get("authorization") ?? "";
if (!header.startsWith("Bearer ")) return Response.json({ error: "No autenticado" }, { status: 401 });
try {
return Response.json({ orders: await getMyOrders(header.slice(7)) });
} catch (error) {
return Response.json({ error: (error as Error).message }, { status: (error as { status?: number }).status ?? 400 });
}
}
@@ -0,0 +1,11 @@
import { getMyReviews } from "@/lib/headless/providers/medusa-reviews";
export async function GET(request: Request) {
const header = request.headers.get("authorization") ?? "";
if (!header.startsWith("Bearer ")) return Response.json({ error: "No autenticado" }, { status: 401 });
try {
return Response.json({ reviews: await getMyReviews(header.slice(7)) });
} catch (error) {
return Response.json({ error: (error as Error).message }, { status: (error as { status?: number }).status ?? 400 });
}
}
@@ -0,0 +1,30 @@
import { createReview, getProductReviews } from "@/lib/headless/providers/medusa-reviews";
function bearer(request: Request): string | null {
const header = request.headers.get("authorization") ?? "";
return header.startsWith("Bearer ") ? header.slice(7) : null;
}
export async function GET(request: Request) {
const productId = new URL(request.url).searchParams.get("product_id");
if (!productId) return Response.json({ error: "product_id es obligatorio" }, { status: 400 });
try {
return Response.json(await getProductReviews(productId));
} catch {
// Backend sin el modulo todavia (o caido): la ficha muestra "sin
// reseñas" en vez de romperse.
return Response.json({ reviews: [], average: 0, count: 0 });
}
}
export async function POST(request: Request) {
const token = bearer(request);
if (!token) return Response.json({ error: "Inicia sesión para dejar una reseña" }, { status: 401 });
const body = await request.json().catch(() => ({}));
try {
return Response.json(await createReview(token, body), { status: 201 });
} catch (error) {
const status = (error as { status?: number }).status ?? 400;
return Response.json({ error: (error as Error).message }, { status });
}
}
@@ -0,0 +1,9 @@
import { getReviewSummary } from "@/lib/headless/providers/medusa-reviews";
export async function GET() {
try {
return Response.json({ summary: await getReviewSummary() });
} catch {
return Response.json({ summary: {} });
}
}
@@ -0,0 +1,12 @@
import type { Metadata } from "next";
import { OrdersClient } from "@/components/account/orders-client";
export const metadata: Metadata = {
title: "Mis pedidos",
description: "Tus pedidos en ARI Shopping y las reseñas de lo que compraste.",
robots: { index: false },
};
export default function OrdersPage() {
return <OrdersClient />;
}
@@ -1,7 +1,9 @@
import type { Metadata } from "next";
import { notFound } from "next/navigation";
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion";
import { CardRating } from "@/components/product/card-rating";
import { ProductCard } from "@/components/product/product-card";
import { ProductReviews } from "@/components/product/product-reviews";
import { ProductCarousel } from "@/components/product/product-carousel";
import { ProductGallery } from "@/components/product/product-gallery";
import { ProductPurchase } from "@/components/product/product-purchase";
@@ -69,6 +71,7 @@ export default async function ProductPage({ params }: ProductPageProps) {
<div className="min-w-0">
<span className="text-xs font-black uppercase tracking-[.18em] text-ari-coral">{product.category} · {product.collection}</span>
<h1 className="mt-3 text-4xl font-black tracking-tight sm:text-6xl">{product.name}</h1>
<CardRating productId={product.id} href="#resenas" />
<p className="mt-5 text-sm leading-6 text-slate-600">{product.description}</p>
{/* Antes escondido detrás de un click en el acordeón --
siempre visible, estilo Amazon, con los mismos datos
@@ -87,6 +90,7 @@ export default async function ProductPage({ params }: ProductPageProps) {
<AccordionContent>Coordinamos envíos nacionales y entrega según ubicación. Los tiempos se confirman durante la cotización.</AccordionContent>
</AccordionItem>
</Accordion>
<ProductReviews productId={product.id} />
</div>
{/* Buy box estilo Amazon: precio/variantes/carrito en su propia
tarjeta, sticky desde xl mientras el resto de la pagina