El7a2ni
El7a2ni is a software solution for clinics, doctors, and patients alike to streamline and automate the interactions between patients and medical doctors. This encompasses everything from trying to schedule meetings with doctors, conducting on-premise or online meetings, getting prescriptions, and accessing medical history.
The need to modernize healthcare interactions gave rise to El7a2ni. Traditional approaches frequently require a lot of paperwork, which causes delays and inefficiencies. The goal of this project is to provide a seamless digital solution by streamlining and improving communication between doctors and patients.
- Website can't upload multiple files together
- The data takes time to be fetched from backend and MongoDB
- The project needs in the near future to be deployed through AWS Services or alike.
- To create a zoom video call you need to login with a specific account. This will change after zoom approves our app
*Frontend (Client-Side): React, Bootstrap, SweetAlert2
*Backend (Server-Side): Node.js, Express, MongoDB
- Clone the link of repository from github.
- install node.js
- cd to the repo location
npm installcd backendthennpm installcd frontendthennpm install
We use Postman for testing our clinic application. Follow these steps to run the tests:
- Ensure that the clinic application is running locally or on a specified server.
- Open Postman the navigate to My WorkSpace. Click on "New"
- Click on "New"
- Description: Verifies that users can successfully register for an account.
- Steps:
- Send a POST request to the /api/patient/registerPatient endpoint with valid user information.
- click on "Body", then Text , the choose JSON . Then write your data in json format
- Check that the response status is 201 (Created).
- In mongoDB , browse the collections then go to 'Patients' collection and 'Users' collection
- You will find a new document with the data you entered in postman in both collections.
- Description: Verifies that users can successfully login for an account.
- Steps:
- Send a POST request to the /api/user/login endpoint with valid user information.
- click on "Body", then Text , then choose JSON . Then write your data in json format. follow this example when writing data: { "username" : "your_username", "password" : "your_password" }
- Check that the response status is 200.
- Postman will print the following :
- the "_id" in your document.
- the "role" in your document.
- the "token" in your document.
- the "username" in your document. 5.If you wrote a wrong password , postman will print "Invalid Password"
- Use port 4000 for the backend
- You can use the same methodolgy used in the test cases examples above for testing every endpoint in the system. You may find the routes in API references section.
Important Note: Ensure that the clinic application server is running and accessible before running the tests.
The code style is enforced using eslint and prettier. The code style is enforced using pre-commit hooks and pre-commit github action.
-
ADMIN
a) can add/remove another admin b) can remove doctor/patient c) can accept/reject doctor's request to join platform d) add/update/delete health package -
GUEST
a) submit request to join as a doctor b) upload and submit required documents upon regitration c) register as a patient -
PATIENT
a) upload/remove document such as PDF for medical history b) filter appointments c) view/link family member d) filter a doctor by speciality/name e) view/subscribe health package status f) reschedule/cancel an appointment g) chat with doctor/patient h) view/filter/download prescription i) view upcoming/past appointments list -
DOCTOR
a) edit/update Email,Affliation, or Hourly Rate b) view uploaded health records c) filter appointments d) view upcoming/past appointments list e) reschedule/cancel appointment f) schedule follow-up for patient g) start/end video call with patient/doctor h) add/update medice dosage i) add new health record for patient
*Frontend
-
import { useEffect, useState } from "react"; import Swal from "sweetalert2"; import HealthRecordDetails from "../components/HealthRecordDetails"; const ViewpatientHealthRecord = () =>{ const [healthRecord , setHealthRecord] = useState(null) useEffect(() => { const fetchHealthRecord = async () =>{ const response = await fetch('api/healthRecord/getHealthRecordOfPatient') if(response.ok){ const json = await response.json() console.log("patients are ",json) setHealthRecord(json) } else { const errorMessage = await response.text(); Swal.fire({ icon: 'error', title: 'Error', text: "No health record found", }); } } fetchHealthRecord() },[]) return ( <div className="container justify-content-center col-md-7 "> <h2 className="mb-4"> <hr className="linearound"></hr> Your HealthRecord <hr className="linearound"></hr> </h2> {healthRecord && <HealthRecordDetails healthRecord={healthRecord} />} </div> ); } export default ViewpatientHealthRecord; -
import {useState,useEffect} from "react"; import PatientDetails from "../components/PatientDetails"; import Swal from 'sweetalert2'; const ViewAndRemovePatients = ()=> { const [patients, setPatients] = useState([]); const [selectedPatient,setSelectedPatient] = useState(null) console.log("in method") useEffect(() => { fetchResults(); }, []); const fetchResults = async () => { try{ const response = await fetch('api/patient/getPatients',{ method: 'GET', headers: { 'Content-Type':'application/json', }, }); if (response.ok){ const results = await response.json(); setPatients(results) console.log(patients) } else { const errorMessage = await response.text(); Swal.fire({ icon: 'error', title: 'Error', text: 'Could not fetch results. Please try again later.', }); throw new Error(errorMessage) } } catch (error){ setSelectedPatient(null) } }; const handleRemovePatient = async (patientId) => { try { const response = await fetch(`/api/patient/deletePatient/${patientId}`, { method: 'DELETE', }); if (response.ok) { fetchResults(); setSelectedPatient(null); Swal.fire({ icon: 'success', title: 'Success', text: 'The patient has been removed successfully.', }); } else { const errorMessage = await response.text(); Swal.fire({ icon: 'error', title: 'Error', text: errorMessage, }); throw new Error(errorMessage); } } catch (error) { console.error(error); } }; return ( <div className="container mt-4"> <div className="row"> <h2 className="mb-4"> <hr className="linearound"></hr> System patients <hr className="linearound"></hr> </h2> <div className="col-md-5"> <ul className="list-group"> {patients.map((patient) => ( <li key={patient._id} className="list-group-item"> <button className="btn btn-link btn-lg" onClick={() => setSelectedPatient(patient)} style={{ textDecoration: "none", color:'#1B3236' }} > {patient.name} </button> </li> ))} </ul> </div> <div className="col-md-5 mt-5"> {selectedPatient && ( <> <div style={{ marginLeft: '10px' }}> {/* Add margin to the bottom */} <PatientDetails patient={selectedPatient} /> </div> <button className="custom-btn wider-button" style={{ marginLeft: '30px', marginTop:'5px', width:'150px' }} onClick={() => handleRemovePatient(selectedPatient._id)}>Remove</button> </> )} </div> </div> </div> ); }; export default ViewAndRemovePatients
*Backend
-
const getDoctorRequests = asyncHandler(async (req, res) => { try { const DoctorRequests = await DoctorRegistrationModel.find({}).sort({createdAt: -1}) res.status(200).json(DoctorRequests) } catch (error){ res.status(400) throw new Error(error.message) } }) -
const rejectContract = asyncHandler(async (req,res) => { try { const contract = await EmploymentContract.findOne({doctor:req.user.id}); if (!contract) { res.status(404) throw new Error("Contract not found") } contract.status = "REJECTED" await contract.save() res.status(200).json(contract) } catch (error) { res.status(400) throw new Error(error.message) } })
After finishing the Installation process you need to create an .env file in the backend folder.
- Open new terminal.
cd backendnode server.js“wait until MongoDB connected”.- Open new terminal.
cd frontendnpm start“wait until your browser open automatically”.
Then you will be able to become one of the four primary users of our website (User, Admin, Doctor, Patient, and ). You can make an account and login to the website by using the sign up page to create an account, After that, you will be able to utilize our features, log in, and change your password.
We welcome and appreciate contributions from the community to enhance El7a2ni and make it more robust. Whether it's fixing bugs, adding new features, or improving documentation, your contributions are valuable to us.
https://www.youtube.com/@NetNinja
https://www.w3schools.com/html/default.asp
https://www.youtube.com/playlist
list=PL4cUxeGkcC9iJ_KkrkBZWZRHVwnzLIoUE
The project is licensed under the Apache License 2.0.
Zoom has video call service has been used in this
- Admin:
GET api/admin/getAdmin/:id| Parameter | Type | Description |
|---|---|---|
id |
string |
Required. You need to be an admin |
GET api/admin/getAlladmins| Parameter | Type | Description |
|---|---|---|
None |
None |
Required. You need to be an admin |
POST api/admin/addAdmin| Parameter | Type | Description |
|---|---|---|
None |
None |
Required. You need to be an admin |
DELETE api/admin/deleteAdmin| Parameter | Type | Description |
|---|---|---|
id |
String |
Required. You need to be an admin |
- Doctor:
GET api/doctor/searchByNameAndOrSpeciality/:name/:speciality| Parameter | Type | Description |
|---|---|---|
name |
String |
Required. You need to be an patient |
speciality |
String |
Required. You need to be a patient |
POST api/doctor/createDoctor| Parameter | Type | Description |
|---|---|---|
none |
none |
Create doctor |
GET api/doctor/viewDoctor| Parameter | Type | Description |
|---|---|---|
id |
string |
Required the doctor's ID |
GET api/doctor/filterBySpecialityAndDate/:speciality/:date| Parameter | Type | Description |
|---|---|---|
speciality |
string |
Required Doctor speciality |
date |
date |
Required docotr name |
DELETE api/doctor/removeDoctor/:id| Parameter | Type | Description |
|---|---|---|
id |
string |
Required the doctor's ID |
GET api/doctor/getDoctors| Parameter | Type | Description |
|---|---|---|
none |
none |
GET api/doctor/getDoctors| Parameter | Type | Description |
|---|---|---|
none |
none |
Required. You need to be a doctor |
GET api/doctor/getSessionPrice| Parameter | Type | Description |
|---|---|---|
none |
none |
Required. You need to be a patient |
POST api/doctor/getSessionPrice| Parameter | Type | Description |
|---|---|---|
none |
none |
GET api/doctor/getPatientDoctors| Parameter | Type | Description |
|---|---|---|
none |
none |
Required. You need to be a patient |
GET api/doctor/getAmount| Parameter | Type | Description |
|---|---|---|
none |
none |
Required. You need to be a Doctor |
GET api/doctor/searchDoctorsToChatClinic/:name/:specialty| Parameter | Type | Description |
|---|---|---|
name |
string |
Doctor name |
speciality |
string |
Doctor Speciality |
GET api/doctor/searchDoctorsToChat/:name/:specialty| Parameter | Type | Description |
|---|---|---|
name |
string |
Doctor name |
speciality |
string |
Doctor Speciality |
- File:
POST api/file/addSingleFile| Parameter | Type | Description |
|---|---|---|
none |
none |
POST api/file/addSingleFileGuest/:username| Parameter | Type | Description |
|---|---|---|
username |
String |
Guest Username |
GET api/file/getSingleFiles| Parameter | Type | Description |
|---|---|---|
none |
none |
GET api/file/getFileById/:id| Parameter | Type | Description |
|---|---|---|
id |
String |
File ID |
POST api/file/addMultipleFiles| Parameter | Type | Description |
|---|---|---|
none |
none |
GET api/file/getMultipleFiles| Parameter | Type | Description |
|---|---|---|
none |
none |
DELETE api/file/deleteSingleFile/:id| Parameter | Type | Description |
|---|---|---|
id |
String |
File ID |
DELETE api/file/deleteAllSingleFiles| Parameter | Type | Description |
|---|---|---|
none |
none |
GET api/file/uploads/:filename| Parameter | Type | Description |
|---|---|---|
filename |
String |
File Name |
- Health Package Patient:
POST api/healthPackage/subscribeToPackage| Parameter | Type | Description |
|---|---|---|
none |
none |
GET api/healthPackage/getSubscribedPackage| Parameter | Type | Description |
|---|---|---|
none |
none |
GET api/healthPackage/getSubscribedPackageStatus| Parameter | Type | Description |
|---|---|---|
none |
none |
GET api/healthPackage/getPatientPackages| Parameter | Type | Description |
|---|---|---|
none |
none |
DELETE api/healthPackage/cancelSubscription/:familyMemberID| Parameter | Type | Description |
|---|---|---|
id |
String |
Family Member ID |
- Health Record:
POST api/healthPackage/createHealthRecord| Parameter | Type | Description |
|---|---|---|
none |
none |
GET api/healthPackage/getHealthRecordOfPatient| Parameter | Type | Description |
|---|---|---|
none |
none |
GET api/healthPackage/getHealthRecordOfPatients| Parameter | Type | Description |
|---|---|---|
none |
none |
POST api/healthPackage/AddHealthRecord/:patientid| Parameter | Type | Description |
|---|---|---|
id |
String |
Patient ID |
- Patient:
GET api/patient/getPatients| Parameter | Type | Description |
|---|---|---|
none |
none |
GET api/patient/getPatient/:id| Parameter | Type | Description |
|---|---|---|
id |
String |
Patient ID |
POST api/patient/registerPatient| Parameter | Type | Description |
|---|---|---|
none |
none |
DELETE api/patient/deletePatient/:id| Parameter | Type | Description |
|---|---|---|
id |
String |
Patient ID |
PUT api/patient/updatePatient/:id| Parameter | Type | Description |
|---|---|---|
id |
String |
Patient ID |
GET api/patient/getPatientsOfADoctor| Parameter | Type | Description |
|---|---|---|
none |
none |
GET api/patient/getAmount| Parameter | Type | Description |
|---|---|---|
none |
none |
GET api/patient/getInfoHealthPatient/:id| Parameter | Type | Description |
|---|---|---|
id |
String |
Patient ID |
GET api/patient/searchByName/:name| Parameter | Type | Description |
|---|---|---|
name |
String |
Patient name |
GET api/patient/payForSubscription/:familyMemberID/:packageID/:paymentMethod| Parameter | Type | Description |
|---|---|---|
id |
String |
Family member ID |
id |
String |
Package ID |
paymentMethod |
String |
Payment Method |
POST api/patient/subscribeToPackage/:sessionID| Parameter | Type | Description |
|---|---|---|
id |
String |
Session ID |
- Prescription:
GET api/prescription/getPrescriptionsbyPatient| Parameter | Type | Description |
|---|---|---|
none |
none |
GET api/prescription/getPrescriptionbyId/:id| Parameter | Type | Description |
|---|---|---|
id |
String |
Prescription ID |
POST api/prescription/addPrescription| Parameter | Type | Description |
|---|---|---|
none |
none |
GET api/prescription/filterByDoctor/:doctorId| Parameter | Type | Description |
|---|---|---|
id |
String |
Doctor ID |
GET api/prescription/filterByDate/:createdAt| Parameter | Type | Description |
|---|---|---|
date |
date |
The date prescriptions were created at |
GET api/prescription/filterbyStatus/:status| Parameter | Type | Description |
|---|---|---|
status |
String |
The status of prescriptions |
- Doctor Registration:
POST api/doctorRegistration/doctorRegistrationRequest| Parameter | Type | Description |
|---|---|---|
None |
None |
Body:
- doctor (object): The doctor object containing registration details.
GET api/doctorRegistration/getDoctorRequests| Parameter | Type | Description |
|---|---|---|
None |
None |
You need to be an admin |
POST api/doctorRegistration/acceptDoctorRequests/:id| Parameter | Type | Description |
|---|---|---|
id |
string |
Required. Doctor Request ID |
DELETE api/doctorRegistration/rejectDoctorRequests/:id| Parameter | Type | Description |
|---|---|---|
id |
string |
Required. Doctor Request ID |
- Employment Contract:
POST api/employmentContracts/createContracts| Parameter | Type | Description |
|---|---|---|
none |
none |
You need to be an admin |
Body:
- employmentContract (object): The employment contract details.
GET api/employmentContracts/getContracts| Parameter | Type | Description |
|---|---|---|
none |
none |
You need to be an admin |
GET api/employmentContracts/getDoctorContract| Parameter | Type | Description |
|---|---|---|
none |
none |
You need to be a doctor |
PUT api/employmentContracts/acceptContract| Parameter | Type | Description |
|---|---|---|
none |
none |
You need to be a doctor |
PUT api/employmentContracts/rejectContract| Parameter | Type | Description |
|---|---|---|
none |
none |
You need to be a doctor |
- Chat:
POST api/chat/accessChat| Parameter | Type | Description |
|---|---|---|
none |
none |
You need to be a doctor or patient |
Body:
- userId (string): ID of the requested user.
GET api/chat/fetchChats| Parameter | Type | Description |
|---|---|---|
none |
none |
You need to be a doctor or patient |
POST api/chat/accesChatFromPharmacy| Parameter | Type | Description |
|---|---|---|
none |
none |
Body:
- userId (string): ID of the requested user.
- pharmacistUsername (string): Username of the pharmacist requesting the chat.
- pharmacyChatId (string): ID of the chat in the pharmacy's database.
Note: This route does not use the protect middleware because it is accessed by pharmacy users.
- Health Package:
POST api/healthPackage/addPackage| Parameter | Type | Description |
|---|---|---|
none |
none |
You need to be an admin |
Body:
- healthPackage (object): contains details about health package
GET api/healthPackage/getPackage/:id| Parameter | Type | Description |
|---|---|---|
id |
string |
Required. Health Package ID |
GET api/healthPackage/getPackages| Parameter | Type | Description |
|---|---|---|
none |
none |
PUT api/healthPackage/updatePackage/:id| Parameter | Type | Description |
|---|---|---|
id |
string |
Required. Health Package ID |
Body:
- packageName (string): updated name of the package
- yearlySubscription (float): updated yearly subscription price
- doctorSessionDiscount (float): updated appointment discount
- medicineDiscount (float): updated medicine discount
- familyDiscount (float): updated health package discount for family members
DELETE api/healthPackage/deletePackage/:id| Parameter | Type | Description |
|---|---|---|
id |
string |
Required. Health Package ID |
GET api/healthPackage/getPackagesWithDiscount| Parameter | Type | Description |
|---|---|---|
none |
none |
You need to be a patient |
Description:
-
Gets all packages and adds discountedYearlySubscription attribute, but returns empty string if no discount.
-
Notification
GET api/notification/getUserNotifications| Parameter | Type | Description |
|---|---|---|
none |
none |
DELETE api/notification/deleteNotificationById/:id| Parameter | Type | Description |
|---|---|---|
id |
string |
Required. Notification ID |
- User:
POST api/user/login| Parameter | Type | Description |
|---|---|---|
none |
none |
Body:
- username (string)
- password (string)
POST api/user/logout| Parameter | Type | Description |
|---|---|---|
none |
none |
POST api/user/generateOTP| Parameter | Type | Description |
|---|---|---|
none |
none |
Body:
- email (string): E-mail of the user that is requesting the OTP
POST api/user/resetPassword| Parameter | Type | Description |
|---|---|---|
none |
none |
Body:
- email (string): E-mail of the user that is requesting the password reset.
- newPassword (string): Must contain at least one number, one capital letter and one small letter.
POST api/user/changePassword| Parameter | Type | Description |
|---|---|---|
none |
none |
Body:
- currentPassword (string): Current password of the user.
- newPassword (string): Must contain at least one number, one capital letter and one small letter.
- confirmPassword (string): Must be equal to newPassword.
GET api/user/getUser| Parameter | Type | Description |
|---|---|---|
none |
none |
- Appointment:
POST/api/appointment/createAppointment| Parameter | Type | Description |
|---|---|---|
| None | None | Required. Doctor role |
GET/api/appointment/getUpcomingPatientsOfDoctor| Parameter | Type | Description |
|---|---|---|
| None | None | Required. Doctor role |
GET/api/appointment/getAppointment/:patientid/:doctorid| Parameter | Type | Description |
|---|---|---|
patientid |
string |
Required. patient ID |
doctorid |
string |
Required. Doctor ID |
GET/api/appointment/getAppointmentsByDateAndStatus/:appointmentDate/:status| Parameter | Type | Description |
|---|---|---|
appointmentDate |
Date |
Required. appointment |
status |
String |
Required. status |
GET/api/appointment/getAppointments| Parameter | Type | Description |
|---|---|---|
| None | None | Required. Doctor role |
GET/api/appointment/viewAvailableAppointmentsOfDoctor/:doctorId| Parameter | Type | Description |
|---|---|---|
doctorId |
String |
Required. Patient role |
PUT/api/appointment/reserveAppointment/:paymentMethod| Parameter | Type | Description |
|---|---|---|
paymentMethod |
String |
Required. Patient role , paymentMethod |
POST/api/appointment/success/:sessionID| Parameter | Type | Description |
|---|---|---|
sessionID |
String |
Required. Patient role ,sessionID |
GET/api/appointment/upcomingPastAppointmentsOfDoctor| Parameter | Type | Description |
|---|---|---|
| None | None | Required. Doctor role |
GET/api/appointment/upcomingPastAppointmentsOfPatient| Parameter | Type | Description |
|---|---|---|
| None | None | Required. Patient role |
GET/api/appointment/filterAppointmentsByDateOrStatus/:date/:status| Parameter | Type | Description |
|---|---|---|
date |
Date |
Required. date , patient doctor role |
status |
String |
Required. status , patient doctor role |
POST/api/appointment/scheduleFollowUp/:patientId| Parameter | Type | Description |
|---|---|---|
patientId |
String |
Required. Doctor role ,patientId |
PUT/api/appointment/updateStatusToPending/:id/:whichMember| Parameter | Type | Description |
|---|---|---|
id |
String |
Required. id , patient role |
whichMember |
String |
Required. whichMember , patient role |
PUT/api/appointment/updateStatusToFree/:id| Parameter | Type | Description |
|---|---|---|
id |
String |
Required. id , Doctor role |
PUT/api/appointment/acceptFollowUp/:followUpId| Parameter | Type | Description |
|---|---|---|
followUpId |
String |
Required. id , Doctor role |
-Family Member:
GET/api/familyMember/getFamilyMembers| Parameter | Type | Description |
|---|---|---|
| None | None | Required. Patient role |
POST/api/familyMember/addFamilyMember| Parameter | Type | Description |
|---|---|---|
| None | None | Required. Patient role |
POST/api/familyMember/linkFamilyMember| Parameter | Type | Description |
|---|---|---|
| None | None | Required. Patient role |
POST/api/familyMember/getSubscribedPackagesForFamilyMembers| Parameter | Type | Description |
|---|---|---|
| None | None | Required. Patient role |
- Message:
GET/api/message/allMessages/:chatId| Parameter | Type | Description |
|---|---|---|
chatId |
String |
Required. Patient Doctor role |
POST/api/message/sendMessage| Parameter | Type | Description |
|---|---|---|
| None | None | Required. Patient Doctor role |
POST/api/message/sendMessageFromPharmacy| Parameter | Type | Description |
|---|---|---|
| None | None | Required. Patient Paharmacist role |
- Video Call:
POST/api/videoCall/addVideoCall
| Parameter | Type | Description |
|---|---|---|
| None | None | Required. Patient Doctor role |
GET/api/videoCall/getVideoCall| Parameter | Type | Description |
|---|---|---|
| None | None | Required. Patient Doctor role |
DELETE/api/videoCall/deleteVideoCall| Parameter | Type | Description |
|---|---|---|
| None | None | Required. Patient Doctor role |
PUT/api/videoCall/setSocketID| Parameter | Type | Description |
|---|---|---|
| None | None | Required. Patient Doctor role |
PUT/api/videoCall/authZoomAPI| Parameter | Type | Description |
|---|---|---|
| None | None | Required. Patient Doctor role |
POST/api/videoCall/createMeeting| Parameter | Type | Description |
|---|---|---|
| None | None | Required. Patient Doctor role |
GET/api/videoCall/getMeetings| Parameter | Type | Description |
|---|---|---|
| None | None | Required. Patient Doctor role |





