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