El7a2ny Virtual Clinic and Pharmacy is not just a software solution; it's a revolutionary approach to healthcare. In a world where convenience and efficiency matter, our goal is to redefine the concept of "Telehealth" by leveraging cutting-edge technologies and techniques.
To ensure scalability, maintainability, and separation of concerns, the project was developed following the Clean Architecture pattern. This architectural approach allowed clear boundaries between business logic, presentation, and data layers, making the system robust and adaptable to future enhancements.
The current version of El7a2ny Virtual Clinic and Pharmacy is successfully passing all builds. We are committed to delivering a robust and reliable platform. If you found any issues while using the system, you can just reach out to any one of the contributors with your issue.
We are continuously working to enhance the El7a2ny Virtual Clinic and Pharmacy platform. Upcoming features and improvements include:
-
Swagger Integration: API documentation using Swagger will be added very soon to provide an interactive and developer-friendly interface for exploring and testing the backend endpoints.
-
Redis Caching: Integration of Redis is planned to optimize data retrieval, reduce server load, and improve overall response time through efficient caching mechanisms.
-
Testing with Jest: Unit and integration tests will be implemented using Jest to ensure code reliability, catch regressions early, and improve development confidence.
-
Microservices Refactor: The monolithic structure will be progressively refactored into a microservices architecture. This will improve scalability, isolate services for easier maintenance, and allow independent deployment of critical modules.
Code Style Guide
- Naming Conventions: camelCase for variables/functions, PascalCase for React components.
- Routing: Follow RESTful conventions for organized routes.
- Middleware: Use for route-specific logic.
- Naming Conventions: Maintain consistent naming for collections (singular nouns).
- Schema Design: Ensure consistency across collections.
- MUI Components: Leverage Material-UI components and adhere to their guidelines.
- Folder Structure: Organize components by features/functions.
- State Management: Use Context API for complex state (if needed).
- Lifecycle Methods: Prefer hooks and functional components.
- Branching: Follow Gitflow (feature branches, develop, master).
- Pull Requests
Backend Snippet
Patient Controller Snippet
router.patch("/:username/password", async (req, res) => {
try {
const patient = await patientService.updatePatientPassword(
req.params.username,
req.body.password
);
res.status(200).json({ data: patient });
} catch (error) {
errorHandler(error, req, res);
}
});
router.get("/:username/appointments", async (req, res) => {
try {
const appointments = await patientService.getPatientAppointments(
req.params.username,
req.query.status
);
res.status(200).json({ data: appointments });
} catch (error) {
errorHandler(error, req, res);
}
});
Frontend Snippets
Patient Account Page
import { useState } from "react";
import { Box, Container, Stack, Typography } from "@mui/material";
import { Layout as DashboardLayout } from "src/layouts/dashboard/user/layout";
import Message from "src/components/Miscellaneous/Message";
import Title from "src/components/Table/Body/Title";
import LoadingSpinner from "src/components/LoadingSpinner";
import Account from "src/components/Account/Account";
import { BACKEND_ROUTE } from "src/utils/Constants";
import { useGet } from "src/hooks/custom-hooks";
import Cookies from "js-cookie";
const Page = () => {
const [patient, setPatient] = useState({});
const [showError, setShowError] = useState(false);
const [error, setError] = useState("");
const [loading, setLoading] = useState(true);
const fields = [
{ name: "firstName", label: "First Name", type: "text" },
{ name: "lastName", label: "Last Name", type: "text" },
{ name: "email", label: "Email", type: "email" },
{ name: "number", label: "Phone Number", type: "text" },
{ name: "dateOfBirth", label: "Date Of Birth", type: "date" },
{ name: "emergencyContact.name", label: "Emergency Contact Name", type: "text" },
{ name: "emergencyContact.number", label: "Emergency Contact Number", type: "text" },
{ name: "emergencyContact.relation", label: "Emergency Contact Relation", type: "text" },
];
useGet({
url: `${BACKEND_ROUTE}/patients/${Cookies.get("username")}`,
setData: setPatient,
setLoading,
setError,
setShowError,
});
return (
<>
<Title title="My Account" />
<Box component="main" sx={{ flexGrow: 1, py: 8 }}>
<Container maxWidth="lg">
<Stack spacing={3}>
<div>
<Typography variant="h4">Account</Typography>
</div>
<div>{loading ? <LoadingSpinner /> : <Account user={patient} fields={fields} />}</div>
</Stack>
</Container>
</Box>
<Message
condition={showError}
setCondition={setShowError}
title={"Error"}
message={error}
buttonAction={"Close"}
/>
</>
);
};
Page.getLayout = (page) => <DashboardLayout>{page}</DashboardLayout>;
export default Page;
Doctor's Patients Page
import { useState } from "react";
import { Layout as DashboardLayout } from "src/layouts/dashboard/doctor/layout";
import { useGet } from "src/hooks/custom-hooks";
import Cookies from "js-cookie";
import { BACKEND_ROUTE } from "src/utils/Constants";
import { Table } from "src/components/Table/Table";
import ObjectInfo from "src/components/ObjectInfo";
import { DoctorPatientActions } from "src/components/DoctorPatientActions";
import Message from "src/components/Miscellaneous/Message";
const columns = ["Name", "Email", "Date Of Birth", "Actions"];
const Page = () => {
const [allData, setAllData] = useState([]);
const [loading, setLoading] = useState(true);
const [searchName, setSearchName] = useState("");
const [upcoming, setUpcoming] = useState("None");
const [showError, setShowError] = useState(false);
const [error, setError] = useState("");
const [popUpDisplay, setPopUpDisplay] = useState(false);
const [popUpElement, setPopUpElement] = useState();
const username = Cookies.get("username");
const filters = [
{
type: "text",
name: "Search Patient Name",
state: searchName,
setState: setSearchName,
},
{
type: "menu",
name: "Upcoming",
state: upcoming,
setState: setUpcoming,
options: [
{ value: "None", label: "None" },
{ value: "Yes", label: "Yes" },
{ value: "No", label: "No" },
],
},
];
useGet({
url: `${BACKEND_ROUTE}/doctors/${username}/patients`,
setData: setAllData,
setLoading,
setError,
setShowError,
});
const handleData = () => {
return allData.filter((item) => {
if (
searchName !== "" &&
!`${item.patient.firstName} ${item.patient.lastName}`
.toLowerCase()
.includes(searchName.toLowerCase())
)
return false;
if (
upcoming !== "None" &&
((upcoming == "Yes" && item.upcoming) || (upcoming == "No" && !item.upcoming))
)
return false;
return true;
});
};
const data = handleData();
console.log("Data", data);
const tableRows = data.map((item) => {
console.log("item", item);
return (
<>
<ObjectInfo obj={item.patient} attributes={["username", "email", "dateOfBirth"]} />
<DoctorPatientActions patient={item.patient} />
</>
);
});
return (
<>
<Table
value={{
data,
columns,
loading,
setShowError,
setError,
setLoading,
noRecords: "No Patients Found",
setAllData,
tableRows,
popUpDisplay,
popUpElement,
setPopUpDisplay,
setPopUpElement,
}}
filters={filters}
title="Patients"
/>
<Message
condition={showError}
setCondition={setShowError}
title="Error"
message={error}
action="Close"
/>
</>
);
};
Page.getLayout = (page) => <DashboardLayout>{page}</DashboardLayout>;
export default Page;
- Node.js
- Express
- React
- MongoDB
- Mongoose
- Material-UI
- Stripe
- Git
- MongoDB Atlas
- Postman
- VSCode
- Socket IO
- JWT
- Node Mailer
-
Registration and Account Management: Doctors can easily register and manage their accounts. Each doctor has their own wallet, allowing them to handle transactions seamlessly.
-
Hourly Rate Management: Doctors can set their hourly rates and publish their available time slots for appointments.
-
User Registration and Profile: Patients can register, create profiles, and view details about different doctors and their specialties.
-
Appointment Booking: Patients can book appointments with doctors based on their availability.
-
Chat and Video Calls: After completing appointments, patients can engage in chat with doctors and make video calls for follow-up consultations.
-
Health Packages Subscription: Patients can subscribe to health packages (Silver, Gold, Platinum) offering discounts based on the tier.
-
Family Members Management: Patients can add family members to their accounts, extending subscription benefits to them.
-
Pharmacy Services: Patients can purchase medicines from the pharmacy section, checkout, and track their orders. They can also engage in chat with the pharmacy.
-
Password Reset: Patients can reset their passwords via email if forgotten.
-
Registration and Account Management: Pharmacists can register, manage their accounts, and add medicines to the inventory.
-
Medicine Management: Pharmacists can categorize medicines as over-the-counter (OTC) or prescription-only. Medicines can be archived or unarchived as needed.
- Account Approval: Admins have the authority to approve new doctor and pharmacist accounts.
These features collectively make El7a2ny Virtual Clinic and Pharmacy a comprehensive platform for streamlined healthcare services, connecting doctors, patients, and pharmacists efficiently.
- Any Other Third-Party Libraries or Resources Used: Acknowledgment to the creators of any additional libraries or resources that have been utilized in the development of El7a2ny Virtual Clinic and Pharmacy.
We extend our appreciation to the developers, educators, and contributors whose work has played a key role in the success of this project.
Will be added very soon
To get started with the El7a2ny Virtual Clinic and Pharmacy, follow the steps below:
Clone the Clinic repository from GitHub:
git clone https://github.com/advanced-computer-lab-2023/CodeMedics-Clinic
Clone the Clinic repository from GitHub:
git clone https://github.com/advanced-computer-lab-2023/CodeMedics-Pharmacy
-
cd CodeMedics-Clinic
-
npm install
-
cd CodeMedics-Clinic/Frontend/el7a2ny-frontend
-
npm install
-
Setup port to be 8000 and setup MONGO_URI
-
To Run the backend, navigate to the root folder and type in
nodemon app
-
To Run the Frontend, navigate to /frontend/el7a2ny-frontend and type in
npm run dev
-
The Clinic should be accessible at http://localhost:3001/
-
cd CodeMedics-Pharmacy
-
npm install
-
cd CodeMedics-Pharmacy/Frontend/el7a2ny-frontend
-
npm install
-
Setup port to be 8001 and setup MONGO_URI
-
To Run the backend, navigate to the root folder and type in
nodemon app
-
To Run the Frontend, navigate to /frontend/el7a2ny-frontend and type in
npm run dev
-
The Pharmacy should be accessible at http://localhost:3001/
Will be added soon