diff --git a/apps/backend/package.json b/apps/backend/package.json index a916cf70..29667979 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -63,22 +63,14 @@ "typescript": "^5.7.3" }, "jest": { - "moduleFileExtensions": [ - "js", - "json", - "ts" - ], + "moduleFileExtensions": ["js", "json", "ts"], "rootDir": "./", - "modulePaths": [ - "" - ], + "modulePaths": [""], "testRegex": ".*\\.spec\\.ts$", "transform": { "^.+\\.(t|j)s$": "ts-jest" }, - "collectCoverageFrom": [ - "**/*.(t|j)s" - ], + "collectCoverageFrom": ["**/*.(t|j)s"], "coverageDirectory": "../coverage", "testEnvironment": "node" }, diff --git a/apps/backend/src/core/core.module.ts b/apps/backend/src/core/core.module.ts index 917de9fe..171398c5 100644 --- a/apps/backend/src/core/core.module.ts +++ b/apps/backend/src/core/core.module.ts @@ -3,15 +3,16 @@ import { Module } from "@nestjs/common"; import { ConfigModule, ConfigService } from "@nestjs/config"; import { GraphQLModule } from "@nestjs/graphql"; +import { AuthModule } from "src/auth/auth.module"; import { CategoryModule } from "src/modules/categories/category.module"; import { ProductImageModule } from "src/modules/product-image/product-image.module"; import { ProductModule } from "src/modules/product/product.module"; import { UsersModule } from "src/modules/users/users.module"; import { IS_DEV_ENV } from "src/shared/utils/is-dev.util"; +import { MessageModule } from "../modules/message/message.module"; import { getGraphQLConfig } from "./config/graphql.config"; import { PrismaModule } from "./prisma/prisma.module"; -import { AuthModule } from "src/auth/auth.module"; @Module({ imports: [ AuthModule, @@ -30,6 +31,7 @@ import { AuthModule } from "src/auth/auth.module"; ProductModule, ProductImageModule, UsersModule, + MessageModule, ], controllers: [], providers: [], diff --git a/apps/backend/src/core/graphql/schema.gql b/apps/backend/src/core/graphql/schema.gql index 3248a1fa..e1bed4d4 100644 --- a/apps/backend/src/core/graphql/schema.gql +++ b/apps/backend/src/core/graphql/schema.gql @@ -3,33 +3,39 @@ # ------------------------------------------------------ type Category { - createdAt: DateTime! - id: ID! - imageUrl: String - name: String! - updatedAt: DateTime! + createdAt: DateTime! + id: ID! + imageUrl: String + name: String! + updatedAt: DateTime! } input CreateCategoryInput { - name: String! + name: String! +} + +input CreateMessageInput { + content: String! + orderId: String! + senderAddress: String! } input CreateProductInput { - categoryId: String! - description: String - name: String! - price: Float! - slug: String! + categoryId: String! + description: String + name: String! + price: Float! + slug: String! } input CreateUserInput { - country: String! - email: String! - isSeller: Boolean! = false - name: String! - surname: String! - telegramUsername: String - walletAddress: String! + country: String! + email: String! + isSeller: Boolean! = false + name: String! + surname: String! + telegramUsername: String + walletAddress: String! } """ @@ -37,67 +43,78 @@ A date-time string at UTC, such as 2019-12-03T09:54:33Z, compliant with the date """ scalar DateTime +type Message { + content: String! + createdAt: DateTime! + id: ID! + orderId: String! + senderAddress: String! + updatedAt: DateTime! +} + type Mutation { - createCategory(data: CreateCategoryInput!): Category! - createProduct(data: CreateProductInput!): ProductDTO! - createProductImage(createProductImage: ProductImageDTO!): ProductImage! - createUser(data: CreateUserInput!): User! - updateUser(data: UpdateUserInput!, walletAddress: String!): User! + createCategory(data: CreateCategoryInput!): Category! + createProduct(data: CreateProductInput!): ProductDTO! + createProductImage(createProductImage: ProductImageDTO!): ProductImage! + createUser(data: CreateUserInput!): User! + sendMessage(data: CreateMessageInput!): Message! + updateUser(data: UpdateUserInput!, walletAddress: String!): User! } type ProductDTO { - categoryId: String! - createdAt: DateTime! - description: String - id: ID! - name: String! - price: Float! - slug: String! - updatedAt: DateTime! + categoryId: String! + createdAt: DateTime! + description: String + id: ID! + name: String! + price: Float! + slug: String! + updatedAt: DateTime! } type ProductImage { - createdAt: DateTime! - id: ID! - imageUrl: String! - productId: String! - updatedAt: DateTime! + createdAt: DateTime! + id: ID! + imageUrl: String! + productId: String! + updatedAt: DateTime! } input ProductImageDTO { - imageUrl: String! - productId: String! + imageUrl: String! + productId: String! } type Query { - categories: [Category!]! - category(id: String!): Category - product(id: String!): ProductDTO - productImage(id: String!): ProductImage - productImages: [ProductImage!]! - products: [ProductDTO!]! - user(walletAddress: String!): User - users: [User!]! + categories: [Category!]! + category(id: String!): Category + getMessagesByOrder(orderId: String!): [Message!]! + product(id: String!): ProductDTO + productImage(id: String!): ProductImage + productImages: [ProductImage!]! + products: [ProductDTO!]! + user(walletAddress: String!): User + users: [User!]! } input UpdateUserInput { - country: String - email: String - isSeller: Boolean = false - name: String - surname: String - telegramUsername: String - walletAddress: String + country: String + email: String + isSeller: Boolean = false + name: String + surname: String + telegramUsername: String + walletAddress: String } type User { - country: String! - createdAt: DateTime! - email: String! - isSeller: Boolean! - name: String! - surname: String! - telegramUsername: String - updatedAt: DateTime! - walletAddress: String! -} \ No newline at end of file + country: String! + createdAt: DateTime! + email: String! + isSeller: Boolean! + name: String! + surname: String! + telegramUsername: String + updatedAt: DateTime! + walletAddress: String! +} diff --git a/apps/backend/src/modules/message/dto/create-message.input.ts b/apps/backend/src/modules/message/dto/create-message.input.ts index 8c70b43a..2dc8ea41 100644 --- a/apps/backend/src/modules/message/dto/create-message.input.ts +++ b/apps/backend/src/modules/message/dto/create-message.input.ts @@ -1,13 +1,13 @@ -import { InputType, Int, Field } from '@nestjs/graphql'; +import { Field, InputType, Int } from "@nestjs/graphql"; @InputType() export class CreateMessageInput { - @Field() - orderId: string; + @Field() + orderId: string; - @Field() - senderAddress: string; + @Field() + senderAddress: string; - @Field() - content: string; + @Field() + content: string; } diff --git a/apps/backend/src/modules/message/dto/update-message.input.ts b/apps/backend/src/modules/message/dto/update-message.input.ts index c9747d55..23a314c0 100644 --- a/apps/backend/src/modules/message/dto/update-message.input.ts +++ b/apps/backend/src/modules/message/dto/update-message.input.ts @@ -1,8 +1,8 @@ -import { CreateMessageInput } from './create-message.input'; -import { InputType, Field, Int, PartialType } from '@nestjs/graphql'; +import { Field, InputType, Int, PartialType } from "@nestjs/graphql"; +import { CreateMessageInput } from "./create-message.input"; @InputType() export class UpdateMessageInput extends PartialType(CreateMessageInput) { - @Field(() => Int) - id: number; + @Field(() => Int) + id: number; } diff --git a/apps/backend/src/modules/message/entities/message.entity.ts b/apps/backend/src/modules/message/entities/message.entity.ts index 55f14f44..896191e7 100644 --- a/apps/backend/src/modules/message/entities/message.entity.ts +++ b/apps/backend/src/modules/message/entities/message.entity.ts @@ -1,22 +1,22 @@ -import { ObjectType, Field, Int, ID } from '@nestjs/graphql'; +import { Field, ID, Int, ObjectType } from "@nestjs/graphql"; @ObjectType() export class Message { - @Field(() => ID) - id: string; + @Field(() => ID) + id: string; - @Field() - orderId: string; + @Field() + orderId: string; - @Field() - senderAddress: string; + @Field() + senderAddress: string; - @Field() - content: string; + @Field() + content: string; - @Field() - createdAt: Date; + @Field() + createdAt: Date; - @Field() - updatedAt: Date; + @Field() + updatedAt: Date; } diff --git a/apps/backend/src/modules/message/message.module.ts b/apps/backend/src/modules/message/message.module.ts index ada0cc93..133249a5 100644 --- a/apps/backend/src/modules/message/message.module.ts +++ b/apps/backend/src/modules/message/message.module.ts @@ -1,11 +1,9 @@ -import { Module } from '@nestjs/common'; -import { MessageService } from './message.service'; -import { MessageResolver } from './message.resolver'; -import { PrismaService } from 'src/core/prisma/prisma.service'; +import { Module } from "@nestjs/common"; +import { PrismaService } from "src/core/prisma/prisma.service"; +import { MessageResolver } from "./message.resolver"; +import { MessageService } from "./message.service"; @Module({ - providers: [MessageResolver, MessageService, PrismaService], + providers: [MessageResolver, MessageService, PrismaService], }) export class MessageModule {} - - diff --git a/apps/backend/src/modules/message/message.resolver.spec.ts b/apps/backend/src/modules/message/message.resolver.spec.ts index 0c307b73..66a74bbd 100644 --- a/apps/backend/src/modules/message/message.resolver.spec.ts +++ b/apps/backend/src/modules/message/message.resolver.spec.ts @@ -1,88 +1,94 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { MessageResolver } from './message.resolver'; -import { MessageService } from './message.service'; -import { CreateMessageInput } from './dto/create-message.input'; +import { Test, TestingModule } from "@nestjs/testing"; +import { CreateMessageInput } from "./dto/create-message.input"; +import { MessageResolver } from "./message.resolver"; +import { MessageService } from "./message.service"; -describe('MessageResolver', () => { - let resolver: MessageResolver; - let messageService: MessageService; +describe("MessageResolver", () => { + let resolver: MessageResolver; + let messageService: MessageService; - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [ - MessageResolver, - { - provide: MessageService, - useValue: { - getMessagesByOrder: jest.fn(), - sendMessage: jest.fn(), - }, - }, - ], - }).compile(); + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + MessageResolver, + { + provide: MessageService, + useValue: { + getMessagesByOrder: jest.fn(), + sendMessage: jest.fn(), + }, + }, + ], + }).compile(); - resolver = module.get(MessageResolver); - messageService = module.get(MessageService); - }); + resolver = module.get(MessageResolver); + messageService = module.get(MessageService); + }); - it('should be defined', () => { - expect(resolver).toBeDefined(); - }); + it("should be defined", () => { + expect(resolver).toBeDefined(); + }); - describe('getMessagesByOrder', () => { - it('should return messages for a given order', async () => { - const orderId = 'order-id'; - const mockMessages = [ - { - id: 'message-id-1', - orderId: orderId, - senderAddress: 'user-address', - content: 'Test content 1', - createdAt: new Date(), - updatedAt: new Date(), - }, - { - id: 'message-id-2', - orderId: orderId, - senderAddress: 'user-address', - content: 'Test content 2', - createdAt: new Date(), - updatedAt: new Date(), - }, - ]; + describe("getMessagesByOrder", () => { + it("should return messages for a given order", async () => { + const orderId = "order-id"; + const mockMessages = [ + { + id: "message-id-1", + orderId: orderId, + senderAddress: "user-address", + content: "Test content 1", + createdAt: new Date(), + updatedAt: new Date(), + }, + { + id: "message-id-2", + orderId: orderId, + senderAddress: "user-address", + content: "Test content 2", + createdAt: new Date(), + updatedAt: new Date(), + }, + ]; - (messageService.getMessagesByOrder as jest.Mock).mockResolvedValue(mockMessages); + (messageService.getMessagesByOrder as jest.Mock).mockResolvedValue( + mockMessages, + ); - const result = await resolver.getMessagesByOrder(orderId); + const result = await resolver.getMessagesByOrder(orderId); - expect(result).toEqual(mockMessages); - expect(messageService.getMessagesByOrder).toHaveBeenCalledWith(orderId); - }); - }); + expect(result).toEqual(mockMessages); + expect(messageService.getMessagesByOrder).toHaveBeenCalledWith(orderId); + }); + }); - describe('sendMessage', () => { - it('should send a new message and return it', async () => { - const createMessageInput: CreateMessageInput = { - orderId: 'order-id', - senderAddress: 'user-address', - content: 'Test content', - }; + describe("sendMessage", () => { + it("should send a new message and return it", async () => { + const createMessageInput: CreateMessageInput = { + orderId: "order-id", + senderAddress: "user-address", + content: "Test content", + }; - const mockCreatedMessage = { - id: 'message-id', - orderId: createMessageInput.orderId, - senderAddress: createMessageInput.senderAddress, - content: createMessageInput.content, - createdAt: new Date(), - updatedAt: new Date(), - }; + const mockCreatedMessage = { + id: "message-id", + orderId: createMessageInput.orderId, + senderAddress: createMessageInput.senderAddress, + content: createMessageInput.content, + createdAt: new Date(), + updatedAt: new Date(), + }; - (messageService.sendMessage as jest.Mock).mockResolvedValue(mockCreatedMessage); + (messageService.sendMessage as jest.Mock).mockResolvedValue( + mockCreatedMessage, + ); - const result = await resolver.sendMessage(createMessageInput); + const result = await resolver.sendMessage(createMessageInput); - expect(result).toEqual(mockCreatedMessage); - expect(messageService.sendMessage).toHaveBeenCalledWith(createMessageInput); - }); - }); + expect(result).toEqual(mockCreatedMessage); + expect(messageService.sendMessage).toHaveBeenCalledWith( + createMessageInput, + ); + }); + }); }); diff --git a/apps/backend/src/modules/message/message.resolver.ts b/apps/backend/src/modules/message/message.resolver.ts index b48107c8..a2ca901a 100644 --- a/apps/backend/src/modules/message/message.resolver.ts +++ b/apps/backend/src/modules/message/message.resolver.ts @@ -1,21 +1,19 @@ -import { Resolver, Query, Mutation, Args } from '@nestjs/graphql'; -import { MessageService } from './message.service'; -import { Message } from './entities/message.entity'; -import { CreateMessageInput } from './dto/create-message.input'; +import { Args, Mutation, Query, Resolver } from "@nestjs/graphql"; +import { CreateMessageInput } from "./dto/create-message.input"; +import { Message } from "./entities/message.entity"; +import { MessageService } from "./message.service"; @Resolver(() => Message) export class MessageResolver { - constructor(private readonly messageService: MessageService) {} + constructor(private readonly messageService: MessageService) {} - @Query(() => [Message]) - async getMessagesByOrder(@Args('orderId') orderId: string) { - return this.messageService.getMessagesByOrder(orderId); - } - - @Mutation(() => Message) - async sendMessage(@Args('data') data: CreateMessageInput) { - return this.messageService.sendMessage(data); - } + @Query(() => [Message]) + async getMessagesByOrder(@Args("orderId") orderId: string) { + return this.messageService.getMessagesByOrder(orderId); + } + @Mutation(() => Message) + async sendMessage(@Args("data") data: CreateMessageInput) { + return this.messageService.sendMessage(data); + } } - diff --git a/apps/backend/src/modules/message/message.service.spec.ts b/apps/backend/src/modules/message/message.service.spec.ts index 727c4c87..0e39af44 100644 --- a/apps/backend/src/modules/message/message.service.spec.ts +++ b/apps/backend/src/modules/message/message.service.spec.ts @@ -1,97 +1,101 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { MessageService } from './message.service'; -import { PrismaService } from 'src/core/prisma/prisma.service'; -import { CreateMessageInput } from './dto/create-message.input'; +import { Test, TestingModule } from "@nestjs/testing"; +import { PrismaService } from "src/core/prisma/prisma.service"; +import { CreateMessageInput } from "./dto/create-message.input"; +import { MessageService } from "./message.service"; -describe('MessageService', () => { - let service: MessageService; - let prismaService: PrismaService; +describe("MessageService", () => { + let service: MessageService; + let prismaService: PrismaService; - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [ - MessageService, - { - provide: PrismaService, - useValue: { - message: { - create: jest.fn(), - findMany: jest.fn(), - }, - }, - }, - ], - }).compile(); + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + MessageService, + { + provide: PrismaService, + useValue: { + message: { + create: jest.fn(), + findMany: jest.fn(), + }, + }, + }, + ], + }).compile(); - service = module.get(MessageService); - prismaService = module.get(PrismaService); - }); + service = module.get(MessageService); + prismaService = module.get(PrismaService); + }); - describe('sendMessage', () => { - it('should send a new message and return it', async () => { - const createMessageInput: CreateMessageInput = { - orderId: 'order-id', - senderAddress: 'user-address', - content: 'Test content', - }; + describe("sendMessage", () => { + it("should send a new message and return it", async () => { + const createMessageInput: CreateMessageInput = { + orderId: "order-id", + senderAddress: "user-address", + content: "Test content", + }; - const mockCreatedMessage = { - id: 'message-id', - orderId: createMessageInput.orderId, - senderAddress: createMessageInput.senderAddress, - content: createMessageInput.content, - createdAt: new Date(), - updatedAt: new Date(), - }; + const mockCreatedMessage = { + id: "message-id", + orderId: createMessageInput.orderId, + senderAddress: createMessageInput.senderAddress, + content: createMessageInput.content, + createdAt: new Date(), + updatedAt: new Date(), + }; - // Mocking prismaService.message.create - (prismaService.message.create as jest.Mock).mockResolvedValue(mockCreatedMessage); + // Mocking prismaService.message.create + (prismaService.message.create as jest.Mock).mockResolvedValue( + mockCreatedMessage, + ); - const result = await service.sendMessage(createMessageInput); + const result = await service.sendMessage(createMessageInput); - // Assertions - expect(result).toEqual(mockCreatedMessage); - expect(prismaService.message.create).toHaveBeenCalledWith({ - data: { - orderId: createMessageInput.orderId, - senderAddress: createMessageInput.senderAddress, - content: createMessageInput.content, - }, - }); - }); - }); + // Assertions + expect(result).toEqual(mockCreatedMessage); + expect(prismaService.message.create).toHaveBeenCalledWith({ + data: { + orderId: createMessageInput.orderId, + senderAddress: createMessageInput.senderAddress, + content: createMessageInput.content, + }, + }); + }); + }); - describe('getMessagesByOrder', () => { - it('should return all messages for a given order', async () => { - const orderId = 'order-id'; - const mockMessages = [ - { - id: 'message-id-1', - orderId: orderId, - senderAddress: 'user-address', - content: 'Test content 1', - createdAt: new Date(), - updatedAt: new Date(), - }, - { - id: 'message-id-2', - orderId: orderId, - senderAddress: 'user-address', - content: 'Test content 2', - createdAt: new Date(), - updatedAt: new Date(), - }, - ]; + describe("getMessagesByOrder", () => { + it("should return all messages for a given order", async () => { + const orderId = "order-id"; + const mockMessages = [ + { + id: "message-id-1", + orderId: orderId, + senderAddress: "user-address", + content: "Test content 1", + createdAt: new Date(), + updatedAt: new Date(), + }, + { + id: "message-id-2", + orderId: orderId, + senderAddress: "user-address", + content: "Test content 2", + createdAt: new Date(), + updatedAt: new Date(), + }, + ]; - // Mocking prismaService.message.findMany - (prismaService.message.findMany as jest.Mock).mockResolvedValue(mockMessages); + // Mocking prismaService.message.findMany + (prismaService.message.findMany as jest.Mock).mockResolvedValue( + mockMessages, + ); - const result = await service.getMessagesByOrder(orderId); - expect(result).toEqual(mockMessages); - expect(prismaService.message.findMany).toHaveBeenCalledWith({ - where: { orderId: orderId }, - orderBy: { createdAt: 'asc' }, - }); - }); - }); + const result = await service.getMessagesByOrder(orderId); + expect(result).toEqual(mockMessages); + expect(prismaService.message.findMany).toHaveBeenCalledWith({ + where: { orderId: orderId }, + orderBy: { createdAt: "asc" }, + }); + }); + }); }); diff --git a/apps/backend/src/modules/message/message.service.ts b/apps/backend/src/modules/message/message.service.ts index 631dda0d..be507f80 100644 --- a/apps/backend/src/modules/message/message.service.ts +++ b/apps/backend/src/modules/message/message.service.ts @@ -1,27 +1,25 @@ -import { Injectable } from '@nestjs/common'; -import { CreateMessageInput } from './dto/create-message.input'; -import { PrismaService } from 'src/core/prisma/prisma.service'; +import { Injectable } from "@nestjs/common"; +import { PrismaService } from "src/core/prisma/prisma.service"; +import { CreateMessageInput } from "./dto/create-message.input"; @Injectable() export class MessageService { - constructor(private readonly prisma: PrismaService) {} + constructor(private readonly prisma: PrismaService) {} - async sendMessage(data: CreateMessageInput) { - return this.prisma.message.create({ - data: { - orderId: data.orderId, - senderAddress: data.senderAddress, - content: data.content, - }, - }); - } - - async getMessagesByOrder(orderId: string) { - return this.prisma.message.findMany({ - where: { orderId: orderId }, - orderBy: { createdAt: 'asc' }, - }); - } + async sendMessage(data: CreateMessageInput) { + return this.prisma.message.create({ + data: { + orderId: data.orderId, + senderAddress: data.senderAddress, + content: data.content, + }, + }); + } + async getMessagesByOrder(orderId: string) { + return this.prisma.message.findMany({ + where: { orderId: orderId }, + orderBy: { createdAt: "asc" }, + }); + } } - diff --git a/apps/frontend/components/home/featured-products.tsx b/apps/frontend/components/home/featured-products.tsx index 5ee044e5..9a5865ca 100644 --- a/apps/frontend/components/home/featured-products.tsx +++ b/apps/frontend/components/home/featured-products.tsx @@ -29,7 +29,7 @@ export function FeaturedProducts() {

- {t("common.featuredProductsTitle.title")} + {t("common.featuredProductsTitle.title")}