Table of Contents
MangoDB Virtual Clinic is a comprehensive virtual healthcare platform that bridges the gap between patients, doctors, and administrators. Our platform is built on the principles of accessibility, efficiency, and security, ensuring that every interaction within the healthcare ecosystem is seamless and beneficial. The platform offers a user-friendly interface for patients to manage their health records, schedule appointments, and avail of exclusive discounts on medicines through subscription packages. Doctors, on the other hand, have tools to efficiently manage prescriptions, appointments, and patient interactions.
Patient-Centric Features:
-
User Registration and Authentication:
- Securely register as a patient with authentication mechanisms to protect user information.
- Easily change your passowrd anytime.
-
Doctor Interaction:
- View profiles of all available doctors.
- Conduct video calls with doctors for remote consultations.
- Engage in two-way communication with healthcare providers through secure messaging.
-
Convenient Appointment Scheduling:
- Schedule appointments with available doctors.
- Receive automated reminders through our system or by mail well in advance to ensure you never miss a scheduled appointment.
- Receive instant notifications in-app and via email if there are any changes to your scheduled appointments.
-
Subscription Packages:
- Subscribe to yearly packages for exclusive discounts on medicines and additional perks.
- Link family members to extend benefits to them.
-
Prescription Management:
- View and manage all prescriptions written by doctors.
- Download your prescription for easy access.
-
Wallet for Hassle-Free Payments:
- Utilize a wallet for easy and secure payments within the platform.
-
Personalized Health Records:
- Store and manage your health records in a centralized and secure environment.
- Access your medical history anytime, anywhere, facilitating informed decision-making.
Doctor-Empowering Tools:
-
Streamlined Prescription Management:
- View all prescriptions written for patients.
- Modify prescriptions as needed.
-
Patient Interaction Hub:
- View a list of all patients with whom at least one appointment has been scheduled.
- Streamline communication and follow-up care through video calls for enhanced patient outcomes.
- Engage in real-time chat conversations with patients with whom you have scheduled appointments.
-
Efficient Appointment Management:
- Organize and manage appointments efficiently, optimizing the doctor's schedule.
- View upcoming appointments.
-
Notifications System:
- Be promptly informed about cancellations or rescheduling to adapt your plans accordingly.
- Utilize our user-friendly interface to view updated appointment details and take necessary actions.
Administrator Oversight:
-
Centralized System Control:
- Administrators have a powerful interface to oversee and manage all aspects of the MangoDB Virtual Clinic.
- Ensure compliance, security, and seamless operation of the entire healthcare platform.
-
Analytics and Reporting:
- Leverage comprehensive analytics to gain insights into user engagement, appointment trends, and overall system performance.
- Generate detailed reports to inform strategic decisions and enhance the overall user experience.
Tech/Framework used:
- The project is currently in development.
- Unit Tests needs to be implemented.
- Some input fields are case senstive.
- Cookies may be implemented for smoother operations.
- Files sizes too large due to redundant code and could be more organized.
- The use of comments may be increased to aid in future maintenance.
- Ui could be improved.
- There may bugs that isn't found yet.
- Node.js - Ensure Node.js is installed to run the application.
- MongoDB - Set up a MongoDB database to store application data.
- VScode - Install any IDE to run the project on.
- Stripe - Head to Stripe and get your Stipe private key.
-
Clone the repo
git clone https://github.com/advanced-computer-lab-2023/MangoDB-Clinic.git
-
Navigate to the project directory:
cd MangoDB-Clinic
-
Install NPM packages
npm install
-
Navigate to the frontend folder:
cd frontned
-
Install NPM packages
npm install
-
Create a .env File:
In the root directory of MangoDB Virtual Clinic, create a
.env
file with the following content:# MongoDB Connection URI MONGO_URI="your_mongodb_url" # JSON Web Token Secret JWT_SECRET="your_secure_passphrase" # Stripe Private Key STRIPE_PRIVATE_KEY="your_stripe_private_key"
Make sure to replace the placeholder values with your actual MongoDB connection URL, a secure passphrase for JWT, and your Stripe private key.
Note: Keep your `.env file secure and never expose it to the public. It contains sensitive information required for the proper functioning of MangoDB Virtual Clinic.
-
Navigate Back to the Root Directory:
After creating the
.env
file, navigate back to the root directory of MangoDB Virtual Clinic:cd ..
-
Run the Application:
npm run dev
This command will launch MangoDB Virtual Clinic with the specified configurations from your .env file. Access the application in your web browser at http://localhost:3000.
Note: Ensure that MongoDB is running and accessible before starting the application.
-
Open your Web Browser:
- Launch your preferred web browser.
-
Visit MangoDB Virtual Clinic:
- Go to http://localhost:3000 to access the MangoDB Virtual Clinic platform.
-
Register Your Account:
- Sign up as either a patient or a doctor to unlock the platform's rich features.
-
Explore the Patient Dashboard:
- Dive into the intuitive patient dashboard to seamlessly manage your health journey.
-
Schedule Appointments:
- Use the scheduling feature to book appointments with your chosen healthcare professional.
-
Manage Prescriptions:
- Keep track of your prescriptions, and easily modify or renew them when needed.
-
Exclusive Subscription Packages:
- Explore and subscribe to exclusive yearly packages for discounts on medicines and additional perks.
-
For Doctors: Efficiently Manage Appointments:
- Access tools to manage appointments efficiently, ensuring optimal scheduling and patient care.
-
For Doctors: Streamlined Prescription Management:
- View and modify prescriptions with ease, providing accurate and up-to-date medical information.
-
For Doctors: Engage with Patients:
- View patient interactions and communicate effectively to enhance overall healthcare outcomes.
- Indentation: We use spaces for indentation, with a tab width of 2 spaces.
-
Naming Conventions:
- Follow camelCase for variable, function names, and routes.
- Use PascalCase for frontend folders and camelcase for backend folders.
- Comments: Add meaningful comments to explain complex sections of code.
- Files Managment: Files should be placed at the right place.
- Net Ninja
- Material Ui
- Stripe docs
- Mongoose docs
- DailyCo docs
- ReactJs docs
- NodeJs docs
- Caleb Curry Youtube
To set up MangoDB Virtual Clinic locally and start exploring its features, follow these simple steps:
Before you begin, make sure you have the following installed on your machine:
Experience the MangoDB Virtual Clinic by following these simple steps:
Note: To gain full experience try first filling the database with doctors and patients so you can see all the features.
The testing is done using Postman **Note:**For testing any GET, PUT,
Prescriptions test:
Enter the token you got from the login in bearer auth in postmanNote: You may get an empty array in case there are no prescriptions.
Structure:
.
βββ README.md
βββ backend
β βββ config
β β βββ db.js
β βββ controllers
β β βββ adminController.js
β β βββ doctorController.js
β β βββ guestController.js
β β βββ patientController.js
β βββ middleware
β β βββ adminMiddleware.js
β β βββ authMiddleware.js
β β βββ doctorMiddleware.js
β β βββ errorMiddleware.js
β β βββ patientMiddleware.js
β β βββ stripeMiddleware.js
β β βββ upload.js
β βββ models
β β βββ adminModel.js
β β βββ appointmentModel.js
β β βββ doctorModel.js
β β βββ packagesModel.js
β β βββ patientModel.js
β β βββ prescriptionModel.js
β β βββ userModel.js
β β βββ walletModel.js
β βββ routes
β β βββ adminRoutes.js
β β βββ doctorRoutes.js
β β βββ guestRoutes.js
β β βββ patientRoutes.js
β βββ server.js
β βββ views
β βββ addFamilyMember.ejs
β βββ adminDashboard.ejs
β βββ doctorHomePage.ejs
β βββ doctorRegistration.ejs
β βββ patientDashboard.ejs
β βββ patientRegistration.ejs
β βββ selectedPatient.ejs
β βββ viewAllPatients.ejs
βββ frontend
β βββ README.md
β βββ package-lock.json
β βββ package.json
β βββ public
β β βββ favicon.ico
β β βββ icons
β β β βββ accept.svg
β β β βββ add.svg
β β β βββ addMember.svg
β β β βββ address.svg
β β β βββ appointment.svg
β β β βββ approvedDocument.svg
β β β βββ call.svg
β β β βββ cart.svg
β β β βββ certificate.svg
β β β βββ chart.svg
β β β βββ chat.svg
β β β βββ clinic.svg
β β β βββ clinicLogo.svg
β β β βββ clinicLogo2.svg
β β β βββ clinicalDocument.svg
β β β βββ clinicalRecord.svg
β β β βββ creditCard.svg
β β β βββ dashboard.svg
β β β βββ date.svg
β β β βββ defaultLogo.svg
β β β βββ deniedDocument.svg
β β β βββ editDocument.svg
β β β βββ family.svg
β β β βββ familyFolder.svg
β β β βββ filter.svg
β β β βββ finance.svg
β β β βββ healthPackage.svg
β β β βββ index.js
β β β βββ info.svg
β β β βββ login.svg
β β β βββ logoEmblem.svg
β β β βββ logout.svg
β β β βββ meds.svg
β β β βββ medsV2.svg
β β β βββ menu.svg
β β β βββ mobile.svg
β β β βββ notes.svg
β β β βββ notifications.svg
β β β βββ password.svg
β β β βββ patient.svg
β β β βββ person.svg
β β β βββ pharmacist.svg
β β β βββ pharmacy.svg
β β β βββ pharmacyLogo.svg
β β β βββ pharmacyLogo2.svg
β β β βββ preferences.svg
β β β βββ prescription.svg
β β β βββ profile.svg
β β β βββ reject.svg
β β β βββ remove.svg
β β β βββ search.svg
β β β βββ secure.svg
β β β βββ settings.svg
β β β βββ tabIcon.png
β β β βββ ticket.svg
β β β βββ upload.svg
β β β βββ wallet.svg
β β β βββ warning.svg
β β βββ index.html
β β βββ logo192.png
β β βββ logo512.png
β β βββ manifest.json
β β βββ robots.txt
β βββ src
β βββ App.css
β βββ App.js
β βββ App.test.js
β βββ components
β β βββ AccountBalance.js
β β βββ Admin
β β β βββ AddAdmin.jsx
β β β βββ AddPackage.jsx
β β β βββ AdminDashboard.jsx
β β β βββ ChangePasswordAdmin.jsx
β β β βββ Chart.jsx
β β β βββ DateCard.jsx
β β β βββ EditHealthPackage.jsx
β β β βββ ForgotPasswordAdmin.jsx
β β β βββ HealthPackages.jsx
β β β βββ LoginAdmin.jsx
β β β βββ RemoveAdmin.jsx
β β β βββ RemoveDoctor.jsx
β β β βββ RemovePatient.jsx
β β β βββ RequestedDoctors.jsx
β β β βββ RequestedDoctorsTable.jsx
β β β βββ Title.jsx
β β β βββ UserManagement.jsx
β β β βββ listItems.jsx
β β βββ ChangePasswordDoctor.js
β β βββ Dashboard.js
β β βββ Doctor
β β β βββ DoctorForm.js
β β β βββ DoctorListItems.js
β β β βββ Reschedule.js
β β βββ DoctorDetails.js
β β βββ DoctorSearch.js
β β βββ DoctorsTable.js
β β βββ Filter.js
β β βββ GeneralComponents
β β β βββ ForgotPasswordUser.jsx
β β β βββ LoginUser.jsx
β β β βββ PrescriptionsTable.js
β β β βββ Spinner.jsx
β β βββ NavBar.js
β β βββ Patient
β β β βββ ChangePasswordPatient.js
β β β βββ Notification.js
β β β βββ PatientForm.js
β β β βββ patientListItems.js
β β βββ PrescriptionDetails.jsx
β β βββ ReusableTable2.js
β βββ index.css
β βββ index.js
β βββ pages
β β βββ AddHealthRecordsPatient.js
β β βββ AddSlots.js
β β βββ Admin
β β β βββ AddAdminPage.jsx
β β β βββ AddPackagePage.jsx
β β β βββ ChangePasswordPage.jsx
β β β βββ DashboardPage.jsx
β β β βββ EditHealthPackagePage.jsx
β β β βββ ForgotPasswordAdminPage.jsx
β β β βββ HealthPackagesPage.jsx
β β β βββ LoginAdminPage.jsx
β β β βββ RemoveAdminPage.jsx
β β β βββ RemoveDoctorPage.jsx
β β β βββ RemovePatientPage.jsx
β β β βββ RequestedDoctorsPage.jsx
β β β βββ UserManagementPage.jsx
β β βββ Cancel.js
β β βββ Checkout.js
β β βββ Doctor
β β β βββ ChangePasswordDoctorPage.js
β β β βββ DoctorApps.js
β β β βββ EditDoctor.js
β β β βββ PatientDetails.js
β β β βββ PatientList.js
β β β βββ ViewPrescriptionsDoctor.js
β β β βββ doctorDashboard.jsx
β β βββ General
β β β βββ ForgotPasswordUserPage.jsx
β β β βββ LoginUserPage.jsx
β β βββ Home.js
β β βββ LinkFamMember.js
β β βββ LinkPatientAsFam.js
β β βββ Patient
β β β βββ ChangePasswordPatientPage.js
β β β βββ PatientDashboard.jsx
β β β βββ ViewPackagesPatient.js
β β β βββ ViewPrescriptionsPatient.js
β β βββ PrescriptionDetails.js
β β βββ Success.js
β β βββ ViewAppointments.js
β β βββ ViewDoctors.js
β β βββ ViewEmploymentContract.js
β β βββ ViewFamilyMembers.js
β β βββ ViewHealthRecordsPat.js
β β βββ ViewPackages.js
β β βββ ViewProfile.js
β β βββ ViewWallet.js
β β βββ cancelHealthPackageSubscription.js
β β βββ successfulPackagePayment.js
β β βββ viewHealthPackageSubscription.js
β βββ reportWebVitals.js
β βββ services
β β βββ api.js
β βββ setupTests.js
β βββ theme.js
β βββ useFetch.js
βββ package-lock.json
βββ package.json
βββ readme_images
β βββ clinicLogo.svg
β βββ dailyco.png
β βββ doctorDashboard.png
β βββ homepage.png
β βββ pateintDashboard.png
βββ uploads
βββ placeholderImg.jpeg
Styles πͺ:
Get Prescriptions of patient
const getAllPrescriptionsOfPatient = async (req, res) => {
const patientId = req.user._id;
if (!mongoose.Types.ObjectId.isValid(patientId)) {
return res.status(404).json({ error: "Id Not Found" });
}
try {
const patient = await Patient.findById(patientId);
if (!patient) {
return res.status(404).json({ error: "Patient Not Found" });
}
const prescriptions = await Prescription.find({
patientId: patientId,
})
.populate("doctorId")
.populate("patientId");
console.log(prescriptions);
res.status(200).json(prescriptions);
} catch (error) {
console.error(error);
res.status(500).json({ error: "Internal Server Error" });
}
};
Create Video Chat
// @desc Create a new video chat with selected doctor
// @route POST /patient/createVideoChat/:doctorId
// @access Private
const createVideoChat = asyncHandler(async (req, res) => {
const patient = req.user;
const doctor = await Doctor.findById(req.params.doctorId);
if (!doctor) {
res.status(400);
throw new Error("Doctor Not Found");
}
fetch("https://api.daily.co/v1/rooms", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Authorization:
"Bearer 8f336eeba4331019a6bab843ab49c57d657a2a3f80fdc0bda2c8afe600a9b3e9",
},
body: JSON.stringify({
name: `Meeting-${generateRandomId(10)}`,
properties: {
enable_screenshare: true,
enable_chat: true,
enable_knocking: true,
start_video_off: true,
start_audio_off: false,
lang: "en",
},
}),
})
.then((res) => res.json())
.then((json) => {
console.log("json: ", json);
const roomUrl = json.url;
// Send email to doctor
const transporter = nodemailer.createTransport({
service: "Gmail",
auth: {
user: "[email protected]",
pass: "vtzilhuubkdtphww",
},
});
const mailOptions = {
from: "[email protected]",
to: doctor.email,
subject: `Video Chat Request From ${patient.firstName} ${patient.lastName}`,
text: `Hello Dr. ${doctor.lastName},\n\nYou have a video chat scheduled with ${patient.firstName} ${patient.lastName}.\n\nPlease join the video chat using the following URL: ${roomUrl}\n\nBest regards,\nYour Clinic`,
};
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
console.log("Error sending email:", error);
} else {
res.status(200).json({
message: "Video chat created successfully.",
url: roomUrl,
});
console.log("Email sent:", info.response);
}
});
return json;
})
.catch((err) => console.log("error: ", err));
});
Add Prescriptions By Doctor
const addPrescription = async (req, res) => {
const doctorId = req.user.id;
const { patientName, date, medications } = req.body;
if (!patientName || !date) {
return res
.status(400)
.json({ message: "Please enter patient name and date." });
}
try {
const patient = await Patient.findOne({ username: patientName });
if (!patient) {
return res.status(400).json({ message: "Patient not found." });
}
const prescription = await Prescription.create({
patientId: patient._id,
doctorId: doctorId,
medications: medications,
date: date,
});
const updatedPrescription = await prescription.populate("patientId");
console.log(updatedPrescription);
res.status(201).json(updatedPrescription);
} catch (error) {
console.error(error);
res.status(500).json({ message: "Error adding prescription." });
}
};
View Employment Contract By Doctor
const viewEmploymentContract = async (req, res) => {
try {
const doctorId = req.user._id;
const doctor = await Doctor.findById(doctorId);
if (!doctor) {
return res.status(404).json({ error: "Doctor not found" });
}
if (!doctor.employmentContract || !doctor.employmentContract.file) {
return res.status(404).json({ error: "Employment contract not found" });
}
// Construct the file path to the employment contract
const filePath = path.join(
__dirname,
"../uploads/employment_contracts",
doctor.employmentContract.file
);
// Check if the file exists
if (fs.existsSync(filePath)) {
// Return the file as a response
res.download(filePath);
} else {
res.status(404).json({ error: "Employment contract file not found" });
}
} catch (error) {
console.error("Error viewing employment contract:", error);
res.status(500).json({ error: "An error occurred" });
}
};
Create Admin
// @desc Create new admin
// @route POST /admin/create-admin
// @access Private
const createAdmin = asyncHandler(async (req, res) => {
const { email, firstName, lastName } = req.body;
if (!email || !firstName || !lastName) {
res.status(400);
throw new Error("Please Enter All Fields");
}
if (!emailValidator(email)) {
res.status(400);
throw new Error("Invalid Email Format");
}
// Check if admin exists
const adminExists = await Admin.findOne({ email });
if (adminExists) {
res.status(400);
throw new Error("An Admin With This Email Already Exists");
}
const randomUsername = generateRandomUsername();
const password = generateRandomPassword();
// Hash password
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(password, salt);
// Create user
const admin = await Admin.create({
username: randomUsername,
email,
password: hashedPassword,
firstName,
lastName,
});
if (admin) {
res.status(201).json({
_id: admin.id,
name: admin.firstName + " " + admin.lastName,
username: randomUsername,
password: password,
});
} else {
res.status(400);
throw new Error("Invalid Data");
}
});
Login Page return statement:
return (
<ThemeProvider theme={defaultTheme}>
<Container component='main' maxWidth='xs'>
<CssBaseline />
{isLoading ? (
<Spinner />
) : (
<>
<Box
sx={{
marginTop: 8,
display: "flex",
flexDirection: "column",
alignItems: "center",
}}
>
<Avatar sx={{ m: 1, bgcolor: "secondary.main" }}>
<LockOutlinedIcon />
</Avatar>
<Typography component='h1' variant='h5'>
Welcome Back ππ½
</Typography>
<Typography component='h4' variant='h5'>
Login To Use The Dashboard
</Typography>
<Box
component='form'
onSubmit={handleSubmit}
noValidate
sx={{ mt: 1 }}
>
<TextField
margin='normal'
required
fullWidth
id='username'
label='Username'
name='username'
value={formData.username}
onChange={handleInputChange}
autoComplete='username'
autoFocus
/>
<TextField
margin='normal'
required
fullWidth
name='password'
label='Password'
type='password'
id='password'
onChange={handleInputChange}
value={formData.password}
autoComplete='current-password'
/>
<Button
type='submit'
fullWidth
variant='contained'
sx={{ mt: 3, mb: 2 }}
>
Login
</Button>
<Grid container>
<Grid item xs>
<Link href='/forgot-password' color='#2fc4b2'>
Forgot password?
</Link>
</Grid>
<Grid container justifyContent='space-between'>
<Grid item>
<Link href='/patientform' color='#2fc4b2'>
Register As Patient
</Link>
</Grid>
<Grid item>
<Link href='/doctorform' color='#2fc4b2'>
Register As Doctor
</Link>
</Grid>
</Grid>
</Grid>
</Box>
</Box>
<Copyright sx={{ mt: 8, mb: 4 }} />
</>
)}
</Container>
</ThemeProvider>
);
Use Effects hooks for getting the packages
useEffect(() => {
const fetchPackages = async () => {
setIsPending(true);
setError(null);
const token = localStorage.getItem("token");
try {
const res = await fetch(
"http://localhost:4000/patient/view_health_packages",
{
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
}
);
if (!res.ok) {
throw Error("Could not fetch the data for that resource");
}
const data = await res.json();
setPackages(data);
setIsPending(false);
} catch (err) {
setError(err.message);
setIsPending(false);
}
};
fetchPackages();
}, []);
useEffect(() => {
const checkSubscription = async () => {
try {
const data = await subscribedPatient();
console.log("enttt");
if (data.healthPackage.status === "Subscribed") {
setSubscribed(true);
setCancelled(false);
setPackageInfo(data.healthPackage);
setPatient(data.patient);
console.log(data.healthPackage);
console.log(data);
} else if (data.healthPackage.status === "Cancelled") {
setCancelled(true);
setSubscribed(false);
setPackageInfo(data.healthPackage);
setPatient(data.patient);
} else {
setSubscribed(false);
setCancelled(false);
setPackageInfo(null);
setPatient(null);
}
} catch (error) {
console.error("Error while checking subscription:", error);
}
};
checkSubscription();
}, [cancelled, subscribed]);
To view all the routes:
Run at route Directory
npm run generate-swagger
Note: you will find the routes in backend/swagger-output.json
Contributions are always welcomed!
See contributing.md
for ways to get started.
Please adhere to this project's code of conduct
.
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
This project utilizes the Stripe service for payment processing. By using this project, you agree to comply with Stripe's terms of service. Any use of Stripe is subject to their terms and conditions.
This project integrates with Daily.co for video call functionality. Your use of this project is subject to Daily.co's terms of service. Please review their terms and conditions for compliance.
The software is open source under the GPL.3 License. GPT3