Skip to content

Commit b3495cc

Browse files
committed
refactor: update cart and product models to use Prisma types and streamline cart service functions
1 parent 62958de commit b3495cc

File tree

4 files changed

+127
-121
lines changed

4 files changed

+127
-121
lines changed

src/models/cart.model.ts

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,18 @@
11
import { type Product } from "./product.model";
2-
import { type User } from "./user.model";
32

4-
export interface CartItem {
5-
id: number;
3+
import type {
4+
Cart as PrismaCart,
5+
CartItem as PrismaCartItem,
6+
} from "generated/prisma/client";
7+
8+
export type CartItem = PrismaCartItem & {
69
product: Pick<
710
Product,
811
"id" | "title" | "imgSrc" | "alt" | "price" | "isOnSale"
912
>;
10-
quantity: number;
11-
createdAt: string;
12-
updatedAt: string;
13-
}
13+
};
1414

15-
export interface Cart {
16-
id: number;
17-
userId: User["id"] | null;
18-
sessionCartId: string;
19-
items: CartItem[];
20-
createdAt: string;
21-
updatedAt: string;
22-
}
15+
export type Cart = PrismaCart;
2316

2417
export interface CartItemInput {
2518
productId: Product["id"];
@@ -28,3 +21,21 @@ export interface CartItemInput {
2821
price: Product["price"];
2922
imgSrc: Product["imgSrc"];
3023
}
24+
25+
// Tipo para representar un producto simplificado en el carrito
26+
27+
export type CartProductInfo = Pick<
28+
Product,
29+
"id" | "title" | "imgSrc" | "alt" | "price" | "isOnSale"
30+
>;
31+
32+
// Tipo para representar un item de carrito con su producto
33+
export type CartItemWithProduct = {
34+
product: CartProductInfo;
35+
quantity: number;
36+
};
37+
38+
// Tipo para el carrito con items y productos incluidos
39+
export type CartWithItems = Cart & {
40+
items: CartItem[];
41+
};

src/models/product.model.ts

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,5 @@
1-
// import { type Category } from "./category.model";
2-
31
import type { Product as PrismaProduct } from "generated/prisma/client";
42

5-
// export interface Product {
6-
// id: number;
7-
// title: string;
8-
// imgSrc: string;
9-
// alt: string | null;
10-
// price: number;
11-
// description: string | null;
12-
// categoryId: number;
13-
// // categorySlug: Category["slug"];
14-
// isOnSale: boolean;
15-
// features: string[];
16-
// createdAt: string;
17-
// updatedAt: string;
18-
// }
19-
203
export type Product = Omit<PrismaProduct, "price"> & {
214
price: number;
225
};

src/routes/root/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {
1717
Separator,
1818
} from "@/components/ui";
1919
import { getCart } from "@/lib/cart";
20-
import type { Cart } from "@/models/cart.model";
20+
import type { CartWithItems } from "@/models/cart.model";
2121
import { getCurrentUser } from "@/services/auth.service";
2222
import { createRemoteItems } from "@/services/cart.service";
2323
import { commitSession, getSession } from "@/session.server";
@@ -45,7 +45,7 @@ export async function action({ request }: Route.ActionArgs) {
4545
export async function loader({ request }: Route.LoaderArgs) {
4646
const session = await getSession(request.headers.get("Cookie"));
4747
const sessionCartId = session.get("sessionCartId");
48-
let cart: Cart | null = null;
48+
let cart: CartWithItems | null = null;
4949

5050
// Obtenemos el usuario actual (autenticado o no)
5151
const user = await getCurrentUser(request);

src/services/cart.service.ts

Lines changed: 99 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,25 @@
1-
import { type Cart, type CartItem, type User } from "generated/prisma/client";
2-
31
import { prisma } from "@/db/prisma";
2+
import type { CartItemWithProduct, CartWithItems } from "@/models/cart.model";
3+
import type { User } from "@/models/user.model";
44
import { getSession } from "@/session.server";
55

6-
import type { Decimal } from "@prisma/client/runtime/library";
7-
8-
// Tipo para representar un producto simplificado en el carrito
9-
type CartProductInfo = {
10-
id: number;
11-
title: string;
12-
imgSrc: string;
13-
alt: string | null;
14-
price: Decimal;
15-
isOnSale: boolean;
16-
};
17-
18-
// Tipo para representar un item de carrito con su producto
19-
type CartItemWithProduct = {
20-
product: CartProductInfo;
21-
quantity: number;
22-
};
23-
24-
// Tipo para el carrito con items y productos incluidos
25-
type CartWithItems = Cart & {
26-
items: Array<CartItem & {
27-
product: CartProductInfo
28-
}>
29-
};
30-
316
// Función para obtener un carrito con sus ítems
327
async function getCart(
338
userId?: number,
349
sessionCartId?: string,
3510
id?: number
3611
): Promise<CartWithItems | null> {
37-
const whereCondition = userId
38-
? { userId }
39-
: sessionCartId
40-
? { sessionCartId }
41-
: id
42-
? { id }
43-
: undefined;
12+
const whereCondition = userId
13+
? { userId }
14+
: sessionCartId
15+
? { sessionCartId }
16+
: id
17+
? { id }
18+
: undefined;
4419

4520
if (!whereCondition) return null;
4621

47-
return await prisma.cart.findFirst({
22+
const data = await prisma.cart.findFirst({
4823
where: whereCondition,
4924
include: {
5025
items: {
@@ -66,47 +41,74 @@ async function getCart(
6641
},
6742
},
6843
});
44+
45+
if (!data) return null;
46+
47+
return {
48+
...data,
49+
items: data.items.map((item) => ({
50+
...item,
51+
product: {
52+
...item.product,
53+
price: item.product.price.toNumber(),
54+
},
55+
})),
56+
};
6957
}
7058

71-
export async function getRemoteCart(userId: User["id"]): Promise<CartWithItems | null> {
59+
export async function getRemoteCart(
60+
userId: User["id"]
61+
): Promise<CartWithItems | null> {
7262
return await getCart(userId);
7363
}
7464

7565
export async function getOrCreateCart(
7666
userId: User["id"] | undefined,
7767
sessionCartId: string | undefined
7868
): Promise<CartWithItems> {
79-
let cart = await getCart(userId, sessionCartId);
69+
const cart = await getCart(userId, sessionCartId);
70+
71+
if (cart) {
72+
return cart;
73+
}
8074

8175
// Si no se encontró un carrito creamos uno nuevo
82-
if (!cart) {
83-
// Creamos un carrito con userId si se proporciona
84-
cart = await prisma.cart.create({
85-
data: {
86-
userId: userId || null,
87-
},
88-
include: {
89-
items: {
90-
include: {
91-
product: {
92-
select: {
93-
id: true,
94-
title: true,
95-
imgSrc: true,
96-
alt: true,
97-
price: true,
98-
isOnSale: true,
99-
},
76+
77+
// Creamos un carrito con userId si se proporciona
78+
const newCart = await prisma.cart.create({
79+
data: {
80+
userId: userId || null,
81+
},
82+
include: {
83+
items: {
84+
include: {
85+
product: {
86+
select: {
87+
id: true,
88+
title: true,
89+
imgSrc: true,
90+
alt: true,
91+
price: true,
92+
isOnSale: true,
10093
},
10194
},
10295
},
10396
},
104-
});
105-
}
97+
},
98+
});
10699

107-
if (!cart) throw new Error("Failed to create cart");
100+
if (!newCart) throw new Error("Failed to create cart");
108101

109-
return cart;
102+
return {
103+
...newCart,
104+
items: newCart.items.map((item) => ({
105+
...item,
106+
product: {
107+
...item.product,
108+
price: item.product.price.toNumber(),
109+
},
110+
})),
111+
};
110112
}
111113

112114
export async function createRemoteItems(
@@ -126,10 +128,10 @@ export async function createRemoteItems(
126128
// Si hay elementos para agregar, agregarlos
127129
if (items.length > 0) {
128130
await prisma.cartItem.createMany({
129-
data: items.map(item => ({
131+
data: items.map((item) => ({
130132
cartId: cart.id,
131133
productId: item.product.id,
132-
quantity: item.quantity
134+
quantity: item.quantity,
133135
})),
134136
});
135137
}
@@ -174,11 +176,7 @@ export async function alterQuantityCartItem(
174176
});
175177
}
176178

177-
const updatedCart = await getCart(
178-
userId,
179-
cart.sessionCartId,
180-
cart.id
181-
);
179+
const updatedCart = await getCart(userId, cart.sessionCartId, cart.id);
182180

183181
if (!updatedCart) throw new Error("Cart not found after update");
184182

@@ -213,12 +211,12 @@ export async function deleteRemoteCart(request: Request): Promise<void> {
213211
const cart = await getCart(userId, sessionCartId);
214212

215213
if (!cart) throw new Error("Cart not found");
216-
214+
217215
// Eliminar todos los items del carrito primero
218-
await prisma.cartItem.deleteMany({
219-
where: { cartId: cart.id },
220-
});
221-
216+
// await prisma.cartItem.deleteMany({
217+
// where: { cartId: cart.id },
218+
// });
219+
222220
// Luego eliminar el carrito
223221
await prisma.cart.delete({
224222
where: { id: cart.id },
@@ -255,7 +253,16 @@ export async function linkCartToUser(
255253

256254
if (!updatedCart) throw new Error("Cart not found after linking");
257255

258-
return updatedCart;
256+
return {
257+
...updatedCart,
258+
items: updatedCart.items.map((item) => ({
259+
...item,
260+
product: {
261+
...item.product,
262+
price: item.product.price.toNumber(),
263+
},
264+
})),
265+
};
259266
}
260267

261268
export async function mergeGuestCartWithUserCart(
@@ -292,12 +299,21 @@ export async function mergeGuestCartWithUserCart(
292299
},
293300
},
294301
});
295-
return updatedCart;
302+
return {
303+
...updatedCart,
304+
items: updatedCart.items.map((item) => ({
305+
...item,
306+
product: {
307+
...item.product,
308+
price: item.product.price.toNumber(),
309+
},
310+
})),
311+
};
296312
}
297313

298314
// Obtener productos duplicados para eliminarlos del carrito del usuario
299-
const guestProductIds = guestCart.items.map(item => item.productId);
300-
315+
const guestProductIds = guestCart.items.map((item) => item.productId);
316+
301317
// Eliminar productos del carrito usuario que también existan en el carrito invitado
302318
await prisma.cartItem.deleteMany({
303319
where: {
@@ -309,17 +325,13 @@ export async function mergeGuestCartWithUserCart(
309325
});
310326

311327
// Mover los items del carrito de invitado al carrito de usuario
312-
await Promise.all(
313-
guestCart.items.map(async (item) => {
314-
return prisma.cartItem.create({
315-
data: {
316-
cartId: userCart.id,
317-
productId: item.productId,
318-
quantity: item.quantity,
319-
},
320-
});
321-
})
322-
);
328+
await prisma.cartItem.createMany({
329+
data: guestCart.items.map((item) => ({
330+
cartId: userCart.id,
331+
productId: item.productId,
332+
quantity: item.quantity,
333+
})),
334+
});
323335

324336
// Eliminar el carrito de invitado
325337
await prisma.cart.delete({
@@ -328,4 +340,4 @@ export async function mergeGuestCartWithUserCart(
328340

329341
// Devolver el carrito actualizado del usuario
330342
return await getCart(userId);
331-
}
343+
}

0 commit comments

Comments
 (0)