Project Introduction
The Blood Bank Management System is a comprehensive web application designed to streamline the processes involved in blood donation, inventory management, and distribution. Built using Node.js, this platform facilitates the management of donors, blood donation events, blood inventory, and compliance with health regulations. The system supports various user roles, including admin, staff, donor, and hospital, ensuring that all stakeholders can efficiently interact with the platform. The underlying MySQL database schema is structured to maintain data integrity and support the various functionalities required for effective blood bank operations.
Project Objectives
- To develop a user-friendly interface for managing blood donors and their information.
- To implement a system for scheduling and managing blood donation events.
- To maintain an accurate inventory of blood types and quantities available for distribution.
- To ensure compliance with health regulations through proper blood testing and documentation.
- To facilitate the distribution of blood to hospitals and track requests and deliveries.
- To provide a feedback mechanism for donors to share their experiences and ratings.
- To implement a notification system to keep users informed about important updates and events.
Project Modules
- User Management Module:
This module handles user registration, authentication, and role management, allowing users to manage their accounts based on their designated roles.
- Donor Management Module:
This module allows for the registration and management of donor profiles, including personal information, medical history, and donation eligibility status.
- Donation Event Management Module:
This module enables the scheduling and management of blood donation events, including event details and locations.
- Blood Donation Module:
This module tracks individual blood donations, linking them to donors and events, and records relevant details such as blood type and donation date.
- Blood Inventory Management Module:
This module maintains an accurate record of blood types, quantities, expiration dates, and storage conditions to ensure proper inventory management.
- Blood Testing Module:
This module manages the testing of blood donations, recording test results and compliance status to ensure safety and regulatory adherence.
- Blood Distribution Module:
This module facilitates the distribution of blood to hospitals, tracking requests, quantities, and delivery dates.
- Feedback Module:
This module allows donors to provide feedback on their donation experience, including comments and ratings.
- Compliance Module:
This module manages compliance with health regulations, documenting relevant regulations and descriptions.
- Notification Module:
This module sends notifications to users regarding important updates, events, and reminders related to blood donation and management.
Set Up the Project
Initialize a new Node.js project and install the necessary packages.
Create a new directory for your project and navigate into it:
mkdir blood-donation-app
cd blood-donation-app
Initialize a new Node.js project:
npm init -y
Install the required packages:
npm install express sequelize mysql2 ejs body-parser
Create the following directory structure:
blood-donation-app/
├── models/
├── repositories/
├── controllers/
├── routes/
├── views/
├── public/
├── config/
├── app.js
└── package.json
Step 2: Define Sequelize Models
Create Sequelize models for each table in the models directory.
models/User.js
const { Model, DataTypes } = require('sequelize');
const sequelize = require('../config/database');
class User extends Model {}
User .init({
UserId: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
Username: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
PasswordHash: {
type: DataTypes.STRING,
allowNull: false
},
Email: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
FirstName: {
type: DataTypes.STRING,
allowNull: false
},
LastName: {
type: DataTypes.STRING,
allowNull: false
},
RoleId: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: 'Roles',
key: 'RoleId'
}
},
CreatedAt: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW
},
UpdatedAt: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW
}
}, {
sequelize,
modelName: 'User ',
tableName: 'Users',
timestamps: false
});
module.exports = User;
models/Role.js
const { Model, DataTypes } = require('sequelize');
const sequelize = require('../config/database');
class Role extends Model {}
Role.init({
RoleId: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
RoleName: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
CreatedAt: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW
},
UpdatedAt: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW
}
}, {
sequelize,
modelName: 'Role',
tableName: 'Roles',
timestamps: false
});
module.exports = Role;
models/Donor.js
const { Model, DataTypes } = require('sequelize');
const sequelize = require('../config/database');
class Donor extends Model {}
Donor.init({
DonorId: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
UserId: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: 'Users',
key: 'User Id'
}
},
BloodType: {
type: DataTypes.STRING,
allowNull: false
},
LastDonationDate: {
type: DataTypes.DATE
},
CreatedAt: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW
},
UpdatedAt: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW
}
}, {
sequelize,
modelName: 'Donor',
tableName: 'Donors',
timestamps: false
});
module.exports = Donor;
models/Appointment.js javascript const { Model, DataTypes } = require('sequelize'); const sequelize = require('../config/database');
class Appointment extends Model {}
Appointment.init({ AppointmentId: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true }, DonorId: { type: DataTypes.INTEGER, allowNull: false, references: { model: 'Donors', key: 'DonorId' } }, AppointmentDate: { type: DataTypes.DATE, allowNull: false }, Status: { type: DataTypes.STRING, allowNull: false }, CreatedAt: { type: DataTypes.DATE, defaultValue: DataTypes.NOW }, UpdatedAt: { type: DataTypes.DATE, defaultValue: DataTypes.NOW } }, { sequelize, modelName: 'Appointment', tableName: 'Appointments', timestamps: false });
module.exports = Appointment;
models/BloodProduct.js
const { Model, DataTypes } = require('sequelize');
const sequelize = require('../config/database');
class BloodProduct extends Model {}
BloodProduct.init({
BloodProductId: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
BloodType: {
type: DataTypes.STRING,
allowNull: false
},
Quantity: {
type: DataTypes.INTEGER,
allowNull: false
},
ExpiryDate: {
type: DataTypes.DATE,
allowNull: false
},
CollectedAt: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW
},
CreatedAt: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW
},
UpdatedAt: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW
}
}, {
sequelize,
modelName: 'BloodProduct',
tableName: 'BloodProducts',
timestamps: false
});
module.exports = BloodProduct;
models/Inventory.js
const { Model, DataTypes } = require('sequelize');
const sequelize = require('../config/database');
class Inventory extends Model {}
Inventory.init({
InventoryId: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
BloodProductId: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: 'BloodProducts',
key: 'BloodProductId'
}
},
Quantity: {
type: DataTypes.INTEGER,
allowNull: false
},
CreatedAt: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW
},
UpdatedAt: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW
}
}, {
sequelize,
modelName: 'Inventory',
tableName: 'Inventory',
timestamps: false
});
module.exports = Inventory;
models/Order.js
const { Model, DataTypes } = require('sequelize');
const sequelize = require('../config/database');
class Order extends Model {}
Order.init({
OrderId: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
BloodProductId: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: 'BloodProducts',
key: 'BloodProductId'
}
},
Quantity: {
type: DataTypes.INTEGER,
allowNull: false
},
OrderDate: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW
},
Status: {
type: DataTypes.STRING,
allowNull: false
},
CreatedAt: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW
},
UpdatedAt: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW
}
}, {
sequelize,
modelName: 'Order',
tableName: 'Orders',
timestamps: false
});
module.exports = Order;
models/Report.js
const { Model, DataTypes } = require('sequelize');
const sequelize = require('../config/database');
class Report extends Model {}
Report.init({
ReportId: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
UserId: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: 'Users',
key: 'User Id'
}
},
ReportDate: {
type: DataTypes.DATE,
allowNull: false
},
ReportContent: {
type: DataTypes.TEXT
},
CreatedAt: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW
}
}, {
sequelize,
modelName: 'Report',
tableName: 'Reports',
timestamps: false
});
module.exports = Report;
models/QualityControl.js
const { Model, DataTypes } = require('sequelize');
const sequelize = require('../config/database');
class QualityControl extends Model {}
QualityControl.init({
QualityControlId: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
BloodProductId: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: 'BloodProducts',
key: 'BloodProductId'
}
},
InspectionDate: {
type: DataTypes.DATE,
allowNull: false
},
Status: {
type: DataTypes.STRING,
allowNull: false
},
Comments: {
type: DataTypes.TEXT
},
CreatedAt: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW
},
UpdatedAt: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW
}
}, {
sequelize,
modelName: 'QualityControl',
tableName: 'QualityControl',
timestamps: false
});
module.exports = QualityControl;
models/Campaign.js
const { Model, DataTypes } = require('sequelize');
const sequelize = require('../config/database');
class Campaign extends Model {}
Campaign.init({
CampaignId: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
CampaignName: {
type: DataTypes.STRING,
allowNull: false
},
StartDate: {
type: DataTypes.DATE,
allowNull: false
},
EndDate: {
type: DataTypes.DATE,
allowNull: false
},
CreatedAt: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW
},
UpdatedAt: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW
}
}, {
sequelize,
modelName: 'Campaign',
tableName: 'Campaigns',
timestamps: false
});
module.exports = Campaign;
Step 3: Create Repositories
Create repository functions for CRUD operations in the repositories directory.
repositories/userRepository.js
const User = require('../models/User');
class UserRepository {
async createUser (data) {
return await User.create(data);
}
async getAllUsers() {
return await User.findAll();
}
async getUser ById(id) {
return await User.findByPk(id);
}
async updateUser (id, data) {
const user = await this.getUser ById(id);
if (user) {
return await user.update(data);
}
throw new Error('User not found');
}
async deleteUser (id) {
const user = await this.getUser ById(id);
if (user) {
return await user.destroy();
}
throw new Error('User not found');
}
}
module.exports = new UserRepository();
repositories/roleRepository.js
const Role = require('../models/Role');
class RoleRepository {
async createRole(data) {
return await Role.create(data);
}
async getAllRoles() {
return await Role.findAll();
}
async getRoleById(id) {
return await Role.findByPk(id);
}
async updateRole(id, data) {
const role = await this.getRoleById(id);
if (role) {
return await role.update(data);
}
throw new Error('Role not found');
}
async deleteRole(id) {
const role = await this.getRoleById(id);
if (role) {
return await role.destroy();
}
throw new Error('Role not found');
}
}
module.exports = new RoleRepository();
repositories/donorRepository.js
const Donor = require('../models/Donor');
class DonorRepository {
async createDonor(data) {
return await Donor.create(data);
}
async getAllDonors() {
return await Donor.findAll();
}
async getDonorById(id) {
return await Donor.findByPk(id);
}
async updateDonor(id, data) {
const donor = await this.getDonorById(id);
if (donor) {
return await donor.update(data);
}
throw new Error('Donor not found');
}
async deleteDonor(id) {
const donor = await this.getDonorById(id);
if (donor) {
return await donor.destroy();
}
throw new Error('Donor not found');
}
}
module.exports = new DonorRepository();
repositories/appointmentRepository.js
const Appointment = require('../models/Appointment');
class AppointmentRepository {
async createAppointment(data) {
return await Appointment.create(data);
}
async getAllAppointments() {
return await Appointment.findAll();
}
async getAppointmentById(id) {
return await Appointment.findByPk(id);
}
async updateAppointment(id, data) {
const appointment = await this.getAppointmentById(id);
if (appointment) {
return await appointment.update(data);
}
throw new Error('Appointment not found');
}
async deleteAppointment(id) {
const appointment = await this.getAppointmentById(id);
if (appointment) {
return await appointment.destroy();
}
throw new Error('Appointment not found');
}
}
module.exports = new AppointmentRepository();
repositories/bloodProductRepository.js
const BloodProduct = require('../models/BloodProduct');
class BloodProductRepository {
async createBloodProduct(data) {
return await BloodProduct.create(data);
}
async getAllBloodProducts() {
return await BloodProduct.findAll();
}
async getBloodProductById(id) {
return await BloodProduct.findByPk(id);
}
async updateBloodProduct(id, data) {
const bloodProduct = await this.getBloodProductById(id);
if (bloodProduct) {
return await bloodProduct.update(data);
}
throw new Error('Blood Product not found');
}
async deleteBloodProduct(id) {
const bloodProduct = await this.getBloodProductById(id);
if (bloodProduct) {
return await bloodProduct.destroy();
}
throw new Error('Blood Product not found');
}
}
module.exports = new BloodProductRepository();
repositories/inventoryRepository.js
const Inventory = require('../models/Inventory');
class InventoryRepository {
async createInventory(data) {
return await Inventory.create(data);
}
async getAllInventories() {
return await Inventory.findAll();
}
async getInventoryById(id) {
return await Inventory.findByPk(id);
}
async updateInventory(id, data) {
const inventory = await this.getInventoryById(id);
if (inventory) {
return await inventory.update(data);
}
throw new Error('Inventory not found');
}
async deleteInventory(id) {
const inventory = await this.getInventoryById(id);
if (inventory) {
return await inventory.destroy();
}
throw new Error('Inventory not found');
}
}
module.exports = new InventoryRepository();
repositories/orderRepository.js
const Order = require('../models/Order');
class OrderRepository {
async createOrder(data) {
return await Order.create(data);
}
async getAllOrders() {
return await Order.findAll();
}
async getOrderById(id) {
return await Order.findByPk(id);
}
async updateOrder(id, data) {
const order = await this.getOrderById(id);
if (order) {
return await order.update(data);
}
throw new Error('Order not found');
}
async deleteOrder(id) {
const order = await this.getOrderById(id);
if (order) {
return await order.destroy();
}
throw new Error('Order not found');
}
}
module.exports = new OrderRepository();
repositories/reportRepository.js
const Report = require('../models/Report');
class ReportRepository {
async createReport(data) {
return await Report.create(data);
}
async getAllReports() {
return await Report.findAll();
}
async getReportById(id) {
return await Report.findByPk(id);
}
async updateReport(id, data) {
const report = await this.getReportById(id);
if (report) {
return await report.update(data);
}
throw new Error('Report not found');
}
async deleteReport(id) {
const report = await this.getReportById(id);
if (report) {
return await report.destroy();
}
throw new Error('Report not found');
}
}
module.exports = new ReportRepository();
repositories/qualityControlRepository.js
const QualityControl = require('../models/QualityControl');
class QualityControlRepository {
async createQualityControl(data) {
return await QualityControl.create(data);
}
async getAllQualityControls() {
return await QualityControl.findAll();
}
async get QualityControlById(id) {
return await QualityControl.findByPk(id);
}
async updateQualityControl(id, data) {
const qualityControl = await this.getQualityControlById(id);
if (qualityControl) {
return await qualityControl.update(data);
}
throw new Error('Quality Control not found');
}
async deleteQualityControl(id) {
const qualityControl = await this.getQualityControlById(id);
if (qualityControl) {
return await qualityControl.destroy();
}
throw new Error('Quality Control not found');
}
}
module.exports = new QualityControlRepository();
repositories/campaignRepository.js
const Campaign = require('../models/Campaign');
class CampaignRepository {
async createCampaign(data) {
return await Campaign.create(data);
}
async getAllCampaigns() {
return await Campaign.findAll();
}
async getCampaignById(id) {
return await Campaign.findByPk(id);
}
async updateCampaign(id, data) {
const campaign = await this.getCampaignById(id);
if (campaign) {
return await campaign.update(data);
}
throw new Error('Campaign not found');
}
async deleteCampaign(id) {
const campaign = await this.getCampaignById(id);
if (campaign) {
return await campaign.destroy();
}
throw new Error('Campaign not found');
}
}
module.exports = new CampaignRepository();
Step 4: Set Up Controllers
Create controllers to handle requests and responses in the controllers directory.
controllers/userController.js
const userRepository = require('../repositories/userRepository');
class UserController {
async createUser (req, res) {
try {
const user = await userRepository.createUser (req.body);
res.status(201).json(user);
} catch (error) {
res.status(400).json({ error: error.message });
}
}
async getAllUsers(req, res) {
try {
const users = await userRepository.getAllUsers();
res.status(200).json(users);
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async getUser ById(req, res) {
try {
const user = await userRepository.getUser ById(req.params.id);
if (user) {
res.status(200).json(user);
} else {
res.status(404).json({ error: 'User not found' });
}
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async updateUser (req, res) {
try {
const user = await userRepository.updateUser (req.params.id, req.body);
res.status(200).json(user);
} catch (error) {
res.status(400).json({ error: error.message });
}
}
async deleteUser (req, res) {
try {
await userRepository.deleteUser (req.params.id);
res.status(204).send();
} catch (error) {
res.status(400).json({ error: error.message });
}
}
}
module.exports = new UserController();
controllers/roleController.js
const roleRepository = require('../repositories/roleRepository');
class RoleController {
async createRole(req, res) {
try {
const role = await roleRepository.createRole(req.body);
res.status(201).json(role);
} catch (error) {
res.status(400).json({ error: error.message });
}
}
async getAllRoles(req, res) {
try {
const roles = await roleRepository.getAllRoles();
res.status(200).json(roles);
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async getRoleById(req, res) {
try {
const role = await roleRepository.getRoleById(req.params.id);
if (role) {
res.status(200).json(role);
} else {
res.status(404).json({ error: 'Role not found' });
}
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async updateRole(req, res) {
try {
const role = await roleRepository.updateRole(req.params.id, req.body);
res.status(200).json(role);
} catch (error) {
res.status(400).json({ error: error.message });
}
}
async deleteRole(req, res) {
try {
await roleRepository.deleteRole(req.params.id);
res.status(204).send();
} catch (error) {
res.status(400).json({ error: error .message });
}
}
}
module.exports = new RoleController();
controllers/donorController.js
const donorRepository = require('../repositories/donorRepository');
class DonorController {
async createDonor(req, res) {
try {
const donor = await donorRepository.createDonor(req.body);
res.status(201).json(donor);
} catch (error) {
res.status(400).json({ error: error.message });
}
}
async getAllDonors(req, res) {
try {
const donors = await donorRepository.getAllDonors();
res.status(200).json(donors);
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async getDonorById(req, res) {
try {
const donor = await donorRepository.getDonorById(req.params.id);
if (donor) {
res.status(200).json(donor);
} else {
res.status(404).json({ error: 'Donor not found' });
}
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async updateDonor(req, res) {
try {
const donor = await donorRepository.updateDonor(req.params.id, req.body);
res.status(200).json(donor);
} catch (error) {
res.status(400).json({ error: error.message });
}
}
async deleteDonor(req, res) {
try {
await donorRepository.deleteDonor(req.params.id);
res.status(204).send();
} catch (error) {
res.status(400).json({ error: error.message });
}
}
}
module.exports = new DonorController();
controllers/appointmentController.js
const appointmentRepository = require('../repositories/appointmentRepository');
class AppointmentController {
async createAppointment(req, res) {
try {
const appointment = await appointmentRepository.createAppointment(req.body);
res.status(201).json(appointment);
} catch (error) {
res.status(400).json({ error: error.message });
}
}
async getAllAppointments(req, res) {
try {
const appointments = await appointmentRepository.getAllAppointments();
res.status(200).json(appointments);
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async getAppointmentById(req, res) {
try {
const appointment = await appointmentRepository.getAppointmentById(req.params.id);
if (appointment) {
res.status(200).json(appointment);
} else {
res.status(404).json({ error: 'Appointment not found' });
}
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async updateAppointment(req, res) {
try {
const appointment = await appointmentRepository.updateAppointment(req.params.id, req.body);
res.status(200).json(appointment);
} catch (error) {
res.status(400).json({ error: error.message });
}
}
async deleteAppointment(req, res) {
try {
await appointmentRepository.deleteAppointment(req.params.id);
res.status(204).send();
} catch (error) {
res.status(400).json({ error: error.message });
}
}
}
module.exports = new AppointmentController();
controllers/bloodProductController.js
const bloodProductRepository = require('../repositories/bloodProductRepository');
class BloodProductController {
async createBloodProduct(req, res) {
try {
const bloodProduct = await bloodProductRepository.createBloodProduct(req.body);
res.status(201).json(bloodProduct);
} catch (error) {
res.status(400).json({ error: error.message });
}
}
async getAllBloodProducts(req, res) {
try {
const bloodProducts = await bloodProductRepository.getAllBloodProducts();
res.status(200).json(bloodProducts);
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async getBloodProductById(req, res) {
try {
const bloodProduct = await bloodProductRepository.getBloodProductById(req.params.id);
if (bloodProduct) {
res.status(200).json(bloodProduct);
} else {
res.status(404).json({ error: 'Blood Product not found' });
}
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async updateBloodProduct(req, res) {
try {
const bloodProduct = await bloodProductRepository.updateBlood Product(req.params.id, req.body);
res.status(200).json(bloodProduct);
} catch (error) {
res.status(400).json({ error: error.message });
}
}
async deleteBloodProduct(req, res) {
try {
await bloodProductRepository.deleteBloodProduct(req.params.id);
res.status(204).send();
} catch (error) {
res.status(400).json({ error: error.message });
}
}
}
module.exports = new BloodProductController();
controllers/inventoryController.js
const inventoryRepository = require('../repositories/inventoryRepository');
class InventoryController {
async createInventory(req, res) {
try {
const inventory = await inventoryRepository.createInventory(req.body);
res.status(201).json(inventory);
} catch (error) {
res.status(400).json({ error: error.message });
}
}
async getAllInventories(req, res) {
try {
const inventories = await inventoryRepository.getAllInventories();
res.status(200).json(inventories);
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async getInventoryById(req, res) {
try {
const inventory = await inventoryRepository.getInventoryById(req.params.id);
if (inventory) {
res.status(200).json(inventory);
} else {
res.status(404).json({ error: 'Inventory not found' });
}
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async updateInventory(req, res) {
try {
const inventory = await inventoryRepository.updateInventory(req.params.id, req.body);
res.status(200).json(inventory);
} catch (error) {
res.status(400).json({ error: error.message });
}
}
async deleteInventory(req, res) {
try {
await inventoryRepository.deleteInventory(req.params.id);
res.status(204).send();
} catch (error) {
res.status(400).json({ error: error.message });
}
}
}
module.exports = new InventoryController();
controllers/orderController.js
const orderRepository = require('../repositories/orderRepository');
class OrderController {
async createOrder(req, res) {
try {
const order = await orderRepository.createOrder(req.body);
res.status(201).json(order);
} catch (error) {
res.status(400).json({ error: error.message });
}
}
async getAllOrders(req, res) {
try {
const orders = await orderRepository.getAllOrders();
res.status(200).json(orders);
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async getOrderById(req, res) {
try {
const order = await orderRepository.getOrderById(req.params.id);
if (order) {
res.status(200).json(order);
} else {
res.status(404).json({ error: 'Order not found' });
}
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async updateOrder(req, res) {
try {
const order = await orderRepository.updateOrder(req.params.id, req.body);
res.status(200).json(order);
} catch (error) {
res.status(400).json({ error: error.message });
}
}
async deleteOrder(req, res) {
try {
await orderRepository.deleteOrder(req.params.id);
res.status(204).send();
} catch (error) {
res.status(400).json({ error: error.message });
}
}
}
module.exports = new OrderController();
controllers/reportController.js
const reportRepository = require('../repositories/reportRepository');
class ReportController {
async createReport(req, res) {
try {
const report = await reportRepository.createReport(req.body);
res.status(201).json(report);
} catch (error) {
res.status(400).json({ error: error.message });
}
}
async getAllReports(req, res) {
try {
const reports = await reportRepository.getAllReports();
res.status(200).json(reports);
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async getReportById(req, res) {
try {
const report = await reportRepository.getReportById(req.params.id);
if (report) {
res.status(200).json(report);
} else {
res.status(404).json({ error: 'Report not found' });
}
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async updateReport(req, res) {
try {
const report = await reportRepository.updateReport(req.params.id, req.body);
res.status(200).json(report);
} catch (error) {
res.status(400).json({ error: error.message });
}
}
async deleteReport(req, res) {
try {
await reportRepository.deleteReport(req.params.id);
res.status(204).send();
} catch (error) {
res.status(400).json({ error: error.message });
}
}
}
module.exports = new ReportController();
controllers/qualityControlController.js
const qualityControlRepository = require('../repositories/qualityControlRepository');
class QualityControlController {
async createQualityControl(req, res) {
try {
const qualityControl = await qualityControlRepository.createQualityControl(req.body);
res.status(201).json(qualityControl);
} catch (error) {
res.status(400).json({ error: error.message });
}
}
async getAllQualityControls(req, res) {
try {
const qualityControls = await qualityControlRepository.getAllQualityControls();
res.status(200).json(qualityControls);
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async getQualityControlById(req, res) {
try {
const qualityControl = await qualityControlRepository.getQualityControlById(req.params.id);
if (qualityControl) {
res.status(200).json(qualityControl);
} else {
res.status(404).json({ error: 'Quality Control not found' });
}
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async updateQualityControl(req, res) {
try {
const qualityControl = await qualityControlRepository.updateQualityControl(req.params.id, req.body);
res.status(200).json(qualityControl);
} catch (error) {
res.status(400).json({ error: error.message });
}
}
async deleteQualityControl(req, res) {
try {
await qualityControlRepository.deleteQualityControl(req.params.id);
res.status(204).send();
} catch (error) {
res.status(400).json({ error: error.message });
}
}
}
module.exports = new QualityControlController();
controllers/campaignController.js
const campaignRepository = require('../repositories/campaignRepository');
class CampaignController {
async createCampaign(req, res) {
try {
const campaign = await campaignRepository.createCampaign(req.body);
res.status(201).json(campaign);
} catch (error) {
res.status(400).json({ error: error.message });
}
}
async getAllCampaigns(req, res) {
try {
const campaigns = await campaignRepository.getAllCampaigns();
res.status(200).json(campaigns);
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async getCampaignById(req, res) {
try {
const campaign = await campaignRepository.getCampaignById(req.params.id);
if (campaign) {
res.status(200).json(campaign);
} else {
res.status(404).json({ error: 'Campaign not found' });
}
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async updateCampaign(req, res) {
try {
const campaign = await campaignRepository.updateCampaign(req.params.id, req.body);
res.status(200).json(campaign);
} catch (error) {
res.status(400).json({ error: error.message });
}
}
async deleteCampaign(req, res) {
try {
await campaignRepository.deleteCampaign(req.params.id);
res.status(204).send();
} catch (error) {
res.status(400).json({ error: error.message });
}
}
}
module.exports = new CampaignController();
Step 5: Define Routes
Set up routes for the application in the routes directory.
routes/userRoutes.js
const express = require('express');
const userController = require('../controllers/userController');
const router = express.Router();
router.post('/', userController.createUser );
router.get('/', userController.getAllUsers);
router.get('/:id', userController.getUser ById);
router.put('/:id', userController.updateUser );
router.delete('/:id', userController.deleteUser );
module.exports = router;
routes/roleRoutes.js
const express = require('express');
const roleController = require('../controllers/roleController');
const router = express.Router();
router.post('/', roleController.createRole);
router.get('/', roleController.getAllRoles);
router.get('/:id', roleController.getRoleById);
router.put('/:id', roleController.updateRole);
router.delete('/:id', roleController.deleteRole);
module.exports = router;
routes/donorRoutes.js
const express = require('express');
const donorController = require('../controllers/donorController');
const router = express.Router();
router.post('/', donorController.createDonor);
router.get('/', donorController.getAllDonors);
router.get('/:id', donorController.getDonorById);
router.put('/:id', donorController.updateDonor);
router.delete('/:id', donorController.deleteDonor);
module.exports = router;
routes/appointmentRoutes.js
const express = require('express');
const appointmentController = require('../controllers/appointmentController');
const router = express.Router();
router.post('/', appointmentController.createAppointment);
router.get('/', appointmentController.getAllAppointments);
router.get('/:id', appointmentController.getAppointmentById);
router.put('/:id', appointmentController.updateAppointment);
router.delete('/:id', appointmentController.deleteAppointment);
module.exports = router;
routes/bloodProductRoutes.js
const express = require('express');
const bloodProductController = require('../controllers/bloodProductController');
const router = express.Router();
router.post('/', bloodProductController.createBloodProduct);
router.get('/', bloodProductController.getAllBloodProducts);
router.get('/:id', bloodProductController.getBloodProductById);
router.put('/:id', bloodProductController.updateBloodProduct);
router.delete('/:id', bloodProductController.deleteBloodProduct);
module.exports = router;
routes/inventoryRoutes.js
const express = require('express');
const inventoryController = require('../controllers/inventoryController');
const router = express.Router();
router.post('/', inventoryController.createInventory);
router.get('/', inventoryController.getAllInventories);
router.get('/:id', inventoryController.getInventoryById);
router.put('/:id', inventoryController.updateInventory);
router.delete('/:id', inventoryController.deleteInventory);
module.exports = router;
routes/orderRoutes.js
const express = require('express');
const orderController = require('../controllers/orderController');
const router = express.Router();
router.post('/', orderController.createOrder);
router.get('/', orderController.getAllOrders);
router.get('/:id', orderController.getOrderById);
router.put('/:id', orderController.updateOrder);
router.delete('/:id', orderController.deleteOrder);
module.exports = router;
routes/reportRoutes.js
const express = require('express');
const reportController = require('../controllers/reportController');
const router = express.Router();
router.post('/', reportController.createReport);
router.get('/', reportController.getAllReports);
router.get('/:id', reportController.getReportById);
router.put('/:id', reportController.updateReport);
router.delete('/:id', reportController.deleteReport);
module.exports = router;
routes/qualityControlRoutes.js
const express = require('express');
const qualityControlController = require('../controllers/qualityControlController');
const router = express.Router();
router.post('/', qualityControlController.createQualityControl);
router.get('/', qualityControlController.getAllQualityControls);
router.get('/:id', qualityControlController.getQualityControlById);
router.put('/:id', qualityControlController.updateQualityControl);
router.delete('/:id', qualityControlController.deleteQualityControl);
module.exports = router;
routes/campaignRoutes.js
const express = require('express');
const campaignController = require('../controllers/campaignController');
const router = express.Router();
router.post('/', campaignController.createCampaign);
router.get('/', campaignController.getAllCampaigns);
router.get('/:id', campaignController.getCampaignById);
router.put('/:id', campaignController.updateCampaign);
router.delete('/:id', campaignController.deleteCampaign);
module.exports = router;
Step 6: Create EJS Views
Create EJS views using Bootstrap 5 for the frontend in the views directory.
views/users.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<title>Users</title>
</head>
<body>
<div class="container">
<h1 class="mt-5">Users</h1>
<table class="table">
<thead>
<tr>
<th>UserId</th>
<th>Username</th>
<th>Email</th>
<th>Actions</th </tr>
</thead>
<tbody>
<% users.forEach(user => { %>
<tr>
<td><%= user.UserId %></td>
<td><%= user.Username %></td>
<td><%= user.Email %></td>
<td>
<a href="/users/<%= user.UserId %>" class="btn btn-info">View</a>
<a href="/users/edit/<%= user.UserId %>" class="btn btn-warning">Edit</a>
<form action="/users/<%= user.UserId %>" method="POST" style="display:inline;">
<input type="hidden" name="_method" value="DELETE">
<button type="submit" class="btn btn-danger">Delete</button>
</form>
</td>
</tr>
<% }) %>
</tbody>
</table>
<a href="/users/new" class="btn btn-success">Add User</a>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
Step 7: Run the Application
Create the main application file app.js to set up the server and middleware.
app.js
const express = require('express');
const bodyParser = require('body-parser');
const methodOverride = require('method-override');
const userRoutes = require('./routes/userRoutes');
const roleRoutes = require('./routes/roleRoutes');
const donorRoutes = require('./routes/donorRoutes');
const appointmentRoutes = require('./routes/appointmentRoutes');
const bloodProductRoutes = require('./routes/bloodProductRoutes');
const inventoryRoutes = require('./routes/inventoryRoutes');
const orderRoutes = require('./routes/orderRoutes');
const reportRoutes = require('./routes/reportRoutes');
const qualityControlRoutes = require('./routes/qualityControlRoutes');
const campaignRoutes = require('./routes/campaignRoutes');
const app = express();
const PORT = process.env.PORT || 3000;
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(methodOverride('_method'));
app.use(express.static('public'));
app.use('/users', userRoutes);
app.use('/roles', roleRoutes);
app.use('/donors', donorRoutes);
app.use('/appointments', appointmentRoutes);
app.use('/blood-products', bloodProductRoutes);
app.use('/inventories', inventoryRoutes);
app.use('/orders', orderRoutes);
app.use('/reports', reportRoutes);
app.use('/quality-controls', qualityControlRoutes);
app.use('/campaigns', campaignRoutes);
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
Start the application:
node app.js
Open your browser and navigate to http://localhost:3000/users to see the user management interface.
Directory Structure for Views
views/
├── layout.ejs
├── users/
│ ├── index.ejs
│ ├── create.ejs
│ ├── edit.ejs
│ └── show.ejs
├── roles/
│ ├── index.ejs
│ ├── create.ejs
│ ├── edit.ejs
│ └── show.ejs
├── donors/
│ ├── index.ejs
│ ├── create.ejs
│ ├── edit.ejs
│ └── show.ejs
├── appointments/
│ ├── index.ejs
│ ├── create.ejs
│ ├── edit.ejs
│ └── show.ejs
├── bloodProducts/
│ ├── index.ejs
│ ├── create.ejs
│ ├── edit.ejs
│ └── show.ejs
├── inventories/
│ ├── index.ejs
│ ├── create.ejs
│ ├── edit.ejs
│ └── show.ejs
├── orders/
│ ├── index.ejs
│ ├── create.ejs
│ ├── edit.ejs
│ └── show.ejs
├── reports/
│ ├── index.ejs
│ ├── create.ejs
│ ├── edit.ejs
│ └── show.ejs
├── qualityControls/
│ ├── index.ejs
│ ├── create.ejs
│ ├── edit.ejs
│ └── show.ejs
└── campaigns/
├── index.ejs
├── create.ejs
├── edit.ejs
└── show.ejs
Layout File
views/layout.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<title><%= title %></title>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<a class="navbar-brand" href="/">Blood Donation App</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="/users">Users</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/roles">Roles</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/donors">Donors</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/appointments">Appointments</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/blood-products">Blood Products</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/inventories">Inventories</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/orders">Orders</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/reports">Reports</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/quality-controls">Quality Controls</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/campaigns">Campaigns</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="container mt- 4">
<h1><%= title %></h1>
<%- body %>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
Users Views
views/users/index.ejs
<% layout('layout') %>
<table class="table">
<thead>
<tr>
<th>UserId</th>
<th>Username</th>
<th>Email</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% users.forEach(user => { %>
<tr>
<td><%= user.UserId %></td>
<td><%= user.Username %></td>
<td><%= user.Email %></td>
<td>
<a href="/users/<%= user.UserId %>" class="btn btn-info">View</a>
<a href="/users/edit/<%= user.UserId %>" class="btn btn-warning">Edit</a>
<form action="/users/<%= user.UserId %>" method="POST" style="display:inline;">
<input type="hidden" name="_method" value="DELETE">
<button type="submit" class="btn btn-danger">Delete</button>
</form>
</td>
</tr>
<% }) %>
</tbody>
</table>
<a href="/users/create" class="btn btn-success">Add User</a>
views/users/create.ejs
<% layout('layout') %>
<form action="/users" method="POST">
<div class="mb-3">
<label for="Username" class="form-label">Username</label>
<input type="text" class="form-control" id="Username" name="Username" required>
</div>
<div class="mb-3">
<label for="Email" class="form-label">Email</label>
<input type="email" class="form-control" id="Email" name="Email" required>
</div>
<div class="mb-3">
<label for="PasswordHash" class="form-label">Password</label>
<input type="password" class="form-control" id="PasswordHash" name="PasswordHash" required>
</div>
<button type="submit" class="btn btn-primary">Create User</button>
</form>
views/users/edit.ejs
<% layout('layout') %>
<form action="/users/<%= user.UserId %>?_method=PUT" method="POST">
<div class="mb-3">
<label for="Username" class="form-label">Username</label>
<input type="text" class="form-control" id="Username" name="Username" value="<%= user.Username %>" required>
</div>
<div class="mb-3">
<label for="Email" class="form-label">Email</label>
<input type="email" class="form-control" id="Email" name="Email" value="<%= user.Email %>" required>
</div>
<button type="submit" class="btn btn-primary">Update User</button>
</form>
views/users/show.ejs
<% layout('layout') %>
<div>
<h2>User Details</h2>
<p><strong>UserId:</strong> <%= user.UserId %></p>
<p><strong>Username:</strong> <%= user.Username %></p>
<p><strong>Email:</strong> <%= user.Email %></p>
<a href="/users" class="btn btn-secondary">Back to Users</a>
</div>
Roles Views
views/roles/index.ejs
<% layout('layout') %>
<table class="table">
<thead>
<tr>
<th>RoleId</th>
<th>RoleName</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% roles.forEach(role => { %>
<tr>
<td><%= role.RoleId %></td>
<td><%= role.RoleName %></td>
<td>
<a href="/roles/<%= role.RoleId %>" class="btn btn-info">View</a>
<a href="/roles/edit/<%= role.RoleId %>" class="btn btn-warning">Edit</a>
<form action="/roles/<%= role.RoleId %>" method="POST" style="display:inline;">
<input type="hidden" name="_method" value="DELETE">
<button type="submit" class="btn btn-danger">Delete</button>
</form>
</td>
</tr>
<% }) %>
</tbody>
</table>
<a href="/roles/create" class="btn btn-success">Add Role</a>
views/roles/create.ejs
<% layout('layout') %>
<form action="/roles" method="POST">
<div class="mb-3">
<label for="RoleName" class="form-label">Role Name</label>
<input type="text" class="form-control" id="RoleName" name="RoleName" required>
</div>
<button type="submit" class="btn btn-primary">Create Role</button>
</form>
views/roles/edit.ejs
<% layout('layout') %>
<form action="/roles/<%= role.RoleId %>?_method=PUT" method="POST">
<div class="mb-3">
<label for="RoleName" class="form-label">Role Name</label>
<input type="text" class="form-control" id="RoleName" name="RoleName" value="<%= role.RoleName %>" required>
</div>
<button type="submit" class="btn btn-primary">Update Role</button>
</form>
views/roles/show.ejs
<% layout('layout') %>
<div>
<h2>Role Details</h2>
<p><strong>RoleId:</strong> <%= role.RoleId %></p>
<p><strong>RoleName:</strong> <%= role.RoleName %></p>
<a href="/roles" class="btn btn-secondary">Back to Roles</a>
</div>
Donors Views
views/donors/index.ejs
<% layout('layout') %>
<table class="table">
<thead>
<tr>
<th>DonorId</th>
<th>UserId</th>
<th>BloodType</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% donors.forEach(donor => { %>
<tr>
<td><%= donor.DonorId %></td>
<td><%= donor.UserId %></td>
<td><%= donor.BloodType %></td>
<td>
<a href="/donors/<%= donor.DonorId %>" class="btn btn-info">View</a>
<a href="/donors/edit/<%= donor.DonorId %>" class="btn btn-warning">Edit</a>
<form action="/donors/<%= donor.DonorId %>" method="POST" style="display:inline;">
<input type="hidden" name="_method" value="DELETE">
<button type="submit" class="btn btn-danger">Delete</button>
</form>
</td>
</tr>
<% }) %>
</tbody>
</table>
<a href="/donors/create" class="btn btn-success">Add Donor</a>
views/donors/create.ejs
<% layout('layout') %>
<form action="/donors" method="POST">
<div class="mb-3">
<label for="User Id" class="form-label">User ID</label>
<input type="number" class="form-control" id="User Id" name="User Id" required>
</div>
<div class="mb-3">
<label for="BloodType" class="form-label">Blood Type</label>
<input type="text" class="form-control" id="BloodType" name="BloodType" required>
</div>
<button type="submit" class="btn btn-primary">Create Donor</button>
</form>
views/donors/edit.ejs
<% layout('layout') %>
<form action="/donors/<%= donor.DonorId %>?_method=PUT" method="POST">
<div class="mb-3">
<label for="User Id" class="form-label">User ID</label>
<input type="number" class="form-control" id="User Id" name="User Id" value="<%= donor.UserId %>" required>
</div>
<div class="mb-3">
<label for="BloodType" class="form-label">Blood Type</label>
<input type="text" class="form-control" id="BloodType" name="BloodType" value="<%= donor.BloodType %>" required>
</div>
<button type="submit" class="btn btn-primary">Update Donor</button>
</form>
views/donors/show.ejs
<% layout('layout') %>
<div>
<h2>Donor Details</h2>
<p><strong>DonorId:</strong> <%= donor.DonorId %></p>
<p><strong>UserId:</strong> <%= donor.UserId %></p>
<p><strong>BloodType:</strong> <%= donor.BloodType %></p>
<a href="/donors" class="btn btn-secondary">Back to Donors</a>
</div>
Appointments Views
views/appointments/index.ejs
<% layout('layout') %>
<table class="table">
<thead>
<tr>
<th>AppointmentId</th>
<th>DonorId</th>
<th>AppointmentDate</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% appointments.forEach(appointment => { %>
<tr>
<td><%= appointment.AppointmentId %></td>
<td><%= appointment.DonorId %></td>
<td><%= appointment.AppointmentDate %></td>
<td><%= appointment.Status %></td>
<td>
<a href="/appointments/<%= appointment.AppointmentId %>" class="btn btn-info">View</a>
<a href="/appointments/edit/<%= appointment.AppointmentId %>" class="btn btn-warning">Edit</a>
<form action="/appointments/<%= appointment.AppointmentId %>" method="POST" style="display:inline;">
<input type="hidden" name="_method" value="DELETE">
<button type="submit" class="btn btn-danger">Delete</button>
</form>
</td>
</tr>
<% }) %>
</tbody>
</table>
<a href="/appointments/create" class="btn btn-success">Add Appointment</a>
views/appointments/create.ejs
<% layout('layout') %>
<form action="/appointments" method="POST">
<div class="mb-3">
<label for="DonorId" class="form-label">Donor ID</label>
<input type="number" class="form-control" id="DonorId" name="DonorId" required>
</div>
<div class="mb-3">
<label for="AppointmentDate" class="form-label">Appointment Date</label>
<input type="datetime-local" class="form-control" id="AppointmentDate" name="AppointmentDate" required>
</div>
<div class="mb-3">
<label for="Status" class="form-label">Status</label>
<input type="text" class="form-control" id="Status" name="Status" required>
</div>
<button type="submit" class="btn btn-primary">Create Appointment</button>
</form>
views/appointments/edit.ejs
<% layout('layout') %>
<form action="/appointments/<%= appointment.AppointmentId %>?_method=PUT" method="POST">
<div class="mb-3">
<label for="DonorId" class="form-label">Donor ID</label>
<input type="number" class="form-control" id="DonorId" name="DonorId" value="<%= appointment.DonorId %>" required>
</div>
<div class="mb-3">
<label for="AppointmentDate" class="form-label">Appointment Date</label>
<input type="datetime-local" class="form-control" id="AppointmentDate" name="AppointmentDate" value="<%= appointment.AppointmentDate.toISOString().slice(0, 16) %>" required>
</div>
<div class="mb-3">
<label for="Status" class="form-label">Status</label>
<input type="text" class="form-control" id="Status" name="Status" value="<%= appointment.Status %>" required>
</div>
<button type="submit" class="btn btn-primary">Update Appointment</button>
</form>
views/appointments/show.ejs
<% layout('layout') %>
<div>
<h2>Appointment Details</h2>
<p><strong>AppointmentId:</strong> <%= appointment.AppointmentId %></p>
<p><strong>DonorId:</strong> <%= appointment.DonorId %></p>
<p><strong>AppointmentDate:</strong> <%= appointment.AppointmentDate %></p>
<p><strong>Status:</strong> <%= appointment.Status %></p>
<a href="/appointments" class="btn btn-secondary">Back to Appointments</a>
</div>
Blood Products Views
views/bloodProducts/index.ejs
<% layout('layout') %>
<table class="table">
<thead>
<tr>
<th>BloodProductId</th>
<th>BloodType</th>
<th>Quantity</th>
<th>ExpiryDate</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% bloodProducts.forEach(bloodProduct => { %>
<tr>
<td><%= bloodProduct.BloodProductId %></td>
<td><%= bloodProduct.BloodType %></td>
<td><%= bloodProduct.Quantity %></td>
<td><%= bloodProduct.ExpiryDate %></td>
<td>
<a href="/blood-products/<%= bloodProduct.BloodProductId %>" class="btn btn-info">View</a>
<a href="/blood-products/edit/<%= bloodProduct.BloodProductId %>" class="btn btn-warning">Edit</a>
<form action="/blood-products/<%= bloodProduct.BloodProductId %>" method="POST" style="display:inline;">
<input type="hidden" name="_method" value="DELETE">
<button type="submit" class="btn btn-danger">Delete</button>
</form>
</td>
</tr>
<% }) %>
</tbody>
</table>
<a href="/blood-products/create" class="btn btn-success">Add Blood Product</a>
views/bloodProducts/create.ejs
<% layout('layout') %>
<form action="/blood-products" method="POST">
<div class="mb-3">
<label for="BloodType" class="form-label">Blood Type</label>
<input type="text" class="form-control" id="BloodType" name="BloodType" required>
</div>
<div class="mb-3">
<label for="Quantity" class="form-label">Quantity</label>
<input type="number" class="form-control" id="Quantity" name="Quantity" required>
</div>
<div class="mb-3">
<label for="ExpiryDate" class="form-label">Expiry Date</label>
<input type="date" class="form-control" id="ExpiryDate" name="ExpiryDate" required>
</div>
<button type="submit" class="btn btn-primary">Create Blood Product</button>
</form>
views/bloodProducts/edit.ejs
<% layout('layout') %>
<form action="/blood-products/<%= bloodProduct.BloodProductId %>?_method=PUT" method="POST">
<div class="mb-3">
<label for="BloodType" class="form-label">Blood Type</label>
<input type="text" class="form-control" id="BloodType" name="BloodType" value="<%= bloodProduct.BloodType %>" required>
</div>
<div class="mb-3">
<label for="Quantity" class="form-label">Quantity</label>
<input type="number" class="form-control" id="Quantity" name="Quantity" value="<%= bloodProduct.Quantity %>" required>
</div>
<div class="mb-3">
<label for="ExpiryDate" class="form-label">Expiry Date</label>
<input type="date" class="form-control" id="ExpiryDate" name="ExpiryDate" value="<%= bloodProduct.ExpiryDate.toISOString().slice(0, 10) %>" required>
</div>
<button type="submit" class="btn btn-primary">Update Blood Product</button>
</form>
views/bloodProducts/show.ejs
<% layout('layout') %>
<div>
<h2>Blood Product Details</h2>
<p><strong>BloodProductId:</strong> <%= bloodProduct.BloodProductId %></p>
<p><strong>BloodType:</strong> <%= bloodProduct.BloodType %></p>
<p><strong>Quantity:</strong> <%= bloodProduct.Quantity %></p>
<p><strong>ExpiryDate:</strong> <%= bloodProduct.ExpiryDate %></p>
<a href="/blood-products" class="btn btn-secondary">Back to Blood Products</a>
</div>
Inventories Views
views/inventories/index.ejs
<% layout('layout ') %>
<table class="table">
<thead>
<tr>
<th>InventoryId</th>
<th>BloodProductId</th>
<th>Quantity</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% inventories.forEach(inventory => { %>
<tr>
<td><%= inventory.InventoryId %></td>
<td><%= inventory.BloodProductId %></td>
<td><%= inventory.Quantity %></td>
<td>
<a href="/inventories/<%= inventory.InventoryId %>" class="btn btn-info">View</a>
<a href="/inventories/edit/<%= inventory.InventoryId %>" class="btn btn-warning">Edit</a>
<form action="/inventories/<%= inventory.InventoryId %>" method="POST" style="display:inline;">
<input type="hidden" name="_method" value="DELETE">
<button type="submit" class="btn btn-danger">Delete</button>
</form>
</td>
</tr>
<% }) %>
</tbody>
</table>
<a href="/inventories/create" class="btn btn-success">Add Inventory</a>
views/inventories/create.ejs
<% layout('layout') %>
<form action="/inventories" method="POST">
<div class="mb-3">
<label for="BloodProductId" class="form-label">Blood Product ID</label>
<input type="number" class="form-control" id="BloodProductId" name="BloodProductId" required>
</div>
<div class="mb-3">
<label for="Quantity" class="form-label">Quantity</label>
<input type="number" class="form-control" id="Quantity" name="Quantity" required>
</div>
<button type="submit" class="btn btn-primary">Create Inventory</button>
</form>
views/inventories/edit.ejs
<% layout('layout') %>
<form action="/inventories/<%= inventory.InventoryId %>?_method=PUT" method="POST">
<div class="mb-3">
<label for="BloodProductId" class="form-label">Blood Product ID</label>
<input type="number" class="form-control" id="BloodProductId" name="BloodProductId" value="<%= inventory.BloodProductId %>" required>
</div>
<div class="mb-3">
<label for="Quantity" class="form-label">Quantity</label>
<input type="number" class="form-control" id="Quantity" name="Quantity" value="<%= inventory.Quantity %>" required>
</div>
<button type="submit" class="btn btn-primary">Update Inventory</button>
</form>
views/inventories/show.ejs
<% layout('layout') %>
<div>
<h2>Inventory Details</h2>
<p><strong>InventoryId:</strong> <%= inventory.InventoryId %></p>
<p><strong>BloodProductId:</strong> <%= inventory.BloodProductId %></p>
<p><strong>Quantity:</strong> <%= inventory.Quantity %></p>
<a href="/inventories" class="btn btn-secondary">Back to Inventories</a>
</div>
Orders Views
views/orders/index.ejs
<% layout('layout') %>
<table class="table">
<thead>
<tr>
<th>OrderId</th>
<th>BloodProductId</th>
<th>Quantity</th>
<th>OrderDate</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% orders.forEach(order => { %>
<tr>
<td><%= order.OrderId %></td>
<td><%= order.BloodProductId %></td>
<td><%= order.Quantity %></td>
<td><%= order.OrderDate %></td>
<td><%= order.Status %></td>
<td>
<a href="/orders/<%= order.OrderId %>" class="btn btn-info">View</a>
<a href="/orders/edit/<%= order.OrderId %>" class="btn btn-warning">Edit</a>
<form action="/orders/<%= order.OrderId %>" method="POST" style="display:inline;">
<input type="hidden" name="_method" value="DELETE">
<button type="submit" class="btn btn-danger">Delete</button>
</form>
</td>
</tr>
<% }) %>
</tbody>
</table>
<a href="/orders/create" class="btn btn-success">Add Order</a>
views/orders/create.ejs
<% layout('layout') %>
<form action="/orders" method="POST">
<div class="mb-3">
<label for="BloodProductId" class="form-label">Blood Product ID</label>
<input type="number" class="form-control" id="BloodProductId" name="BloodProductId" required>
</div>
<div class="mb-3">
<label for="Quantity" class="form-label">Quantity</label>
<input type="number" class="form-control" id="Quantity" name="Quantity" required>
</div>
<button type="submit" class="btn btn-primary">Create Order</button>
</form>
views/orders/edit.ejs
<% layout('layout') %>
<form action="/orders/<%= order.OrderId %>?_method=PUT" method="POST">
<div class="mb-3">
<label for="BloodProductId" class="form-label">Blood Product ID</label>
<input type="number" class="form-control" id="BloodProductId" name="BloodProductId" value="<%= order.BloodProductId %>" required>
</div>
<div class="mb-3">
<label for="Quantity" class="form-label">Quantity</label>
<input type="number" class="form-control" id="Quantity" name="Quantity" value="<%= order.Quantity %>" required>
</div>
<button type="submit" class="btn btn-primary">Update Order</button>
</form>
views/orders/show.ejs
<% layout('layout') %>
<div>
<h2>Order Details</h2>
<p><strong>OrderId:</strong> <%= order.OrderId %></p>
<p><strong>BloodProductId:</strong> <%= order.BloodProductId %></p>
<p><strong>Quantity:</strong> <%= order.Quantity %></p>
<p><strong>OrderDate:</strong> <%= order.OrderDate %></p>
<p><strong>Status:</strong> <%= order.Status %></p>
<a href="/orders" class="btn btn-secondary">Back to Orders</a>
</div>
Reports Views
views/reports/index.ejs
<% layout('layout') %>
<table class="table">
<thead>
<tr>
<th>ReportId</th>
<th>UserId</th>
<th>ReportDate</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% reports.forEach(report => { %>
<tr>
<td><%= report.ReportId %></td>
<td><%= report.UserId %></td>
<td><%= report.ReportDate %></td>
<td>
<a href="/reports/<%= report.ReportId %>" class="btn btn-info">View</a>
<a href="/reports/edit/<%= report.ReportId %>" class="btn btn-warning">Edit</a>
<form action="/reports/<%= report.ReportId %>" method="POST" style="display:inline;">
<input type="hidden" name="_method" value="DELETE">
<button type="submit" class="btn btn-danger">Delete</button>
</form>
</td>
</tr>
<% }) %>
</tbody>
</table>
<a href="/reports/create" class="btn btn-success">Add Report</a>
views/reports/create.ejs
<% layout('layout') %>
<form action="/reports" method="POST">
<div class="mb-3">
<label for="User Id" class="form-label">User ID</label>
<input type="number" class="form-control" id="User Id" name="User Id" required>
</div>
<div class="mb-3">
<label for="ReportDate" class="form-label">Report Date</label>
<input type="datetime-local" class="form-control" id="ReportDate" name="ReportDate" required>
</div>
<div class="mb-3">
<label for="ReportContent" class="form-label">Report Content</label>
<textarea class="form-control" id="ReportContent" name="ReportContent" required></textarea>
</div>
<button type="submit" class=" btn btn-primary">Create Report</button>
</form>
views/reports/edit.ejs
<% layout('layout') %>
<form action="/reports/<%= report.ReportId %>?_method=PUT" method="POST">
<div class="mb-3">
<label for="User Id" class="form-label">User ID</label>
<input type="number" class="form-control" id="User Id" name="User Id" value="<%= report.UserId %>" required>
</div>
<div class="mb-3">
<label for="ReportDate" class="form-label">Report Date</label>
<input type="datetime-local" class="form-control" id="ReportDate" name="ReportDate" value="<%= report.ReportDate.toISOString().slice(0, 16) %>" required>
</div>
<div class="mb-3">
<label for="ReportContent" class="form-label">Report Content</label>
<textarea class="form-control" id="ReportContent" name="ReportContent" required><%= report.ReportContent %></textarea>
</div>
<button type="submit" class="btn btn-primary">Update Report</button>
</form>
views/reports/show.ejs
<% layout('layout') %>
<div>
<h2>Report Details</h2>
<p><strong>ReportId:</strong> <%= report.ReportId %></p>
<p><strong>UserId:</strong> <%= report.UserId %></p>
<p><strong>ReportDate:</strong> <%= report.ReportDate %></p>
<p><strong>ReportContent:</strong> <%= report.ReportContent %></p>
<a href="/reports" class="btn btn-secondary">Back to Reports</a>
</div>
Quality Controls Views
views/qualityControls/index.ejs
<% layout('layout') %>
<table class="table">
<thead>
<tr>
<th>QualityControlId</th>
<th>BloodProductId</th>
<th>InspectionDate</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% qualityControls.forEach(qualityControl => { %>
<tr>
<td><%= qualityControl.QualityControlId %></td>
<td><%= qualityControl.BloodProductId %></td>
<td><%= qualityControl.InspectionDate %></td>
<td><%= qualityControl.Status %></td>
<td>
<a href="/quality-controls/<%= qualityControl.QualityControlId %>" class="btn btn-info">View</a>
<a href="/quality-controls/edit/<%= qualityControl.QualityControlId %>" class="btn btn-warning">Edit</a>
<form action="/quality-controls/<%= qualityControl.QualityControlId %>" method="POST" style="display:inline;">
<input type="hidden" name="_method" value="DELETE">
<button type="submit" class="btn btn-danger">Delete</button>
</form>
</td>
</tr>
<% }) %>
</tbody>
</table>
<a href="/quality-controls/create" class="btn btn-success">Add Quality Control</a>
views/qualityControls/create.ejs
<% layout('layout') %>
<form action="/quality-controls" method="POST">
<div class="mb-3">
<label for="BloodProductId" class="form-label">Blood Product ID</label>
<input type="number" class="form-control" id="BloodProductId" name="BloodProductId" required>
</div>
<div class="mb-3">
<label for="InspectionDate" class="form-label">Inspection Date</label>
<input type="datetime-local" class="form-control" id="InspectionDate" name="InspectionDate" required>
</div>
<div class="mb-3">
<label for="Status" class="form-label">Status</label>
<input type="text" class="form-control" id="Status" name="Status" required>
</div>
<div class="mb-3">
<label for="Comments" class="form-label">Comments</label>
<textarea class="form-control" id="Comments" name="Comments"></textarea>
</div>
<button type="submit" class="btn btn-primary">Create Quality Control</button>
</form>
views/qualityControls/edit.ejs
<% layout('layout') %>
<form action="/quality-controls/<%= qualityControl.QualityControlId %>?_method=PUT" method="POST">
<div class="mb-3">
<label for="BloodProductId" class="form-label">Blood Product ID</label>
<input type="number" class="form-control" id="BloodProductId" name="BloodProductId" value="<%= qualityControl.BloodProductId %>" required>
</div>
<div class="mb-3">
<label for="InspectionDate" class="form-label">Inspection Date</label>
<input type="datetime-local" class="form-control" id="InspectionDate" name="InspectionDate" value="<%= qualityControl.InspectionDate.toISOString().slice(0, 16) %>" required>
</div>
<div class="mb-3">
<label for="Status" class="form-label">Status</label>
<input type="text" class="form-control" id="Status" name="Status" value="<%= qualityControl.Status %>" required>
</div>
<div class="mb-3">
<label for="Comments" class="form-label">Comments</label>
<textarea class="form-control" id="Comments" name="Comments"><%= qualityControl.Comments %></textarea>
</div>
<button type="submit" class="btn btn-primary">Update Quality Control</button>
</form>
views/qualityControls/show.ejs
<% layout('layout') %>
<div>
<h2>Quality Control Details</h2>
<p><strong>QualityControlId:</strong> <%= qualityControl.QualityControlId %></p>
<p><strong>BloodProductId:</strong> <%= qualityControl.BloodProductId %></p>
<p><strong>InspectionDate:</strong> <%= qualityControl.InspectionDate %></p>
<p><strong>Status:</strong> <%= qualityControl.Status %></p>
<p><strong>Comments:</strong> <%= qualityControl.Comments %></p>
<a href="/quality-controls" class="btn btn-secondary">Back to Quality Controls</a>
</div>
Campaigns Views
views/campaigns/index.ejs
<% layout('layout') %>
<table class="table">
<thead>
<tr>
<th>CampaignId</th>
<th>CampaignName</th>
<th>StartDate</th>
<th>EndDate</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% campaigns.forEach(campaign => { %>
<tr>
<td><%= campaign.CampaignId %></td>
<td><%= campaign.CampaignName %></td>
<td><%= campaign.StartDate %></td>
<td><%= campaign.EndDate %></td>
<td>
<a href="/campaigns/<%= campaign.CampaignId %>" class="btn btn-info">View</a>
<a href="/campaigns/edit/<%= campaign.CampaignId %>" class="btn btn-warning">Edit</a>
<form action="/campaigns/<%= campaign.CampaignId %>" method="POST" style="display:inline;">
<input type="hidden" name="_method" value="DELETE">
<button type="submit" class="btn btn-danger">Delete</button>
</form>
</td>
</tr>
<% }) %>
</tbody>
</table>
<a href="/campaigns/create" class="btn btn-success">Add Campaign</a>
views/campaigns/create.ejs
<% layout('layout') %>
<form action="/campaigns" method="POST">
<div class="mb-3">
<label for="CampaignName" class="form-label">Campaign Name</label>
<input type="text" class="form-control" id="CampaignName" name="CampaignName" required>
</div>
<div class="mb-3">
<label for="StartDate" class="form-label">Start Date</label>
<input type="datetime-local" class="form-control" id="StartDate" name="StartDate" required>
</div>
<div class="mb-3">
<label for="EndDate" class="form-label">End Date</label>
<input type="datetime-local" class="form-control" id="EndDate" name="EndDate" required>
</div>
<button type="submit" class="btn btn-primary">Create Campaign</button>
</form>
views/campaigns/edit.ejs
<% layout('layout') %>
<form action="/campaigns/<%= campaign.CampaignId %>?_method=PUT" method="POST"> <div class="mb-3"> <label for="CampaignName" class="form-label">Campaign Name</label> <input type="text" class="form-control" id="CampaignName" name="CampaignName" value="<%= campaign.CampaignName %>" required> </div> <div class="mb-3"> <label for="StartDate" class="form-label">Start Date</label> <input type="datetime-local" class="form-control" id="StartDate" name="StartDate" value="<%= campaign.StartDate.toISOString().slice(0, 16) %>" required> </div> <div class="mb-3"> <label for="EndDate" class="form-label">End Date</label> <input type="datetime-local" class="form-control" id="EndDate" name="EndDate" value="<%= campaign.EndDate.toISOString().slice(0, 16) %>" required> </div> <button type="submit" class="btn btn-primary">Update Campaign</button> </form>
views/campaigns/show.ejs
<% layout('layout') %>
<div>
<h2>Campaign Details</h2>
<p><strong>CampaignId:</strong> <%= campaign.CampaignId %></p>
<p><strong>CampaignName:</strong> <%= campaign.CampaignName %></p>
<p><strong>StartDate:</strong> <%= campaign.StartDate %></p>
<p><strong>EndDate:</strong> <%= campaign.EndDate %></p>
<a href="/campaigns" class="btn btn-secondary">Back to Campaigns</a>
</div>
This completes the set of EJS views for all controllers in your Node.js application, using Bootstrap 5 for styling and a consistent layout structure. Each view allows for CRUD operations, providing a user-friendly interface for managing users, roles, donors, appointments, blood products, inventories, orders, reports, quality controls, and campaigns.
To create a dashboard page that displays consolidated data related to your blood donation project, we will follow these steps:
Step 1: Create the Dashboard View
views/dashboard/index.ejs
<% layout('layout') %>
<h2>Dashboard</h2>
<div class="row">
<div class="col-md-4">
<div class="card text-white bg-primary mb-3">
<div class="card-header">Total Users</div>
<div class="card-body">
<h5 class="card-title"><%= totalUsers %></h5>
<p class="card-text">Number of registered users in the system.</p>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card text-white bg-success mb-3">
<div class="card-header">Total Donors</div>
<div class="card-body">
<h5 class="card-title"><%= totalDonors %></h5>
<p class="card-text">Total number of registered donors.</p>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card text-white bg-danger mb-3">
<div class="card-header">Total Appointments</div>
<div class="card-body">
<h5 class="card-title"><%= totalAppointments %></h5>
<p class="card-text">Total number of scheduled appointments.</p>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<h3>Recent Activities</h3>
<table class="table table-striped">
<thead>
<tr>
<th>Activity</th>
<th>User</th>
<th>Date</th>
</tr>
</thead>
<tbody>
<% recentActivities.forEach(activity => { %>
<tr>
<td><%= activity.description %></td>
<td><%= activity.user %></td>
<td><%= activity.date %></td>
</tr>
<% }) %>
</tbody>
</table>
</div>
</div>
Step 2: Create the Dashboard Controller
controllers/dashboardController.js
const User = require('../models/User');
const Donor = require('../models/Donor');
const Appointment = require('../models/Appointment');
class DashboardController {
async getDashboard(req, res) {
try {
const totalUsers = await User.count();
const totalDonors = await Donor.count();
const totalAppointments = await Appointment.count();
// Example recent activities (you can fetch this from your database)
const recentActivities = [
{ description: 'User JohnDoe registered.', user: 'JohnDoe', date: new Date().toLocaleString() },
{ description: 'Donor JaneDoe made a donation.', user: 'JaneDoe', date: new Date().toLocaleString() },
{ description: 'Appointment scheduled for Donor JohnDoe.', user: 'JohnDoe', date: new Date().toLocaleString() },
// Add more activities as needed
];
res.render('dashboard/index', {
title: 'Dashboard',
totalUsers,
totalDonors,
totalAppointments,
recentActivities
});
} catch (error) {
console.error('Error fetching dashboard data:', error);
res.status(500).send('Internal Server Error');
}
}
}
module.exports = new DashboardController();
Step 3: Define Routes for the Dashboard
routes/dashboardRoutes.js
const express = require('express');
const router = express.Router();
const dashboardController = require('../controllers/dashboardController');
router.get('/', dashboardController.getDashboard);
module.exports = router;
Step 4: Integrate the Dashboard into the Application
Make sure to integrate the dashboard route into your main application file (usually app.js or server.js).
app.js
const express = require('express');
const bodyParser = require('body-parser');
const methodOverride = require('method-override');
const userRoutes = require('./routes/userRoutes');
const roleRoutes = require('./routes/roleRoutes');
const donorRoutes = require('./routes/donorRoutes');
const appointmentRoutes = require('./routes/appointmentRoutes');
const bloodProductRoutes = require('./routes/bloodProductRoutes');
const inventoryRoutes = require('./routes/inventoryRoutes');
const orderRoutes = require('./routes/orderRoutes');
const reportRoutes = require('./routes/reportRoutes');
const qualityControlRoutes = require('./routes/qualityControlRoutes');
const campaignRoutes = require('./routes/campaignRoutes');
const dashboardRoutes = require('./routes/dashboardRoutes');
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(methodOverride('_method'));
app.set('view engine', 'ejs');
app.set('views', './views');
// Use routes
app.use('/users', userRoutes);
app.use('/roles', roleRoutes);
app.use('/donors', donorRoutes);
app.use('/appointments', appointmentRoutes);
app.use('/blood-products', bloodProductRoutes);
app.use('/inventories', inventoryRoutes);
app.use('/orders', orderRoutes);
app.use('/reports', reportRoutes);
app.use('/quality-controls', qualityControlRoutes);
app.use('/campaigns', campaignRoutes);
app.use('/dashboard', dashboardRoutes);
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
With these steps, you have created a dashboard page that displays consolidated data related to your blood donation project. The dashboard includes total counts of users, donors, and appointments, along with a table of recent activities. The controller fetches the necessary data, and the routes ensure that the dashboard is accessible from the main application.