Skip to content

Commit

Permalink
Feat-Notification-Management
Browse files Browse the repository at this point in the history
  • Loading branch information
Calebgisa72 committed Jun 2, 2024
1 parent 89ac0c5 commit c60805f
Show file tree
Hide file tree
Showing 10 changed files with 273 additions and 1 deletion.
10 changes: 10 additions & 0 deletions src/controllers/notificarionControllers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Request, Response } from 'express';
import { getNotificationsService, deleteNotificationService } from '../services';

export const getAllNotifications = async (req: Request, res: Response) => {
await getNotificationsService(req, res);
};

export const deleteNotification = async (req: Request, res: Response) => {
await deleteNotificationService(req, res);
};
48 changes: 48 additions & 0 deletions src/entities/Notification.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import {
Entity,
PrimaryGeneratedColumn,
Column,
ManyToOne,
OneToMany,
CreateDateColumn,
UpdateDateColumn,
} from 'typeorm';
import { IsNotEmpty } from 'class-validator';
import { User } from './User';
import { NotificationItem } from './NotificationItem';

@Entity()
export class Notification {
@PrimaryGeneratedColumn('uuid')
@IsNotEmpty()
id!: string;

@ManyToOne(() => User)
user!: User;

@OneToMany(() => NotificationItem, notificationItem => notificationItem.notification)
allNotifications!: NotificationItem[];

@Column('decimal')
unRead: number = 0;

@CreateDateColumn()
createdAt!: Date;

@UpdateDateColumn()
updatedAt!: Date;

updateUnread (): void {
if (this.allNotifications) {
let unRead: number = 0;
for (let i = 0; i < this.allNotifications.length; i++) {
if(this.allNotifications[i].isRead === false){
unRead +=1
}
}
this.unRead = unRead;
} else {
this.unRead = 0;
}
}
}
47 changes: 47 additions & 0 deletions src/entities/NotificationItem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {
Entity,
PrimaryGeneratedColumn,
Column,
ManyToOne,
CreateDateColumn,
} from 'typeorm';
import { IsNotEmpty, IsIn, IsBoolean } from 'class-validator';
import { Notification } from './Notification';

@Entity()
export class NotificationItem{
@PrimaryGeneratedColumn('uuid')
@IsNotEmpty()
id!: string;

@ManyToOne(() => Notification, nofication => nofication.allNotifications, { onDelete: 'CASCADE' })
@IsNotEmpty()
notification!: Notification;

@Column()
@IsNotEmpty()
content!: string

@Column()
@IsNotEmpty()
@IsIn([
'product',
'cart',
'order',
'user',
'wish list',
'coupon',
])
type!: string

@Column({ default: false })
@IsNotEmpty()
@IsBoolean()
isRead!: boolean

@Column({ nullable: true })
link!: string

@CreateDateColumn()
createdAt!: Date;
}
9 changes: 9 additions & 0 deletions src/routes/NoficationRoutes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { RequestHandler, Router } from 'express';
import { authMiddleware } from '../middlewares/verifyToken';
import {getAllNotifications, deleteNotification} from '../controllers/notificarionControllers'

const router = Router();
router.get('/', authMiddleware as RequestHandler, getAllNotifications);
router.delete('/:id', authMiddleware as RequestHandler, deleteNotification);

export default router;
2 changes: 2 additions & 0 deletions src/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import productRoutes from './ProductRoutes';
import wishListRoutes from './wishListRoute';
import couponRoute from './couponRoutes';
import cartRoutes from './CartRoutes';
import notificationRoute from './NoficationRoutes'

const router = Router();

Expand All @@ -17,5 +18,6 @@ router.use('/product', productRoutes);
router.use('/wish-list', wishListRoutes);
router.use('/cart', cartRoutes);
router.use('/coupons', couponRoute);
router.use('/notification', notificationRoute);

export default router;
19 changes: 18 additions & 1 deletion src/services/adminOrderServices/updateOrder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Request, Response } from 'express';
import { Not, getRepository } from 'typeorm';
import { responseSuccess, responseError } from '../../utils/response.utils';
import { VendorOrderItem } from '../../entities/VendorOrderItem';
import { sendNotification } from '../../utils/sendNotification';
import { VendorOrders } from '../../entities/vendorOrders';
import { Order } from '../../entities/Order';
import { getIO } from '../../utils/socket';
Expand Down Expand Up @@ -38,7 +39,7 @@ export const updateBuyerVendorOrderService = async (req: Request, res: Response)
id: order.id,
},
},
relations: ['vendor', 'vendorOrderItems', 'vendorOrderItems.product'],
relations: ['vendor','order.buyer','vendorOrderItems', 'vendorOrderItems.product'],
});

for (const order of vendorOrders) {
Expand All @@ -52,9 +53,25 @@ export const updateBuyerVendorOrderService = async (req: Request, res: Response)
order.orderStatus = 'completed';
await orderRepository.save(order);

await sendNotification({
content: 'Your order was marked completed',
type: 'order',
user: order.buyer,
link: `product/client/orders/${order.id}`
})

const updatedVendorOrder = vendorOrders.map(async order => {
order.orderStatus = 'completed';
await vendorOrderRepository.save(order);

console.log(order.order.buyer.firstName);
console.log(order.order.buyer.lastName);
await sendNotification({
content:`Order from buyer "${order.order.buyer.firstName} ${order.order.buyer.lastName}" has been marked completed`,
type: 'order',
user: order.vendor,
link: `product/vendor/orders/${order.id}`
})
});

const sanitizedOrderResponse = {
Expand Down
4 changes: 4 additions & 0 deletions src/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,7 @@ export * from './vendorOrderServices/updateVendorOrder';
// vendor order management
export * from './adminOrderServices/readOrder';
export * from './adminOrderServices/updateOrder';

// Nofication management
export * from './notificationServices/getNotifications'
export * from './notificationServices/deleteNotification'
52 changes: 52 additions & 0 deletions src/services/notificationServices/deleteNotification.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Request, Response } from 'express';
import { Notification } from '../../entities/Notification';
import { NotificationItem } from '../../entities/NotificationItem';
import { responseSuccess, responseError } from '../../utils/response.utils';
import { getRepository } from 'typeorm';

export const deleteNotificationService = async(req: Request, res: Response) => {
try {
if (!req.params.id) {
return responseError(res, 400, 'Notification id is required');
}
const notificationRepo = getRepository(Notification);
const notificationItemRepo = getRepository(NotificationItem);

const notificationItem = await notificationItemRepo
.findOne({where: {id: req.params.id}, relations: ['notification']});

if(!notificationItem){
return responseError(res, 404, 'Notification not found');
}

if(notificationItem.notification.user.id !== req.user?.id){
return responseError(res, 401, "You are not authorized to perform this");
}

await notificationItemRepo.remove(notificationItem as NotificationItem);

const notification = await notificationRepo
.findOne({where: {user: { id: req.user?.id }}, relations: ['allNotifications', 'user'] });

if(notification){
notification.updateUnread();
await notificationRepo.save(notification);

const notificationDeatils = {
id: notification.id,
user: {
id: notification.user.id,
firstName: notification.user.firstName,
lastName: notification.user.lastName
},
notifications: notification.allNotifications,
unRead: notification.unRead
}

return responseSuccess(res, 200, 'Notifications deleted successfully', { notificationDeatils });
}

} catch (error) {
return responseError(res, 400, (error as Error).message);
}
}
36 changes: 36 additions & 0 deletions src/services/notificationServices/getNotifications.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Request, Response } from 'express';
import { Notification } from '../../entities/Notification';
import { responseSuccess, responseError } from '../../utils/response.utils';
import { getRepository } from 'typeorm';

export const getNotificationsService = async(req: Request, res: Response) => {
try {
const notificationRepo = getRepository(Notification);

const notification = await notificationRepo
.findOne({where: {user: { id: req.user?.id }}, relations: ['user','allNotifications'],
order: {
createdAt: 'DESC',
},
})

if(!notification){
return responseSuccess(res, 200, `No notifications`, { notifications: [] });
}

const notificationDeatils = {
id: notification.id,
user: {
id: notification.user.id,
firstName: notification.user.firstName,
lastName: notification.user.lastName
},
notifications: notification.allNotifications,
unRead: notification.unRead
}

return responseSuccess(res, 200, 'Notifications retrieved successfully', { notificationDeatils });
} catch (error) {
return responseError(res, 400, (error as Error).message);
}
}
47 changes: 47 additions & 0 deletions src/utils/sendNotification.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Notification } from "../entities/Notification";
import { NotificationItem } from "../entities/NotificationItem";
import { getRepository } from 'typeorm';
import { User } from "../entities/User";

interface noticationInfo{
content: string;
type: 'product'|'cart'|'order'|'user'|'wish list'|'coupon';
user: User;
link?: string;
}

export const sendNotification = async(data: noticationInfo) =>{
try {
const notificationRepo = getRepository(Notification)
const notiificationItemRepo = getRepository(NotificationItem);

let notification = await notificationRepo
.findOne({where: {user: {id: data.user.id}}, relations: ['allNotifications', 'user'] });

if(!notification){
notification = new Notification();
notification.user = data.user;
await notificationRepo.save(notification);
}

const notificationItem = new NotificationItem();
notificationItem.notification = notification;
notificationItem.content = data.content;
notificationItem.type = data.type;
if(data.link){
notificationItem.link = data.link
}
await notiificationItemRepo.save(notificationItem);

//Update numbers
notification = await notificationRepo
.findOne({where: {id: notification.id, user: {id: data.user.id}}, relations: ['allNotifications', 'user'] });

if(notification){
notification.updateUnread();
await notificationRepo.save(notification);
}
} catch (error) {
console.log(error);
}
}

0 comments on commit c60805f

Please sign in to comment.