From 8e754bcfece036991482a0b45c418d034c2b10ac Mon Sep 17 00:00:00 2001 From: morteza-mortezai Date: Sun, 1 Feb 2026 10:35:09 +0330 Subject: [PATCH] admin --- src/modules/admin/dto/create-admin.dto.ts | 7 +- src/modules/admin/entities/admin.entity.ts | 8 +- src/modules/admin/providers/admin.service.ts | 48 +- .../notification/dto/create-preference.dto.ts | 10 +- .../notification-preference.entity.ts | 20 +- .../entities/notification.entity.ts | 8 +- .../interfaces/jobs-queue.interface.ts | 4 +- .../interfaces/notification.interface.ts | 20 +- .../notification-preference.service.ts | 2 +- .../services/notification.service.ts | 452 +++++++++--------- .../order/listeners/order.listeners.ts | 2 +- .../payment/listeners/payment.listeners.ts | 2 +- .../data/notification-preferences.data.ts | 44 +- 13 files changed, 330 insertions(+), 297 deletions(-) diff --git a/src/modules/admin/dto/create-admin.dto.ts b/src/modules/admin/dto/create-admin.dto.ts index 81430bd..069f510 100644 --- a/src/modules/admin/dto/create-admin.dto.ts +++ b/src/modules/admin/dto/create-admin.dto.ts @@ -1,5 +1,6 @@ import { ApiProperty } from '@nestjs/swagger'; -import { IsMobilePhone, IsNotEmpty, IsOptional, IsString } from 'class-validator'; +import { IsArray, IsMobilePhone, IsNotEmpty, IsOptional, IsString } from 'class-validator'; +import { NotifEvent } from 'src/modules/notification/interfaces/notification.interface'; export class CreateAdminDto { @ApiProperty({ description: 'Mobile phone number' }) @@ -22,4 +23,8 @@ export class CreateAdminDto { @IsNotEmpty() @IsString() roleId!: string; + + @ApiProperty({}) + @IsArray() + notificationPrefrences:NotifEvent[] } diff --git a/src/modules/admin/entities/admin.entity.ts b/src/modules/admin/entities/admin.entity.ts index d63284c..597aee6 100644 --- a/src/modules/admin/entities/admin.entity.ts +++ b/src/modules/admin/entities/admin.entity.ts @@ -1,8 +1,9 @@ -import { Entity, ManyToOne, OneToOne, PrimaryKey, Property } from '@mikro-orm/core'; +import { Cascade, Entity, ManyToOne, OneToOne, PrimaryKey, Property } from '@mikro-orm/core'; import { BaseEntity } from '../../../common/entities/base.entity'; import { normalizePhone } from '../../util/phone.util'; import { Role } from 'src/modules/roles/entities/role.entity'; import { ulid } from 'ulid'; +import { NotificationPreference } from 'src/modules/notification/entities/notification-preference.entity'; @Entity({ tableName: 'admins' }) export class Admin extends BaseEntity { @@ -29,4 +30,9 @@ export class Admin extends BaseEntity { @ManyToOne(() => Role) role: Role + + // @OneToOne(() => NotificationPreference, pref => pref.admin, { + + // }) + // notificationPreference!: NotificationPreference; } diff --git a/src/modules/admin/providers/admin.service.ts b/src/modules/admin/providers/admin.service.ts index e59f419..56587da 100644 --- a/src/modules/admin/providers/admin.service.ts +++ b/src/modules/admin/providers/admin.service.ts @@ -1,12 +1,13 @@ import { BadRequestException, ConflictException, Injectable, NotFoundException } from '@nestjs/common'; import { Admin } from '../entities/admin.entity'; import { Role } from '../../roles/entities/role.entity'; -import { EntityManager, RequiredEntityData } from '@mikro-orm/postgresql'; +import { EntityManager } from '@mikro-orm/postgresql'; import { UpdateAdminDto } from '../dto/update-admin.dto'; import { normalizePhone } from '../../util/phone.util'; import { CreateAdminDto } from '../dto/create-admin.dto'; import { AdminRepository } from '../repositories/admin.repository'; import { RoleRepository } from 'src/modules/roles/respository/role.repository'; +import { NotificationPreference } from 'src/modules/notification/entities/notification-preference.entity'; @Injectable() export class AdminService { @@ -17,7 +18,7 @@ export class AdminService { ) { } async create(dto: CreateAdminDto) { - const { phone, firstName, lastName, roleId } = dto; + const { phone, firstName, lastName, roleId, notificationPrefrences } = dto; const normalizedPhone = normalizePhone(phone); @@ -25,25 +26,34 @@ export class AdminService { phone: normalizedPhone, }); if (exist) { - throw new NotFoundException('This phone number is already used'); + throw new BadRequestException('This phone number is already used'); } const role = await this.roleRepository.findOne({ id: roleId }) if (!role) { - throw new NotFoundException('Role not found'); + throw new BadRequestException('Role not found'); } - const createData: RequiredEntityData = { - phone: normalizedPhone, - firstName, - lastName, - role - } - const admin = this.adminRepository.create(createData) - await this.em.persistAndFlush(admin); + return this.em.transactional(async em => { + + const admin = em.create(Admin, { + phone: normalizedPhone, + firstName, + lastName, + role + }) + + const notificationPreference = em.create(NotificationPreference, { + admin, + events: notificationPrefrences, + }) + + await this.em.persistAndFlush([admin, notificationPreference]); + + return admin + }) - return admin; } async findByPhone(phone: string): Promise { @@ -82,6 +92,18 @@ export class AdminService { if (rest.lastName !== undefined) { admin.lastName = rest.lastName; } + + if (rest.notificationPrefrences) { + // + const nf = await this.em.findOne(NotificationPreference, { + admin + }) + if (!nf) { + throw new BadRequestException('Notification prefrences not found!') + } + nf.events = rest.notificationPrefrences + await this.em.flush() + } if (rest.phone !== undefined && rest.phone !== admin.phone) { const normalizedPhone = normalizePhone(rest.phone); const exists = await this.adminRepository.findOne({ phone: normalizedPhone }); diff --git a/src/modules/notification/dto/create-preference.dto.ts b/src/modules/notification/dto/create-preference.dto.ts index 63583fc..35b7cf2 100644 --- a/src/modules/notification/dto/create-preference.dto.ts +++ b/src/modules/notification/dto/create-preference.dto.ts @@ -1,17 +1,17 @@ import { IsNotEmpty, IsEnum, IsArray } from 'class-validator'; import { ApiProperty } from '@nestjs/swagger'; -import { NotifTitleEnum } from '../interfaces/notification.interface'; +import { NotifEvent } from '../interfaces/notification.interface'; import { NotifChannelEnum } from '../interfaces/notification.interface'; export class CreatePreferenceDto { @ApiProperty({ description: 'Notification title/type (e.g., order.created, review.created)', - enum: NotifTitleEnum, - example: NotifTitleEnum.ORDER_CREATED, + enum: NotifEvent, + example: NotifEvent.NEW_ORDER, }) - @IsEnum(NotifTitleEnum) + @IsEnum(NotifEvent) @IsNotEmpty() - title!: NotifTitleEnum; + title!: NotifEvent; @ApiProperty({ description: 'Notification type (SMS, PUSH, BOTH, or NONE)', diff --git a/src/modules/notification/entities/notification-preference.entity.ts b/src/modules/notification/entities/notification-preference.entity.ts index 805755a..fbc54dc 100644 --- a/src/modules/notification/entities/notification-preference.entity.ts +++ b/src/modules/notification/entities/notification-preference.entity.ts @@ -1,16 +1,16 @@ -import { Entity, Property, ManyToOne, Unique, PrimaryKey } from '@mikro-orm/core'; +import { Entity, Property, ManyToOne, Unique, PrimaryKey, OneToOne, Cascade } from '@mikro-orm/core'; import { BaseEntity } from '../../../common/entities/base.entity'; -import { NotifTitleEnum } from '../interfaces/notification.interface'; -import { NotifChannelEnum } from '../interfaces/notification.interface'; +import { NotifEvent } from '../interfaces/notification.interface'; +import { Admin } from 'src/modules/admin/entities/admin.entity'; @Entity({ tableName: 'notification_preferences' }) export class NotificationPreference extends BaseEntity { - @PrimaryKey({ type: 'bigint', autoincrement: true }) - id: bigint - - @Property() - title!: NotifTitleEnum; + @PrimaryKey({ type: 'int', autoincrement: true }) + id: number - @Property({ type: 'json' }) - channels: NotifChannelEnum[] = []; + @OneToOne(() => Admin, { owner: true, unique: true, cascade: [Cascade.PERSIST, Cascade.REMOVE] }) + admin!: Admin; + + @Property({ type: 'json', nullable: true }) + events: NotifEvent[] = []; } diff --git a/src/modules/notification/entities/notification.entity.ts b/src/modules/notification/entities/notification.entity.ts index 01e424e..165d0d5 100644 --- a/src/modules/notification/entities/notification.entity.ts +++ b/src/modules/notification/entities/notification.entity.ts @@ -1,22 +1,22 @@ import { Entity, Property, ManyToOne, Enum, PrimaryKey } from '@mikro-orm/core'; import { BaseEntity } from '../../../common/entities/base.entity'; import { User } from '../../user/entities/user.entity'; -import { NotifTitleEnum } from '../interfaces/notification.interface'; +import { NotifEvent } from '../interfaces/notification.interface'; import { Admin } from 'src/modules/admin/entities/admin.entity'; @Entity({ tableName: 'notifications' }) export class Notification extends BaseEntity { @PrimaryKey({ type: 'bigint', autoincrement: true }) id: bigint - + @ManyToOne(() => User, { nullable: true }) user?: User; @ManyToOne(() => Admin, { nullable: true }) admin?: Admin; - @Enum(() => NotifTitleEnum) - title!: NotifTitleEnum; + @Enum(() => NotifEvent) + title!: NotifEvent; @Property() content!: string; diff --git a/src/modules/notification/interfaces/jobs-queue.interface.ts b/src/modules/notification/interfaces/jobs-queue.interface.ts index 7a576ad..b9173a3 100644 --- a/src/modules/notification/interfaces/jobs-queue.interface.ts +++ b/src/modules/notification/interfaces/jobs-queue.interface.ts @@ -1,4 +1,4 @@ -import type { NotifTitleEnum, recipientType } from './notification.interface'; +import type { NotifEvent, recipientType } from './notification.interface'; export interface SmsNotificationQueueJob { recipient: recipientType; @@ -18,7 +18,7 @@ export interface PushNotificationQueueJob { } export interface InAppNotificationQueueJob { recipient: { adminId: string; }; - subject: NotifTitleEnum; + subject: NotifEvent; body: string; notificationId: string; } diff --git a/src/modules/notification/interfaces/notification.interface.ts b/src/modules/notification/interfaces/notification.interface.ts index a3bcab9..cee31c2 100644 --- a/src/modules/notification/interfaces/notification.interface.ts +++ b/src/modules/notification/interfaces/notification.interface.ts @@ -8,17 +8,17 @@ export enum NotifTypeEnum { PROMOTIONAL = 'promotional', SYSTEM = 'system', } -export enum NotifTitleEnum { - PAGER_CREATED = 'pager.created', - ORDER_CREATED = 'order.created', - PAYMENT_SUCCESS = 'payment.success', - REVIEW_CREATED = 'review.created', - ORDER_STATUS_CHANGED = 'order.status.changed', +export enum NotifEvent { + NEW_REQUEST = 'newRequest', + INVOICED = 'invoiced', + NEW_ORDER = 'newOrder', // for chapkhane sms bere + DESIGNER_ASSIGN = 'designerAssign', + PAYMENT_SUCCESS = 'paymentSuccess', } export type recipientType = { userId: string } | { adminId: string }; export interface NotifRequestMessage { - title: NotifTitleEnum; + title: NotifEvent; content: string; sms: { templateId: string; @@ -53,11 +53,11 @@ interface INotifySmsPayload { } interface INotifySms { phone: string; - subject: NotifTitleEnum; + subject: NotifEvent; } export interface IInAppNotificationPayload { notificationId: string; - subject: NotifTitleEnum; + subject: NotifEvent; body: string; } @@ -68,7 +68,7 @@ interface IPaymentSuccessSmsNotifyPayload extends INotifySmsPayload { } interface IPaymentSuccessSmsNotify extends INotifySms { - subject: NotifTitleEnum.PAYMENT_SUCCESS; + subject: NotifEvent.PAYMENT_SUCCESS; payload: IPaymentSuccessSmsNotifyPayload; } diff --git a/src/modules/notification/services/notification-preference.service.ts b/src/modules/notification/services/notification-preference.service.ts index 47b4fac..6e2c491 100644 --- a/src/modules/notification/services/notification-preference.service.ts +++ b/src/modules/notification/services/notification-preference.service.ts @@ -3,7 +3,7 @@ import { EntityManager } from '@mikro-orm/postgresql'; import { NotificationPreference } from '../entities/notification-preference.entity'; import { CreatePreferenceDto } from '../dto/create-preference.dto'; import { UpdatePreferenceDto } from '../dto/update-preference.dto'; -import { NotifTitleEnum } from '../interfaces/notification.interface'; +import { NotifEvent } from '../interfaces/notification.interface'; @Injectable() export class NotificationPreferenceService { diff --git a/src/modules/notification/services/notification.service.ts b/src/modules/notification/services/notification.service.ts index 5312d66..6b66122 100644 --- a/src/modules/notification/services/notification.service.ts +++ b/src/modules/notification/services/notification.service.ts @@ -4,7 +4,7 @@ import { Notification } from '../entities/notification.entity'; import { NotificationPreferenceService } from './notification-preference.service'; import { NotificationQueueService } from './notification-queue.service'; import { NotificationsGateway } from '../notifications.gateway'; -import { NotifChannelEnum, NotifRequest, NotifTitleEnum } from '../interfaces/notification.interface'; +import { NotifChannelEnum, NotifRequest, NotifEvent } from '../interfaces/notification.interface'; import { SmsLog } from '../entities/smsLogs.entity'; import { SmsLogRepository } from '../repositories/sms-log.repository'; import { PaginatedResult } from '../../../common/interfaces/pagination.interface'; @@ -21,259 +21,259 @@ export class NotificationService { private readonly smsLogRepository: SmsLogRepository, ) { } -// async sendNotification(params: NotifRequest): Promise { -// const { recipients, message, metadata, } = params; + // async sendNotification(params: NotifRequest): Promise { + // const { recipients, message, metadata, } = params; -// // create Database notifications -// const notifications = await this.createAdminBulkNotifications( -// recipients.map(recipient => ({ -// title: message.title, -// content: message.content, -// adminId: 'adminId' in recipient ? recipient.adminId : null, -// userId: 'userId' in recipient ? recipient.userId : null, -// })), -// ); + // // create Database notifications + // const notifications = await this.createAdminBulkNotifications( + // recipients.map(recipient => ({ + // title: message.title, + // content: message.content, + // adminId: 'adminId' in recipient ? recipient.adminId : null, + // userId: 'userId' in recipient ? recipient.userId : null, + // })), + // ); -// // get admin prefrences -// const preference = await this.preferenceService.findByRestaurantAndType(, message.title); + // // get admin prefrences + // const preference = await this.preferenceService.findByRestaurantAndType(, message.title); -// if(preference?.channels?.length === 0) { -// this.logger.warn(`Notification type is NONE for restaurant ${}, title ${message.title}`); -// return notifications; -// } + // if(preference?.channels?.length === 0) { + // this.logger.warn(`Notification type is NONE for restaurant ${}, title ${message.title}`); + // return notifications; + // } -// // send in app notification -// if (preference?.channels?.includes(NotifChannelEnum.IN_APP)) { -// await this.queueService.addBulkInAppNotifications( -// notifications.map(notification => ({ -// recipient: { adminId: notification.admin?.id || '', }, -// subject: message.title, -// body: message.content, -// notificationId: notification.id, -// })), -// ); -// } + // // send in app notification + // if (preference?.channels?.includes(NotifChannelEnum.IN_APP)) { + // await this.queueService.addBulkInAppNotifications( + // notifications.map(notification => ({ + // recipient: { adminId: notification.admin?.id || '', }, + // subject: message.title, + // body: message.content, + // notificationId: notification.id, + // })), + // ); + // } -// // add sms notifications to queue -// if (preference?.channels?.includes(NotifChannelEnum.SMS)) { -// await this.queueService.addBulkSmsNotifications( -// recipients.map(recipient => ({ -// recipient, -// templateId: message.sms.templateId, -// parameters: message.sms.parameters, -// })), -// ); -// } + // // add sms notifications to queue + // if (preference?.channels?.includes(NotifChannelEnum.SMS)) { + // await this.queueService.addBulkSmsNotifications( + // recipients.map(recipient => ({ + // recipient, + // templateId: message.sms.templateId, + // parameters: message.sms.parameters, + // })), + // ); + // } -// this.logger.log(`Queued notification for restaurant ${}, title ${message.title}`); + // this.logger.log(`Queued notification for restaurant ${}, title ${message.title}`); -// return notifications; -// } + // return notifications; + // } -// async createAdminBulkNotifications( -// params: { - -// title: NotifTitleEnum; -// content: string; -// adminId: string | null; -// userId: string | null; -// }[], -// ): Promise < Notification[] > { -// const notifications = params.map(param => { -// return this.em.create(Notification, { -// admin: param.adminId, -// user: param.userId && param.userId.trim() !== '' ? param.userId : null, -// title: param.title, -// content: param.content, -// }); -// }); -// await this.em.persistAndFlush(notifications); -// return notifications; -// } + // async createAdminBulkNotifications( + // params: { -// async findOne(id: string): Promise < Notification > { -// const notification = await this.em.findOne(Notification, { id }, { populate: ['restaurant', 'user'] }); -// if(!notification) { -// throw new NotFoundException('Notification not found'); -// } -// return notification; -// } + // title: NotifTitleEnum; + // content: string; + // adminId: string | null; + // userId: string | null; + // }[], + // ): Promise < Notification[] > { + // const notifications = params.map(param => { + // return this.em.create(Notification, { + // admin: param.adminId, + // user: param.userId && param.userId.trim() !== '' ? param.userId : null, + // title: param.title, + // content: param.content, + // }); + // }); + // await this.em.persistAndFlush(notifications); + // return notifications; + // } -// async findByRestaurant( -// : string, -// adminId: string, -// limit = 50, -// cursor ?: string, -// status ?: 'seen' | 'unseen', -// ): Promise < { data: Notification[]; nextCursor: string | null } > { -// const where: FilterQuery = { -// restaurant: { id: }, -// admin: { id: adminId }, -// }; + // async findOne(id: string): Promise < Notification > { + // const notification = await this.em.findOne(Notification, { id }, { populate: ['restaurant', 'user'] }); + // if(!notification) { + // throw new NotFoundException('Notification not found'); + // } + // return notification; + // } -// // Filter by status (seen/unseen) -// if (status === 'seen') { -// where.seenAt = { $ne: null }; -// } else if (status === 'unseen') { -// where.seenAt = null; -// } + // async findByRestaurant( + // : string, + // adminId: string, + // limit = 50, + // cursor ?: string, + // status ?: 'seen' | 'unseen', + // ): Promise < { data: Notification[]; nextCursor: string | null } > { + // const where: FilterQuery = { + // restaurant: { id: }, + // admin: { id: adminId }, + // }; -// // Cursor-based pagination: if cursor is provided, get items with id < cursor -// if (cursor) { -// where.id = { $lt: cursor }; -// } + // // Filter by status (seen/unseen) + // if (status === 'seen') { + // where.seenAt = { $ne: null }; + // } else if (status === 'unseen') { + // where.seenAt = null; + // } -// const notifications = await this.em.find(Notification, where, { -// orderBy: { createdAt: 'DESC', id: 'DESC' }, -// limit: limit + 1, // fetch one extra to determine next page -// populate: ['user'], -// }); + // // Cursor-based pagination: if cursor is provided, get items with id < cursor + // if (cursor) { + // where.id = { $lt: cursor }; + // } -// const hasNextPage = notifications.length > limit; -// const data = hasNextPage ? notifications.slice(0, limit) : notifications; -// const nextCursor = hasNextPage && data.length > 0 ? data[data.length - 1].id : null; + // const notifications = await this.em.find(Notification, where, { + // orderBy: { createdAt: 'DESC', id: 'DESC' }, + // limit: limit + 1, // fetch one extra to determine next page + // populate: ['user'], + // }); -// return { -// data, -// nextCursor: nextCursor ?? null, -// }; -// } + // const hasNextPage = notifications.length > limit; + // const data = hasNextPage ? notifications.slice(0, limit) : notifications; + // const nextCursor = hasNextPage && data.length > 0 ? data[data.length - 1].id : null; -// async findByUserAndRestaurant( -// userId: string, -// : string, -// limit = 50, -// cursor ?: string, -// status ?: 'seen' | 'unseen', -// ): Promise < { data: Notification[]; nextCursor: string | null } > { -// const where: FilterQuery = { -// user: { id: userId }, -// restaurant: { id: }, -// }; + // return { + // data, + // nextCursor: nextCursor ?? null, + // }; + // } -// // Filter by status (seen/unseen) -// if (status === 'seen') { -// where.seenAt = { $ne: null }; -// } else if (status === 'unseen') { -// where.seenAt = null; -// } + // async findByUserAndRestaurant( + // userId: string, + // : string, + // limit = 50, + // cursor ?: string, + // status ?: 'seen' | 'unseen', + // ): Promise < { data: Notification[]; nextCursor: string | null } > { + // const where: FilterQuery = { + // user: { id: userId }, + // restaurant: { id: }, + // }; -// // Cursor-based pagination: if cursor is provided, get items with id < cursor (since ULIDs are time-ordered) -// if (cursor) { -// where.id = { $lt: cursor }; -// } + // // Filter by status (seen/unseen) + // if (status === 'seen') { + // where.seenAt = { $ne: null }; + // } else if (status === 'unseen') { + // where.seenAt = null; + // } -// const notifications = await this.em.find(Notification, where, { -// orderBy: { createdAt: 'DESC', id: 'DESC' }, -// limit: limit + 1, // Fetch one extra to determine if there's a next page -// }); + // // Cursor-based pagination: if cursor is provided, get items with id < cursor (since ULIDs are time-ordered) + // if (cursor) { + // where.id = { $lt: cursor }; + // } -// // Check if there's a next page -// const hasNextPage = notifications.length > limit; -// const data = hasNextPage ? notifications.slice(0, limit) : notifications; -// const nextCursor = hasNextPage && data.length > 0 ? data[data.length - 1].id : null; + // const notifications = await this.em.find(Notification, where, { + // orderBy: { createdAt: 'DESC', id: 'DESC' }, + // limit: limit + 1, // Fetch one extra to determine if there's a next page + // }); -// return { -// data, -// nextCursor: nextCursor ?? null, -// }; -// } + // // Check if there's a next page + // const hasNextPage = notifications.length > limit; + // const data = hasNextPage ? notifications.slice(0, limit) : notifications; + // const nextCursor = hasNextPage && data.length > 0 ? data[data.length - 1].id : null; -// async readNotificationAdmin(id: string, adminId: string, : string): Promise < void> { -// const notification = await this.em.findOne(Notification, { -// id, -// admin: { id: adminId }, -// restaurant: { id: }, -// }); -// if(!notification) { -// throw new NotFoundException('Notification not found'); -// } -// notification.seenAt = new Date(); -// await this.em.persistAndFlush(notification); -// } -// async readNotificationAsUser(id: string, userId: string, : string): Promise < void> { -// const notification = await this.em.findOne(Notification, { -// id, -// user: { id: userId }, -// restaurant: { id: }, -// }); -// if(!notification) { -// throw new NotFoundException('Notification not found'); -// } -// notification.seenAt = new Date(); -// await this.em.persistAndFlush(notification); -// } + // return { + // data, + // nextCursor: nextCursor ?? null, + // }; + // } -// async findByRestaurantAndType(: string, title: NotifTitleEnum, limit = 50): Promise < Notification[] > { -// return this.em.find( -// Notification, -// { -// restaurant: { id: }, -// title, -// }, -// { -// orderBy: { createdAt: 'DESC' }, -// limit, -// populate: ['user'], -// }, -// ); -// } + // async readNotificationAdmin(id: string, adminId: string, : string): Promise < void> { + // const notification = await this.em.findOne(Notification, { + // id, + // admin: { id: adminId }, + // restaurant: { id: }, + // }); + // if(!notification) { + // throw new NotFoundException('Notification not found'); + // } + // notification.seenAt = new Date(); + // await this.em.persistAndFlush(notification); + // } + // async readNotificationAsUser(id: string, userId: string, : string): Promise < void> { + // const notification = await this.em.findOne(Notification, { + // id, + // user: { id: userId }, + // restaurant: { id: }, + // }); + // if(!notification) { + // throw new NotFoundException('Notification not found'); + // } + // notification.seenAt = new Date(); + // await this.em.persistAndFlush(notification); + // } -// async findByAdminAndRestaurant(adminId: string, : string, limit = 50): Promise < Notification[] > { -// return this.em.find( -// Notification, -// { admin: { id: adminId }, restaurant: { id: } }, -// { -// orderBy: { createdAt: 'DESC' }, -// limit, -// }, -// ); -// } + // async findByRestaurantAndType(: string, title: NotifTitleEnum, limit = 50): Promise < Notification[] > { + // return this.em.find( + // Notification, + // { + // restaurant: { id: }, + // title, + // }, + // { + // orderBy: { createdAt: 'DESC' }, + // limit, + // populate: ['user'], + // }, + // ); + // } -// async countUnseenByUserAndRestaurant(userId: string, : string): Promise < number > { -// const where: FilterQuery = { -// user: { id: userId }, -// restaurant: { id: }, -// seenAt: null, -// }; -// return this.em.count(Notification, where); -// } + // async findByAdminAndRestaurant(adminId: string, : string, limit = 50): Promise < Notification[] > { + // return this.em.find( + // Notification, + // { admin: { id: adminId }, restaurant: { id: } }, + // { + // orderBy: { createdAt: 'DESC' }, + // limit, + // }, + // ); + // } -// async countUnseenByRestaurant(adminId: string, : string): Promise < number > { -// const where: FilterQuery = { -// admin: { id: adminId }, -// restaurant: { id: }, -// seenAt: null, -// }; -// return this.em.count(Notification, where); -// } + // async countUnseenByUserAndRestaurant(userId: string, : string): Promise < number > { + // const where: FilterQuery = { + // user: { id: userId }, + // restaurant: { id: }, + // seenAt: null, + // }; + // return this.em.count(Notification, where); + // } -// readAllNotifsAsUser(userId: string, : string): Promise < number > { -// const where: FilterQuery = { -// user: { id: userId }, -// restaurant: { id: }, -// seenAt: null, -// }; -// return this.em.nativeUpdate(Notification, where, { seenAt: new Date() }); -// } + // async countUnseenByRestaurant(adminId: string, : string): Promise < number > { + // const where: FilterQuery = { + // admin: { id: adminId }, + // restaurant: { id: }, + // seenAt: null, + // }; + // return this.em.count(Notification, where); + // } -// readAllNotifsAsAdmin(adminId: string, : string): Promise < number > { -// const where: FilterQuery = { -// admin: { id: adminId }, -// restaurant: { id: }, -// seenAt: null, -// }; -// return this.em.nativeUpdate(Notification, where, { seenAt: new Date() }); -// } + // readAllNotifsAsUser(userId: string, : string): Promise < number > { + // const where: FilterQuery = { + // user: { id: userId }, + // restaurant: { id: }, + // seenAt: null, + // }; + // return this.em.nativeUpdate(Notification, where, { seenAt: new Date() }); + // } -// async getSmsCountByRestaurant( -// page: number = 1, -// limit: number = 10, -// ): Promise < PaginatedResult < { : string; restaurantName: string; smsCount: number } >> { -// return this.smsLogRepository.getSmsCountByRestaurant(page, limit); -// } + // readAllNotifsAsAdmin(adminId: string, : string): Promise < number > { + // const where: FilterQuery = { + // admin: { id: adminId }, + // restaurant: { id: }, + // seenAt: null, + // }; + // return this.em.nativeUpdate(Notification, where, { seenAt: new Date() }); + // } -// async getSmsCountBy(: string): Promise < number > { -// return this.smsLogRepository.getSmsCountBy(); -// } + // async getSmsCountByRestaurant( + // page: number = 1, + // limit: number = 10, + // ): Promise < PaginatedResult < { : string; restaurantName: string; smsCount: number } >> { + // return this.smsLogRepository.getSmsCountByRestaurant(page, limit); + // } + + // async getSmsCountBy(: string): Promise < number > { + // return this.smsLogRepository.getSmsCountBy(); + // } } diff --git a/src/modules/order/listeners/order.listeners.ts b/src/modules/order/listeners/order.listeners.ts index 9b214d1..6f45f34 100644 --- a/src/modules/order/listeners/order.listeners.ts +++ b/src/modules/order/listeners/order.listeners.ts @@ -3,7 +3,7 @@ import { OnEvent } from '@nestjs/event-emitter'; import { AdminRepository } from 'src/modules/admin/repositories/admin.repository'; import { OrderCreatedEvent, OrderStatusChangedEvent } from '../events/order.events'; import { Permission } from 'src/common/enums/permission.enum'; -import { NotifTitleEnum } from 'src/modules/notification/interfaces/notification.interface'; +import { NotifEvent } from 'src/modules/notification/interfaces/notification.interface'; import { NotificationService } from 'src/modules/notification/services/notification.service'; import { ConfigService } from '@nestjs/config'; import { OrderRepository } from '../repositories/order.repository'; diff --git a/src/modules/payment/listeners/payment.listeners.ts b/src/modules/payment/listeners/payment.listeners.ts index 50fbc91..c5288d2 100644 --- a/src/modules/payment/listeners/payment.listeners.ts +++ b/src/modules/payment/listeners/payment.listeners.ts @@ -3,7 +3,7 @@ import { OnEvent } from '@nestjs/event-emitter'; import { AdminRepository } from 'src/modules/admin/repositories/admin.repository'; import { onlinePaymentSucceedEvent, paymentSucceedEvent } from '../events/payment.events'; import { Permission } from 'src/common/enums/permission.enum'; -import { NotifTitleEnum } from 'src/modules/notification/interfaces/notification.interface'; +import { NotifEvent } from 'src/modules/notification/interfaces/notification.interface'; import { NotificationService } from 'src/modules/notification/services/notification.service'; import { ConfigService } from '@nestjs/config'; import { OrderService } from 'src/modules/order/providers/order.service'; diff --git a/src/seeders/data/notification-preferences.data.ts b/src/seeders/data/notification-preferences.data.ts index 6c8677d..d6be6a4 100644 --- a/src/seeders/data/notification-preferences.data.ts +++ b/src/seeders/data/notification-preferences.data.ts @@ -1,29 +1,29 @@ -import { NotifChannelEnum, NotifTitleEnum } from '../../modules/notification/interfaces/notification.interface'; +import { NotifChannelEnum, NotifEvent } from '../../modules/notification/interfaces/notification.interface'; export interface NotificationPreferenceData { - title: NotifTitleEnum; + title: NotifEvent; channels: NotifChannelEnum[]; } export const notificationPreferencesData: NotificationPreferenceData[] = [ - { - title: NotifTitleEnum.PAGER_CREATED, - channels: [NotifChannelEnum.SMS, NotifChannelEnum.PUSH, NotifChannelEnum.IN_APP], - }, - { - title: NotifTitleEnum.ORDER_CREATED, - channels: [NotifChannelEnum.SMS, NotifChannelEnum.PUSH, NotifChannelEnum.IN_APP], - }, - { - title: NotifTitleEnum.PAYMENT_SUCCESS, - channels: [NotifChannelEnum.SMS, NotifChannelEnum.PUSH, NotifChannelEnum.IN_APP], - }, - { - title: NotifTitleEnum.REVIEW_CREATED, - channels: [NotifChannelEnum.SMS, NotifChannelEnum.PUSH, NotifChannelEnum.IN_APP], - }, - { - title: NotifTitleEnum.ORDER_STATUS_CHANGED, - channels: [NotifChannelEnum.SMS, NotifChannelEnum.PUSH, NotifChannelEnum.IN_APP], - }, + // { + // title: NotifEvent.PAGER_CREATED, + // channels: [NotifChannelEnum.SMS, NotifChannelEnum.PUSH, NotifChannelEnum.IN_APP], + // }, + // { + // title: NotifEvent.ORDER_CREATED, + // channels: [NotifChannelEnum.SMS, NotifChannelEnum.PUSH, NotifChannelEnum.IN_APP], + // }, + // { + // title: NotifEvent.PAYMENT_SUCCESS, + // channels: [NotifChannelEnum.SMS, NotifChannelEnum.PUSH, NotifChannelEnum.IN_APP], + // }, + // { + // title: NotifEvent.REVIEW_CREATED, + // channels: [NotifChannelEnum.SMS, NotifChannelEnum.PUSH, NotifChannelEnum.IN_APP], + // }, + // { + // title: NotifEvent.ORDER_STATUS_CHANGED, + // channels: [NotifChannelEnum.SMS, NotifChannelEnum.PUSH, NotifChannelEnum.IN_APP], + // }, ];