Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
2466cf6
feat: update product variant UI
Aug 22, 2025
58cb9d0
feat: update inital data and update product service to get price
JanetHugarcia Aug 22, 2025
f5dbce2
Merge pull request #254 from codeableorg/feature/product-with-variants
Vazzukoff Aug 23, 2025
f448d4b
Refactor: sticker UI update
Vazzukoff Aug 23, 2025
73d3ba7
Merge branch 'grupo-3-main' into feat/update-product-variant-ui
Vazzukoff Aug 23, 2025
3524492
Merge pull request #250 from codeableorg/feat/update-product-variant-ui
JanetHugarcia Aug 23, 2025
ef1925a
Fix: Product-card
Vazzukoff Aug 23, 2025
68c6f1d
Merge branch 'grupo-3-main' of https://github.com/codeableorg/fullsto…
mykeVera Aug 27, 2025
ca8e64f
fix: correct sticker category check and improve price filter logic
mykeVera Aug 28, 2025
cd32444
Merge pull request #263 from codeableorg/grupo-3-mike-2
JanetHugarcia Aug 28, 2025
ccc1059
feat: refactor cart and product models to use attributeValueId, updat…
mykeVera Aug 29, 2025
f796181
Merge pull request #266 from codeableorg/grupo-3-mike-3
Vazzukoff Aug 30, 2025
819617e
refactor: product.service & UI and chatbot update
Vazzukoff Aug 30, 2025
937f49a
Merge branch 'grupo-3-main' into feat/update-product-variant-ui
mykeVera Aug 30, 2025
35dddc6
Merge pull request #267 from codeableorg/feat/update-product-variant-ui
Vazzukoff Aug 30, 2025
6da9f5b
feat: integration product detail with cart service
JanetHugarcia Aug 29, 2025
8c8318c
feat: add variantId in product detail to persist data
JanetHugarcia Aug 30, 2025
9d43502
feat: add filter by price from bd
JanetHugarcia Aug 30, 2025
027de23
feat: update variant attribute values and improve product pricing logic
mykeVera Sep 1, 2025
9b3b553
Merge branch 'grupo-3-main' into grupo-3-mike-5
mykeVera Sep 1, 2025
00a60c7
Merge pull request #274 from codeableorg/grupo-3-mike-5
mykeVera Sep 1, 2025
63d4785
feat: enhance cart and checkout components to display variant attribu…
mykeVera Sep 1, 2025
e1cae5e
Merge pull request #275 from codeableorg/grupo-3-mike-6
mykeVera Sep 1, 2025
45c9826
feat: overhaul README to document fullstack e-commerce features and v…
mykeVera Sep 1, 2025
13a759a
Merge pull request #276 from codeableorg/grupo-3-mike-7
mykeVera Sep 1, 2025
a0d3f93
feat: update chatbot prompts and add context for new product variants
Vazzukoff Sep 1, 2025
aaa189c
Merge pull request #277 from codeableorg/feat/sebastian-chatbot-update
mykeVera Sep 1, 2025
e7ad0bf
feat: update data models and cart logic to support variant attribute …
mykeVera Sep 1, 2025
e75aa01
Merge pull request #278 from codeableorg/grupo-3-mike-orders
Vazzukoff Sep 1, 2025
80cfcae
feat: enhance order service tests and improve error handling in getOr…
mykeVera Sep 1, 2025
b7bc308
Fix: UI and README.md update
Vazzukoff Sep 1, 2025
1faad85
Merge pull request #279 from codeableorg/grupo-3-mike-orders-test
Vazzukoff Sep 1, 2025
3d0babc
Merge pull request #280 from codeableorg/fix/UI-update-for-responsive…
Vazzukoff Sep 1, 2025
8e73418
feat: update product service test
JanetHugarcia Sep 1, 2025
bccd340
feat: add product page service
JanetHugarcia Sep 1, 2025
1bd306c
Merge pull request #281 from codeableorg/feature/product-unit-test
JanetHugarcia Sep 1, 2025
e475948
fix: remove pre in product detail
JanetHugarcia Sep 1, 2025
ee3ef83
Merge branch 'main' into grupo-3-main
mykeVera Sep 1, 2025
8d01b90
fix: update variant attribute structure and types in tests and models
mykeVera Sep 1, 2025
aa09356
fix: update type for lint
JanetHugarcia Sep 1, 2025
7b3ba9d
fix: remove orig and logs
JanetHugarcia Sep 1, 2025
40f130c
refactor: update product model and related services to use single var…
mykeVera Sep 1, 2025
8675f20
Merge branch 'grupo-3-main' into grupo-3-variant
mykeVera Sep 1, 2025
0516ca9
Merge pull request #283 from codeableorg/grupo-3-variant
mykeVera Sep 1, 2025
f94c668
feat: add variant attributes and values to seed data, update product …
mykeVera Sep 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat: update inital data and update product service to get price
  • Loading branch information
JanetHugarcia committed Aug 22, 2025
commit 58cb9d0e8bec297e25e1d5cfe9ca783646bb1ad8
32 changes: 16 additions & 16 deletions prisma/initial_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -395,36 +395,36 @@ export const variantAttributeValues = [

// --- STICKERS (dimensiones: 3x3, 6x6, 9x9) ---
{ attributeId: 2, productId: 10, value: "3x3", price: 2.99 },
{ attributeId: 2, productId: 10, value: "6x6", price: 3.99 },
{ attributeId: 2, productId: 10, value: "9x9", price: 4.99 },
{ attributeId: 2, productId: 10, value: "5x5", price: 3.99 },
{ attributeId: 2, productId: 10, value: "10x10", price: 4.99 },

{ attributeId: 2, productId: 11, value: "3x3", price: 2.49 },
{ attributeId: 2, productId: 11, value: "6x6", price: 3.49 },
{ attributeId: 2, productId: 11, value: "9x9", price: 4.49 },
{ attributeId: 2, productId: 11, value: "5x5", price: 3.49 },
{ attributeId: 2, productId: 11, value: "10x10", price: 4.49 },

{ attributeId: 2, productId: 12, value: "3x3", price: 3.99 },
{ attributeId: 2, productId: 12, value: "6x6", price: 4.99 },
{ attributeId: 2, productId: 12, value: "9x9", price: 5.99 },
{ attributeId: 2, productId: 12, value: "5x5", price: 4.99 },
{ attributeId: 2, productId: 12, value: "10x10", price: 5.99 },

{ attributeId: 2, productId: 13, value: "3x3", price: 2.99 },
{ attributeId: 2, productId: 13, value: "6x6", price: 3.99 },
{ attributeId: 2, productId: 13, value: "9x9", price: 4.99 },
{ attributeId: 2, productId: 13, value: "5x5", price: 3.99 },
{ attributeId: 2, productId: 13, value: "10x10", price: 4.99 },

{ attributeId: 2, productId: 14, value: "3x3", price: 2.49 },
{ attributeId: 2, productId: 14, value: "6x6", price: 3.49 },
{ attributeId: 2, productId: 14, value: "9x9", price: 4.49 },
{ attributeId: 2, productId: 14, value: "5x5", price: 3.49 },
{ attributeId: 2, productId: 14, value: "10x10", price: 4.49 },

{ attributeId: 2, productId: 15, value: "3x3", price: 2.49 },
{ attributeId: 2, productId: 15, value: "6x6", price: 3.49 },
{ attributeId: 2, productId: 15, value: "9x9", price: 4.49 },
{ attributeId: 2, productId: 15, value: "5x5", price: 3.49 },
{ attributeId: 2, productId: 15, value: "10x10", price: 4.49 },

{ attributeId: 2, productId: 16, value: "3x3", price: 2.99 },
{ attributeId: 2, productId: 16, value: "6x6", price: 3.99 },
{ attributeId: 2, productId: 16, value: "9x9", price: 4.99 },
{ attributeId: 2, productId: 16, value: "5x5", price: 3.99 },
{ attributeId: 2, productId: 16, value: "10x10", price: 4.99 },

{ attributeId: 2, productId: 17, value: "3x3", price: 2.99 },
{ attributeId: 2, productId: 17, value: "6x6", price: 3.99 },
{ attributeId: 2, productId: 17, value: "9x9", price: .99 },
{ attributeId: 2, productId: 17, value: "5x5", price: 3.99 },
{ attributeId: 2, productId: 17, value: "10x10", price: .99 },

// --- TAZAS (no aplica: Único) ---
{ attributeId: 3, productId: 18, value: "Único", price: 14.99 },
Expand Down
11 changes: 9 additions & 2 deletions src/models/product.model.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import type { VariantAttributeValue } from "./variant-attribute.model";
import type { Product as PrismaProduct } from "@/../generated/prisma/client";

export type Product = Omit<PrismaProduct, "price"> & {
price: number;
export type Product = PrismaProduct & {
price?: number | null;
minPrice?: number | null;
maxPrice?: number | null;
};

export type ProductVariantValue = PrismaProduct & {
variantAttributeValues: VariantAttributeValue[];
}
2 changes: 2 additions & 0 deletions src/models/variant-attribute.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import type { VariantAttributeValue as PrismaVariantAttributeValue } from "@/../generated/prisma/client";
export type VariantAttributeValue= PrismaVariantAttributeValue
9 changes: 9 additions & 0 deletions src/routes/category/components/product-card/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ interface ProductCardProps {

export function ProductCard({ product }: ProductCardProps) {
return (
<>
<Link
to={`/products/${product.id}`}
className="block"
Expand All @@ -25,7 +26,14 @@ export function ProductCard({ product }: ProductCardProps) {
<div className="flex grow flex-col gap-2 p-4">
<h2 className="text-sm font-medium">{product.title}</h2>
<p className="text-sm text-muted-foreground">{product.description}</p>
{
product?.price &&
<p className="mt-auto text-base font-medium">S/{product.price}</p>
}
{
product?.minPrice &&
<p className="mt-auto text-base font-medium">Entre S/{product.minPrice} - {product.maxPrice}</p>
}
</div>
{product.isOnSale && (
<span className="absolute top-0 right-0 rounded-bl-xl bg-primary px-2 py-1 text-sm font-medium text-primary-foreground">
Expand All @@ -34,5 +42,6 @@ export function ProductCard({ product }: ProductCardProps) {
)}
</div>
</Link>
</>
);
}
20 changes: 18 additions & 2 deletions src/routes/category/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,24 @@ export async function loader({ params, request }: Route.LoaderArgs) {
const min = minPrice ? parseFloat(minPrice) : 0;
const max = maxPrice ? parseFloat(maxPrice) : Infinity;
return products.filter(
(product) => product.price >= min && product.price <= max
);
(product) => {
const minProductPrice = product.minPrice||0
const maxProductPrice = product.maxPrice ||0
const productPrice = product.price || 0

if (min && max) {
return ((productPrice||minProductPrice) >= min) && ((productPrice||maxProductPrice) <= max)
}

if (min) {
return (productPrice||minProductPrice) >= min
}
if (max) {
return (productPrice||maxProductPrice) <= max

}
return true
});
};

const filteredProducts = filterProductsByPrice(
Expand Down
2 changes: 1 addition & 1 deletion src/routes/root/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export async function loader({ request }: Route.LoaderArgs) {
}

const totalItems =
cart?.items.reduce((total, item) => total + item.quantity, 0) || 0;
cart?.items?.reduce((total, item) => total + item.quantity, 0) || 0;

// Preparar datos de respuesta según estado de autenticación
const responseData = user ? { user, totalItems } : { totalItems };
Expand Down
70 changes: 40 additions & 30 deletions src/services/cart.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,42 +18,52 @@ async function getCart(
: undefined;

if (!whereCondition) return null;
try {

const data = await prisma.cart.findFirst({
where: whereCondition,
include: {
items: {
include: {
product: {
select: {
id: true,
title: true,
imgSrc: true,
alt: true,
price: true,
isOnSale: true,
const data = await prisma.cart.findFirst({
where: whereCondition,
include: {
items: {
include: {
product: {
select: {
id: true,
title: true,
imgSrc: true,
alt: true,
price: true,
isOnSale: true,
},
},
},
},
orderBy: {
id: "asc",
orderBy: {
id: "asc",
},
},
},
},
});

if (!data) return null;
});

if (!data) return null;

return {
...data,
items: data.items.map((item) => ({
...item,
product: {
...item.product,
price: item.product.price.toNumber(),
},
})),
};
}catch(e) {
console.log(e)
return {
error: true,
status: 500,
message: "Error al obtener el carrito. Verifica el modelo Product.",
};
}

return {
...data,
items: data.items.map((item) => ({
...item,
product: {
...item.product,
price: item.product.price.toNumber(),
},
})),
};
}

export async function getRemoteCart(
Expand Down
48 changes: 38 additions & 10 deletions src/services/product.service.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,66 @@
import { prisma } from "@/db/prisma";
import type { Category } from "@/models/category.model";
import type { Product } from "@/models/product.model";
import type { Product, ProductVariantValue } from "@/models/product.model";
import type { VariantAttributeValue } from "@/models/variant-attribute.model";

import { getCategoryBySlug } from "./category.service";

const formattedProduct = (product: ProductVariantValue) => {
const {variantAttributeValues, ...rest} = product
const prices = variantAttributeValues.map((v: VariantAttributeValue) => Number(v.price))
const minPrice = Math.min(...prices)
const maxPrice = Math.max(...prices)
if (minPrice === maxPrice) {
return {
...rest,
price: minPrice
}
}
return {
...rest,
minPrice,
maxPrice
}
}

export async function getProductsByCategorySlug(
categorySlug: Category["slug"]
): Promise<Product[]> {
const category = await getCategoryBySlug(categorySlug);
const products = await prisma.product.findMany({
where: { categoryId: category.id },
include: {
variantAttributeValues: true
}
});

return products.map((product) => ({
...product,
price: product.price.toNumber(),
}));
return products.map(formattedProduct)
}

export async function getProductById(id: number): Promise<Product> {
const product = await prisma.product.findUnique({
where: { id },
include: {
variantAttributeValues: true
}
});

if (!product) {
throw new Error("Product not found");
}
const variants = product.variantAttributeValues.map((variant)=> ({
...variant,
price: Number(variant.price)
}))

return { ...product, price: product.price.toNumber() };
return {...product, variantAttributeValues: variants } as Product
}

export async function getAllProducts(): Promise<Product[]> {
return (await prisma.product.findMany()).map((p) => ({
...p,
price: p.price.toNumber(),
}));
const products = await prisma.product.findMany({
include: {
variantAttributeValues: true
}
});
return products.map(formattedProduct)
}