diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..8dc294ae --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 advanced-computer-lab-2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index fdde5378..fde29c97 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,39 @@ -# poly-medica-clinic - - -## Motivation - -Welcome to poly-medica, a pioneering virtual clinic system designed to revolutionise healthcare accessibility by providing a seamless platform for patients and healthcare providers. Offering effortless appointment scheduling, online consultations, and streamlined access to medical records, our focus is on empowering patients while enabling healthcare professionals to prioritise patient care over administrative burdens. Join us in redefining the clinic experience, ensuring convenient, patient-centric healthcare services. +# Poly Medica + + +PolyMedica is a comprehensive healthcare solution that seamlessly integrates two virtual platforms: [PolyMedica Clinics](https://github.com/advanced-computer-lab-2023/poly-medica-Clinic) and [PolyMedica Pharmacy](https://github.com/advanced-computer-lab-2023/poly-medica-Pharmacy). This innovative system is built on a microservices architecture, ensuring flexibility, scalability, and efficiency. +
+The Systen mainly composed of 6 services, the communication among them is done by either asynchronous HTTP requests using Axios or synchronous communication using Apache Kafka: + * Clinic Service + * Patient Service + * Authentication Service + * Communication Service + * Payment Service + * Pharmacy Service +--- + +## Badges + +
+ Github Actions badge + Git badge + Express badge + Jest Badge + Node badge + React badge + Mongo badge + Socket badge + ES6 badge + Redux badge + ESLINT badge + JWT badge + Docker badge + Kafka badge + Stripe badge + Swagger badge +
+ +--- ## Build Status @@ -17,12 +47,10 @@ Welcome to poly-medica, a pioneering virtual clinic system designed to revolutio [![Payment CI](https://github.com/advanced-computer-lab-2023/poly-medica-Clinic/actions/workflows/payment-microservice-ci.yml/badge.svg)](https://github.com/advanced-computer-lab-2023/poly-medica-Clinic/actions/workflows/payment-microservice-ci.yml) +--- ### Planned Features -#### Microservices with Kafka - -We're planning to implement a microservices architecture using Kafka as the messaging system. This will enable scalable and decoupled communication between various components of our system, ensuring robustness and flexibility. #### Frontend Automated Testing with Jest for React MUI @@ -34,7 +62,11 @@ We're excited to introduce AI models to augment our system's capabilities: - *Doctor Assistance AI*: This AI model will assist doctors by analyzing symptoms input by the patient, suggesting suitable medicines, and providing dosage recommendations. It will also create reminders for doctors regarding prescribed medications and their quantities. -## Code Style Guide +- *Patient Assistance AI*: Suggest replacements for medicines out of stock for the patient + +--- +
+

Code Style Guide

### JavaScript (Node.js and React) @@ -66,104 +98,137 @@ We're excited to introduce AI models to augment our system's capabilities: - *Branching*: Follow Gitflow (feature branches, develop, master). - *Pull Requests*: Require clear descriptions and peer reviews before merging. +
+--- -## Screenshots 🖵 -
-Admin - -
-Add New Helath Packages - -![WhatsApp Image 2023-12-17 at 5 00 28 AM (1)](https://github.com/advanced-computer-lab-2023/poly-medica-Clinic/assets/101880627/36a7386d-2d20-435c-acc3-349988abeb52) +

Microservices Structure

+ + ```bash + Poly-Medica Clinic +├── clinic +│ ├── ... +│ └── (Clinic Service Code) +├── patient +│ ├── ... +│ └── (Patient Service Code) +├── authentication +│ ├── ... +│ └── (Authentication Service Code) +├── communication +│ ├── ... +│ └── (Communication Service Code) +├── payment +│ ├── ... +│ └── (Payment Service Code) +└── client + ├── ... + └── (Client Application Code) + +Poly-Medica Pharmacy +├── pharmacy +│ ├── ... +│ └── (Pharmacy Service Code) +└── client + ├── ... + └── (Client Application Code) + ``` -
-
+--- - -
-Patient +## Screenshots 🖵
-Home Page - -![WhatsApp Image 2023-12-17 at 5 00 29 AM (1)](https://github.com/advanced-computer-lab-2023/poly-medica-Clinic/assets/101880627/7fdf73b9-bc45-4f2c-ac3d-3bcbb4abf9a6) - - +Login Page + + ![login](https://github.com/advanced-computer-lab-2023/poly-medica-Clinic/assets/102627389/56325872-aaac-4b78-843f-635c8edf4849) +
-View Appointments +Home Page + + ![home](https://github.com/advanced-computer-lab-2023/poly-medica-Clinic/assets/102627389/5bfe411b-d6a7-4472-96db-0b88cf9353b6) + +
-![WhatsApp Image 2023-12-17 at 5 00 28 AM](https://github.com/advanced-computer-lab-2023/poly-medica-Clinic/assets/101880627/62230d66-c83e-4186-a991-24f3c3879ace) - +
+Appointments Page + + ![appointments](https://github.com/advanced-computer-lab-2023/poly-medica-Clinic/assets/102627389/4095f6da-2857-4ac1-bd5d-f2b61d911dc1) +
-Select a Doctor - -![WhatsApp Image 2023-12-17 at 5 00 29 AM](https://github.com/advanced-computer-lab-2023/poly-medica-Clinic/assets/101880627/7420601b-bd39-4a8c-9fc0-3338fad3c294) - - +Health Package Page + + ![health-package](https://github.com/advanced-computer-lab-2023/poly-medica-Clinic/assets/102627389/ef6c952f-107a-4438-8462-f74652dc8ffa) +
- +
+Apply Filter on doctors + +![apply-filter](https://github.com/advanced-computer-lab-2023/poly-medica-Clinic/assets/102627389/a8b3508f-52dd-4e17-8292-48c788667916) +
- - - -
-Doctor +Patient Adding family members + +![add-member](https://github.com/advanced-computer-lab-2023/poly-medica-Clinic/assets/102627389/e11252e9-487b-4b4f-b33e-efa325a854fb) + +
-Follow-up requests - - ![WhatsApp Image 2023-12-17 at 5 00 28 AM (2)](https://github.com/advanced-computer-lab-2023/poly-medica-Clinic/assets/101880627/51774f22-2b4c-41c1-a073-390703f5b911) - - +Doctor Receiving Notification + +![notification](https://github.com/advanced-computer-lab-2023/poly-medica-Clinic/assets/102627389/f2a8d218-3002-4d7e-9129-25b537392adb) +
-confirmation message +Admin Viewing Requests + +![requests](https://github.com/advanced-computer-lab-2023/poly-medica-Clinic/assets/102627389/b7643d4d-ac7b-4d18-b2e8-8f5b0fb9e84b) - ![WhatsApp Image 2023-12-17 at 5 00 29 AM (2)](https://github.com/advanced-computer-lab-2023/poly-medica-Clinic/assets/101880627/7097c174-83d2-4fd2-8718-669282a5595c) +
-
- - - - + + --- ## Tech/Framework used - [Node.js](https://nodejs.org/en/) - [Express](https://expressjs.com/) - [React](https://reactjs.org/) - - [MongoDB](https://www.mongodb.com/) - [Mongoose](https://mongoosejs.com/) - [Jest](https://jestjs.io/) - - [Material-UI](https://material-ui.com/) - [Stripe](https://stripe.com/) - - [Git](https://git-scm.com/) - [Github Actions](github.com/features/actions) - - [MongoDB Atlas](https://www.mongodb.com/cloud/atlas) - [Postman](https://www.postman.com/) - [VSCode](https://code.visualstudio.com/) -- [Babel](https://babeljs.io/) +- [Babel](https://babeljs.io/) +- [Socket IO](https://socket.io/) +- [JWT](https://jwt.io/) +- [Docker](https://www.docker.com/) +- [Apache Kafka](https://kafka.apache.org/) +- [ESlint](https://eslint.org/) +- [Redux](https://react-redux.js.org/) +- [Node Mailer](https://nodemailer.com/) +--- ## Features @@ -230,7 +295,7 @@ The system serves different type of users (Patient, Doctor , Admin )
- As a Admin I can + As an Admin I can - Add another adminstrator - Remove a doctor or a patient or an admin from the system @@ -246,44 +311,92 @@ The system serves different type of users (Patient, Doctor , Admin )
- Filter Context + Admin Details ```javascript +import React from 'react'; +import DoctorIcon from '../../../assets/images/icons/DoctorIcon.png'; +import EmailIcon from '@mui/icons-material/Email'; +import StarBorderIcon from '@mui/icons-material/StarBorder'; +import { + Dialog, + DialogTitle, + DialogContent, + Typography, + DialogActions, + Button, + useTheme, +} from '@mui/material'; +import { styled } from '@mui/system'; +import { useAdminContext } from 'hooks/useAdminContext'; +import { commonStyles } from 'ui-component/CommonStyles'; + +const useStyles = styled(() => commonStyles); + +const AdminDetails = () => { + const classes = useStyles(); + const theme = useTheme(); + const title = ' '; -import React, { createContext, useContext, useState } from 'react'; - -const FilterContext = createContext(); - -export const FilterProvider = ({ children }) => { - const [filterData, setFilterData] = useState( - [ - { - attribute: '', - values: [], - selectedValue: '', - } - ]); + const { setSelectedAdmin, setErrorMessage, selectedAdmin } = useAdminContext(); - const updateFilter = (newFilterData) => { - setFilterData(newFilterData); - }; + const handleDialogClose = () => { + setSelectedAdmin(null); + setErrorMessage(''); + }; - return ( - - {children} - - ); + return ( + 800 ? 500 : 300 } }} + > + {selectedAdmin && ( + <> + + {selectedAdmin.userName} + + +
+
+ {`${title} + + {`${title} ${selectedAdmin.userName}`} + +
+
+
+ + {selectedAdmin.email} +
+
+ + + {selectedAdmin.mainAdmin ? 'Main Admin' : 'Sub Admin'} + +
+
+
+
+ + + + + )} +
+ ); }; -export const useFilter = () => { - const context = useContext(FilterContext); - if (!context) { - throw new Error('useFilter must be used within a FilterProvider'); - } - return context; -}; +export default AdminDetails; ```
@@ -324,182 +437,80 @@ export const SearchProvider = ({ children }) => {
- Side Bar + Get admins API ```javascript -import PropTypes from 'prop-types'; - -import { useTheme } from '@mui/material/styles'; -import { Box, Chip, Drawer, Stack, useMediaQuery } from '@mui/material'; - -import PerfectScrollbar from 'react-perfect-scrollbar'; -import { BrowserView, MobileView } from 'react-device-detect'; - -import MenuList from './MenuList'; -import LogoSection from './LogoSection'; -import { drawerWidth } from 'store/constant'; - - -const Sidebar = ({ drawerOpen, drawerToggle, window }) => { - const theme = useTheme(); - const matchUpMd = useMediaQuery(theme.breakpoints.up('md')); - - const drawer = ( - <> - - - - - - - - - - - - - - - - - - - - - - - ); - - const container = window !== undefined ? () => window.document.body : undefined; - - return ( - - - {drawer} - - - ); -}; - -Sidebar.propTypes = { - drawerOpen: PropTypes.bool, - drawerToggle: PropTypes.func, - window: PropTypes.object -}; - -export default Sidebar; - + app.get('/admins', async (req, res) => { + try { + const admins = await service.findAllAdmins(); + res.status(OK_STATUS_CODE).json({ admins }); + } catch (err) { + res.status(ERROR_STATUS_CODE).json({ err: err.message }); + } + }); ```
- Order API + Users Model ```javascript -import OrderService from '../service/order-service.js'; -import { isValidMongoId } from '../utils/Validation.js'; - -import { - OK_STATUS_CODE, - ERROR_STATUS_CODE, -} from '../utils/Constants.js'; - -export const order = (app) => { - const service = new OrderService(); - - app.get('/order/pending', async (req, res) => { - try { - const data = await service.getPendingOrders(); - res.status(OK_STATUS_CODE).json(data); - } catch (err) { - res.status(ERROR_STATUS_CODE).json({ - message: 'error occurred while fetching orders', - }); - } - }); - - app.get('/order/:patientId', async (req, res) => { - const { patientId } = req.params; - if (!isValidMongoId(patientId)) { - return res.status(ERROR_STATUS_CODE).json({ - message: 'Patient ID is invalid', - }); - } - try { - const data = await service.getOrders(patientId); - res.status(OK_STATUS_CODE).json(data); - } catch (err) { - res.status(ERROR_STATUS_CODE).json({ - message: 'error occurred while fetching orders', - }); - } - }); - - app.post('/order', async (req, res) => { - try { - const { order } = req.body; - console.log(order); - const data = await service.addOrder(order); - res.status(OK_STATUS_CODE).json(data); - } catch (err) { - res.status(ERROR_STATUS_CODE).json({ - message: 'error occurred while adding order', - error: err.message, - }); - } - }); - - app.patch('/order/:orderId', async (req, res) => { - const { orderId } = req.params; - if (!isValidMongoId(orderId)) { - return res.status(ERROR_STATUS_CODE).json({ - message: 'Order ID is invalid', - }); - } - try { - const { order } = req.body; - const data = await service.updateOrder(orderId, order); - res.status(OK_STATUS_CODE).json(data); - } catch (err) { - res.status(ERROR_STATUS_CODE).json({ - message: 'error occurred while updating order', - error: err.message, - }); - } +import mongoose from 'mongoose'; +import { USER_ARR_ENUM } from '../../utils/Constants.js'; + +const userSchema = mongoose.Schema({ + userId:{ + type: mongoose.Schema.Types.ObjectId, + required:true, + unique: true, + }, + email:{ + type:String, + required:true, + unique: true, + }, + userName:{ + type:String, + required:true, + unique: true + }, + password:{ + type:String, + required:true + }, + type:{ + type: String, + enum: USER_ARR_ENUM, + required:true + }, +}); + +userSchema.statics.signup = async function ( + userId, + email, + password, + userName, + type, +) { + const userRecord = new this({ + userId: new mongoose.Types.ObjectId(userId), + email, + password, + userName, + type, }); + const result = await userRecord.save(); + return result; }; +const User = mongoose.model('User', userSchema); + +export default User; ``` @@ -607,37 +618,20 @@ export default Sidebar; - - - - - - - - - - - - - - - +--- ## Installation - -Install my-project with `npm` - + ```bash > git clone https://github.com/advanced-computer-lab-2023/poly-medica-Clinic.git > cd poly-medica-clinic -> cd authentication && npm i && cd.. -> cd clinic && npm i && cd.. -> cd communication && npm i && cd.. -> cd patient && npm i && cd.. -> cd payment && npm i && cd.. -> cd client && npm i +> chmod +x install-all.sh +> ./install-all.sh ``` + +--- + ## API Refrences ### Authentication Endpoints @@ -733,72 +727,39 @@ Install my-project with `npm` POST /payment/wallet POST /payment-salary/doctor/:doctorId/wallet +--- + ## Tests -The testing is done using `jest`. To run the tests, run the following command. - +The testing is done using `jest`. To run the tests, run the following command: +- Make sure you are at the root directory of the project + ```bash -> cd authentication && npm run test -``` -```bash -> cd clinic && npm run test -``` -```bash -> cd communication && npm run test -``` -```bash -> cd patient && npm run test -``` -```bash -> cd payment && npm run test +> chmod +x run-tests.sh +>./run-tests.sh ``` ![image](https://github.com/advanced-computer-lab-2023/poly-medica-Clinic/assets/101880627/3b31ae18-a4af-47ed-aee3-cf8e1be5a2d2) - -### Models tests +### Model tests `Faker.js` is used to generate data to test different models -There is tests done for the following models : `User` , `Admin` , `Patient` , `Doctor` , `Appointment` , `Health Package` , `Order` , `Prescription` - - - +There are tests done for the following models : `User` , `Admin` , `Patient` , `Doctor` , `Appointment` , `Health Package` , `Order` , `Prescription` ## How to use -To run backend -#### authentication service -```bash -cd authentication && nodemon start -``` -#### clinic service -```bash -cd clinic && nodemon start -``` -#### patient service -```bash -cd patient && nodemon start -``` -#### patient service -```bash -cd patient && nodemon start -``` -#### payment service -```bash -cd patient && nodemon start -``` -#### communication service -```bash -cd communication && nodemon start -``` +To run the project +- Make sure you are at the root directory of the project +- The script will run all the services and the client except the pharmacy service, which could be found at [this repository](https://github.com/advanced-computer-lab-2023/poly-medica-Pharmacy) -To run frontend ```bash -cd client && npm start +> npm install -g concurrently +> chmod +x run-all.sh +> ./run-all.sh ``` All services and client will be running on the specified ports on your env files. @@ -836,11 +797,6 @@ Contributions are always welcome! 8. Wait for your pull request to be reviewed and merged - - - - - # Credits - [NodeJs docs](https://nodejs.org/en/docs/) - [Express docs](https://expressjs.com/en/4x/api.html) @@ -855,18 +811,19 @@ Contributions are always welcome! - [Designing Data Intensive Applications](https://www.oreilly.com/library/view/designing-data-intensive-applications/9781491903063/) - - +--- ## License -#### Stripe License -This project uses Stripe to process payments. By using this project, you agree to be bound by the Stripe Services Agreement. - -You can find the full text of the Stripe Services Agreement at the following link: - -https://stripe.com/legal +The Project is open source following [MIT License](https://opensource.org/license/mit/) -Please make sure to read and understand the Stripe Services Agreement before using this project. +--- -If you have any questions about the Stripe Services Agreement or how it applies to your use of this project, please contact Stripe at support@stripe.com. \ No newline at end of file +### Contributers: +- [Mohamed Khaled](https://github.com/Mohamed-Khaled308) +- [Amir Tarek](https://github.com/amir-awad) +- [Malek Mohamed](https://github.com/malekelkssas) +- [Ahmad Hoseiny](https://github.com/AhmadHoseiny) +- [Mohamed Hassan](https://github.com/mohamedhassans) +- [Abdelrahman Amr](https://github.com/Aelmeky) +- [Yehia Mohamed](https://github.com/YehiaFarghaly) diff --git a/authentication/src/tests/api-tests/AuthenticationAPI.test.js b/authentication/src/tests/api-tests/AuthenticationAPI.test.js index 96cdbe8c..a97b52a5 100644 --- a/authentication/src/tests/api-tests/AuthenticationAPI.test.js +++ b/authentication/src/tests/api-tests/AuthenticationAPI.test.js @@ -3,7 +3,7 @@ import app from '../../../app.js'; import { connectDBTest, disconnectDBTest -} from '../../utils/testing-utils.js'; +} from '../../utils/TestingUtils.js'; import User from '../../database/models/Users.js'; import { describe, beforeEach, afterEach, expect, it, jest } from '@jest/globals'; import generateUser from '../model-generators/generateUser.js'; diff --git a/authentication/src/utils/testing-utils.js b/authentication/src/utils/TestingUtils.js similarity index 100% rename from authentication/src/utils/testing-utils.js rename to authentication/src/utils/TestingUtils.js diff --git a/client/src/api/AdminAPI.js b/client/src/api/AdminAPI.js index 26da7164..e1e7056a 100644 --- a/client/src/api/AdminAPI.js +++ b/client/src/api/AdminAPI.js @@ -20,3 +20,23 @@ export const deleteAdmin = async (adminToDelete) => { const response = await clinicAxios.delete(`/admins/${adminToDelete}`); return response.data; }; + +export const getHealthPackages = async () => { + const response = await clinicAxios.get('/packages'); + return response.data; +}; + +export const addHealthPackage = async (newPackage) => { + const response = await clinicAxios.post('/packages', { newPackage }); + return response.data; +}; + +export const updateHealthPackage = async (selectedEditPackage) => { + const response = await clinicAxios.patch(`/package/${selectedEditPackage._id}`, { selectedEditPackage }); + return response.data; +}; + +export const deleteHealthPackage = async (healthPackage) => { + const response = await clinicAxios.delete(`/packages/${healthPackage._id}`); + return response.data; +}; \ No newline at end of file diff --git a/client/src/api/DoctorAPI.js b/client/src/api/DoctorAPI.js index 9ed1d6cd..89bbfb56 100644 --- a/client/src/api/DoctorAPI.js +++ b/client/src/api/DoctorAPI.js @@ -1,4 +1,4 @@ -import { clinicAxios, communicationAxios } from 'utils/AxiosConfig'; +import { clinicAxios, communicationAxios, patientAxios } from 'utils/AxiosConfig'; import { DOCTOR_TYPE_ENUM, PHARMACIST_TYPE_ENUM, @@ -82,4 +82,16 @@ export const addDoctorChat = async (doctor) => { ], }, }); +}; + +export const updatePrescription = async (selectedEditPrescription) => { + const response = await patientAxios.patch('/prescriptions/' + selectedEditPrescription._id, { + prescription: selectedEditPrescription, + }); + return response.data; +}; + +export const createPrescription = async (prescription) => { + const response = await patientAxios.post('/prescriptions', { prescription }); + return response.data; }; \ No newline at end of file diff --git a/client/src/api/PatientAPI.js b/client/src/api/PatientAPI.js index d7d77199..f5e74d81 100644 --- a/client/src/api/PatientAPI.js +++ b/client/src/api/PatientAPI.js @@ -1,5 +1,15 @@ import { patientAxios, clinicAxios } from 'utils/AxiosConfig'; +export const getPatient = async (patientID) => { + const response = await patientAxios.get(`/patients/${patientID}`); + return response.data; +}; + +export const getPatientHealthPackage = async (patientID) => { + const response = await patientAxios.get(`/patient/${patientID}/health-packages`); + return response.data; +}; + export const getPatients = async () => { const response = await patientAxios.get('/patients'); return response.data; @@ -8,4 +18,29 @@ export const getPatients = async () => { export const deletePatient = async (patientToDelete) => { const response = await clinicAxios.delete(`/patients/${patientToDelete}`); return response.data; +}; + +export const getFamilyMembers = async (userId) => { + const response = await patientAxios.get('/family-members/' + userId); + return response.data; +}; + +export const updateFamilyMembers = async (userId, newMember) => { + const response = await patientAxios.patch('/family-members/' + userId, { member: newMember }); + return response.data; +}; + +export const getPatientDiscount = async (user) => { + const response = await patientAxios.get(`/patient/${user.id}/discount`); + return response.data; +}; + +export const updateHealthPackageStatus = async (user, subscribedPackage) => { + const response = await patientAxios.patch(`patient/${user.id}/health-packages/${subscribedPackage.packageId}`); + return response.data; +}; + +export const getPatientPrescription = async (patientID) => { + const response = await patientAxios.get(`patient/${patientID}/prescriptions`); + return response.data; }; \ No newline at end of file diff --git a/client/src/assets/images/boarding.jpg b/client/src/assets/images/boarding.jpg new file mode 100644 index 00000000..a47e4efe Binary files /dev/null and b/client/src/assets/images/boarding.jpg differ diff --git a/client/src/assets/images/logo.png b/client/src/assets/images/logo.png index 2894136b..1f2126bb 100644 Binary files a/client/src/assets/images/logo.png and b/client/src/assets/images/logo.png differ diff --git a/client/src/contexts/AdminContext.js b/client/src/contexts/AdminContext.js index fd8e0e58..e3996337 100644 --- a/client/src/contexts/AdminContext.js +++ b/client/src/contexts/AdminContext.js @@ -19,6 +19,15 @@ const AdminProvider = ({ children }) => { const [selectedAdmin, setSelectedAdmin] = useState(null); const [strength, setStrength] = useState(0); const [level, setLevel] = useState(); + const [newPackage, setNewPackage] = useState({ + name: '', + price: '', + discountOfDoctor: '', + discountOfMedicin: '', + discountOfFamily: '', + }); + const [selectedEditPackages, setSelectedEditPackages] = useState(null); + const [isEditDialogOpen, setIsEditDialogOpen] = useState(false); const contextValue = { admins, setAdmins, isLoading, setIsLoading, openAddDialog, setOpenAddDialog, newAdminEmail, @@ -27,7 +36,8 @@ const AdminProvider = ({ children }) => { adminToDelete, setAdminToDelete, addAdmin, setAddAdmin, removeAdmin, setRemoveAdmin, adminIsBeingAdded, setAdminIsBeingAdded, adminIsBeingDeleted, setAdminIsBeingDeleted, errorMessage, setErrorMessage, selectedAdmin, setSelectedAdmin, strength, setStrength, - level, setLevel + level, setLevel, newPackage, setNewPackage, selectedEditPackages, setSelectedEditPackages, isEditDialogOpen, + setIsEditDialogOpen }; return ( diff --git a/client/src/contexts/DoctorContext.js b/client/src/contexts/DoctorContext.js index f20c6a28..28acdaf5 100644 --- a/client/src/contexts/DoctorContext.js +++ b/client/src/contexts/DoctorContext.js @@ -13,19 +13,17 @@ const DoctorProvider = ({ children }) => { const [errorMessage, setErrorMessage] = useState(''); const [availableSlots, setAvailableSlots] = useState([]); const [selectedDate, setSelectedDate] = useState(null); - const [selectedTime, setSelectedTime] = useState(null); - const [patients, setPatients] = useState([]); - const [originalPatients, setOriginalPatients] = useState([]); - const [appointments, setAppointments] = useState([]); - const [loggedInDoctor, setLoggedInDoctor] = useState(null); - const [selectedPatient, setSelectedPatient] = useState(null); - + const [selectedTime, setSelectedTime] = useState(null); + const [appointments, setAppointments] = useState([]); + const [loggedInDoctor, setLoggedInDoctor] = useState(null); + const [selectedDoctor, setSelectedDoctor] = useState(null); + const [originalDoctors, setOriginalDoctors] = useState([]); + const contextValue = { doctors, setDoctors, isLoading, setIsLoading, confirmDeleteDialogOpen, setConfirmDeleteDialogOpen, setSelectedTime, - doctorToDelete, setDoctorToDelete, doctorIsBeingDeleted, setDoctorIsBeingDeleted, doctorDeleted, selectedTime, + doctorToDelete, setDoctorToDelete, doctorIsBeingDeleted, setDoctorIsBeingDeleted, doctorDeleted, selectedTime, setOriginalDoctors, setDoctorDeleted, errorMessage, setErrorMessage, availableSlots, setAvailableSlots, selectedDate, setSelectedDate, - patients, setPatients, originalPatients, setOriginalPatients, appointments, setAppointments, loggedInDoctor, setLoggedInDoctor, - selectedPatient, setSelectedPatient + appointments, setAppointments, loggedInDoctor, setLoggedInDoctor, selectedDoctor, setSelectedDoctor, originalDoctors }; return ( diff --git a/client/src/contexts/PatientContext.js b/client/src/contexts/PatientContext.js index 3d74515e..9ba83c0e 100644 --- a/client/src/contexts/PatientContext.js +++ b/client/src/contexts/PatientContext.js @@ -5,18 +5,40 @@ export const PatientContext = createContext(); const PatientProvider = ({ children }) => { const [patients, setPatients] = useState([]); - const [isLoading, setIsLoading] = useState(true); - const [confirmDeleteDialogOpen, setConfirmDeleteDialogOpen] = useState(false); - const [patientToDelete, setPatientToDelete] = useState(null); - const [patientIsBeingDeleted, setPatientIsBeingDeleted] = useState(false); - const [patientDeleted, setPatientDeleted] = useState(false); - const [errorMessage, setErrorMessage] = useState(''); - const [selectedPatient, setSelectedPatient] = useState(null); - + const [originalPatients, setOriginalPatients] = useState([]); + const [isLoading, setIsLoading] = useState(true); + const [confirmDeleteDialogOpen, setConfirmDeleteDialogOpen] = useState(false); + const [patientToDelete, setPatientToDelete] = useState(null); + const [patientIsBeingDeleted, setPatientIsBeingDeleted] = useState(false); + const [patientDeleted, setPatientDeleted] = useState(false); + const [errorMessage, setErrorMessage] = useState(''); + const [selectedPatient, setSelectedPatient] = useState(null); + const [loggedInPatient, setLoggedInPatient] = useState(null); + const [loggedInPatientHealthPackage, setLoggedInPatientHealthPackage] = useState(null); + const [FamilyMembers, setFamilyMembers] = useState([]); + const [openPackages, setOpenPackages] = useState(false); + const [error, setError] = useState(false); + const [newMember, setNewMember] = useState({ + name: '', + nationalId: '', + age: '', + gender: '', + relation: '', + email: '', + mobileNumber: '', + id: '' + }); + const [memberId, setMemberId] = useState(null); + const [packages, setPackages] = useState([]); + const [subscribedPackage, setSubscribedPackage] = useState(null); + const [discount, setDiscount] = useState(0); + const [isPaymentOpen, setIsPaymentOpen] = useState(false); const contextValue = { - patients, setPatients, isLoading, setIsLoading, confirmDeleteDialogOpen, setConfirmDeleteDialogOpen, patientToDelete, setPatientToDelete, - patientIsBeingDeleted, setPatientIsBeingDeleted, patientDeleted, setPatientDeleted, errorMessage, setErrorMessage, selectedPatient, - setSelectedPatient + patients, setPatients, isLoading, setIsLoading, confirmDeleteDialogOpen, setConfirmDeleteDialogOpen, patientToDelete, setPatientToDelete, FamilyMembers, + patientIsBeingDeleted, setPatientIsBeingDeleted, patientDeleted, setPatientDeleted, errorMessage, setErrorMessage, selectedPatient, setFamilyMembers, + setSelectedPatient, originalPatients, setOriginalPatients, loggedInPatient, setLoggedInPatient, loggedInPatientHealthPackage, + openPackages, setOpenPackages, error, setError, newMember, setNewMember, memberId, setMemberId, setLoggedInPatientHealthPackage, + packages, setPackages, subscribedPackage, setSubscribedPackage, discount, setDiscount, isPaymentOpen, setIsPaymentOpen }; return ( diff --git a/client/src/layout/MainLayout/Header/ProfileSection/UpgradePlanCard.js b/client/src/layout/MainLayout/Header/ProfileSection/UpgradePlanCard.js index 3fa18646..f3837a13 100644 --- a/client/src/layout/MainLayout/Header/ProfileSection/UpgradePlanCard.js +++ b/client/src/layout/MainLayout/Header/ProfileSection/UpgradePlanCard.js @@ -5,9 +5,9 @@ import { Button, Card, CardContent, Grid, Stack, Typography } from '@mui/materia import { useUserContext } from 'hooks/useUserContext'; // project imports import AnimateButton from 'ui-component/extended/AnimateButton'; -import { patientAxios } from 'utils/AxiosConfig'; import { HEALTH_PACKAGE_STATUS } from 'utils/Constants'; import { useNavigate } from 'react-router-dom'; +import { getPatientHealthPackage } from 'api/PatientAPI'; // styles const CardStyle = styled(Card)(({ theme }) => ({ background: theme.palette.warning.light, @@ -49,8 +49,8 @@ const UpgradePlanCard = () => { const formattedRenewalDate = renewalDate.toLocaleString('en-US', options); const navigate = useNavigate(); useEffect(() => { - patientAxios.get(`/patient/${user.id}/health-packages`).then((response) => { - setHealthPackages(response.data.healthPackages); + getPatientHealthPackage(user.id).then((response) => { + setHealthPackages(response.healthPackages); }).catch((err) => { console.log(err); }); diff --git a/client/src/layout/MainLayout/Header/SearchSection/FilterDropdown.js b/client/src/layout/MainLayout/Header/SearchSection/FilterDropdown.js index f9663318..9f6dd35d 100644 --- a/client/src/layout/MainLayout/Header/SearchSection/FilterDropdown.js +++ b/client/src/layout/MainLayout/Header/SearchSection/FilterDropdown.js @@ -1,71 +1,87 @@ -import React from 'react'; +import React, { useState } from 'react'; import { Drawer, - Select, Typography, - MenuItem, - FormControl, - InputLabel, Card, Grid, - TextField, + FormControl, + Radio, + RadioGroup, + FormControlLabel, + IconButton, Slide, + TextField } from '@mui/material'; +import ArrowForwardIcon from '@mui/icons-material/ArrowForward'; +import ArrowBackIcon from '@mui/icons-material/ArrowBack'; const FilterDropdown = ({ filterData, onChange, isDrawerOpen, handleDrawerClose }) => { + const [activeFilterIndex, setActiveFilterIndex] = useState(0); + + const handleArrowClick = (direction) => { + if (direction === 'left') { + setActiveFilterIndex((prevIndex) => (prevIndex - 1 + filterData.length) % filterData.length); + } else if (direction === 'right') { + setActiveFilterIndex((prevIndex) => (prevIndex + 1) % filterData.length); + } + }; + return ( {filterData.length > 0 ? ( - - - - Apply Filters on this page: + + + + Apply Filters: - {filterData.map((filter, index) => ( - - - - Filter By {filter.attribute} + + + + handleArrowClick('left')}> + + + + {filterData[activeFilterIndex].attribute} - {filter.attribute === 'Available Slots' ? ( - onChange(index, event.target.value)} - InputLabelProps={{ - shrink: true, - }} - fullWidth - sx={{ mb: 2 }} - /> - ) : ( - - Select... - - - )} - - - ))} + handleArrowClick('right')}> + + + + {filterData[activeFilterIndex].attribute === 'Available Slots' ? ( + onChange(activeFilterIndex, event.target.value)} + InputLabelProps={{ + shrink: true, + }} + fullWidth + sx={{ mb: 2 }} + /> + ) : ( + + onChange(activeFilterIndex, event.target.value)} + > + {filterData[activeFilterIndex].values.map((value) => ( + } label={value} /> + ))} + + + )} + + ) : ( - + No Filter Data on this page )} diff --git a/client/src/pages/Appointment/Appointment.js b/client/src/pages/Appointment/Appointment.js index 8dffe7cb..5574ec73 100644 --- a/client/src/pages/Appointment/Appointment.js +++ b/client/src/pages/Appointment/Appointment.js @@ -2,7 +2,7 @@ import { useState, useEffect, useRef } from 'react'; import { clinicAxios } from 'pages/utilities/AxiosConfig'; import MainCard from 'ui-component/cards/MainCard'; import AppointmentList from './AppointmentList.js'; -import AppointmentOptions from './AppointmentOptions/AppointmentOptions.js'; +import AppointmentOptions from './appointment-options/AppointmentOptions.js'; import { useUserContext } from 'hooks/useUserContext.js'; import { useFilter } from 'contexts/FilterContext.js'; import { diff --git a/client/src/pages/Appointment/AppointmentOptions/AppointmentDetails.js b/client/src/pages/Appointment/appointment-options/AppointmentDetails.js similarity index 91% rename from client/src/pages/Appointment/AppointmentOptions/AppointmentDetails.js rename to client/src/pages/Appointment/appointment-options/AppointmentDetails.js index e8a53b75..460e0411 100644 --- a/client/src/pages/Appointment/AppointmentOptions/AppointmentDetails.js +++ b/client/src/pages/Appointment/appointment-options/AppointmentDetails.js @@ -8,7 +8,6 @@ import CalendarTodayIcon from '@mui/icons-material/CalendarToday'; import HelpCenterIcon from '@mui/icons-material/HelpCenter'; import StyleIcon from '@mui/icons-material/Style'; import AttachMoneyIcon from '@mui/icons-material/AttachMoney'; -import { useTheme } from '@mui/material/styles'; import Swal from 'sweetalert2'; import '../../../assets/css/swalStyle.css'; import { clinicAxios, communicationAxios } from 'pages/utilities/AxiosConfig'; @@ -18,7 +17,7 @@ import { chatExist } from 'utils/ChatUtils.js'; import { useUserContext } from 'hooks/useUserContext.js'; import { getDay, getTime } from '../../../utils/DateFormatter.js'; import { patientCanRefund } from '../../../utils/AppointmentUtils.js'; -import AppointmentStatus from '../AppointmentStatus'; +import AppointmentStatus from '../AppointmentStatus.js'; import { useNavigate } from 'react-router-dom'; import { usePayment } from 'contexts/PaymentContext'; import { showSuccessAlert } from 'utils/swal'; @@ -29,8 +28,6 @@ const AppointmentDetails = ({ setSelectedAppointment, handleAppoinmentUpdate }) => { - const theme = useTheme(); - console.log('theme = ', theme); const { chats, setChats } = useChat(); const { user } = useUserContext(); const navigate = useNavigate(); @@ -82,7 +79,6 @@ const AppointmentDetails = ({ }; const handleComplete = async () => { // TODO: implement this function after merge with communication-service - console.log('appointment completed'); clinicAxios .patch(`/appointments/complete/${selectedAppointment._id}`) .then((response) => { @@ -261,25 +257,29 @@ const AppointmentDetails = ({ } - - - + ':hover': { + backgroundColor: '#BE001C', + boxShadow: '0 2px 14px 0 rgb(32 40 45 / 8%)', + }, + }} + onClick={handleCancelConfirmation} + disabled={cannotCompleteOrCancel} + > + Cancel + + + } { user.type == 'doctor' diff --git a/client/src/pages/Appointment/AppointmentOptions/AppointmentOptions.js b/client/src/pages/Appointment/appointment-options/AppointmentOptions.js similarity index 100% rename from client/src/pages/Appointment/AppointmentOptions/AppointmentOptions.js rename to client/src/pages/Appointment/appointment-options/AppointmentOptions.js diff --git a/client/src/pages/Appointment/AppointmentOptions/AppointmentReschedule.js b/client/src/pages/Appointment/appointment-options/AppointmentReschedule.js similarity index 96% rename from client/src/pages/Appointment/AppointmentOptions/AppointmentReschedule.js rename to client/src/pages/Appointment/appointment-options/AppointmentReschedule.js index 2e174743..31b99808 100644 --- a/client/src/pages/Appointment/AppointmentOptions/AppointmentReschedule.js +++ b/client/src/pages/Appointment/appointment-options/AppointmentReschedule.js @@ -1,7 +1,7 @@ import { useState, useEffect } from 'react'; import { clinicAxios } from 'pages/utilities/AxiosConfig'; import { Typography } from '@mui/material'; -import AvailableSlotsList from './AvailableSlotsList.js'; +import AvailableSlotsList from '../../../ui-component/AvailableSlotsList.js'; import Swal from 'sweetalert2'; import '../../../assets/css/swalStyle.css'; import { communicationAxios } from 'utils/AxiosConfig.js'; @@ -17,7 +17,6 @@ const AppointmentReschedule = ({ }) => { const { user } = useUserContext(); - console.log('selectedAppointment', selectedAppointment); const [doctorAvailableSlots, setDoctorAvailableSlots] = useState(null); const [isLoading, setIsLoading] = useState(true); useEffect(() => { @@ -68,7 +67,6 @@ const AppointmentReschedule = ({ .catch((error) => { console.log(error); }); - console.log('availableSlotsIdx', availableSlotsIdx); }; const handleConfirmation = (event) => { const availableSlotsIdx = parseInt(event.target.id); diff --git a/client/src/pages/Appointment/AppointmentOptions/FollowUp.js b/client/src/pages/Appointment/appointment-options/FollowUp.js similarity index 96% rename from client/src/pages/Appointment/AppointmentOptions/FollowUp.js rename to client/src/pages/Appointment/appointment-options/FollowUp.js index 875bf2f4..fef7e99d 100644 --- a/client/src/pages/Appointment/AppointmentOptions/FollowUp.js +++ b/client/src/pages/Appointment/appointment-options/FollowUp.js @@ -1,7 +1,7 @@ import { useState, useEffect } from 'react'; import { clinicAxios } from 'pages/utilities/AxiosConfig'; import { Typography } from '@mui/material'; -import AvailableSlotsList from './AvailableSlotsList.js'; +import AvailableSlotsList from '../../../ui-component/AvailableSlotsList.js'; import Swal from 'sweetalert2'; import '../../../assets/css/swalStyle.css'; import { useNavigate } from 'react-router-dom'; @@ -25,7 +25,6 @@ const FollowUp = ({ selectedAppointment }) => { } , []); const handleFollowUpRequest = async (availableSlotsIdx) => { - console.log('availableSlotsIdx', availableSlotsIdx); const appointmentData = { patientId: selectedAppointment.patientId, doctorId: selectedAppointment.doctorId, diff --git a/client/src/pages/admin/admin-control/AdminDetails.js b/client/src/pages/admin/admin-control/AdminDetails.js index fe4f210c..d30d88c6 100644 --- a/client/src/pages/admin/admin-control/AdminDetails.js +++ b/client/src/pages/admin/admin-control/AdminDetails.js @@ -14,6 +14,7 @@ import { import { styled } from '@mui/system'; import { useAdminContext } from 'hooks/useAdminContext'; import { commonStyles } from 'ui-component/CommonStyles'; + const useStyles = styled(() => commonStyles); const AdminDetails = () => { diff --git a/client/src/pages/admin/admin-doctors/Doctors.js b/client/src/pages/admin/admin-doctors/Doctors.js index e0f18ba9..832c1b95 100644 --- a/client/src/pages/admin/admin-doctors/Doctors.js +++ b/client/src/pages/admin/admin-doctors/Doctors.js @@ -26,7 +26,6 @@ const Doctors = () => { useEffect(() => { getDoctors().then((response) => { - console.log('response = ', response); setDoctors(response); setIsLoading(false); }) diff --git a/client/src/pages/authentication/AuthCardWrapper.js b/client/src/pages/authentication/AuthCardWrapper.js index aeb337a8..3becebca 100644 --- a/client/src/pages/authentication/AuthCardWrapper.js +++ b/client/src/pages/authentication/AuthCardWrapper.js @@ -11,7 +11,6 @@ const AuthCardWrapper = ({ children, ...other }) => ( *': { flexGrow: 1, flexBasis: '50%' diff --git a/client/src/pages/authentication/authentication3/ForgetPassword.js b/client/src/pages/authentication/authentication3/ForgetPassword.js index 0b915c14..23926254 100644 --- a/client/src/pages/authentication/authentication3/ForgetPassword.js +++ b/client/src/pages/authentication/authentication3/ForgetPassword.js @@ -35,10 +35,10 @@ const ForgetPassword = () => { - forget Password + forget Password - Enter your Email + Enter your Email @@ -53,7 +53,7 @@ const ForgetPassword = () => { - Back to Login + Back to Login diff --git a/client/src/pages/authentication/authentication3/Login3.js b/client/src/pages/authentication/authentication3/Login3.js index f6768a18..30bebc1f 100644 --- a/client/src/pages/authentication/authentication3/Login3.js +++ b/client/src/pages/authentication/authentication3/Login3.js @@ -3,7 +3,7 @@ import { Link } from 'react-router-dom'; import { useTheme } from '@mui/material/styles'; import { Divider, Grid, Stack, Typography, useMediaQuery } from '@mui/material'; - +import boardingImage from 'assets/images/boarding.jpg'; import AuthWrapper1 from '../AuthWrapper1'; import AuthCardWrapper from '../AuthCardWrapper'; import AuthLogin from '../auth-forms/AuthLogin'; @@ -19,12 +19,15 @@ const Login = () => { return ( - + - - + + + Boarding + + - + @@ -35,10 +38,10 @@ const Login = () => { - Hi, Welcome Back + Hi, Welcome Back - Enter your credentials to continue + Enter your credentials to continue @@ -53,7 +56,7 @@ const Login = () => { - Don't have an account? + Don't have an account? diff --git a/client/src/pages/authentication/authentication3/Register3.js b/client/src/pages/authentication/authentication3/Register3.js index 02a95647..81b20e00 100644 --- a/client/src/pages/authentication/authentication3/Register3.js +++ b/client/src/pages/authentication/authentication3/Register3.js @@ -40,16 +40,16 @@ const Register = () => { - Sign up as + Sign up as - - @@ -60,7 +60,7 @@ const Register = () => { {selectedButton && selectedButton == 'patient' && } - {selectedButton && (selectedButton == 'doctor') && } + {selectedButton && (selectedButton == 'doctor') && } @@ -68,7 +68,7 @@ const Register = () => { - Already have an account? + Already have an account? diff --git a/client/src/pages/chat/Chat.js b/client/src/pages/chat/Chat.js index ce3de812..6c2245bd 100644 --- a/client/src/pages/chat/Chat.js +++ b/client/src/pages/chat/Chat.js @@ -38,7 +38,7 @@ const Chat = ({ children }) => { height: '100%', display: 'flex', flexDirection: 'row', - justifyContent: isChatOpen && isChatOpen && window.innerWidth > 1000? 'start' : 'center', + justifyContent: isChatOpen && isChatOpen && window.innerWidth > 1000 ? 'start' : 'center', }; const updatePosition = () => { diff --git a/client/src/pages/chat/ChatBox.js b/client/src/pages/chat/ChatBox.js index 098eaa8a..fa3a6198 100644 --- a/client/src/pages/chat/ChatBox.js +++ b/client/src/pages/chat/ChatBox.js @@ -75,7 +75,6 @@ const ChatBox = ({ setChatOpen }) => { } action={ { - // console.log(chats, selectedChat); setSelectedChat(null); setChatOpen(false); }}> diff --git a/client/src/pages/chat/ChatListCard.js b/client/src/pages/chat/ChatListCard.js index 9bee76eb..fc164ac4 100644 --- a/client/src/pages/chat/ChatListCard.js +++ b/client/src/pages/chat/ChatListCard.js @@ -14,7 +14,6 @@ const ChatListCard = ({ chat }) => { } else { setUnseen(chat.users[1].unseen); } - console.log(chat); }, [chat]); useEffect(() => { diff --git a/client/src/pages/doctor/doctor-patients/DoctorListofPatients.js b/client/src/pages/doctor/doctor-patients/DoctorListofPatients.js index 5e742cf4..afcd8bab 100644 --- a/client/src/pages/doctor/doctor-patients/DoctorListofPatients.js +++ b/client/src/pages/doctor/doctor-patients/DoctorListofPatients.js @@ -8,6 +8,7 @@ import { useSearch } from 'contexts/SearchContext'; import { useFilter } from 'contexts/FilterContext'; import { useLocation } from 'react-router-dom'; import { useDoctorContext } from 'hooks/useDoctorContext'; +import { usePatientContext } from 'hooks/usePatientContext'; import { isUpcomingAppointment } from 'utils/DoctorUtils'; import { getAppointments, getDoctorPatients, getDoctor } from 'api/DoctorAPI'; import Loader from 'ui-component/Loader'; @@ -19,8 +20,9 @@ const Patients = () => { redirectedPatient = location.state.selectedPatient; } - const { patients, setPatients, originalPatients, setOriginalPatients, isLoading, setIsLoading, - appointments, setAppointments, setLoggedInDoctor, setSelectedPatient } = useDoctorContext(); + const { appointments, setAppointments, setLoggedInDoctor } = useDoctorContext(); + + const { patients, setPatients, isLoading, setIsLoading, originalPatients, setOriginalPatients, setSelectedPatient } = usePatientContext(); const { searchQuery } = useSearch(); const { filterData, updateFilter } = useFilter(); @@ -76,7 +78,6 @@ const Patients = () => { }); }, []); - return ( {isLoading ? ( @@ -97,5 +98,4 @@ const Patients = () => { ); }; - export default Patients; diff --git a/client/src/pages/doctor/doctor-patients/DoctorPatientCard.js b/client/src/pages/doctor/doctor-patients/DoctorPatientCard.js index 48e05963..035bd6a2 100644 --- a/client/src/pages/doctor/doctor-patients/DoctorPatientCard.js +++ b/client/src/pages/doctor/doctor-patients/DoctorPatientCard.js @@ -4,13 +4,17 @@ import { ListItemAvatar, } from '@mui/material'; import DoctorIcon from '../../../assets/images/icons/DoctorIcon.png'; -import { useDoctorContext } from 'hooks/useDoctorContext'; +import { usePatientContext } from 'hooks/usePatientContext'; import { getTitle } from 'utils/CommonUtils'; +import { commonStyles } from 'ui-component/CommonStyles'; +import { styled } from '@mui/system'; -const DoctorPatientCard = ({ patient }) => { - const { setSelectedPatient } = useDoctorContext(); +const useStyles = styled(() => commonStyles); +const DoctorPatientCard = ({ patient }) => { + const { setSelectedPatient } = usePatientContext(); const title = getTitle(patient); + const classes = useStyles(); return ( setSelectedPatient(patient)}> @@ -25,11 +29,7 @@ const DoctorPatientCard = ({ patient }) => { ); diff --git a/client/src/pages/doctor/doctor-patients/DoctorPatientDetails.js b/client/src/pages/doctor/doctor-patients/DoctorPatientDetails.js index 7235d641..c153e459 100644 --- a/client/src/pages/doctor/doctor-patients/DoctorPatientDetails.js +++ b/client/src/pages/doctor/doctor-patients/DoctorPatientDetails.js @@ -8,27 +8,11 @@ import PhoneIcon from '@mui/icons-material/Phone'; import ContactEmergencyIcon from '@mui/icons-material/ContactEmergency'; import { getDay } from '../../../utils/DateFormatter'; import { useNavigate } from 'react-router-dom'; -import { useDoctorContext } from 'hooks/useDoctorContext'; +import { usePatientContext } from 'hooks/usePatientContext'; import { getTitle } from 'utils/CommonUtils'; -const PatientDetailsContainer = styled('div')({ - display: 'flex', - justifyContent: 'space-around', - alignItems: 'center', - flexDirection: 'row', - marginBottom: '5em', -}); +import { commonStyles } from 'ui-component/CommonStyles'; -const PatientInfoContainer = styled('div')({ - display: 'flex', - flexDirection: 'column', - gap: '0.7em', -}); - -const IconContainer = styled('div')({ - display: 'flex', - alignItems: 'center', - flexDirection: 'row', -}); +const useStyles = styled(() => commonStyles); const StyledButton = styled(Button)({ marginTop: '2%', @@ -36,43 +20,43 @@ const StyledButton = styled(Button)({ const DoctorPatientDetails = () => { const navigate = useNavigate(); - const { selectedPatient } = useDoctorContext(); + const { selectedPatient } = usePatientContext(); const title = getTitle(selectedPatient); - + const classes = useStyles(); return ( <> {selectedPatient && ( <> - -
- {`${title} - - {`${title} ${selectedPatient.name}`} - -
- - +
+ + {`${title} + + {`${title} ${selectedPatient.name}`} + +
+ +
{`${selectedPatient.email}`} - - +
+
{`Born on ${getDay(selectedPatient.dateOfBirth)}`} - - +
+
{`${selectedPatient.gender}`} - - +
+
{`${selectedPatient.mobileNumber}`} - - +
+
{`${selectedPatient.emergencyContact.name} - ${selectedPatient.emergencyContact.mobile}`} - - - +
+
+
navigate(`/doctor/pages/profile/${selectedPatient._id}`, { state: { selectedPatient } })}> diff --git a/client/src/pages/doctor/doctor-patients/DoctorPatientDialog.js b/client/src/pages/doctor/doctor-patients/DoctorPatientDialog.js index 3746cc2d..598757d2 100644 --- a/client/src/pages/doctor/doctor-patients/DoctorPatientDialog.js +++ b/client/src/pages/doctor/doctor-patients/DoctorPatientDialog.js @@ -14,9 +14,10 @@ import TabPanel from '@mui/lab/TabPanel'; import DoctorPatientDetails from './DoctorPatientDetails'; import FollowUp from './FollowUp'; import { useDoctorContext } from 'hooks/useDoctorContext'; +import { usePatientContext } from 'hooks/usePatientContext'; const DoctorPatientDialog = () => { - const { selectedPatient, loggedInDoctor, setLoggedInDoctor, setSelectedPatient } = useDoctorContext(); - + const { loggedInDoctor, setLoggedInDoctor } = useDoctorContext(); + const { selectedPatient, setSelectedPatient } = usePatientContext(); const [tabValue, setTabValue] = useState('1'); const handleDialogClose = () => { diff --git a/client/src/pages/doctor/doctor-patients/FollowUp.js b/client/src/pages/doctor/doctor-patients/FollowUp.js index c1ebc2ab..c1f96701 100644 --- a/client/src/pages/doctor/doctor-patients/FollowUp.js +++ b/client/src/pages/doctor/doctor-patients/FollowUp.js @@ -1,22 +1,18 @@ import React, { useState } from 'react'; import { - Button, Typography, - Grid, - Card, - CardContent, } from '@mui/material'; -import { getDay, getTime } from '../../../utils/DateFormatter.js'; import Swal from 'sweetalert2'; import '../../../assets/css/swalStyle.css'; import { useDoctorContext } from 'hooks/useDoctorContext.js'; import { getTitle } from 'utils/CommonUtils.js'; import { addAppointment } from 'api/DoctorAPI.js'; import { showSuccessAlert } from 'utils/swal.js'; - +import { usePatientContext } from 'hooks/usePatientContext.js'; +import AvailableSlotsList from '../../../ui-component/AvailableSlotsList.js'; const FollowUp = () => { - const { selectedPatient, loggedInDoctor, setLoggedInDoctor } = useDoctorContext(); - + const { loggedInDoctor, setLoggedInDoctor } = useDoctorContext(); + const { selectedPatient } = usePatientContext(); const title = getTitle(selectedPatient); const [availableSlots, setAvailableSlots] = useState( @@ -87,60 +83,11 @@ const FollowUp = () => { )} { selectedPatient && - - {Array.isArray(availableSlots) && - availableSlots.length > 0 && - availableSlots.map((slot, index) => ( - - - theme.palette.mode === 'light' - ? theme.palette.grey[200] - : theme.palette.grey[700], - }} - > - - - {getDay(slot.from)} - - - - {`From : ${getTime(slot.from)}`} - - - {`To : ${getTime(slot.until)}`} - - - - - - - ))} - + } ); diff --git a/client/src/pages/follow-up-requests/FollowUpRequestCard.js b/client/src/pages/follow-up-requests/FollowUpRequestCard.js index 117c9b4a..e6b145ad 100644 --- a/client/src/pages/follow-up-requests/FollowUpRequestCard.js +++ b/client/src/pages/follow-up-requests/FollowUpRequestCard.js @@ -37,7 +37,6 @@ const FollowUpRequestCard = ({ followUpStatus = 'Accepted'; } else{ - console.log('heeeeeere!!!'); followUpStatus = 'Rejected'; } } diff --git a/client/src/pages/follow-up-requests/FollowUpRequests.js b/client/src/pages/follow-up-requests/FollowUpRequests.js index dca413bc..c0ad595c 100644 --- a/client/src/pages/follow-up-requests/FollowUpRequests.js +++ b/client/src/pages/follow-up-requests/FollowUpRequests.js @@ -6,10 +6,10 @@ import { List } from '@mui/material'; import FollowUpRequestCard from './FollowUpRequestCard.js'; import NoDataFound from '../NoDataFound.js'; const FollowUpRequests = () => { + const [followUpRequests, setFollowUpRequests] = useState([]); const [isLoading, setIsLoading] = useState(true); const { user } = useUserContext(); - console.log('user = ', user); useEffect(() => { clinicAxios .get(`/appointments/follow-up-requests/${user.id}`) @@ -17,7 +17,6 @@ const FollowUpRequests = () => { const resFollowUpRequests = response.data; setFollowUpRequests(resFollowUpRequests); setIsLoading(false); - console.log('resFollowUpRequests = ', resFollowUpRequests); }) .catch((error) => { console.log(error); diff --git a/client/src/pages/health-packages/AddHealthPackages.js b/client/src/pages/health-packages/AddHealthPackages.js index b76c3342..ac345e78 100644 --- a/client/src/pages/health-packages/AddHealthPackages.js +++ b/client/src/pages/health-packages/AddHealthPackages.js @@ -7,90 +7,126 @@ import { TextField, FormControl } from '@mui/material'; +import { useAdminContext } from 'hooks/useAdminContext'; +import { usePatientContext } from 'hooks/usePatientContext'; +import { addHealthPackage } from 'api/AdminAPI'; +const AddHealthPackages = () => { + + const { openAddDialog: isAddDialogOpen, setOpenAddDialog: setIsAddDialogOpen, newPackage, setNewPackage } = useAdminContext(); + const { setPackages } = usePatientContext(); + const handleFormInputChange = (e) => { + const { name, value } = e.target; + setNewPackage((prevPackage) => ({ + ...prevPackage, + [name]: value, + })); + }; + + const handleAddDialogClose = () => { + setIsAddDialogOpen(false); + setNewPackage({ + name: '', + price: '', + discountOfDoctor: '', + discountOfMedicin: '', + discountOfFamily: '', + }); + }; + + const handleAddPackage = (e) => { + e.preventDefault(); + + addHealthPackage(newPackage).then((response) => { + const newPackageData = response.data; + setPackages((prevPackage) => [...prevPackage, newPackageData]); + handleAddDialogClose(); + }) + .catch(() => { + handleAddDialogClose(); + }); + }; -const AddHealthPackages = ({ isAddDialogOpen, handleAddDialogClose, handleFormInputChange, handleAddPackage, newPackage }) => { - return ( - - Add New Package - -
handleAddPackage(e)} id='addPackageForm'> - - - - - - - - - - - - - - - - -
-
- - - - -
- ); + + Add New Package + +
handleAddPackage(e)} id='addPackageForm'> + + + + + + + + + + + + + + + + +
+
+ + + + +
+ ); }; export default AddHealthPackages; \ No newline at end of file diff --git a/client/src/pages/health-packages/EditHealthPackage.js b/client/src/pages/health-packages/EditHealthPackage.js index 6a27e6e5..affb4925 100644 --- a/client/src/pages/health-packages/EditHealthPackage.js +++ b/client/src/pages/health-packages/EditHealthPackage.js @@ -8,8 +8,33 @@ import { TextField, FormControl } from '@mui/material'; +import { useAdminContext } from 'hooks/useAdminContext'; +import { updateHealthPackage } from 'api/AdminAPI'; +import { usePatientContext } from 'hooks/usePatientContext'; + +const EditHealthPackage = () => { + const { isEditDialogOpen, setIsEditDialogOpen, setSelectedEditPackage, selectedEditPackages } = useAdminContext(); + const { setPackages } = usePatientContext(); + const handleSaveEdit = (e) => { + e.preventDefault(); + if (selectedEditPackages) { + updateHealthPackage(selectedEditPackages) + .then(() => { + setIsEditDialogOpen(false); + setPackages((prevPackage) => { + const updatedPackages = prevPackage.map((packages) => { + if (packages._id === selectedEditPackages._id) { + return selectedEditPackages; + } + return packages; + }); + return updatedPackages; + }); + setSelectedEditPackage(null); + }); + } + }; -const EditHealthPackage = ({ isEditDialogOpen, setIsEditDialogOpen, setSelectedEditPackage, handleSaveEdit, selectedEditPackage }) => { return ( Edit Health Package - {selectedEditPackage && ( + {selectedEditPackages && (
handleSaveEdit(e)} id='editPackageForm'> @@ -27,8 +52,8 @@ const EditHealthPackage = ({ isEditDialogOpen, setIsEditDialogOpen, setSelectedE variant="outlined" fullWidth margin="normal" - value={selectedEditPackage.name} - onChange={(e) => setSelectedEditPackage({ ...selectedEditPackage, name: e.target.value })} + value={selectedEditPackages.name} + onChange={(e) => setSelectedEditPackage({ ...selectedEditPackages, name: e.target.value })} required /> @@ -39,8 +64,8 @@ const EditHealthPackage = ({ isEditDialogOpen, setIsEditDialogOpen, setSelectedE variant="outlined" fullWidth margin="normal" - value={selectedEditPackage.price} - onChange={(e) => setSelectedEditPackage({ ...selectedEditPackage, price: e.target.value })} + value={selectedEditPackages.price} + onChange={(e) => setSelectedEditPackage({ ...selectedEditPackages, price: e.target.value })} required /> @@ -52,8 +77,8 @@ const EditHealthPackage = ({ isEditDialogOpen, setIsEditDialogOpen, setSelectedE variant="outlined" fullWidth margin="normal" - value={selectedEditPackage.discountOfDoctor} - onChange={(e) => setSelectedEditPackage({ ...selectedEditPackage, discountOfDoctor: e.target.value })} + value={selectedEditPackages.discountOfDoctor} + onChange={(e) => setSelectedEditPackage({ ...selectedEditPackages, discountOfDoctor: e.target.value })} required /> @@ -64,8 +89,8 @@ const EditHealthPackage = ({ isEditDialogOpen, setIsEditDialogOpen, setSelectedE variant="outlined" fullWidth margin="normal" - value={selectedEditPackage.discountOfMedicin} - onChange={(e) => setSelectedEditPackage({ ...selectedEditPackage, discountOfMedicin: e.target.value })} + value={selectedEditPackages.discountOfMedicin} + onChange={(e) => setSelectedEditPackage({ ...selectedEditPackages, discountOfMedicin: e.target.value })} required /> @@ -76,8 +101,8 @@ const EditHealthPackage = ({ isEditDialogOpen, setIsEditDialogOpen, setSelectedE variant="outlined" fullWidth margin="normal" - value={selectedEditPackage.discountOfFamily} - onChange={(e) => setSelectedEditPackage({ ...selectedEditPackage, discountOfFamily: e.target.value })} + value={selectedEditPackages.discountOfFamily} + onChange={(e) => setSelectedEditPackage({ ...selectedEditPackages, discountOfFamily: e.target.value })} required /> diff --git a/client/src/pages/health-packages/HealthPackage.js b/client/src/pages/health-packages/HealthPackage.js index e9f06599..893fd89c 100644 --- a/client/src/pages/health-packages/HealthPackage.js +++ b/client/src/pages/health-packages/HealthPackage.js @@ -1,61 +1,45 @@ -import React, { useState, useEffect } from 'react'; +import React, { useEffect } from 'react'; import { Fab } from '@mui/material'; import MainCard from '../../ui-component/cards/MainCard'; -import { clinicAxios } from '../../utils/AxiosConfig'; import HealthPackagesList from './HealthPackagesList'; import { Add } from '@mui/icons-material'; import AddHealthPackages from './AddHealthPackages'; import EditHealthPackages from './EditHealthPackage'; import { useUserContext } from 'hooks/useUserContext'; -import { patientAxios } from 'pages/utilities/AxiosConfig'; import Loader from 'ui-component/Loader'; import { ADMIN_TYPE_ENUM, PATIENT_TYPE_ENUM } from 'utils/Constants'; +import { getHealthPackages } from 'api/AdminAPI'; +import { getPatientHealthPackage, getPatientDiscount } from 'api/PatientAPI'; +import { useAdminContext } from 'hooks/useAdminContext'; +import { usePatientContext } from 'hooks/usePatientContext'; const HealthPackages = () => { - const [packages, setPackage] = useState([]); - const [subscribedPackage, setSubscribedPackage] = useState(null); - const [isAddDialogOpen, setIsAddDialogOpen] = useState(false); - const [loading, setLoading] = useState(true); - const [discount, setDiscount] = useState(0); - const [newPackage, setNewPackage] = useState({ - name: '', - price: '', - discountOfDoctor: '', - discountOfMedicin: '', - discountOfFamily: '', - }); - const [selectedEditPackages, setSelectedEditPackages] = useState(null); - const [isEditDialogOpen, setIsEditDialogOpen] = useState(false); + + const { setPackages, setSubscribedPackage, isLoading: loading, + setIsLoading: setLoading, setDiscount, isPaymentOpen } = usePatientContext(); + const { setOpenAddDialog: setIsAddDialogOpen } = useAdminContext(); const { user } = useUserContext(); - const [isPaymentOpen, setIsPaymentOpen] = useState(false); - useEffect(() => { - clinicAxios.get('/packages') - .then((response) => { - console.log(response.data.allPackages); - setPackage(response.data.allPackages); - }).then(() => { - if (user.type === PATIENT_TYPE_ENUM) { - patientAxios.get(`/patient/${user.id}/health-packages`).then((response) => { - setSubscribedPackage(response.data.healthPackages[0]); - }).then(() => { - patientAxios.get(`/patient/${user.id}/discount`).then((response) => { - setDiscount(response.data.maxDiscount); - setLoading(false); - } - ); - }); - } - else { - setLoading(false); - } - }) - .catch(error => { - console.log(error); + useEffect(() => { + getHealthPackages().then((response) => { + setPackages(response.allPackages); + }).then(() => { + if (user.type === PATIENT_TYPE_ENUM) { + getPatientHealthPackage(user.id).then((response) => { + setSubscribedPackage(response.healthPackages[0]); + }).then(() => { + getPatientDiscount(user).then((response) => { + setDiscount(response.maxDiscount); + setLoading(false); + } + ); + }); + } + else { setLoading(false); - }); - + } + }); }, [isPaymentOpen]); @@ -63,91 +47,12 @@ const HealthPackages = () => { setIsAddDialogOpen(true); }; - const handleAddDialogClose = () => { - setIsAddDialogOpen(false); - setNewPackage({ - name: '', - price: '', - discountOfDoctor: '', - discountOfMedicin: '', - discountOfFamily: '', - }); - }; - - const handleFormInputChange = (e) => { - const { name, value } = e.target; - setNewPackage((prevPackage) => ({ - ...prevPackage, - [name]: value, - })); - }; - - const handleAddPackages = (e) => { - e.preventDefault(); - - clinicAxios.post('/packages', { newPackage }).then((response) => { - const newPackageData = response.data.data; - setPackage((prevPackage) => [...prevPackage, newPackageData]); - handleAddDialogClose(); - }) - .catch((error) => { - console.log('Error adding health package:', error); - handleAddDialogClose(); - }); - }; - - const handleEditButtonClick = (packages, event) => { - event.stopPropagation(); - setSelectedEditPackages(packages); - setIsEditDialogOpen(true); - }; - - const handleDeleteButtonClick = (pack) => { - console.log(pack); - clinicAxios.delete(`/packages/${pack._id}`) - .then(() => { - setPackage((prevPackage) => { - const updatedPackages = prevPackage.filter((packages) => { - if (pack._id !== packages._id) { - return packages; - } - }); - return updatedPackages; - }); - }).catch((error) => { - console.log('Error deleting health package:', error); - }); - }; - - const handleSaveEdit = (e) => { - e.preventDefault(); - if (selectedEditPackages) { - clinicAxios.patch(`/package/${selectedEditPackages._id}`, { selectedEditPackages }) - .then(() => { - setIsEditDialogOpen(false); - setPackage((prevPackage) => { - const updatedPackages = prevPackage.map((packages) => { - if (packages._id === selectedEditPackages._id) { - return selectedEditPackages; - } - return packages; - }); - return updatedPackages; - }); - setSelectedEditPackages(null); - }) - .catch((error) => { - console.log('Error updating health package:', error); - }); - } - }; - if (loading) return (); + if (loading) return (); else { - console.log(discount); return ( - + { user.type === ADMIN_TYPE_ENUM && @@ -165,10 +70,8 @@ const HealthPackages = () => { } - - + + ); } diff --git a/client/src/pages/health-packages/HealthPackagesList.js b/client/src/pages/health-packages/HealthPackagesList.js index b48c8dd8..e21f5505 100644 --- a/client/src/pages/health-packages/HealthPackagesList.js +++ b/client/src/pages/health-packages/HealthPackagesList.js @@ -1,34 +1,51 @@ import { Typography, Grid, Card, CardHeader, Box, CardActions, Button, CardContent } from '@mui/material'; -import { Star } from '@mui/icons-material'; import EditIcon from '@mui/icons-material/Edit'; import DeleteIcon from '@mui/icons-material/Delete'; import Stack from '@mui/material/Stack'; import { useUserContext } from 'hooks/useUserContext'; import Swal from 'sweetalert2'; import { useState } from 'react'; -import { patientAxios } from 'utils/AxiosConfig'; -import { ADMIN_TYPE_ENUM, HEALTH_PACKAGE_STATUS, PATIENT_TYPE_ENUM, PAYMENT_ITEM_TYPES } from 'utils/Constants'; +import { ADMIN_TYPE_ENUM, PATIENT_TYPE_ENUM, PAYMENT_ITEM_TYPES } from 'utils/Constants'; import { ChoosePayment } from 'utils/PaymentOptions'; -const HealthPackagesList = ({ packages, handleEditButtonClick, isPaymentOpen, setIsPaymentOpen, handleDeleteButtonClick, subscribedPackage, setSubscribedPackage, discount }) => { +import { createPackageData, isSubscribedPackage } from 'utils/HealthPackageUtils'; +import { usePatientContext } from 'hooks/usePatientContext'; +import { useAdminContext } from 'hooks/useAdminContext'; +import { deleteHealthPackage } from 'api/AdminAPI'; +import { updateHealthPackageStatus } from 'api/PatientAPI'; +const HealthPackagesList = () => { + + const { packages, isPaymentOpen, setIsPaymentOpen, subscribedPackage, setSubscribedPackage, discount, setPackages } = usePatientContext(); const { user } = useUserContext(); const [totalPrice, setTotalPrice] = useState(0); const [data, setData] = useState(null); - + const { setIsEditDialogOpen, setSelectedEditPackages } = useAdminContext(); const handleSubscribe = (pack) => { - const healthPackage = {}; - healthPackage.packageId = pack._id; - healthPackage.subscribtionDate = new Date(); - healthPackage.renewalDate = new Date(healthPackage.subscribtionDate); - healthPackage.renewalDate.setMonth(healthPackage.renewalDate.getMonth() + 1); - healthPackage.status = HEALTH_PACKAGE_STATUS[1]; - const packageData = {}; - packageData.healthPackage = healthPackage; + const packageData = createPackageData(pack); setData(packageData); setTotalPrice(pack.price); setIsPaymentOpen(true); }; + const handleEditButtonClick = (pack, event) => { + event.stopPropagation(); + setSelectedEditPackages(pack); + setIsEditDialogOpen(true); + }; + + const handleDeleteButtonClick = (pack) => { + deleteHealthPackage(pack).then(() => { + setPackages((prevPackage) => { + const updatedPackages = prevPackage.filter((packages) => { + if (pack._id !== packages._id) { + return packages; + } + }); + return updatedPackages; + }); + }); + }; + const handleCancel = () => { Swal.fire({ title: 'Confirm Cancellation', @@ -38,22 +55,15 @@ const HealthPackagesList = ({ packages, handleEditButtonClick, isPaymentOpen, se confirmButtonText: 'Yes, cancel it!' }).then((result) => { if (result.isConfirmed) { - patientAxios.patch(`patient/${user.id}/health-packages/${subscribedPackage.packageId}`).then((response => { - if (response.status === 200) { - Swal.fire({ title: 'Cancelled successfully', icon: 'success' }); - setSubscribedPackage(null); - } - })); + updateHealthPackageStatus(user, subscribedPackage).then(() => { + Swal.fire({ title: 'Cancelled successfully', icon: 'success' }); + setSubscribedPackage(null); + } + ); } }); }; - const isSubscribedPackage = (pack) => { - console.log('Subscribed Package = ', subscribedPackage); - console.log('pack = ', pack); - return subscribedPackage && pack.name === subscribedPackage.name && subscribedPackage.status === HEALTH_PACKAGE_STATUS[1]; - }; - return ( {Array.isArray(packages) && packages.map((pack) => ( @@ -61,17 +71,14 @@ const HealthPackagesList = ({ packages, handleEditButtonClick, isPaymentOpen, se item key={pack.name} xs={12} - sm={pack.name === 'platinium' ? 12 : 6} + sm={6} md={4} > : null} - subheaderTypographyProps={{ - align: 'center', - }} + subheaderTypographyProps={{ align: 'center' }} sx={{ backgroundColor: (theme) => theme.palette.mode === 'light' @@ -140,15 +147,15 @@ const HealthPackagesList = ({ packages, handleEditButtonClick, isPaymentOpen, se { user.type === PATIENT_TYPE_ENUM && - } diff --git a/client/src/pages/patient/family-members/AddFamilyMember.js b/client/src/pages/patient/family-members/AddFamilyMember.js index 9052ed2b..801ca130 100644 --- a/client/src/pages/patient/family-members/AddFamilyMember.js +++ b/client/src/pages/patient/family-members/AddFamilyMember.js @@ -3,42 +3,34 @@ import { DialogContent, DialogTitle, DialogActions, - TextField, - MenuItem, Button, - FormControl, - Typography, } from '@mui/material'; import { useState } from 'react'; import { useUserContext } from 'hooks/useUserContext'; -import { patientAxios } from '../../../utils/AxiosConfig'; +import { updateFamilyMembers } from 'api/PatientAPI'; import FamilyMemberOptions from './FamilyMemeberOptions'; +import { REGISTERED_MEMBER, UNREGISTERED_MEMBER } from 'utils/Constants'; +import UnregisteredForm from './UnregisteredForm'; +import RegisteredForm from './RegisteredForm'; +import { usePatientContext } from 'hooks/usePatientContext'; -const genders = ['MALE', 'FEMALE']; -const relations = ['HUSBAND', 'WIFE', 'CHILD']; - -const AddFamilyMember = ({ - setFamilyMembers, - isOpen, - setIsOpen, - newMember, - handleFormInputChange, - error, - setError, -}) => { - const [value, setValue] = useState('Registered-Family-Member'); +const AddFamilyMember = ({ isOpen, setIsOpen }) => { const { user } = useUserContext(); + const { setFamilyMembers, newMember, setError } = usePatientContext(); + + const [value, setValue] = useState(REGISTERED_MEMBER); + const userId = user.id; + const handleSubmit = (e) => { e.preventDefault(); newMember.gender = newMember.gender.toUpperCase(); newMember.relation = newMember.relation.toUpperCase(); - patientAxios - .patch('/family-members/' + userId, { member: newMember }) - .then((data) => { + + updateFamilyMembers(userId, newMember).then((response) => { setIsOpen(false); - setFamilyMembers(data.data.familyMembers); + setFamilyMembers(response.familyMembers); }) .catch((err) => { setError(true); @@ -64,141 +56,11 @@ const AddFamilyMember = ({ value={value} /> - {value === 'Unregistered-Family-Member' && ( - <> - - - - - - - - - - - - {genders.map((option) => ( - - {option} - - ))} - - - - - {relations.map((option) => ( - - {option} - - ))} - - - + {value === UNREGISTERED_MEMBER && ( + )} - {value === 'Registered-Family-Member' && ( - <> - {error && ( - - Please enter a valid email or mobile - number - - )} - - - - - - - - - {relations.map((option) => ( - - {option} - - ))} - - - + {value === REGISTERED_MEMBER && ( + )} - {/* must have this empty typography for the accordion - to work properly (acts as summary) */} -
+
{ - selectedBookingType == 'family' && -
+ selectedBookingType == FAMILY_BOOKING_TYPE && +
} onChange={handleChange} /> @@ -191,7 +164,7 @@ const DoctorDetailsAppointmentsCard = ({ sx={{ borderRadius: 5 }} - disabled={selectedBookingType == 'family' && !selectedMember} + disabled={selectedBookingType == FAMILY_BOOKING_TYPE && !selectedMember} onClick={handleBookNow} > Book Now diff --git a/client/src/pages/patient/patient-doctors/DoctorDetailsHeader.js b/client/src/pages/patient/patient-doctors/DoctorDetailsHeader.js index 56014a40..78731ac8 100644 --- a/client/src/pages/patient/patient-doctors/DoctorDetailsHeader.js +++ b/client/src/pages/patient/patient-doctors/DoctorDetailsHeader.js @@ -6,54 +6,50 @@ import CoronavirusIcon from '@mui/icons-material/Coronavirus'; import WorkIcon from '@mui/icons-material/Work'; import SchoolIcon from '@mui/icons-material/School'; import PaidIcon from '@mui/icons-material/Paid'; +import { styled } from '@mui/system'; +import { commonStyles } from 'ui-component/CommonStyles.js'; +const useStyles = styled(() => commonStyles); const DoctorDetailsHeader = ({ selectedDoctor, loggedInPatientHealthPackage }) => { - const price = calcPrice(selectedDoctor.hourlyRate, loggedInPatientHealthPackage && loggedInPatientHealthPackage.doctorDiscount); + const classes = useStyles(); + const price = calcPrice(selectedDoctor.hourlyRate, loggedInPatientHealthPackage && loggedInPatientHealthPackage.doctorDiscount); return ( <> -
+
{selectedDoctor.userData.name} -
-
- +
+
+ {`${selectedDoctor.speciality}`}
-
- +
+ {`${selectedDoctor.affiliation}`}
-
- +
+ {`${selectedDoctor.educationalBackground}`}
-
- +
+ - +
diff --git a/client/src/pages/patient/patient-doctors/DoctorList.js b/client/src/pages/patient/patient-doctors/DoctorList.js index 48e309f6..ed1ae413 100644 --- a/client/src/pages/patient/patient-doctors/DoctorList.js +++ b/client/src/pages/patient/patient-doctors/DoctorList.js @@ -1,8 +1,9 @@ import React from 'react'; import { List } from '@mui/material'; import DoctorCard from './DoctorCard.js'; - -const DoctorList = ({ doctors, setSelectedDoctor, loggedInPatientHealthPackage }) => { +import { useDoctorContext } from 'hooks/useDoctorContext.js'; +const DoctorList = () => { + const { doctors } = useDoctorContext(); return ( {Array.isArray(doctors) && @@ -11,8 +12,6 @@ const DoctorList = ({ doctors, setSelectedDoctor, loggedInPatientHealthPackage }
diff --git a/client/src/pages/patient/patient-doctors/Doctors.js b/client/src/pages/patient/patient-doctors/Doctors.js index e3b22c0c..09ed3b4f 100644 --- a/client/src/pages/patient/patient-doctors/Doctors.js +++ b/client/src/pages/patient/patient-doctors/Doctors.js @@ -1,166 +1,137 @@ -import { useState, useEffect } from 'react'; -import { doctorAxios, patientAxios } from 'pages/utilities/AxiosConfig'; -import MainCard from 'ui-component/cards/MainCard'; -import DoctorList from './DoctorList.js'; -import DoctorDetails from './DoctorDetails.js'; -import { useUserContext } from 'hooks/useUserContext'; -import { useFilter } from 'contexts/FilterContext.js'; -import { useSearch } from 'contexts/SearchContext.js'; -import { isDateInAvailableSlots } from 'utils/AppointmentUtils.js'; -import { useLocation } from 'react-router-dom'; - - -const Doctors = () => { - const { user } = useUserContext(); - const patientID = user.id; - const [doctors, setDoctors] = useState([]); - const [selectedDoctor, setSelectedDoctor] = useState(null); - const [originalDoctors, setOriginalDoctors] = useState([]); - const [loggedInPatient, setLoggedInPatient] = useState(null); - const [loggedInPatientHealthPackage, setLoggedInPatientHealthPackage] = useState(null); - const [isLoaded, setIsLoaded] = useState(false); - const [redirected, setRedirceted] = useState(false); - const { filterData, updateFilter } = useFilter(); - const { searchQuery } = useSearch(); - const specialities = []; - const location = useLocation(); - useEffect(() => { - doctorAxios - .get('/doctors') - .then((response) => { - setDoctors(response.data); - setOriginalDoctors(response.data); - for (let i = 0; i < response.data.length; i++) { - const doctor = response.data[i]; - specialities.push(doctor.speciality); - } - console.log(response); - updateFilter([ - { - attribute: 'Speciality', - values: specialities, - }, - { - attribute: 'Available Slots', - }, - { - attribute: 'Search Method', - values: ['Name', 'Speciality', 'Both'], - }, - ]); - }) - .catch((error) => { - console.log(error); - }); - - if (location.state) { - setSelectedDoctor(location.state.selectedDoctor); - setRedirceted(true); - } - }, []); - - const applySelectedSearch = (doctor, value) => { - if (value === 'Name') { - return doctor.userData.name - .toLowerCase() - .includes(searchQuery.toLowerCase()); - } else if (value === 'Speciality') { - return doctor.speciality - .toLowerCase() - .includes(searchQuery.toLowerCase()); - } else { - return ( - doctor.userData.name - .toLowerCase() - .includes(searchQuery.toLowerCase()) || - doctor.speciality - .toLowerCase() - .includes(searchQuery.toLowerCase()) - ); - } - }; - - useEffect(() => { - const filteredDoctors = originalDoctors.filter( - (doctor) => - applySelectedSearch( - doctor, - filterData[2].selectedValue || 'Both' - ) && - (!filterData[0].selectedValue || - doctor.speciality.toString() === - filterData[0].selectedValue.toString()) && - (!filterData[1].selectedValue || - isDateInAvailableSlots( - new Date(filterData[1].selectedValue), - doctor.availableSlots - )) - ); - - setDoctors(filteredDoctors); - }, [filterData, originalDoctors, searchQuery]); - - const handleDialogClose = () => { - setSelectedDoctor(null); - }; - - useEffect(() => { - patientAxios - .get(`/patients/${patientID}`) - .then((response) => { - const patient = response.data.patient; - const filteredMembers = patient.familyMembers.filter(member => !member.id); - patient.familyMembers = filteredMembers; - setLoggedInPatient(patient); - }) - .catch((error) => { - console.log(error); - }); - }, []); - - useEffect(() => { - patientAxios - .get(`/patient/${patientID}/health-packages`) - .then((response) => { - let healthPackage = { - doctorDiscount: 0 - }; - const healthPackages = response.data.healthPackages; - if (healthPackages.length) { - healthPackage = healthPackages[0]; - } - setLoggedInPatientHealthPackage(healthPackage); - setIsLoaded(true); - }) - .catch((error) => { - console.log(error); - }); - }, []); - - return ( - isLoaded - && - - - {redirected && - } - - - ); -}; - -export default Doctors; +import { useState, useEffect } from 'react'; +import MainCard from 'ui-component/cards/MainCard'; +import DoctorList from './DoctorList.js'; +import DoctorDetails from './DoctorDetails.js'; +import { useUserContext } from 'hooks/useUserContext'; +import { useFilter } from 'contexts/FilterContext.js'; +import { useSearch } from 'contexts/SearchContext.js'; +import { isDateInAvailableSlots } from 'utils/AppointmentUtils.js'; +import { useLocation } from 'react-router-dom'; +import { useDoctorContext } from 'hooks/useDoctorContext.js'; +import { usePatientContext } from 'hooks/usePatientContext.js'; +import { getDoctors } from 'api/DoctorAPI.js'; +import { getPatient, getPatientHealthPackage } from 'api/PatientAPI.js'; +const Doctors = () => { + const { user } = useUserContext(); + const patientID = user.id; + const { setDoctors, originalDoctors, setOriginalDoctors, setSelectedDoctor } = useDoctorContext(); + const { setLoggedInPatient, setLoggedInPatientHealthPackage } = usePatientContext(); + const [isLoaded, setIsLoaded] = useState(false); + const [redirected, setRedirceted] = useState(false); + const { filterData, updateFilter } = useFilter(); + const { searchQuery } = useSearch(); + const specialities = []; + const location = useLocation(); + + useEffect(() => { + getDoctors() + .then((response) => { + setDoctors(response); + setOriginalDoctors(response); + for (let i = 0; i < response.length; i++) { + const doctor = response[i]; + specialities.push(doctor.speciality); + } + updateFilter([ + { + attribute: 'Speciality', + values: specialities, + }, + { + attribute: 'Available Slots', + }, + { + attribute: 'Search Method', + values: ['Name', 'Speciality', 'Both'], + }, + ]); + }) + .catch((error) => { + console.log(error); + }); + + if (location.state) { + setSelectedDoctor(location.state.selectedDoctor); + setRedirceted(true); + } + }, []); + + const applySelectedSearch = (doctor, value) => { + if (value === 'Name') { + return doctor.userData.name + .toLowerCase() + .includes(searchQuery.toLowerCase()); + } else if (value === 'Speciality') { + return doctor.speciality + .toLowerCase() + .includes(searchQuery.toLowerCase()); + } else { + return ( + doctor.userData.name + .toLowerCase() + .includes(searchQuery.toLowerCase()) || + doctor.speciality + .toLowerCase() + .includes(searchQuery.toLowerCase()) + ); + } + }; + + useEffect(() => { + const filteredDoctors = originalDoctors.filter( + (doctor) => + applySelectedSearch( + doctor, + filterData[2].selectedValue || 'Both' + ) && + (!filterData[0].selectedValue || + doctor.speciality.toString() === + filterData[0].selectedValue.toString()) && + (!filterData[1].selectedValue || + isDateInAvailableSlots( + new Date(filterData[1].selectedValue), + doctor.availableSlots + )) + ); + + setDoctors(filteredDoctors); + }, [filterData, originalDoctors, searchQuery]); + + useEffect(() => { + getPatient(patientID) + .then((response) => { + const patient = response.patient; + const filteredMembers = patient.familyMembers.filter(member => !member.id); + patient.familyMembers = filteredMembers; + setLoggedInPatient(patient); + }); + }, []); + + useEffect(() => { + getPatientHealthPackage(patientID) + .then((response) => { + let healthPackage = { + doctorDiscount: 0 + }; + const healthPackages = response.healthPackages; + if (healthPackages.length) { + healthPackage = healthPackages[0]; + } + setLoggedInPatientHealthPackage(healthPackage); + setIsLoaded(true); + }); + }, []); + + return ( + isLoaded + && + + + {redirected && + } + + + ); +}; + +export default Doctors; diff --git a/client/src/pages/payment/Checkout.js b/client/src/pages/payment/Checkout.js index 3c8fdbc5..dcbe3c40 100644 --- a/client/src/pages/payment/Checkout.js +++ b/client/src/pages/payment/Checkout.js @@ -74,7 +74,6 @@ export default function CheckoutForm({ item, type, selectedDoctor }) { if (type === PAYMENT_ITEM_TYPES[0]) { navigate('/patient/pages/packages'); } else if (type === PAYMENT_ITEM_TYPES[1]) { - console.log('was here'); if (selectedDoctor != '') { navigate('/patient/pages/doctors', { state: { selectedDoctor } }); } diff --git a/client/src/pages/prescriptions/MedicineCard.js b/client/src/pages/prescriptions/MedicineCard.js index c172944d..b85db42c 100644 --- a/client/src/pages/prescriptions/MedicineCard.js +++ b/client/src/pages/prescriptions/MedicineCard.js @@ -11,8 +11,6 @@ export default function MedicineCard({ userType, }) { - console.log('medicine: ', medicine); - console.log('selected presc: ', selectedPrescription); const handleMedicineAmount = (value) => { medicine.amount += value; if (medicine.amount < 1) medicine.amount = 1; diff --git a/client/src/pages/prescriptions/PrescriptionItem.js b/client/src/pages/prescriptions/PrescriptionItem.js index 99a8d656..a796443d 100644 --- a/client/src/pages/prescriptions/PrescriptionItem.js +++ b/client/src/pages/prescriptions/PrescriptionItem.js @@ -7,7 +7,7 @@ import { IconButton, Tooltip, } from '@mui/material'; - +import { getDoctor } from 'api/DoctorAPI'; import { Edit as EditIcon } from '@mui/icons-material'; import FileDownloadIcon from '@mui/icons-material/FileDownload'; import CheckIcon from '@mui/icons-material/Check'; @@ -16,7 +16,6 @@ import dayjs from 'dayjs'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import prescrptionImage from '../utilities/prescription.png'; -import { clinicAxios } from '../../utils/AxiosConfig'; import { useUserContext } from 'hooks/useUserContext'; import { PATIENT_BASE_URL } from 'utils/Constants'; @@ -29,20 +28,18 @@ const PrescriptionItem = ({ const [doctor, setDoctor] = useState({}); const [Loading, setLoading] = useState(true); useEffect(() => { - try { - const getDoctor = () => { - clinicAxios - .get(`doctor/${prescription.doctorId}`) + try { + const fetchDoctor = () => { + getDoctor(prescription.doctorId) .then((responseClinic) => { - setDoctor(responseClinic.data.doctor); + setDoctor(responseClinic.doctor); setLoading(false); }) - .catch((err) => { - console.log(err); + .catch(() => { setLoading(false); }); }; - getDoctor(); + fetchDoctor(); } catch (err) { console.log(err); } @@ -89,7 +86,6 @@ const PrescriptionItem = ({ maxHeight: '3em', }} /> - {/* {dayjs(prescription.date).format('LL')} */} {user.type === 'doctor' && !prescription.filled && ( diff --git a/client/src/pages/prescriptions/Prescriptions.js b/client/src/pages/prescriptions/Prescriptions.js index de391c88..6be03a5e 100644 --- a/client/src/pages/prescriptions/Prescriptions.js +++ b/client/src/pages/prescriptions/Prescriptions.js @@ -4,7 +4,8 @@ import PrescriptionsList from './PrescriptionsList'; import EditPrescription from './EditPrescription'; import AddPrescription from './AddPrescription'; import MainCard from '../../ui-component/cards/MainCard'; -import { patientAxios } from '../../utils/AxiosConfig'; +import { updatePrescription, createPrescription } from 'api/DoctorAPI'; +import { getPatientPrescription, getPatient } from 'api/PatientAPI'; import PrescriptionDetails from './PrescriptionDetails'; import { useUserContext } from 'hooks/useUserContext'; import { useFilter } from 'contexts/FilterContext'; @@ -21,7 +22,6 @@ import AddIcon from '@mui/icons-material/Add'; import ArrowBackIcon from '@mui/icons-material/ArrowBack'; import { useLocation, useNavigate } from 'react-router-dom'; - const Prescriptions = () => { const navigate = useNavigate(); const location = useLocation(); @@ -46,27 +46,25 @@ const Prescriptions = () => { const [description, setDescription] = useState(''); const [patientName, setPatientName] = useState(''); let selectedPatient = ''; - if(location.state){ + if (location.state) { selectedPatient = location.state.selectedPatient; } - + useEffect(() => { const getPrescriptions = async () => { try { - const patientResponses = await patientAxios.get( - `patient/${patientID}/prescriptions`, - ); + let patientResponses = await getPatientPrescription(patientID); if (singlePatientPrescriptions) { - const filteredPrescriptions = patientResponses.data.filter( + const filteredPrescriptions = patientResponses.filter( (prescription) => prescription.doctorId === user.id, ); - patientResponses.data = filteredPrescriptions; + patientResponses = filteredPrescriptions; } - setPrescriptions(patientResponses.data); - setOriginalPrescritpions(patientResponses.data); - for (let i = 0; i < patientResponses.data.length; i++) { - const patientResponse = patientResponses.data[i]; + setPrescriptions(patientResponses); + setOriginalPrescritpions(patientResponses); + for (let i = 0; i < patientResponses.length; i++) { + const patientResponse = patientResponses[i]; doctors.push(patientResponse.doctorName); } updateFilter([ @@ -84,7 +82,6 @@ const Prescriptions = () => { }, ]); setLoadingPrescription(false); - console.log('prescription now false'); } catch (err) { setLoadingPrescription(false); console.log(err); @@ -94,8 +91,8 @@ const Prescriptions = () => { }, [prescriptions.length]); useEffect(() => { - patientAxios.get(`/patients/${patientID}`).then((response) => { - setPatientName(response.data.patient.name); + getPatient(patientID).then((response) => { + setPatientName(response.patient.name); } ); }, []); @@ -135,8 +132,6 @@ const Prescriptions = () => { }; const handleSelectingPrescription = (prescription, doctor) => { - console.log('prescription 000 === ', prescription); - console.log('doctor 0000 === ', doctor); setSelectedPrescription(prescription); setPrescriptionDoctor(doctor); }; @@ -149,26 +144,22 @@ const Prescriptions = () => { const handleSaveEdit = (e) => { e.preventDefault(); - patientAxios - .patch('/prescriptions/' + selectedEditPrescription._id, { - prescription: selectedEditPrescription, - }) - .then((response) => { - const updatedPrescription = response.data; - const updatedPrescriptions = prescriptions.map((prescription) => { - if (prescription._id === updatedPrescription._id) { - return updatedPrescription; - } - return prescription; - }); - setIsEditDialogOpen(false); - setTimeout(() => { - setPrescriptions(updatedPrescriptions); - setOriginalPrescritpions(updatedPrescriptions); - setSelectedEditPrescription(null); - setEditErrorMessage(''); - }, 1000); - }) + updatePrescription(selectedEditPrescription).then((response) => { + const updatedPrescription = response; + const updatedPrescriptions = prescriptions.map((prescription) => { + if (prescription._id === updatedPrescription._id) { + return updatedPrescription; + } + return prescription; + }); + setIsEditDialogOpen(false); + setTimeout(() => { + setPrescriptions(updatedPrescriptions); + setOriginalPrescritpions(updatedPrescriptions); + setSelectedEditPrescription(null); + setEditErrorMessage(''); + }, 1000); + }) .catch((err) => { console.log(err); setEditErrorMessage('Error updating prescription'); @@ -197,8 +188,7 @@ const Prescriptions = () => { medicines: [], price: 0, }; - patientAxios - .post('/prescriptions', { prescription }) + createPrescription(prescription) .then(() => { setPrescriptions((prev) => [...prev, prescription]); setIsAddDialogOpen(false); @@ -213,63 +203,63 @@ const Prescriptions = () => { ) : ( <> - {(user.type === DOCTOR_TYPE_ENUM && patientID) && ( - - ) - } - - + {(user.type === DOCTOR_TYPE_ENUM && patientID) && ( + + ) + } + + - + - + - {user.type === DOCTOR_TYPE_ENUM && ( - - - - )} + {user.type === DOCTOR_TYPE_ENUM && ( + + + + )} - + - + ); }; diff --git a/client/src/routes/AdminRoutes.js b/client/src/routes/AdminRoutes.js index 9f9972c5..6ebb80f3 100644 --- a/client/src/routes/AdminRoutes.js +++ b/client/src/routes/AdminRoutes.js @@ -16,7 +16,7 @@ const Account = Loadable(lazy(() => import('pages/profile/Account'))); const LazyPackages = Loadable( lazy(() => import('pages/health-packages/HealthPackage')), ); -const LazyHome = Loadable(lazy(() => import('pages/Home/Home'))); +const LazyHome = Loadable(lazy(() => import('pages/home/Home'))); // utilities routing const UtilsTypography = Loadable( lazy(() => import('pages/utilities/Typography')), @@ -79,7 +79,13 @@ const AdminRoutes = { }, { path: 'packages', - element: , + element: + + + + + + , }, ], }, diff --git a/client/src/routes/DoctorRoutes.js b/client/src/routes/DoctorRoutes.js index 5bb09723..ee79be58 100644 --- a/client/src/routes/DoctorRoutes.js +++ b/client/src/routes/DoctorRoutes.js @@ -5,12 +5,14 @@ import MainLayout from 'layout/MainLayout'; import Loadable from 'ui-component/Loadable'; import { DOCTOR_TYPE_ENUM } from 'utils/Constants'; import DoctorProvider from 'contexts/DoctorContext'; +import PatientProvider from 'contexts/PatientContext'; + // dashboard routing const LazyDoctorListofPatients = Loadable( lazy(() => import('pages/doctor/doctor-patients/DoctorListofPatients')) ); const LazyAppointments = Loadable( - lazy(() => import('pages/Appointment/Appointment')) + lazy(() => import('pages/appointment/Appointment')) ); const LazyFollowUpRequests = Loadable( lazy(() => import('pages/follow-up-requests/FollowUpRequests')), @@ -25,7 +27,7 @@ const LazyPrescriptions = Loadable( const LazyChat = Loadable(lazy(() => import('pages/chat/Chat'))); -const LazyHome = Loadable(lazy(() => import('pages/Home/Home'))); +const LazyHome = Loadable(lazy(() => import('pages/home/Home'))); const Account = Loadable(lazy(() => import('pages/profile/Account'))); const LazyVideoChat = Loadable(lazy(() => import('pages/chat/VideoChat.js'))); @@ -81,7 +83,9 @@ const DoctorRoutes = { path: 'my-patients', element: - + + + , }, diff --git a/client/src/routes/PatientRoutes.js b/client/src/routes/PatientRoutes.js index c9a1c176..4f950074 100644 --- a/client/src/routes/PatientRoutes.js +++ b/client/src/routes/PatientRoutes.js @@ -12,11 +12,12 @@ const LazyPrescriptions = Loadable( const LazyPackages = Loadable( lazy(() => import('pages/health-packages/HealthPackage')), ); - - +import DoctorProvider from 'contexts/DoctorContext'; +import PatientProvider from 'contexts/PatientContext'; +import AdminProvider from 'contexts/AdminContext'; const LazyClinicDoctors = Loadable(lazy(() => import('pages/patient/patient-doctors/Doctors'))); const LazyAppointments = Loadable( - lazy(() => import('pages/Appointment/Appointment')), + lazy(() => import('pages/appointment/Appointment')), ); const LazyFollowUpRequests = Loadable( lazy(() => import('pages/follow-up-requests/FollowUpRequests')), @@ -27,7 +28,7 @@ const LazyAccount = Loadable(lazy(() => import('pages/profile/Account'))); //TOD const LazyFamilyMembers = Loadable(lazy(() => import('pages/patient/family-members/FamilyMembers.js'))); const LazyVideoChat = Loadable(lazy(() => import('pages/chat/VideoChat.js'))); const LazyChat = Loadable(lazy(() => import('pages/chat/Chat'))); -const LazyHome = Loadable(lazy(() => import('pages/Home/Home'))); +const LazyHome = Loadable(lazy(() => import('pages/home/Home'))); // utilities routing const UtilsTypography = Loadable( @@ -62,7 +63,11 @@ const MainRoutes = { }, { path: 'family-members', - element: , + element: + + + + , }, { path: 'appointments', @@ -78,7 +83,13 @@ const MainRoutes = { }, { path: 'packages', - element: , + element: + + + + + + , }, { path: 'payment', @@ -86,7 +97,13 @@ const MainRoutes = { }, { path: 'doctors', - element: , + element: + + + + + + , }, { path: 'chat', @@ -94,7 +111,7 @@ const MainRoutes = { }, { path: 'video-chat/:idToCall', - element: + element: } ], }, diff --git a/client/src/pages/Appointment/AppointmentOptions/AvailableSlotsList.js b/client/src/ui-component/AvailableSlotsList.js similarity index 97% rename from client/src/pages/Appointment/AppointmentOptions/AvailableSlotsList.js rename to client/src/ui-component/AvailableSlotsList.js index 83ac8bc9..91182db4 100644 --- a/client/src/pages/Appointment/AppointmentOptions/AvailableSlotsList.js +++ b/client/src/ui-component/AvailableSlotsList.js @@ -5,7 +5,7 @@ import { Card, CardContent, } from '@mui/material'; -import { getDay, getTime } from '../../../utils/DateFormatter.js'; +import { getDay, getTime } from '../utils/DateFormatter.js'; const AvailableSlotsList = ({ availableSlots, textOnButton, handleClick }) => { diff --git a/client/src/ui-component/CommonStyles.js b/client/src/ui-component/CommonStyles.js index fb357d0c..d53a971f 100644 --- a/client/src/ui-component/CommonStyles.js +++ b/client/src/ui-component/CommonStyles.js @@ -1,22 +1,54 @@ -export const commonStyles = { - container: { - display: 'flex', - justifyContent: 'space-around', - alignItems: 'center', - flexDirection: 'row', - marginBottom: '5em', - }, - infoContainer: { - display: 'flex', - flexDirection: 'column', - gap: '0.7em', - }, - emailContainer: { - display: 'flex', - alignItems: 'center', - flexDirection: 'row', - }, - iconMargin: { - marginRight: '0.4em', - }, +export const commonStyles = { + container: { + display: 'flex', + justifyContent: 'space-around', + alignItems: 'center', + flexDirection: 'row', + marginBottom: '5em', + }, + infoContainer: { + display: 'flex', + flexDirection: 'column', + gap: '0.7em', + }, + emailContainer: { + display: 'flex', + alignItems: 'center', + flexDirection: 'row', + }, + iconMargin: { + marginRight: '0.4em', + }, + listItemText: { + width: '60%', + lineHeight: '1.5em', + maxHeight: '3em', + }, + appointmentCard: { + display: 'flex', + justifyContent: 'center', + flexDirection: 'column', + textAlign: 'center' + }, + accordion: { + display: 'flex', + justifyContent: 'space-around', + flexDirection: 'row', + textAlign: 'center', + marginBottom: '2em' + }, + + autoCompleteContainer: { + display: 'flex', + justifyContent: 'center', + marginBottom: '2em' + }, + autoComplete: { + '&.MuiAutocomplete-hasPopupIcon .MuiAutocomplete-inputRoot': { + padding: '0.3em', + fontSize: '1em', + fontWeight: 500, + }, + width: 160 + } }; \ No newline at end of file diff --git a/client/src/utils/CommonUtils.js b/client/src/utils/CommonUtils.js index e1c3088c..c5b9aeb3 100644 --- a/client/src/utils/CommonUtils.js +++ b/client/src/utils/CommonUtils.js @@ -1,5 +1,4 @@ export const downloadDocument = (data) => { - console.log('date == ' + data); const blob = new Blob([data], { type: 'application/octet-stream' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); diff --git a/client/src/utils/Constants.js b/client/src/utils/Constants.js index 0e41e7cf..eb7e9b91 100644 --- a/client/src/utils/Constants.js +++ b/client/src/utils/Constants.js @@ -2,7 +2,8 @@ export const CLINIC_BASE_URL = 'http://localhost:8001'; export const PATIENT_BASE_URL = 'http://localhost:8002'; export const PHARMACY_BASE_URL = 'http://localhost:8003'; export const COMMUNICATION_BASE_URL = 'http://localhost:8006'; - +export const FAMILY_BOOKING_TYPE = 'family'; +export const MY_SELF_BOOKING_TYPE = 'myself'; export const PHARMACY_MONGO_ID = '5fc7a921328d333b8ce85141'; const APPOINTMENT_STATUS = [ @@ -66,3 +67,11 @@ export const PAYMENT_ITEM_TYPES = ['Health-Package', 'appointment']; export const LIMIT_PER_PAGE = 5; export const TWO_SECONDS = 2000; + +export const GENDERS = ['MALE', 'FEMALE']; + +export const RELATIONS = ['HUSBAND', 'WIFE', 'CHILD']; + +export const REGISTERED_MEMBER = 'Registered-Family-Member'; + +export const UNREGISTERED_MEMBER = 'Unregistered-Family-Member'; \ No newline at end of file diff --git a/client/src/utils/HealthPackageUtils.js b/client/src/utils/HealthPackageUtils.js new file mode 100644 index 00000000..a1c47ec4 --- /dev/null +++ b/client/src/utils/HealthPackageUtils.js @@ -0,0 +1,17 @@ +import { HEALTH_PACKAGE_STATUS } from './Constants'; + +export const createPackageData = (pack) => { + const healthPackage = {}; + healthPackage.packageId = pack._id; + healthPackage.subscribtionDate = new Date(); + healthPackage.renewalDate = new Date(healthPackage.subscribtionDate); + healthPackage.renewalDate.setMonth(healthPackage.renewalDate.getMonth() + 1); + healthPackage.status = HEALTH_PACKAGE_STATUS[1]; + const packageData = {}; + packageData.healthPackage = healthPackage; + return packageData; +}; + +export const isSubscribedPackage = (pack, subscribedPackage) => { + return subscribedPackage && pack.name === subscribedPackage.name && subscribedPackage.status === HEALTH_PACKAGE_STATUS[1]; +}; \ No newline at end of file diff --git a/client/src/utils/PaymentOptions.js b/client/src/utils/PaymentOptions.js index 95fa5d2d..6c925a36 100644 --- a/client/src/utils/PaymentOptions.js +++ b/client/src/utils/PaymentOptions.js @@ -34,15 +34,13 @@ export const ChoosePayment = ({ isAddDialogOpen, setIsAddDialogOpen, items, amou const userId = user.id; const { setPaymentDone } = usePayment(); - console.log('items ', items); - console.log('price = ', amountToPay); const [value, setValue] = useState('credit-card'); useEffect( () => { if (user.type !== ADMIN_TYPE_ENUM) { patientAxios.get(`/patients/${userId}/wallet`).then((response) => { - setAmountInWallet(response.data.walletAmount); + setAmountInWallet(response.data.walletAmount.toFixed(2)); }). catch(error => { Swal.fire('error', error, 'error'); diff --git a/client/src/utils/PaymentUtils.js b/client/src/utils/PaymentUtils.js index d10dd2e6..c73c301c 100644 --- a/client/src/utils/PaymentUtils.js +++ b/client/src/utils/PaymentUtils.js @@ -1,12 +1,9 @@ -import { clinicAxios, patientAxios, paymentAxios } from './AxiosConfig'; +import { clinicAxios, patientAxios, paymentAxios, communicationAxios } from './AxiosConfig'; import { PAYMENT_ITEM_TYPES } from './Constants'; import { showFailureAlert, showSuccessAlert } from './swal'; export const successfulPayment = (userId, items, type) => { - console.log('items = ', items); - console.log('type = ', type); if (type === PAYMENT_ITEM_TYPES[0]) { - console.log('condition true'); patientAxios.patch(`/patient/${userId}/health-packages`, { items }) .catch((error) => { console.log('Error in placing the order', error); @@ -16,9 +13,17 @@ export const successfulPayment = (userId, items, type) => { clinicAxios.post('/appointments', { items }) .then(() => { // payment to doctor - payDoctor(items).catch((err) => { - console.log('err = ', err); - }); + payDoctor(items) + .then(async () => { + await communicationAxios.post(`/notification/${items.doctorId}/type/appointment`, { + senderName: items.doctorName, + notificationHead: 'Appointment Booked', + notificationBody: `Mr/Miss ${items.patientName} has booked an appointment with you` + }); + }) + .catch((err) => { + console.log('err = ', err); + }); }) .catch((error) => { console.log('Error in placing the order', error); @@ -64,10 +69,9 @@ export const paymentElementOptions = { } }; -export const payDoctor = (items) => { +export const payDoctor = async (items) => { const { doctorId, pricePaidToDoctor } = items; - console.log('pricePaidToDoctor = ', pricePaidToDoctor); - return paymentAxios.post(`/payment-salary/doctor/${doctorId}/wallet`, { + return await paymentAxios.post(`/payment-salary/doctor/${doctorId}/wallet`, { pricePaidToDoctor }); }; \ No newline at end of file diff --git a/clinic/src/api/AdminAPI.js b/clinic/src/api/AdminAPI.js index bbebc9f5..248c0677 100644 --- a/clinic/src/api/AdminAPI.js +++ b/clinic/src/api/AdminAPI.js @@ -54,7 +54,6 @@ export const admin = (app) => { }); app.delete('/admins/:id', async (req, res) => { - console.log('delete admin'); try { const { id } = req.params; if (!isValidMongoId(id)) diff --git a/clinic/src/api/DoctorAPI.js b/clinic/src/api/DoctorAPI.js index e9852443..b89952d7 100644 --- a/clinic/src/api/DoctorAPI.js +++ b/clinic/src/api/DoctorAPI.js @@ -185,7 +185,6 @@ export const doctor = (app) => { }); } } catch (error) { - // console.log(error); if(error.response){ res.status(BAD_REQUEST_CODE_400).send({ message: error.response.data.message }); } @@ -254,7 +253,6 @@ export const doctor = (app) => { try { const id = req.params.id; const from = req.body.from; // Date - console.log('from' + ' ' + from); if (!isValidMongoId(id)) return res.status(ERROR_STATUS_CODE).json({ message: 'Invalid ID' }); const doctor = await service.addSlot(id, from); @@ -313,7 +311,6 @@ export const doctor = (app) => { } // walletChange is +ve if paid to doctor, -ve if deducted from doctor const walletChange = parseFloat(req.body.walletChange); - console.log('walletChange = ', walletChange); const updatedDoctor = await service.updateWallet(doctorId, walletChange); res.status(OK_STATUS_CODE).json({ updatedDoctor }); } catch (error) { diff --git a/clinic/src/api/HealthPackageAPI.js b/clinic/src/api/HealthPackageAPI.js index 5e46f4a3..43657702 100644 --- a/clinic/src/api/HealthPackageAPI.js +++ b/clinic/src/api/HealthPackageAPI.js @@ -54,7 +54,6 @@ export const healthPackage = (app) => { .status(ERROR_STATUS_CODE) .json({ message: 'Invalid ID' }); try { - console.log(selectedEditPackages); const updatedPackage = await service.updatePackage( id, selectedEditPackages @@ -68,7 +67,6 @@ export const healthPackage = (app) => { app.delete('/packages/:id', async (req, res) => { const id = req.params.id; try { - console.log(id); const deletedPackage = await service.deletePackage(id); res.status(OK_STATUS_CODE).json({ deletedPackage }); } catch (err) { diff --git a/clinic/src/tests/api-tests/AdminAPI.test.js b/clinic/src/tests/api-tests/AdminAPI.test.js index 0da387bf..9dcc7d76 100644 --- a/clinic/src/tests/api-tests/AdminAPI.test.js +++ b/clinic/src/tests/api-tests/AdminAPI.test.js @@ -1,6 +1,6 @@ import request from 'supertest'; import app from '../../../app.js'; -import { connectDBTest, disconnectDBTest } from '../../utils/testing-utils.js'; +import { connectDBTest, disconnectDBTest } from '../../utils/TestingUtils.js'; import { OK_STATUS_CODE, ERROR_STATUS_CODE, diff --git a/clinic/src/tests/api-tests/AppointmentAPI.test.js b/clinic/src/tests/api-tests/AppointmentAPI.test.js index 5cf7106d..7690f40f 100644 --- a/clinic/src/tests/api-tests/AppointmentAPI.test.js +++ b/clinic/src/tests/api-tests/AppointmentAPI.test.js @@ -1,6 +1,6 @@ import request from 'supertest'; import app from '../../../app.js'; -import { connectDBTest, disconnectDBTest } from '../../utils/testing-utils.js'; +import { connectDBTest, disconnectDBTest } from '../../utils/TestingUtils.js'; import { OK_STATUS_CODE, ONE, ERROR_STATUS_CODE, @@ -19,14 +19,6 @@ import { describe, beforeEach, afterEach, expect, it, jest } from '@jest/globals import { faker } from '@faker-js/faker'; jest.setTimeout(TIME_OUT); -// const NEGONE = -1; -// const printAllDoctors = async (num) => { -// const docs = await DoctorModel.find({}); -// console.log('docsLen', docs.length, 'num', num); -// docs.forEach((doc) => { -// console.log('doc', doc); -// }); -// }; describe('POST /appointments', () => { beforeEach(async () => { diff --git a/clinic/src/tests/api-tests/DoctorAPI.test.js b/clinic/src/tests/api-tests/DoctorAPI.test.js index 06c5cb81..89f4c929 100644 --- a/clinic/src/tests/api-tests/DoctorAPI.test.js +++ b/clinic/src/tests/api-tests/DoctorAPI.test.js @@ -1,6 +1,6 @@ import request from 'supertest'; import app from '../../../app.js'; -import { connectDBTest, disconnectDBTest } from '../../utils/testing-utils.js'; +import { connectDBTest, disconnectDBTest } from '../../utils/TestingUtils.js'; import { OK_STATUS_CODE, NOT_FOUND_STATUS_CODE, @@ -35,7 +35,6 @@ describe('GET /doctor/:id', () => { it('should return 200 OK and retrieve the doctor correctly', async () => { const doctor = new DoctorModel(generateDoctor()); await doctor.save(); - // console.log('DoctorAPI doctor', doctor); const id = doctor._id.toString(); const res = await request(app).get(`/doctor/${id}`); expect(res.status).toBe(OK_STATUS_CODE); @@ -304,7 +303,6 @@ describe('GET /appointments', () => { } const res = await request(app).get('/appointments'); - console.log('dsdsds', res._body); expect(res.status).toBe(OK_STATUS_CODE); expect(res._body.allAppointments.length).toBe(len); for (let i = 0; i < len; i++) { @@ -387,7 +385,6 @@ describe('GET /doctors/:id/slots', () => { const id = doctor._id.toString(); const res = await request(app).get(`/doctors/${id}/slots`); expect(res.status).toBe(OK_STATUS_CODE); - console.log('dsdsddsds', res._body); for (let i = 0; i < doctor.availableSlots.length; i++) { expect(new Date(res._body[i].from)).toStrictEqual( @@ -435,7 +432,6 @@ describe('POST /doctors/:id/slots', () => { .send({ from }); expect(res.status).toBe(OK_STATUS_CODE); - console.log('dsdsddsds', res._body); for (let i = 0; i < doctor.availableSlots.length; i++) { expect(new Date(res._body[i].from)).toStrictEqual( doctor.availableSlots[i].from @@ -500,7 +496,6 @@ describe('GET /doctors/:id/wallet', () => { await doctor.save(); const id = doctor._id.toString(); const res = await request(app).get(`/doctors/${id}/wallet`); - console.log('res._body', res._body); expect(res.status).toBe(OK_STATUS_CODE); expect(res._body.walletAmount).toBe(doctor.walletAmount); }); diff --git a/clinic/src/tests/api-tests/DoctorRequestsAPI.test.js b/clinic/src/tests/api-tests/DoctorRequestsAPI.test.js index 3055ff45..45272533 100644 --- a/clinic/src/tests/api-tests/DoctorRequestsAPI.test.js +++ b/clinic/src/tests/api-tests/DoctorRequestsAPI.test.js @@ -1,6 +1,6 @@ import request from 'supertest'; import app from '../../../app.js'; -import { connectDBTest, disconnectDBTest } from '../../utils/testing-utils.js'; +import { connectDBTest, disconnectDBTest } from '../../utils/TestingUtils.js'; import { OK_STATUS_CODE, ERROR_STATUS_CODE, diff --git a/clinic/src/tests/model-generators/generateAdmin.js b/clinic/src/tests/model-generators/generateAdmin.js index 879c86ac..d71a2bfe 100644 --- a/clinic/src/tests/model-generators/generateAdmin.js +++ b/clinic/src/tests/model-generators/generateAdmin.js @@ -5,6 +5,7 @@ const generateAdmin = () => { userName: faker.internet.userName(), password: faker.internet.password(), mainAdmin: faker.datatype.boolean(), + email: faker.internet.email() }; }; diff --git a/communication/src/utils/testing-utils.js b/clinic/src/utils/TestingUtils.js similarity index 93% rename from communication/src/utils/testing-utils.js rename to clinic/src/utils/TestingUtils.js index c03f79e7..38794352 100644 --- a/communication/src/utils/testing-utils.js +++ b/clinic/src/utils/TestingUtils.js @@ -6,7 +6,6 @@ const connectDBTest = async () => { try { const mongoURL = process.env.MONGO_URI_TEST; await mongoose.connect(mongoURL); - console.log('Database connected', mongoURL); await mongoose.connection.db.dropDatabase(); } catch (err) { console.error('Error connecting to the database:', err.message); diff --git a/communication/app.js b/communication/app.js index 299eb280..4704e851 100644 --- a/communication/app.js +++ b/communication/app.js @@ -89,27 +89,27 @@ io.on('connection', (socket) => { const newUserSocket = new UserSocketModel(newUser); newUserSocket.save(); } - socket.emit("me", socket.id); + socket.emit('me', socket.id); } catch (err) { console.log('err: ', err.message); } }); - socket.on("disconnect", () => { - socket.broadcast.emit("callEnded"); + socket.on('disconnect', () => { + socket.broadcast.emit('callEnded'); }); - socket.on("callUser", async ({ userToCall, signalData, from, name }) => { + socket.on('callUser', async ({ userToCall, signalData, from, name }) => { console.log('called user succeessfully'); const userSocketId = await UserSocketModel.findOne({ userId: userToCall }); - io.to(userSocketId.socketId).emit("callUser", { signal: signalData, from, name }); + io.to(userSocketId.socketId).emit('callUser', { signal: signalData, from, name }); }); - socket.on("answerCall", (data) => { + socket.on('answerCall', (data) => { console.log('inside answer call'); io.to(data.to).emit('hello'); - io.to(data.to).emit("callAccepted", data.signal) + io.to(data.to).emit('callAccepted', data.signal); }); }); diff --git a/communication/package.json b/communication/package.json index 7a57054b..c847f315 100644 --- a/communication/package.json +++ b/communication/package.json @@ -6,7 +6,7 @@ "main": "./src/app.js", "scripts": { "dev": "nodemon ./start.js", - "test": "jest -i", + "test": "jest -i --forceExit", "lint": "eslint . --fix" }, "author": "", diff --git a/communication/src/api/NotificationAPI.js b/communication/src/api/NotificationAPI.js index 964f9453..34118231 100644 --- a/communication/src/api/NotificationAPI.js +++ b/communication/src/api/NotificationAPI.js @@ -1,56 +1,57 @@ import NotificationService from '../service/notification-service.js'; import { AUTH_BASE_URL, BAD_REQUEST_CODE, DUPLICATE_KEY_ERROR_CODE, ERROR_STATUS_CODE, MEDICINE_NOTIFICATION_TYPE_ENUM, OK_STATUS_CODE, SERVER_ERROR_MESSAGE, ZERO_INDEX } from '../utils/Constants.js'; -import { socket } from '../utils/serverUtils.js'; +import { socket } from '../utils/ServerUtils.js'; import axios from 'axios'; import nodemailer from 'nodemailer'; export const notification = (app) => { const service = new NotificationService(); - const addNotificationForUser = async(userId, type, notification) =>{ + const addNotificationForUser = async(userId, type, notification) => { // const userId = req.params.userId; - // const type = req.params.type; - // const notification = req.body; - await service.postNotification(userId, notification, type); - let email = await axios.get(`${AUTH_BASE_URL}/user/${userId}/email`); - email = email.data; - const transporter = nodemailer.createTransport({ - service: 'Gmail', - host: 'setup.gmail.com', - port: 587, - secure: true, - auth: { - user: process.env.RESETEMAIL, - pass: process.env.RESETPASSWORD, - }, - }); + // const type = req.params.type; + // const notification = req.body; + await service.postNotification(userId, notification, type); - const mailOptions = { - from: { - name:'acl notification', - address:`${process.env.RESETEMAIL}` }, - to: [email], - subject: `${notification.notificationHead}`, - text: `${notification.notificationBody}`, - }; - - transporter.sendMail(mailOptions, (error, info) => { - console.log('info = ', info); - if (error) { - console.log(error); - // res.status(500).json({ message: 'Failed to send email' }); - } else { - // res.json({ message: 'Email sent' }); - } - }); + let email = await axios.get(`${AUTH_BASE_URL}/user/${userId}/email`); + email = email.data; + const transporter = nodemailer.createTransport({ + service: 'Gmail', + host: 'setup.gmail.com', + port: 587, + secure: true, + auth: { + user: process.env.RESETEMAIL, + pass: process.env.RESETPASSWORD, + }, + }); - socket.emit('update notifications', userId); - } + const mailOptions = { + from: { + name:'acl notification', + address:`${process.env.RESETEMAIL}` + }, + to: [email], + subject: `${notification.notificationHead}`, + text: `${notification.notificationBody}`, + }; + + transporter.sendMail(mailOptions, (error, info) => { + console.log('info = ', info); + if (error) { + console.log(error); + // res.status(500).json({ message: 'Failed to send email' }); + } else { + // res.json({ message: 'Email sent' }); + } + }); + + socket.emit('update notifications', userId); + }; const detectCustumizedErrorMessage = (messages) => { let errorMessages = new String(); Object.keys(messages).forEach((field) => { if (messages[field].kind === 'required') { - // console.log(`Custom error for ${field}:`, err.errors); errorMessages += messages[field].message + '\n'; } }); @@ -155,9 +156,9 @@ export const notification = (app) => { const medicineName = req.params.medicineName; const type = MEDICINE_NOTIFICATION_TYPE_ENUM; const notification = { - notificationHead:`medicine out of stock`, - notificationBody: `the medicine ${medicineName} is out of stock`, - senderName : "system" + notificationHead:'medicine out of stock', + notificationBody:`the medicine ${medicineName} is out of stock`, + senderName : 'system' }; for(let i = 0; i !=pharmacist.length; i++){ const userId = pharmacist[i]; @@ -168,5 +169,5 @@ export const notification = (app) => { res.status(ERROR_STATUS_CODE).send({ errMessage: error.message }); console.log(error); } - }) + }); }; \ No newline at end of file diff --git a/communication/src/database/models/UserSocket.js b/communication/src/database/models/UserSocket.js index 8aca4e40..cdd9977d 100644 --- a/communication/src/database/models/UserSocket.js +++ b/communication/src/database/models/UserSocket.js @@ -1,14 +1,14 @@ import mongoose from 'mongoose'; const UserSocketSchema = mongoose.Schema( - { - userId: { - type: String, - }, - socketId: { - type: String - } - } + { + userId: { + type: String, + }, + socketId: { + type: String + } + } ); const UserSocketModel = mongoose.model('UserSocket', UserSocketSchema); diff --git a/communication/src/tests/api-tests/ChatAPI.test.js b/communication/src/tests/api-tests/ChatAPI.test.js index 270bd159..6396c9c6 100644 --- a/communication/src/tests/api-tests/ChatAPI.test.js +++ b/communication/src/tests/api-tests/ChatAPI.test.js @@ -1,6 +1,6 @@ import request from 'supertest'; import server from '../../../app.js'; -import { connectDBTest, disconnectDBTest } from '../../utils/testing-utils.js'; +import { connectDBTest, disconnectDBTest } from '../../utils/TestingUtils.js'; import { OK_STATUS_CODE, ERROR_STATUS_CODE, ZERO, TIME_OUT } from '../../utils/Constants.js'; import ChatModel from '../../database/models/Chat.js'; '../../database/models/Chat.js'; import generateChat from '../model-generators/generateChat.js'; diff --git a/communication/src/tests/api-tests/MessageAPI.test.js b/communication/src/tests/api-tests/MessageAPI.test.js index d29847d6..b8becbae 100644 --- a/communication/src/tests/api-tests/MessageAPI.test.js +++ b/communication/src/tests/api-tests/MessageAPI.test.js @@ -1,6 +1,6 @@ import request from 'supertest'; import server from '../../../app.js'; -import { connectDBTest, disconnectDBTest } from '../../utils/testing-utils.js'; +import { connectDBTest, disconnectDBTest } from '../../utils/TestingUtils.js'; import { OK_STATUS_CODE, ERROR_STATUS_CODE, TIME_OUT } from '../../utils/Constants.js'; import MessageModel from '../../database/models/Message.js'; import generateMessage from '../model-generators/generateMessage.js'; diff --git a/communication/src/tests/api-tests/NotificationAPI.test.js b/communication/src/tests/api-tests/NotificationAPI.test.js index 90288bfe..db805345 100644 --- a/communication/src/tests/api-tests/NotificationAPI.test.js +++ b/communication/src/tests/api-tests/NotificationAPI.test.js @@ -3,9 +3,9 @@ import app from '../../../app.js'; import { connectDBTest, disconnectDBTest -} from '../../utils/testing-utils.js'; +} from '../../utils/TestingUtils.js'; import Notification from '../../database/models/Notification.js'; -import { describe, beforeEach, afterEach, expect, it } from '@jest/globals'; +import { describe, beforeEach, afterEach, expect, it, jest } from '@jest/globals'; import generateNotification from '../model-generators/generateNotification.js'; import { faker } from '@faker-js/faker'; import { @@ -17,8 +17,13 @@ import { OK_STATUS_CODE, ZERO, ONE, - TWO + TWO, + TIME_OUT, } from '../../utils/Constants.js'; +// import nodemailer from 'nodemailer'; +import axios from 'axios'; + +jest.setTimeout(TIME_OUT); describe('GET /notifications/:userId', () => { @@ -64,6 +69,8 @@ describe('POST /user/:id', () => { }); }); + +jest.mock('axios'); describe('POST /notification/:userId/type/:type', () => { beforeEach(async () => { @@ -74,6 +81,7 @@ describe('POST /notification/:userId/type/:type', () => { const userId = faker.database.mongodbObjectId(); await Notification.create({ userId }); const notification = generateNotification(); + axios.get.mockResolvedValue({ data: 'mock123@gmail.com' }); const res = await request(app).post(`/notification/${userId}/type/${NORMAL_NOTIFICATION_TYPE_ENUM}`).send(notification); expect(res.status).toBe(OK_STATUS_CODE); }); diff --git a/clinic/src/utils/testing-utils.js b/communication/src/utils/TestingUtils.js similarity index 90% rename from clinic/src/utils/testing-utils.js rename to communication/src/utils/TestingUtils.js index d2dcdc3e..38794352 100644 --- a/clinic/src/utils/testing-utils.js +++ b/communication/src/utils/TestingUtils.js @@ -1,30 +1,29 @@ -const mongoose = require('mongoose'); -const dotenv = require('dotenv'); -dotenv.config(); - -const connectDBTest = async () => { - try { - const mongoURL = process.env.MONGO_URI_TEST; - await mongoose.connect(mongoURL); - console.log('Database connected', mongoURL); - await mongoose.connection.db.dropDatabase(); - } catch (err) { - console.error('Error connecting to the database:', err.message); - } -}; - -const disconnectDBTest = async () => { - try { - const collections = mongoose.connection.collections; - - for (const key in collections) { - const collection = collections[key]; - await collection.deleteMany({}); - } - await mongoose.disconnect(); - } catch (err) { - console.error('Error connecting to the database:', err.message); - } -}; - +const mongoose = require('mongoose'); +const dotenv = require('dotenv'); +dotenv.config(); + +const connectDBTest = async () => { + try { + const mongoURL = process.env.MONGO_URI_TEST; + await mongoose.connect(mongoURL); + await mongoose.connection.db.dropDatabase(); + } catch (err) { + console.error('Error connecting to the database:', err.message); + } +}; + +const disconnectDBTest = async () => { + try { + const collections = mongoose.connection.collections; + + for (const key in collections) { + const collection = collections[key]; + await collection.deleteMany({}); + } + await mongoose.disconnect(); + } catch (err) { + console.error('Error connecting to the database:', err.message); + } +}; + export { connectDBTest, disconnectDBTest }; \ No newline at end of file diff --git a/install-all.sh b/install-all.sh new file mode 100644 index 00000000..bc305192 --- /dev/null +++ b/install-all.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +services=("authentication" "clinic" "communication" "patient" "payment" "client") + +for service in "${services[@]}"; do + cd "$service" || exit + npm i + cd .. +done diff --git a/patient/src/api/OrderAPI.js b/patient/src/api/OrderAPI.js index 927177a4..595f4e7e 100644 --- a/patient/src/api/OrderAPI.js +++ b/patient/src/api/OrderAPI.js @@ -40,7 +40,6 @@ export const order = (app) => { app.post('/order', async (req, res) => { try { const { order } = req.body; - console.log(order); const data = await service.addOrder(order); res.status(OK_STATUS_CODE).json(data); } catch (err) { diff --git a/patient/src/api/PatientAPI.js b/patient/src/api/PatientAPI.js index 48aa368e..1ec0d631 100644 --- a/patient/src/api/PatientAPI.js +++ b/patient/src/api/PatientAPI.js @@ -15,7 +15,7 @@ import { ZERO } from '../utils/Constants.js'; -import { calcAge } from '../utils/Patient-utils.js'; +import { calcAge } from '../utils/PatientUtils.js'; export const patient = (app) => { const service = new PatientService(); @@ -36,7 +36,6 @@ export const patient = (app) => { }); app.get('/patients/:id', async (req, res) => { - console.log('heeeere!'); const { id } = req.params; if (!isValidMongoId(id)) { return res.status(ERROR_STATUS_CODE).json({ message: 'Invalid ID' }); @@ -76,7 +75,6 @@ export const patient = (app) => { .json({ message: 'Invalid ID' }); } const deletedPatient = await service.deletePatient(id); - console.log(deletedPatient, 'deletedPatient'); if (!deletedPatient) { return res.status(NOT_FOUND_STATUS_CODE).json({ message: 'patient not found!', @@ -126,7 +124,6 @@ export const patient = (app) => { } try { const { member } = req.body; - console.log('member = ', member); if (member.email || member.mobileNumber) { const patient = await service.getPatient(member); if (!patient) { @@ -278,7 +275,6 @@ export const patient = (app) => { try { const { id } = req.params; const { title } = req.body; - console.log('title ======================================= ', title); const healthRecord = {}; healthRecord.recordTitle = title; healthRecord.documentName = req.file ? req.file.filename : ''; @@ -338,7 +334,6 @@ export const patient = (app) => { const duplicateKeyAttrb = Object.keys(err.keyPattern)[ ZERO_INDEX ]; - console.log(duplicateKeyAttrb); res.status(BAD_REQUEST_CODE_400).send({ errCode: DUPLICATE_KEY_ERROR_CODE, errMessage: `that ${duplicateKeyAttrb} is already registered`, @@ -421,7 +416,6 @@ export const patient = (app) => { app.patch('/patients/:patientId/wallet', async (req, res) => { const { patientId } = req.params; const { walletChange } = req.body; - console.log('walletChange = ', walletChange); if (!isValidMongoId(patientId)) { return res .status(ERROR_STATUS_CODE) diff --git a/patient/src/api/PrescriptionAPI.js b/patient/src/api/PrescriptionAPI.js index 2cd4dd5c..11a9c10a 100644 --- a/patient/src/api/PrescriptionAPI.js +++ b/patient/src/api/PrescriptionAPI.js @@ -28,7 +28,6 @@ export const prescription = (app) => { }); } const { prescription } = req.body; - console.log('prescription in patch == ', prescription); const data = await service.updatePrescription( prescriptionId, prescription, @@ -51,7 +50,6 @@ export const prescription = (app) => { }); } const prescription = await service.getPrescriptionById(prescriptionId); - console.log('prescription' + ' ' + prescription); if (!prescription) { return res.status(ERROR_STATUS_CODE).json({ message: 'Prescription not found', @@ -62,7 +60,6 @@ export const prescription = (app) => { await generatePrescriptionPDF(prescription, date); const fileName = `prescription-${date}-${prescription._id}.pdf`; const filePath = service.getFile(fileName); - console.log('filePath in PATEITN API' + ' ' + filePath); res.status(OK_STATUS_CODE).sendFile(filePath); } catch (err) { res.status(ERROR_STATUS_CODE).json({ diff --git a/patient/src/database/repository/patient-repository.js b/patient/src/database/repository/patient-repository.js index 8f203292..0611d160 100644 --- a/patient/src/database/repository/patient-repository.js +++ b/patient/src/database/repository/patient-repository.js @@ -25,12 +25,10 @@ class PatientRepository { } async findFamilyMembers(id) { - console.log('id = ', id); const familyMembers = await PatientModel.findById( id, FAMILY_MEMBERS_PROJECTION, ); - console.log('Family = ', familyMembers); return familyMembers; } diff --git a/patient/src/tests/api-tests/OrderAPI.test.js b/patient/src/tests/api-tests/OrderAPI.test.js index a39a485e..ff9fd14d 100644 --- a/patient/src/tests/api-tests/OrderAPI.test.js +++ b/patient/src/tests/api-tests/OrderAPI.test.js @@ -1,6 +1,6 @@ import request from 'supertest'; import app from '../../../app.js'; -import { connectDBTest, disconnectDBTest } from '../../utils/testing-utils.js'; +import { connectDBTest, disconnectDBTest } from '../../utils/TestingUtils.js'; import { OK_STATUS_CODE, ERROR_STATUS_CODE, @@ -57,14 +57,8 @@ describe('POST /order', () => { it('should return 200 OK and create a new order', async () => { const patient = new PatientModel(generatePatient()); await patient.save(); - const order = new OrderModel(generateOrder(patient._id, ORDER_STATUS[ZERO_INDEX])); - await order.save(); - const newOrder = { - patientId: order.patientId, - details: order.details, - amount: order.amount, - }; - const res = await request(app).post('/order').send({ order: newOrder }); + const order = generateOrder(patient._id, ORDER_STATUS[ZERO_INDEX]); + const res = await request(app).post('/order').send({ order }); expect(res.status).toBe(OK_STATUS_CODE); expect(res._body.patientId.toString()).toBe(order.patientId.toString()); }); diff --git a/patient/src/tests/api-tests/PatientAPI.test.js b/patient/src/tests/api-tests/PatientAPI.test.js index 03a1f559..49f65adc 100644 --- a/patient/src/tests/api-tests/PatientAPI.test.js +++ b/patient/src/tests/api-tests/PatientAPI.test.js @@ -1,6 +1,6 @@ import request from 'supertest'; import app from '../../../app.js'; -import { connectDBTest, disconnectDBTest } from '../../utils/testing-utils.js'; +import { connectDBTest, disconnectDBTest } from '../../utils/TestingUtils.js'; import { OK_STATUS_CODE, NOT_FOUND_STATUS_CODE, @@ -64,7 +64,6 @@ describe('GET /patient/:id/health-packages', () => { const res = await fetchPackages(id); expect(res.status).toBe(OK_STATUS_CODE); - console.log(res._body); expect(res._body.healthPackages.length).toBe(ONE); }); @@ -283,7 +282,6 @@ describe('GET /patient/:id/prescriptions (get all prescriptions of a patient)', ); await prescription.save(); } - console.log(mainPatientId); const res = await request(app).get( `/patient/${mainPatientId}/prescriptions` ); diff --git a/patient/src/tests/api-tests/PrescriptionAPI.test.js b/patient/src/tests/api-tests/PrescriptionAPI.test.js index 5fe84f97..203a8af7 100644 --- a/patient/src/tests/api-tests/PrescriptionAPI.test.js +++ b/patient/src/tests/api-tests/PrescriptionAPI.test.js @@ -1,6 +1,6 @@ import request from 'supertest'; import app from '../../../app.js'; -import { connectDBTest, disconnectDBTest } from '../../utils/testing-utils.js'; +import { connectDBTest, disconnectDBTest } from '../../utils/TestingUtils.js'; import { OK_STATUS_CODE, ERROR_STATUS_CODE, diff --git a/patient/src/tests/model-generators/generateOrder.js b/patient/src/tests/model-generators/generateOrder.js index 59b2a7d4..7b0f8d07 100644 --- a/patient/src/tests/model-generators/generateOrder.js +++ b/patient/src/tests/model-generators/generateOrder.js @@ -2,6 +2,7 @@ import { faker } from '@faker-js/faker'; const generateItem = () => { return { + medicineId: faker.database.mongodbObjectId(), name: faker.lorem.words({ min: 5, max: 10 }), price: faker.number.int({ min: 3, max: 10 }), quantity: faker.number.int({ min: 1, max: 10 }), @@ -22,6 +23,7 @@ const generateOrder = (patientId, orderStatus) => { details, amount: total, status: orderStatus, + paymentMethod: 'credit card', }; }; diff --git a/patient/src/utils/Patient-utils.js b/patient/src/utils/Patient-utils.js deleted file mode 100644 index c0bbf3ce..00000000 --- a/patient/src/utils/Patient-utils.js +++ /dev/null @@ -1,5 +0,0 @@ -export const calcAge = (dateOfBirth) => { - const today = new Date(); - const birthDate = new Date(dateOfBirth); - return today.getFullYear() - birthDate.getFullYear(); -}; \ No newline at end of file diff --git a/patient/src/utils/PatientUtils.js b/patient/src/utils/PatientUtils.js index fcabe6ee..b1193ab7 100644 --- a/patient/src/utils/PatientUtils.js +++ b/patient/src/utils/PatientUtils.js @@ -6,4 +6,10 @@ export const patientHasPackage = (patient, packageChosen) => { return true; } return false; +}; + +export const calcAge = (dateOfBirth) => { + const today = new Date(); + const birthDate = new Date(dateOfBirth); + return today.getFullYear() - birthDate.getFullYear(); }; \ No newline at end of file diff --git a/patient/src/utils/testing-utils.js b/patient/src/utils/TestingUtils.js similarity index 90% rename from patient/src/utils/testing-utils.js rename to patient/src/utils/TestingUtils.js index c28ce219..e0536a49 100644 --- a/patient/src/utils/testing-utils.js +++ b/patient/src/utils/TestingUtils.js @@ -1,31 +1,30 @@ -const mongoose = require('mongoose'); -const dotenv = require('dotenv'); -dotenv.config(); - -const connectDBTest = async () => { - try { - const mongoURL = process.env.MONGO_URI_TEST; - await mongoose.connect(mongoURL); - console.log('Database connected', mongoURL); - await mongoose.connection.db.dropDatabase(); - } catch (err) { - console.error('Error connecting to the database:', err.message); - } -}; - -const disconnectDBTest = async () => { - try { - const collections = mongoose.connection.collections; - - for (const key in collections) { - const collection = collections[key]; - await collection.deleteMany({}); - } - - await mongoose.disconnect(); - } catch (err) { - console.error('Error connecting to the database:', err.message); - } -}; - +const mongoose = require('mongoose'); +const dotenv = require('dotenv'); +dotenv.config(); + +const connectDBTest = async () => { + try { + const mongoURL = process.env.MONGO_URI_TEST; + await mongoose.connect(mongoURL); + await mongoose.connection.db.dropDatabase(); + } catch (err) { + console.error('Error connecting to the database:', err.message); + } +}; + +const disconnectDBTest = async () => { + try { + const collections = mongoose.connection.collections; + + for (const key in collections) { + const collection = collections[key]; + await collection.deleteMany({}); + } + + await mongoose.disconnect(); + } catch (err) { + console.error('Error connecting to the database:', err.message); + } +}; + export { connectDBTest, disconnectDBTest }; \ No newline at end of file diff --git a/payment/src/api/PaymentAPI.js b/payment/src/api/PaymentAPI.js index 58f45ad1..e455694a 100644 --- a/payment/src/api/PaymentAPI.js +++ b/payment/src/api/PaymentAPI.js @@ -61,11 +61,9 @@ export const payment = (app) => { }); } const walletChange = parseFloat(req.body.pricePaidToDoctor); - console.log('walletChange = ', walletChange); const axiosRes = await axios.patch(`${CLINIC_BASE_URL}/doctors/${doctorId}/wallet`, { walletChange }); - // console.log('axiosRes = ', axiosRes); res.status(OK_STATUS_CODE).json({ updatedDoctor: axiosRes.data.updatedDoctor }); } catch(err){ diff --git a/run-all.sh b/run-all.sh new file mode 100644 index 00000000..0f13dea9 --- /dev/null +++ b/run-all.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +concurrently "cd authentication && nodemon start" "cd clinic && nodemon start" "cd patient && nodemon start" "cd payment && nodemon start" "cd communication && nodemon start" "cd client && npm start" diff --git a/run-tests.sh b/run-tests.sh new file mode 100644 index 00000000..ed4fad71 --- /dev/null +++ b/run-tests.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +services=("authentication" "clinic" "communication" "patient" "payment") + +for service in "${services[@]}"; do + cd "$service" || exit + npm run test + cd .. +done