update
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { Module, forwardRef } from '@nestjs/common';
|
||||
import { AdminService } from './providers/admin.service';
|
||||
import { MikroOrmModule } from '@mikro-orm/nestjs';
|
||||
import { Admin } from './entities/admin.entity';
|
||||
@@ -19,7 +19,7 @@ import { AdminRole } from './entities/adminRole.entity';
|
||||
MikroOrmModule.forFeature([Admin, Role, Permission, RolePermission, AdminRole]),
|
||||
JwtModule,
|
||||
UtilsModule,
|
||||
RestaurantsModule,
|
||||
forwardRef(() => RestaurantsModule),
|
||||
],
|
||||
exports: [AdminService, AdminRepository],
|
||||
})
|
||||
|
||||
@@ -28,6 +28,7 @@ export class NotificationsGateway implements OnGatewayConnection, OnGatewayDisco
|
||||
server!: Server;
|
||||
|
||||
private readonly logger = new Logger(NotificationsGateway.name);
|
||||
private readonly pingIntervals = new Map<string, NodeJS.Timeout>();
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => NotificationService))
|
||||
@@ -41,6 +42,13 @@ export class NotificationsGateway implements OnGatewayConnection, OnGatewayDisco
|
||||
const authenticatedClient = client as AuthenticatedSocket;
|
||||
this.logger.log(`Admin connected: ${authenticatedClient.adminId}`);
|
||||
this.handleJoinRoom(authenticatedClient);
|
||||
|
||||
// Start ping interval for this client
|
||||
// const intervalId = setInterval(() => {
|
||||
// void authenticatedClient.emit('ping', { message: 'ping', timestamp: new Date().toISOString() });
|
||||
// }, 2000);
|
||||
|
||||
// this.pingIntervals.set(client.id, intervalId);
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
`Connection authentication failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
||||
@@ -53,6 +61,13 @@ export class NotificationsGateway implements OnGatewayConnection, OnGatewayDisco
|
||||
handleDisconnect(client: Socket) {
|
||||
this.logger.log(`Client disconnected: ${client.id}`);
|
||||
this.handleLeaveRoom(client);
|
||||
|
||||
// Clear ping interval for this client
|
||||
// const intervalId = this.pingIntervals.get(client.id);
|
||||
// if (intervalId) {
|
||||
// clearInterval(intervalId);
|
||||
// this.pingIntervals.delete(client.id);
|
||||
// }
|
||||
}
|
||||
|
||||
sendInAppNotification(repipient: { adminId: string; restaurantId: string }, payload: IInAppNotificationPayload) {
|
||||
@@ -65,7 +80,7 @@ export class NotificationsGateway implements OnGatewayConnection, OnGatewayDisco
|
||||
private getRoom(adminId: string, restaurantId: string) {
|
||||
return `restaurant:${restaurantId}-admin:${adminId}`;
|
||||
}
|
||||
|
||||
|
||||
handleLeaveRoom(client: AuthenticatedSocket) {
|
||||
const room = this.getRoom(client.adminId!, client.restId!);
|
||||
void client.leave(room);
|
||||
|
||||
@@ -9,6 +9,7 @@ import { UserId } from 'src/common/decorators/user-id.decorator';
|
||||
import { RestId } from 'src/common/decorators';
|
||||
import { FindUsersDto } from '../dto/find-user.dto';
|
||||
import { AdminAuthGuard } from 'src/modules/auth/guards/adminAuth.guard';
|
||||
import { ConvertScoreToWalletDto } from '../dto/convert-score-to-wallet.dto';
|
||||
|
||||
@ApiTags('User')
|
||||
@Controller()
|
||||
@@ -117,4 +118,19 @@ export class UsersController {
|
||||
) {
|
||||
return this.userService.findAll(restId, query);
|
||||
}
|
||||
|
||||
@UseGuards(AuthGuard)
|
||||
@ApiBearerAuth()
|
||||
@ApiOperation({ summary: 'Convert user score (points) to wallet balance' })
|
||||
@ApiBody({ type: ConvertScoreToWalletDto })
|
||||
@Post('public/user/convert-score-to-wallet')
|
||||
async convertScoreToWallet(@UserId() userId: string, @Body() dto: ConvertScoreToWalletDto, @RestId() restId: string) {
|
||||
const user = await this.userService.convertScoreToWallet(userId, restId, dto);
|
||||
return {
|
||||
id: user.id,
|
||||
wallet: user.wallet,
|
||||
points: user.points,
|
||||
message: 'Score converted to wallet successfully',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { IsNumber, IsOptional, Min } from 'class-validator';
|
||||
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||
|
||||
/**
|
||||
* DTO for converting user score (points) to wallet balance.
|
||||
*/
|
||||
export class ConvertScoreToWalletDto {
|
||||
@ApiPropertyOptional({
|
||||
description: 'Amount of points to convert. If not provided, converts all available points',
|
||||
example: 100,
|
||||
minimum: 1,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@Min(1)
|
||||
points?: number;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common';
|
||||
import { FilterQuery, RequiredEntityData } from '@mikro-orm/core';
|
||||
import { User } from '../entities/user.entity';
|
||||
import { UserAddress } from '../entities/user-address.entity';
|
||||
@@ -10,11 +10,14 @@ import { UpdateUserAddressDto } from '../dto/update-user-address.dto';
|
||||
import { PaginatedResult } from 'src/common/interfaces/pagination.interface';
|
||||
import { UserRepository } from '../repositories/user.repository';
|
||||
import { normalizePhone } from '../../utils/phone.util';
|
||||
import { ConvertScoreToWalletDto } from '../dto/convert-score-to-wallet.dto';
|
||||
import { RestRepository } from 'src/modules/restaurants/repositories/rest.repository';
|
||||
|
||||
@Injectable()
|
||||
export class UserService {
|
||||
constructor(
|
||||
private readonly userRepository: UserRepository,
|
||||
private readonly restaurantRepository: RestRepository,
|
||||
private readonly em: EntityManager,
|
||||
) {}
|
||||
|
||||
@@ -283,4 +286,48 @@ export class UserService {
|
||||
|
||||
return address;
|
||||
}
|
||||
|
||||
async convertScoreToWallet(userId: string, restId: string, dto: ConvertScoreToWalletDto): Promise<User> {
|
||||
const user = await this.userRepository.findOne({ id: userId });
|
||||
if (!user) {
|
||||
throw new NotFoundException(`User with ID ${userId} not found.`);
|
||||
}
|
||||
|
||||
// Determine how many points to convert
|
||||
const pointsToConvert = dto.points ?? user.points;
|
||||
|
||||
// Validate points to convert
|
||||
if (pointsToConvert <= 0) {
|
||||
throw new BadRequestException('Points to convert must be greater than 0.');
|
||||
}
|
||||
|
||||
if (user.points < pointsToConvert) {
|
||||
throw new BadRequestException(`Insufficient points. Available: ${user.points}, Requested: ${pointsToConvert}.`);
|
||||
}
|
||||
const restaurant = await this.restaurantRepository.findOne({ id: restId });
|
||||
if (!restaurant) {
|
||||
throw new NotFoundException(`Restaurant with ID ${restId} not found.`);
|
||||
}
|
||||
if (!restaurant.score) {
|
||||
throw new BadRequestException('Restaurant score not found.');
|
||||
}
|
||||
if (!restaurant.score.purchaseScore) {
|
||||
throw new BadRequestException('Restaurant purchase score not found.');
|
||||
}
|
||||
if (!restaurant.score.purchaseAmount) {
|
||||
throw new BadRequestException('Restaurant purchase amount not found.');
|
||||
}
|
||||
const walletIncreaseAmount =
|
||||
(Number(pointsToConvert) * Number(restaurant.score.purchaseAmount)) / Number(restaurant.score.purchaseScore);
|
||||
// Convert points to wallet (1:1 ratio - can be made configurable)
|
||||
|
||||
|
||||
// Update user's wallet and points
|
||||
user.wallet = (user.wallet || 0) + walletIncreaseAmount;
|
||||
user.points = user.points - pointsToConvert;
|
||||
|
||||
await this.em.flush();
|
||||
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,11 +6,12 @@ import { User } from './entities/user.entity';
|
||||
import { UserAddress } from './entities/user-address.entity';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
import { UserRepository } from './repositories/user.repository';
|
||||
import { RestaurantsModule } from '../restaurants/restaurants.module';
|
||||
|
||||
@Module({
|
||||
providers: [UserService, UserRepository],
|
||||
controllers: [UsersController],
|
||||
imports: [MikroOrmModule.forFeature([User, UserAddress]), JwtModule],
|
||||
imports: [MikroOrmModule.forFeature([User, UserAddress]), JwtModule, RestaurantsModule],
|
||||
exports: [UserService, UserRepository],
|
||||
})
|
||||
export class UserModule {}
|
||||
|
||||
Reference in New Issue
Block a user