Добавлены модели и функциональность для работы с избранными товарами, включая мутации и запросы в GraphQL. Обновлены компоненты для отображения и управления избранным, улучшен интерфейс взаимодействия с пользователем. Реализована логика добавления и удаления товаров из избранного.

This commit is contained in:
Bivekich
2025-07-17 19:36:41 +03:00
parent f377fbab5f
commit 3d28051bde
12 changed files with 1074 additions and 141 deletions

View File

@ -817,4 +817,61 @@ export const CLEAR_CART = gql`
mutation ClearCart {
clearCart
}
`
// Мутации для избранного
export const ADD_TO_FAVORITES = gql`
mutation AddToFavorites($productId: ID!) {
addToFavorites(productId: $productId) {
success
message
favorites {
id
name
article
price
quantity
images
mainImage
category {
id
name
}
organization {
id
name
fullName
inn
}
}
}
}
`
export const REMOVE_FROM_FAVORITES = gql`
mutation RemoveFromFavorites($productId: ID!) {
removeFromFavorites(productId: $productId) {
success
message
favorites {
id
name
article
price
quantity
images
mainImage
category {
id
name
}
organization {
id
name
fullName
inn
}
}
}
}
`

View File

@ -436,4 +436,44 @@ export const GET_MY_CART = gql`
updatedAt
}
}
`
export const GET_MY_FAVORITES = gql`
query GetMyFavorites {
myFavorites {
id
name
article
description
price
quantity
brand
color
size
images
mainImage
isActive
createdAt
updatedAt
category {
id
name
}
organization {
id
inn
name
fullName
type
address
phones
emails
users {
id
avatar
managerName
}
}
}
}
`

View File

@ -638,6 +638,44 @@ export const resolvers = {
}
return cart
},
// Избранные товары пользователя
myFavorites: async (_: unknown, __: unknown, context: Context) => {
if (!context.user) {
throw new GraphQLError('Требуется авторизация', {
extensions: { code: 'UNAUTHENTICATED' }
})
}
const currentUser = await prisma.user.findUnique({
where: { id: context.user.id },
include: { organization: true }
})
if (!currentUser?.organization) {
throw new GraphQLError('У пользователя нет организации')
}
// Получаем избранные товары
const favorites = await prisma.favorites.findMany({
where: { organizationId: currentUser.organization.id },
include: {
product: {
include: {
category: true,
organization: {
include: {
users: true
}
}
}
}
},
orderBy: { createdAt: 'desc' }
})
return favorites.map(favorite => favorite.product)
}
},
@ -2844,6 +2882,165 @@ export const resolvers = {
console.error('Error clearing cart:', error)
return false
}
},
// Добавить товар в избранное
addToFavorites: async (_: unknown, args: { productId: string }, context: Context) => {
if (!context.user) {
throw new GraphQLError('Требуется авторизация', {
extensions: { code: 'UNAUTHENTICATED' }
})
}
const currentUser = await prisma.user.findUnique({
where: { id: context.user.id },
include: { organization: true }
})
if (!currentUser?.organization) {
throw new GraphQLError('У пользователя нет организации')
}
// Проверяем, что товар существует и активен
const product = await prisma.product.findFirst({
where: {
id: args.productId,
isActive: true
},
include: {
organization: true
}
})
if (!product) {
return {
success: false,
message: 'Товар не найден или неактивен'
}
}
// Проверяем, что пользователь не пытается добавить свой собственный товар
if (product.organizationId === currentUser.organization.id) {
return {
success: false,
message: 'Нельзя добавлять собственные товары в избранное'
}
}
try {
// Проверяем, есть ли уже такой товар в избранном
const existingFavorite = await prisma.favorites.findUnique({
where: {
organizationId_productId: {
organizationId: currentUser.organization.id,
productId: args.productId
}
}
})
if (existingFavorite) {
return {
success: false,
message: 'Товар уже в избранном'
}
}
// Добавляем товар в избранное
await prisma.favorites.create({
data: {
organizationId: currentUser.organization.id,
productId: args.productId
}
})
// Возвращаем обновленный список избранного
const favorites = await prisma.favorites.findMany({
where: { organizationId: currentUser.organization.id },
include: {
product: {
include: {
category: true,
organization: {
include: {
users: true
}
}
}
}
},
orderBy: { createdAt: 'desc' }
})
return {
success: true,
message: 'Товар добавлен в избранное',
favorites: favorites.map(favorite => favorite.product)
}
} catch (error) {
console.error('Error adding to favorites:', error)
return {
success: false,
message: 'Ошибка при добавлении в избранное'
}
}
},
// Удалить товар из избранного
removeFromFavorites: async (_: unknown, args: { productId: string }, context: Context) => {
if (!context.user) {
throw new GraphQLError('Требуется авторизация', {
extensions: { code: 'UNAUTHENTICATED' }
})
}
const currentUser = await prisma.user.findUnique({
where: { id: context.user.id },
include: { organization: true }
})
if (!currentUser?.organization) {
throw new GraphQLError('У пользователя нет организации')
}
try {
// Удаляем товар из избранного
await prisma.favorites.deleteMany({
where: {
organizationId: currentUser.organization.id,
productId: args.productId
}
})
// Возвращаем обновленный список избранного
const favorites = await prisma.favorites.findMany({
where: { organizationId: currentUser.organization.id },
include: {
product: {
include: {
category: true,
organization: {
include: {
users: true
}
}
}
}
},
orderBy: { createdAt: 'desc' }
})
return {
success: true,
message: 'Товар удален из избранного',
favorites: favorites.map(favorite => favorite.product)
}
} catch (error) {
console.error('Error removing from favorites:', error)
return {
success: false,
message: 'Ошибка при удалении из избранного'
}
}
}
},

View File

@ -40,6 +40,9 @@ export const typeDefs = gql`
# Корзина пользователя
myCart: Cart
# Избранные товары пользователя
myFavorites: [Product!]!
}
type Mutation {
@ -100,6 +103,10 @@ export const typeDefs = gql`
updateCartItem(productId: ID!, quantity: Int!): CartResponse!
removeFromCart(productId: ID!): CartResponse!
clearCart: Boolean!
# Работа с избранным
addToFavorites(productId: ID!): FavoritesResponse!
removeFromFavorites(productId: ID!): FavoritesResponse!
}
# Типы данных
@ -456,6 +463,13 @@ export const typeDefs = gql`
cart: Cart
}
# Типы для избранного
type FavoritesResponse {
success: Boolean!
message: String!
favorites: [Product!]
}
# JSON скаляр
scalar JSON
`