diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 9a7f678..c6ad710 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -143,11 +143,11 @@ model User { packages Package[] addresses Address[] wallet Wallet? + notifications Notification[] createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz() updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz() deletedAt DateTime? @map("deleted_at") @db.Timestamptz() - Notification Notification? @@map("users") } @@ -207,11 +207,11 @@ model VerificationStatus { model Notification { id String @id @default(uuid()) @db.Uuid - userId String @unique @map("user_id") @db.Uuid + userId String @map("user_id") @db.Uuid packageId String? @map("package_id") @db.Uuid tripId String? @map("trip_id") @db.Uuid content String @db.Text - isSeen Boolean @default(false) + unread Boolean @default(true) // Relations user User @relation(fields: [userId], references: [id], onDelete: Cascade) diff --git a/src/modules/dashboard/dashboard.dto.ts b/src/modules/dashboard/dashboard.dto.ts index 7a73481..3c6a70b 100644 --- a/src/modules/dashboard/dashboard.dto.ts +++ b/src/modules/dashboard/dashboard.dto.ts @@ -29,6 +29,9 @@ export class DashboardResponseDto { @Expose() totalWalletBalance: number; + + @Expose() + notificationCount: number; @Expose() role?: AuthRoles; diff --git a/src/modules/dashboard/dashboard.service.ts b/src/modules/dashboard/dashboard.service.ts index 1696162..d3683c0 100644 --- a/src/modules/dashboard/dashboard.service.ts +++ b/src/modules/dashboard/dashboard.service.ts @@ -20,7 +20,12 @@ export class DashboardService { ) {} async getDashboard(userId: string) { - const { transporter, wallet, role, ...user } = await this.prisma.user + const { + transporter, + wallet, + role, + ...user + } = await this.prisma.user .findFirstOrThrow({ where: { id: userId }, select: { @@ -42,9 +47,17 @@ export class DashboardService { }, }, role: true, + _count: { + select: { + notifications: { + where: { + unread: true + } + } + } + } }, - }) - .catch((error: Error) => { + }).catch((error: Error) => { formatPrismaError(error); throw error; }); @@ -84,6 +97,7 @@ export class DashboardService { experience, bio: transporter?.bio, statistics, + notificationCount: user._count.notifications }; } diff --git a/src/modules/financial/financial.service.ts b/src/modules/financial/financial.service.ts index 7ba1766..2bc11ce 100644 --- a/src/modules/financial/financial.service.ts +++ b/src/modules/financial/financial.service.ts @@ -20,7 +20,8 @@ export class FinancialService { tx: PrismaTransaction = this.prisma ) { const skip = (page - 1) * limit; - return tx.wallet.findUniqueOrThrow({ + + const wallet = await tx.wallet.findUniqueOrThrow({ where: { userId }, include: { transactions: { @@ -35,6 +36,18 @@ export class FinancialService { formatPrismaError(error); throw error; }); + + return { + ...wallet, + balance: wallet.balance.toString(), + totalEarned: wallet.totalEarned.toString(), + totalSpent: wallet.totalSpent.toString(), + transactions: wallet.transactions.map(transaction => ({ + ...transaction, + amount: transaction.amount.toString(), + balanceBefore: transaction.balanceBefore?.toString(), + })) + }; } async addFunds( @@ -62,7 +75,7 @@ export class FinancialService { walletId: wallet.id, transactionType: TransactionTypeEnum.deposit, amount: BigInt(amount), - balanceBefore: wallet.balance, + balanceBefore: BigInt(wallet.balance), reason: 'Funds added to wallet.', gatewayTransactionId } @@ -117,7 +130,7 @@ export class FinancialService { const finalPrice = matchedRequest.package.finalPrice; const senderWallet = await this.getWallet(senderId, 1, 0); - if (senderWallet.balance < BigInt(finalPrice)) { + if (Number(senderWallet.balance) < finalPrice) { throw new BadRequestException(BadRequestMessages.NotEnoughBalance); } @@ -142,7 +155,7 @@ export class FinancialService { walletId: senderWallet.id, transactionType: TransactionTypeEnum.escrow, amount: finalPrice, - balanceBefore: senderWallet.balance, + balanceBefore: BigInt(senderWallet.balance), reason: `Escrowed payment for package ${matchedRequest.package.id}.`, matchedRequestId: matchedRequest.id } @@ -153,7 +166,7 @@ export class FinancialService { walletId: transporterWallet.id, transactionType: TransactionTypeEnum.escrow, amount: matchedRequest.request.offeredPrice, - balanceBefore: transporterWallet.balance, + balanceBefore: BigInt(transporterWallet.balance), reason: `Escrowed payment for package ${matchedRequest.package.id}.`, matchedRequestId: matchedRequest.id } @@ -263,7 +276,7 @@ export class FinancialService { walletId: transporterWallet.id, transactionType: TransactionTypeEnum.release, amount: BigInt(transporterEarnings), - balanceBefore: transporterWallet.balance, + balanceBefore: BigInt(transporterWallet.balance), reason: `Payment received for package ${matchedRequest.packageId}.`, matchedRequestId: matchedRequest.id, } diff --git a/src/modules/notification/notification.service.ts b/src/modules/notification/notification.service.ts index cd7f33b..296091d 100644 --- a/src/modules/notification/notification.service.ts +++ b/src/modules/notification/notification.service.ts @@ -1,6 +1,7 @@ import { Injectable } from '@nestjs/common'; import { PrismaService } from '../prisma/prisma.service'; import { PrismaTransaction } from '../prisma/prisma.types'; +import { formatPrismaError } from 'src/common/utilities'; @Injectable() export class NotificationService { @@ -35,13 +36,26 @@ export class NotificationService { limit = 10 ) { const skip = (page - 1) * limit; - return this.prisma.notification.findMany({ - where: { userId }, - orderBy: { - createdAt: 'desc' - }, - skip, - take: limit + return this.prisma.$transaction(async tx => { + // Update notifications => unread: true + await tx.notification.updateMany({ + where: { userId }, + data: { + unread: false + } + }); + + return this.prisma.notification.findMany({ + where: { userId }, + orderBy: { + createdAt: 'desc' + }, + skip, + take: limit + }); + }).catch((error: Error) => { + formatPrismaError(error); + throw error; }); } } diff --git a/src/modules/trip/trip.service.ts b/src/modules/trip/trip.service.ts index 432a24c..a6bcb8c 100644 --- a/src/modules/trip/trip.service.ts +++ b/src/modules/trip/trip.service.ts @@ -851,7 +851,8 @@ export class TripService { async finishTrip(id: string) { const { status: tripStatus, - matchedRequests + matchedRequests, + transporter } = await this.prisma.trip.findUniqueOrThrow({ where: { id }, select: { @@ -860,6 +861,12 @@ export class TripService { select: { deliveryTime: true } + }, + transporter: { + select: { + id: true, + firstTripDate: true, + } } } }).catch((error: Error) => { @@ -876,7 +883,22 @@ export class TripService { throw new BadRequestException(BadRequestMessages.CannotFinishTrip); } - return this.updateStatus(id, TripStatusEnum.completed); + // Update firstTripDate/lastTripDate + const updateTransporter: Prisma.TransporterUpdateInput = {}; + if (!transporter.firstTripDate) { + updateTransporter.firstTripDate = new Date(); + } else { + updateTransporter.lastTripDate = new Date(); + } + + return this.prisma.$transaction(async tx => { + tx.transporter.update({ + where: { id: transporter.id }, + data: updateTransporter + }); + + return this.updateStatus(id, TripStatusEnum.completed, tx); + }); } async addTripNote(