├── frontend ├── public │ ├── robots.txt │ ├── tabiconcircle.png │ ├── manifest.json │ └── index.html ├── src │ ├── Auth │ │ └── AuthContext.js │ ├── image │ │ ├── co1.jpg │ │ ├── co2.jpg │ │ ├── co3.jpg │ │ ├── co4.jpg │ │ ├── co5.jpg │ │ ├── doctor.jpg │ │ ├── tabicon.png │ │ ├── doctorlogin.png │ │ ├── doctorlogo.jpg │ │ ├── navbaricon1.png │ │ ├── patientlogin.png │ │ └── tabiconcircle.png │ ├── App.css │ ├── index.js │ ├── Dashbaord │ │ ├── dashboard.css │ │ ├── Option.js │ │ ├── LeftsidePatient.js │ │ └── LeftsideDoctor.js │ ├── calendarSampleCode │ │ ├── Readme.md │ │ ├── refer.js │ │ └── refer2.js │ ├── index.css │ ├── Pages │ │ ├── Home.js │ │ ├── Error.js │ │ ├── DoctorLogin.js │ │ ├── DoctorDashboard.js │ │ └── PaitentDashboard.js │ ├── Doctor │ │ ├── specialization.js │ │ ├── TodaysSchedule.js │ │ ├── Trie.js │ │ ├── FeedbackDetails.js │ │ ├── PersonalDetails.js │ │ ├── PaymentHistory.js │ │ ├── BookingSlots.js │ │ └── Search.js │ ├── Patient │ │ ├── SearchDoctor.js │ │ ├── Feedback.js │ │ ├── Selectdate.js │ │ ├── PerviousAppointments.js │ │ ├── AppointmentStatus.js │ │ └── Payment.js │ ├── Home │ │ ├── LoginButton.js │ │ ├── About.js │ │ ├── Jumbo.js │ │ └── Card.js │ ├── Basic │ │ ├── Footer.js │ │ └── Navbar.js │ ├── components │ │ ├── patient.logingoogle.component.js │ │ └── PhoneNumber.js │ ├── Doctorlogin │ │ └── LoginForm.js │ └── App.js ├── env-info.txt ├── .gitignore ├── package.json └── README.md ├── backend ├── Readme.md ├── env-info.txt ├── bcrypt │ └── bcrypt.js ├── models │ ├── patient.model.js │ ├── doctor.model.js │ └── appointment.model.js ├── test │ ├── 1_server.test.js │ ├── 3_patients.test.js │ └── 2_doctors.test.js ├── package.json ├── server.js └── routes │ ├── appointments.js │ ├── patients.js │ └── doctors.js ├── Software-Engineering ├── README.md ├── User_Stories.pdf ├── SE_SCE_SRS.docx.pdf ├── Stakeholders&Views.pdf └── Screenshots │ ├── original_payment.jpg │ ├── original_login both.jpg │ ├── original_select date.jpg │ ├── original_card details.jpg │ ├── original_doctor login.jpg │ ├── original_login patient.jpg │ ├── original_search doctor.jpg │ ├── original_address details.jpg │ ├── original_booking status.jpg │ ├── original_doctor feedback.jpg │ ├── original_patient feedback.jpg │ ├── original_todays schedule.png │ ├── original_appointment status.jpg │ ├── original_previous appointments.jpg │ ├── original_doctor personal details.jpg │ ├── original_patient_personal details.png │ └── original_doctor previous appointments.png ├── .github ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md └── workflows │ └── node.js.yml ├── .gitignore └── README.md /frontend/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /frontend/src/Auth/AuthContext.js: -------------------------------------------------------------------------------- 1 | import {createContext} from 'react'; 2 | 3 | export const AuthContext = createContext(); -------------------------------------------------------------------------------- /backend/Readme.md: -------------------------------------------------------------------------------- 1 | create .env file and paste contents of env-info.txt 2 | 3 | npm install (installs all dependancies) \ 4 | npm start 5 | -------------------------------------------------------------------------------- /frontend/src/image/co1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/frontend/src/image/co1.jpg -------------------------------------------------------------------------------- /frontend/src/image/co2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/frontend/src/image/co2.jpg -------------------------------------------------------------------------------- /frontend/src/image/co3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/frontend/src/image/co3.jpg -------------------------------------------------------------------------------- /frontend/src/image/co4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/frontend/src/image/co4.jpg -------------------------------------------------------------------------------- /frontend/src/image/co5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/frontend/src/image/co5.jpg -------------------------------------------------------------------------------- /frontend/src/image/doctor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/frontend/src/image/doctor.jpg -------------------------------------------------------------------------------- /frontend/src/image/tabicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/frontend/src/image/tabicon.png -------------------------------------------------------------------------------- /frontend/public/tabiconcircle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/frontend/public/tabiconcircle.png -------------------------------------------------------------------------------- /frontend/src/image/doctorlogin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/frontend/src/image/doctorlogin.png -------------------------------------------------------------------------------- /frontend/src/image/doctorlogo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/frontend/src/image/doctorlogo.jpg -------------------------------------------------------------------------------- /frontend/src/image/navbaricon1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/frontend/src/image/navbaricon1.png -------------------------------------------------------------------------------- /Software-Engineering/README.md: -------------------------------------------------------------------------------- 1 | ## Software Engineering Documents 2 | 3 | - [User Stories](User_Stories.pdf) 4 | - [StakeHolders And Their Views](Stakeholders&Views.pdf) 5 | -------------------------------------------------------------------------------- /Software-Engineering/User_Stories.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/Software-Engineering/User_Stories.pdf -------------------------------------------------------------------------------- /backend/env-info.txt: -------------------------------------------------------------------------------- 1 | PORT = 5000 2 | ATLAS_URI = 3 | ATLAS_URI_TEST = 4 | NODE_ENV = dev 5 | KEY = SECRETKEY 6 | ALGORITHM = HS256 7 | CLIENT_ID = 8 | PASSWORD_SALT = -------------------------------------------------------------------------------- /frontend/src/image/patientlogin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/frontend/src/image/patientlogin.png -------------------------------------------------------------------------------- /frontend/src/image/tabiconcircle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/frontend/src/image/tabiconcircle.png -------------------------------------------------------------------------------- /Software-Engineering/SE_SCE_SRS.docx.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/Software-Engineering/SE_SCE_SRS.docx.pdf -------------------------------------------------------------------------------- /frontend/src/App.css: -------------------------------------------------------------------------------- 1 | *{ 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | font-family: 'Roboto', sans-serif; 6 | /* background-color: #1a1a1a; */ 7 | } -------------------------------------------------------------------------------- /Software-Engineering/Stakeholders&Views.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/Software-Engineering/Stakeholders&Views.pdf -------------------------------------------------------------------------------- /Software-Engineering/Screenshots/original_payment.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/Software-Engineering/Screenshots/original_payment.jpg -------------------------------------------------------------------------------- /Software-Engineering/Screenshots/original_login both.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/Software-Engineering/Screenshots/original_login both.jpg -------------------------------------------------------------------------------- /Software-Engineering/Screenshots/original_select date.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/Software-Engineering/Screenshots/original_select date.jpg -------------------------------------------------------------------------------- /frontend/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import App from "./App"; 4 | import "./index.css"; 5 | 6 | ReactDOM.render(, document.getElementById("root")); 7 | -------------------------------------------------------------------------------- /Software-Engineering/Screenshots/original_card details.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/Software-Engineering/Screenshots/original_card details.jpg -------------------------------------------------------------------------------- /Software-Engineering/Screenshots/original_doctor login.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/Software-Engineering/Screenshots/original_doctor login.jpg -------------------------------------------------------------------------------- /Software-Engineering/Screenshots/original_login patient.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/Software-Engineering/Screenshots/original_login patient.jpg -------------------------------------------------------------------------------- /Software-Engineering/Screenshots/original_search doctor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/Software-Engineering/Screenshots/original_search doctor.jpg -------------------------------------------------------------------------------- /Software-Engineering/Screenshots/original_address details.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/Software-Engineering/Screenshots/original_address details.jpg -------------------------------------------------------------------------------- /Software-Engineering/Screenshots/original_booking status.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/Software-Engineering/Screenshots/original_booking status.jpg -------------------------------------------------------------------------------- /Software-Engineering/Screenshots/original_doctor feedback.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/Software-Engineering/Screenshots/original_doctor feedback.jpg -------------------------------------------------------------------------------- /Software-Engineering/Screenshots/original_patient feedback.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/Software-Engineering/Screenshots/original_patient feedback.jpg -------------------------------------------------------------------------------- /Software-Engineering/Screenshots/original_todays schedule.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/Software-Engineering/Screenshots/original_todays schedule.png -------------------------------------------------------------------------------- /Software-Engineering/Screenshots/original_appointment status.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/Software-Engineering/Screenshots/original_appointment status.jpg -------------------------------------------------------------------------------- /Software-Engineering/Screenshots/original_previous appointments.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/Software-Engineering/Screenshots/original_previous appointments.jpg -------------------------------------------------------------------------------- /Software-Engineering/Screenshots/original_doctor personal details.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/Software-Engineering/Screenshots/original_doctor personal details.jpg -------------------------------------------------------------------------------- /Software-Engineering/Screenshots/original_patient_personal details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/Software-Engineering/Screenshots/original_patient_personal details.png -------------------------------------------------------------------------------- /Software-Engineering/Screenshots/original_doctor previous appointments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/HEAD/Software-Engineering/Screenshots/original_doctor previous appointments.png -------------------------------------------------------------------------------- /frontend/env-info.txt: -------------------------------------------------------------------------------- 1 | REACT_APP_SERVER_URL=http://localhost:5000 2 | REACT_APP_CLIENT_ID= 3 | REACT_APP_API_KEY= 4 | REACT_APP_DISCOVERY_DOCS=https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest 5 | REACT_APP_SCOPE=https://www.googleapis.com/auth/calendar -------------------------------------------------------------------------------- /frontend/src/Dashbaord/dashboard.css: -------------------------------------------------------------------------------- 1 | 2 | .main 3 | { 4 | float: left; 5 | width: 1085px; 6 | height: 577px; 7 | top: 67px; 8 | left: 409px; 9 | position: absolute; 10 | background-color: #81817f; 11 | 12 | } 13 | li{ 14 | text-decoration: none; 15 | list-style:none 16 | } 17 | 18 | 19 | -------------------------------------------------------------------------------- /backend/bcrypt/bcrypt.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config(); 2 | 3 | function hash(plainTextPassword, salt) { 4 | return (plainTextPassword + "," + salt).split(',')[0] 5 | } 6 | 7 | function compare(encryptedPassword, actualPassword) { 8 | return hash(encryptedPassword, process.env.PASSWORD_SALT) === actualPassword 9 | } 10 | 11 | module.exports = { 12 | hash, 13 | compare 14 | } -------------------------------------------------------------------------------- /frontend/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/calendarSampleCode/Readme.md: -------------------------------------------------------------------------------- 1 | ## Google ColorID's For Calendar Events 2 | 3 | - Color: Blue | ID: 1 4 | - Color: Green | ID: 2 5 | - Color: Purple | ID: 3 6 | - Color: Red | ID: 4 7 | - Color: Yellow | ID: 5 8 | - Color: Orange | ID: 6 9 | - Color: Turquoise | ID: 7 10 | - Color: Gray | ID: 8 11 | - Color: Bold Blue | ID: 9 12 | - Color: Bold Green | ID: 10 13 | - Color: bold red | ID: 11 14 | -------------------------------------------------------------------------------- /frontend/src/Dashbaord/Option.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Option =({Value="info",})=>{ 4 | 5 | 6 | return( 7 | 15 | ) 16 | 17 | } 18 | 19 | export default Option; -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | package-lock.json 8 | 9 | # testing 10 | /coverage 11 | 12 | # production 13 | /build 14 | 15 | # misc 16 | .DS_Store 17 | .env.local 18 | .env.development.local 19 | .env.test.local 20 | .env.production.local 21 | 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | -------------------------------------------------------------------------------- /frontend/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | background-color: #242B2E; 9 | 10 | 11 | 12 | } 13 | 14 | code { 15 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 16 | monospace; 17 | } 18 | 19 | -------------------------------------------------------------------------------- /frontend/src/Pages/Home.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Footer from "../Basic/Footer"; 3 | import Navbar from "../Basic/Navbar"; 4 | import About from "../Home/About"; 5 | import Jumbo from "../Home/Jumbo"; 6 | import LoginButton from "../Home/LoginButton"; 7 | 8 | const Home = () => { 9 | return ( 10 |
11 | 12 | 13 | 14 | 15 |
16 |
17 | ); 18 | }; 19 | 20 | export default Home; 21 | -------------------------------------------------------------------------------- /frontend/src/Pages/Error.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Link } from "react-router-dom"; 3 | const Error = () => { 4 | return ( 5 |
6 |

Page Not Found

7 |
8 | 9 | 12 | 13 |
14 |
15 | ); 16 | }; 17 | 18 | export default Error; 19 | -------------------------------------------------------------------------------- /frontend/src/Doctor/specialization.js: -------------------------------------------------------------------------------- 1 | export default `addiction medicine 2 | anaesthesia 3 | dermatology 4 | emergency medicine 5 | general practice 6 | intensive care medicine 7 | medical administration 8 | obstetrics and gynecology 9 | occupational and environmental medicine 10 | ophthalmology 11 | pediatrics and child health 12 | pain medicine 13 | pathology 14 | physician 15 | psychiatry 16 | public health medicine 17 | radiation oncology 18 | radiology 19 | rehabilitation medicine 20 | sexual health medicine 21 | sport and exercise medicine 22 | surgery`.split("\n"); 23 | -------------------------------------------------------------------------------- /backend/models/patient.model.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const Schema = mongoose.Schema; 4 | 5 | const patientSchema = new Schema({ 6 | googleId: { 7 | type: String, 8 | required: true, 9 | unique: true 10 | }, 11 | email : { 12 | type: String 13 | }, 14 | name: { 15 | type: String 16 | }, 17 | picture: { 18 | type: String 19 | }, 20 | phoneNumber: { 21 | type: String 22 | } 23 | }); 24 | 25 | const Patient = mongoose.model('Patient', patientSchema); 26 | 27 | module.exports = Patient; -------------------------------------------------------------------------------- /frontend/src/Pages/DoctorLogin.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Footer from '../Basic/Footer'; 3 | import Navbar from '../Basic/Navbar'; 4 | import LoginForm from '../Doctorlogin/LoginForm'; 5 | 6 | 7 | const DoctorLogin=()=>{ 8 | 9 | return( 10 |
11 |
12 | 13 | 14 |
15 | 16 |
17 |
18 |
19 | 20 |
21 | ) 22 | 23 | } 24 | 25 | export default DoctorLogin -------------------------------------------------------------------------------- /backend/test/1_server.test.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = 'test' 2 | 3 | let chai = require('chai'); 4 | let chaiHttp = require('chai-http'); 5 | let server = require('../server'); 6 | let expect = chai.expect; 7 | 8 | chai.use(chaiHttp); 9 | 10 | describe('Check if the server is up', function () { 11 | it('GET /', function (done) { 12 | chai.request(server) 13 | .get('/') 14 | .end((err, res) => { 15 | if (err) { 16 | // console.log(err) 17 | done(err) 18 | } 19 | expect(res).to.have.status(200) 20 | done() 21 | }); 22 | }) 23 | }) -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backend", 3 | "version": "1.0.0", 4 | "description": "Backend of Health Appointment App", 5 | "main": "server.js", 6 | "scripts": { 7 | "start": "node server.js", 8 | "dev": "nodemon server.js", 9 | "test": "mocha test --timeout 10000", 10 | "coverage": "nyc npm run test" 11 | }, 12 | "author": "PBL Team IT", 13 | "license": "ISC", 14 | "dependencies": { 15 | "cors": "^2.8.5", 16 | "dotenv": "^8.2.0", 17 | "express": "^4.17.1", 18 | "jsonwebtoken": "^8.5.1", 19 | "mongoose": "^5.11.15", 20 | "stripe": "^8.141.0", 21 | "url": "^0.11.0", 22 | "uuid": "^8.3.2" 23 | }, 24 | "devDependencies": { 25 | "chai": "^4.3.3", 26 | "chai-http": "^4.3.0", 27 | "mocha": "^8.3.1", 28 | "nyc": "^15.1.0" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /.github/workflows/node.js.yml: -------------------------------------------------------------------------------- 1 | # Runs on every push and pr 2 | 3 | name: Node.js CI 4 | 5 | on: 6 | push: 7 | branches: [ main ] 8 | pull_request: 9 | branches: [ main ] 10 | 11 | jobs: 12 | build: 13 | 14 | runs-on: ubuntu-latest 15 | 16 | strategy: 17 | matrix: 18 | node-version: [ 12.x ] 19 | 20 | steps: 21 | - uses: actions/checkout@v2 22 | - name: Use Node.js ${{ matrix.node-version }} 23 | uses: actions/setup-node@v1 24 | with: 25 | node-version: ${{ matrix.node-version }} 26 | - run: | 27 | cd backend 28 | npm ci 29 | npm run build --if-present 30 | npm test 31 | env: 32 | CI: true 33 | ATLAS_URI: ${{ secrets.ATLAS_URI }} 34 | ATLAS_URI_TEST: ${{ secrets.ATLAS_URI_TEST }} 35 | CLIENT_ID: ${{ secrets.CLIENT_ID }} 36 | -------------------------------------------------------------------------------- /frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Hospital Management System 11 | 12 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | -------------------------------------------------------------------------------- /frontend/src/Patient/SearchDoctor.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Navbar from "../Basic/Navbar"; 3 | import LeftsidePatient from "../Dashbaord/LeftsidePatient"; 4 | import Search from "../Doctor/Search"; 5 | 6 | const SearchDoctor = () => { 7 | return ( 8 |
9 | 10 |
11 |
12 |
13 | 14 |
15 |
23 | 24 |
25 |
26 |
27 |
28 | ); 29 | }; 30 | 31 | export default SearchDoctor; 32 | -------------------------------------------------------------------------------- /frontend/src/Dashbaord/LeftsidePatient.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Option from "./Option"; 3 | import "./dashboard.css"; 4 | import { Link } from "react-router-dom"; 5 | 6 | const LeftsidePatient = () => { 7 | return ( 8 |
9 | 34 |
35 | ); 36 | }; 37 | 38 | export default LeftsidePatient; 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /frontend/src/Pages/DoctorDashboard.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Navbar from "../Basic/Navbar"; 3 | import Leftside from "../Dashbaord/LeftsideDoctor"; 4 | import TodaysSchedule from "../Doctor/TodaysSchedule"; 5 | import "../Dashbaord/dashboard.css"; 6 | 7 | const DoctorDashboard = () => { 8 | return ( 9 |
10 | 11 |
12 |
13 |
17 | 18 |
19 |
27 | 28 |
29 |
30 |
31 |
32 | ); 33 | }; 34 | 35 | export default DoctorDashboard; 36 | -------------------------------------------------------------------------------- /frontend/src/Dashbaord/LeftsideDoctor.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Option from "./Option"; 3 | import "./dashboard.css"; 4 | import { Link } from "react-router-dom"; 5 | 6 | const LeftsideDoctor = () => { 7 | return ( 8 |
9 | 33 |
34 | ); 35 | }; 36 | 37 | export default LeftsideDoctor; 38 | -------------------------------------------------------------------------------- /frontend/src/Home/LoginButton.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Card from "./Card"; 3 | 4 | import doctorlogin from "../image/doctorlogin.png"; 5 | import patientlogin from "../image/patientlogin.png"; 6 | 7 | const LoginButton = () => { 8 | return ( 9 |
10 | 11 | 17 |
18 | ); 19 | }; 20 | 21 | export default LoginButton; 22 | 23 | //
32 | //
33 | // 34 | //
35 | //
36 | // 42 | //
43 | //
44 | -------------------------------------------------------------------------------- /frontend/src/Basic/Footer.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Link } from "react-router-dom"; 3 | 4 | const Footer=()=> { 5 | 6 | return ( 7 | 8 | 9 |
11 | 12 |
13 |

Contact Us

14 |

15 | ABC 5078, Mumbai, India 16 |

17 |

18 | +919307531964 19 |

20 | 21 |
22 | 23 |
24 |

Social Media

25 |
    26 |
  • Facebook
  • 27 |
  • Instagram
  • 28 |
  • Twitter
  • 29 |
30 |
31 |
32 | 33 | 34 | ); 35 | } 36 | 37 | export default Footer; 38 | -------------------------------------------------------------------------------- /backend/models/doctor.model.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const Schema = mongoose.Schema; 4 | 5 | const slotSchema = new Schema({ 6 | time : { 7 | type: String, 8 | }, 9 | isBooked : { 10 | type: Boolean, 11 | default: false 12 | } 13 | }) 14 | 15 | const dateSchedule = new Schema({ 16 | date : { 17 | type: String 18 | }, 19 | slots : [slotSchema] 20 | }) 21 | 22 | const doctorSchema = new Schema({ 23 | username: { 24 | type: String, 25 | required: true, 26 | unique: true 27 | }, 28 | password: { 29 | type: String, 30 | required: true 31 | }, 32 | name: { 33 | type: String 34 | }, 35 | email : { 36 | type: String 37 | }, 38 | phoneNumber: { 39 | type: String 40 | }, 41 | specialization: { 42 | type: String 43 | }, 44 | feesPerSession: { 45 | type: String 46 | }, 47 | dates : [dateSchedule] 48 | }); 49 | 50 | const Doctor = mongoose.model('Doctor', doctorSchema); 51 | const Slot = mongoose.model('Slot', slotSchema); 52 | const DateSchedule = mongoose.model('DateSchedule', dateSchedule); 53 | 54 | module.exports = { 55 | Doctor, 56 | Slot, 57 | DateSchedule 58 | }; -------------------------------------------------------------------------------- /frontend/src/components/patient.logingoogle.component.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react'; 2 | import { GoogleLogin } from 'react-google-login'; 3 | 4 | function LoginGoogle() { 5 | const [isLoggedIn, setIsLoggedIn] = useState(window.localStorage.getItem("googleId") ? true : false); 6 | 7 | useEffect(() => {}, [isLoggedIn]) 8 | 9 | function successResponse(response) { 10 | console.log(response); 11 | window.localStorage.setItem("googleId", response.googleId); 12 | window.localStorage.setItem("token", response.tokenId) 13 | setIsLoggedIn(true); 14 | } 15 | 16 | function failureResponse(response) { 17 | console.log(response); 18 | } 19 | 20 | function logout() { 21 | setIsLoggedIn(false); 22 | window.localStorage.removeItem("googleId"); 23 | window.localStorage.removeItem("token"); 24 | } 25 | 26 | return ( 27 |
28 | {!isLoggedIn && } 35 | { 36 | isLoggedIn && 37 | } 38 | 39 |
40 | ) 41 | } 42 | 43 | export default LoginGoogle; -------------------------------------------------------------------------------- /backend/models/appointment.model.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const Schema = mongoose.Schema; 3 | 4 | const feedback = new Schema({ 5 | given : { 6 | type : Boolean, 7 | default : false 8 | }, 9 | stars : { 10 | type : Number, 11 | default : 0, 12 | min : 0, 13 | max : 5 14 | }, 15 | title : { 16 | type : String, 17 | default : "" 18 | }, 19 | review : { 20 | type : String, 21 | default : "" 22 | } 23 | }) 24 | 25 | const appointmentSchema = new Schema({ 26 | doctorId : { 27 | required: true, 28 | type: String 29 | }, 30 | dateId : { 31 | required: true, 32 | type: String 33 | }, 34 | slotId : { 35 | required: true, 36 | type: String 37 | }, 38 | patientId : { 39 | required: true, 40 | type: String 41 | }, 42 | date : { 43 | type: String 44 | }, 45 | slotTime : { 46 | type: String 47 | }, 48 | doctorName : { 49 | type : String 50 | }, 51 | doctorEmail : { 52 | type : String 53 | }, 54 | patientName : { 55 | type : String 56 | }, 57 | googleMeetLink : { 58 | type : String 59 | }, 60 | feedback : feedback 61 | }); 62 | 63 | const Appointment = mongoose.model('Appointment', appointmentSchema); 64 | const Feedback = mongoose.model('Feedback', feedback); 65 | 66 | module.exports = { Appointment, Feedback }; -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.11.4", 7 | "@testing-library/react": "^11.1.0", 8 | "@testing-library/user-event": "^12.1.10", 9 | "axios": "^0.21.1", 10 | "bootstrap": "^4.6.0", 11 | "jquery": "^3.6.0", 12 | "jwt-decode": "^3.1.2", 13 | "mdbreact": "^5.0.1", 14 | "popper.js": "^1.16.1", 15 | "react": "^17.0.1", 16 | "react-bootstrap": "^1.5.1", 17 | "react-calendar": "^3.3.1", 18 | "react-datepicker": "^3.6.0", 19 | "react-dom": "^17.0.1", 20 | "react-google-login": "^5.2.2", 21 | "react-icons": "^4.2.0", 22 | "react-router-dom": "^5.2.0", 23 | "react-scripts": "4.0.3", 24 | "react-scrollbars-custom": "^4.0.25", 25 | "react-star-picker": "^2.0.4", 26 | "react-stripe-checkout": "^2.6.3", 27 | "react-toastify": "^7.0.3", 28 | "reactstrap": "^8.9.0", 29 | "web-vitals": "^1.0.1" 30 | }, 31 | "scripts": { 32 | "start": "react-scripts start", 33 | "build": "react-scripts build", 34 | "test": "react-scripts test", 35 | "eject": "react-scripts eject" 36 | }, 37 | "eslintConfig": { 38 | "extends": [ 39 | "react-app", 40 | "react-app/jest" 41 | ] 42 | }, 43 | "browserslist": { 44 | "production": [ 45 | ">0.2%", 46 | "not dead", 47 | "not op_mini all" 48 | ], 49 | "development": [ 50 | "last 1 chrome version", 51 | "last 1 firefox version", 52 | "last 1 safari version" 53 | ] 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /frontend/src/Doctor/TodaysSchedule.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import Axios from "axios"; 3 | import jwt_decode from "jwt-decode"; 4 | 5 | const TodaysSchedule = () => { 6 | const [appointments, setAppointments] = useState([]); 7 | 8 | useEffect(() => { 9 | const fetchAppointments = async () => { 10 | var token = localStorage.getItem("token"); 11 | var decoded = jwt_decode(token); 12 | const { data } = await Axios.post( 13 | `${process.env.REACT_APP_SERVER_URL}/doctors/todays-appointments`, 14 | { 15 | doctorId: decoded._id, 16 | } 17 | ); 18 | 19 | setAppointments(data); 20 | console.log(data); 21 | }; 22 | 23 | fetchAppointments(); 24 | }, []); 25 | 26 | return ( 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | {appointments.map((appointment) => ( 38 | 39 | 40 | 41 | 42 | 43 | 44 | ))} 45 | 46 |
DateTimePatient NameMeet Link
{appointment.date}{appointment.slotTime}{appointment.patientName}Join Meet
47 | ); 48 | }; 49 | 50 | export default TodaysSchedule; 51 | -------------------------------------------------------------------------------- /frontend/src/Doctor/Trie.js: -------------------------------------------------------------------------------- 1 | function TrieNode(key) { 2 | this.key = key; 3 | this.parent = null; 4 | this.children = {}; 5 | this.end = false; 6 | } 7 | 8 | TrieNode.prototype.getWord = function () { 9 | var output = []; 10 | var node = this; 11 | 12 | while (node !== null) { 13 | output.unshift(node.key); 14 | node = node.parent; 15 | } 16 | 17 | return output.join(''); 18 | }; 19 | 20 | export default function Trie() { 21 | this.root = new TrieNode(''); 22 | } 23 | 24 | Trie.prototype.insert = function (word) { 25 | var node = this.root; 26 | 27 | for (var i = 0; i < word.length; i++) { 28 | if (!node.children[word[i]]) { 29 | node.children[word[i]] = new TrieNode(word[i]); 30 | node.children[word[i]].parent = node; 31 | } 32 | 33 | node = node.children[word[i]]; 34 | 35 | if (i === word.length - 1) { 36 | node.end = true; 37 | } 38 | } 39 | }; 40 | 41 | Trie.prototype.contains = function (word) { 42 | var node = this.root; 43 | 44 | for (var i = 0; i < word.length; i++) { 45 | if (node.children[word[i]]) { 46 | node = node.children[word[i]]; 47 | } else { 48 | return false; 49 | } 50 | } 51 | 52 | return node.end; 53 | }; 54 | 55 | Trie.prototype.find = function (prefix) { 56 | var node = this.root; 57 | var output = []; 58 | 59 | for (var i = 0; i < prefix.length; i++) { 60 | if (node.children[prefix[i]]) { 61 | node = node.children[prefix[i]]; 62 | } else { 63 | return output; 64 | } 65 | } 66 | 67 | findAllWords(node, output); 68 | 69 | return output; 70 | }; 71 | 72 | function findAllWords(node, arr) { 73 | if (node.end) { 74 | arr.unshift(node.getWord()); 75 | } 76 | for (var child in node.children) { 77 | findAllWords(node.children[child], arr); 78 | } 79 | } -------------------------------------------------------------------------------- /frontend/src/Home/About.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import Image from "../image/doctor.jpg"; 4 | 5 | const About = () => { 6 | return ( 7 |
8 |
9 |
10 |
11 | ... 15 |
16 |
17 |
18 |
Hospital Appointment Booking System
19 |

20 | One of main issue with current pandemic situation is that the 21 | hospitals are bit busy dealing with covid patients and other 22 | patients showing similar symptoms so its not easy for their 23 | regular patients who used to get a checkup or consultation. This 24 | is worsened by the restrictions due to lockdowns and the fear of 25 | contracting the contagious virus. So to deal with this issue we 26 | have come up with an approach and built this system which provides 27 | medical services and allows users to connect and consult with 28 | doctors. The aim was to build a minimalist UI for the system so 29 | people of any age group could easily navigate through it. A 30 | hospital can register their doctors in the system through their 31 | legal process and then patients can search doctors from varied 32 | specialization for consultation. 33 |

34 |
35 |
36 |
37 |
38 |
39 | ); 40 | }; 41 | 42 | export default About; 43 | -------------------------------------------------------------------------------- /backend/server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const app = express(); 3 | const cors = require('cors'); 4 | const mongoose = require('mongoose'); 5 | const patientsRouter = require('./routes/patients'); 6 | const doctorsRotuer = require('./routes/doctors'); 7 | const appointmentRouter = require('./routes/appointments'); 8 | require('dotenv').config(); 9 | 10 | app.use(express.json()); 11 | app.use(cors( 12 | { 13 | origin: "*", // allow the server to accept request from different origin 14 | methods: "GET,HEAD,PUT,PATCH,POST,DELETE", 15 | credentials: true // allow session cookie from browser to pass through 16 | } 17 | )); 18 | 19 | app.use('/patients', patientsRouter); 20 | app.use('/doctors', doctorsRotuer); 21 | app.use('/appointments', appointmentRouter); 22 | 23 | const port = process.env.PORT || 5000; 24 | let uri = ''; 25 | process.env.NODE_ENV === 'test' ? uri = process.env.ATLAS_URI_TEST : uri = process.env.ATLAS_URI; 26 | 27 | mongoose.connect(uri, { useNewUrlParser: true, useCreateIndex: true, useUnifiedTopology: true, useFindAndModify: false }, (err) => { 28 | if (!err) { 29 | console.log("Connection to database successful!"); 30 | } 31 | }); 32 | 33 | function getCurrentTime() { 34 | const date = new Date() 35 | console.log(date) 36 | } 37 | 38 | function getEndDateTime(dateTime) { 39 | // 2021-03-22T09:00:00 40 | const hrs = (parseInt(dateTime.split('T')[1].split(':')[0]) + 1).toString().padStart(2, '0') 41 | const time = hrs + ':00:00' 42 | const date = dateTime.split('T')[0] 43 | return date + 'T' + time 44 | } 45 | 46 | app.listen(port, () => { 47 | console.log(`Listening on port ${port}`) 48 | console.log(`NODE_ENV = ${process.env.NODE_ENV}`) 49 | getCurrentTime() 50 | getEndDateTime("2021-03-22T09:00:00") 51 | }) 52 | 53 | app.get('/', (req, res) => { 54 | res.status(200).json("Hello"); 55 | }) 56 | 57 | module.exports = app; -------------------------------------------------------------------------------- /backend/routes/appointments.js: -------------------------------------------------------------------------------- 1 | const router = require('express').Router(); 2 | const appointmentImport = require("../models/appointment.model"); 3 | const { Appointment, Feedback } = appointmentImport; 4 | 5 | router.route('/add-meet-link').put((req, res) => { 6 | const meetLink = req.body.meetLink; 7 | const appointmentId = req.body.appointmentId; 8 | 9 | Appointment.findOne({ _id: appointmentId }).then((appointment) => { 10 | if (appointment) { 11 | appointment.googleMeetLink = meetLink; 12 | console.log(`Received meet link : ${meetLink}`); 13 | 14 | appointment.save().then(() => { 15 | console.log(`Updated the meet link!`); 16 | res.status(200).json({ message: "Meet link updated!" }); 17 | }).catch((err) => { 18 | console.log(`Cannot add meet link to the appointment due to ${err}`); 19 | res.status(400).json({ message: `Cannot add meet link to the appointment due to ${err}` }); 20 | }) 21 | } 22 | }) 23 | }) 24 | 25 | router.route('/feedback').put((req, res) => { 26 | const appointmentId = req.body.appointmentId; 27 | const stars = req.body.stars; 28 | const title = req.body.title; 29 | const review = req.body.review; 30 | 31 | Appointment.findOne({ _id : appointmentId }).then((appointment) => { 32 | if(appointment) { 33 | appointment.feedback.stars = stars; 34 | appointment.feedback.title = title; 35 | appointment.feedback.review = review; 36 | appointment.feedback.given = true; 37 | 38 | appointment.save().then(() => { 39 | res.status(200).json({message : `Feedback updated successfully!`}); 40 | }).catch(err => { 41 | console.log(err); 42 | res.status(400).json(err); 43 | }) 44 | } 45 | }).catch(err => { 46 | console.log(err); 47 | res.status(400).json(err); 48 | }) 49 | }) 50 | 51 | module.exports = router; -------------------------------------------------------------------------------- /frontend/src/Home/Jumbo.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Carousel from "react-bootstrap/Carousel"; 3 | import co1 from "../image/co1.jpg" 4 | import co2 from "../image/co2.jpg" 5 | import co4 from "../image/co4.jpg" 6 | // import co3 from "../image/co3.jpg" 7 | // import co5 from "../image/co5.jpg" 8 | 9 | 10 | 11 | const Jumbo=()=>{ 12 | return( 13 |
14 |
23 |
24 | 25 | 26 | carousel-image1 34 | {/* 35 | 36 |

First

37 |
*/} 38 |
39 | 40 | carousel-image2 47 | {/* 48 |

Second

49 |
*/} 50 |
51 | 52 | carousel-image3 58 | {/* 59 |

Third

60 |
*/} 61 |
62 |
63 |
64 |
65 |
66 | ) 67 | } 68 | 69 | 70 | export default Jumbo -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env.test 73 | 74 | # parcel-bundler cache (https://parceljs.org/) 75 | .cache 76 | 77 | # Next.js build output 78 | .next 79 | 80 | # Nuxt.js build / generate output 81 | .nuxt 82 | dist 83 | 84 | # Gatsby files 85 | .cache/ 86 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 87 | # https://nextjs.org/blog/next-9-1#public-directory-support 88 | # public 89 | 90 | # vuepress build output 91 | .vuepress/dist 92 | 93 | # Serverless directories 94 | .serverless/ 95 | 96 | # FuseBox cache 97 | .fusebox/ 98 | 99 | # DynamoDB Local files 100 | .dynamodb/ 101 | 102 | # TernJS port file 103 | .tern-port 104 | frontend/package-lock.json 105 | package-lock.json 106 | backend/package-lock.json 107 | 108 | .env -------------------------------------------------------------------------------- /frontend/src/Doctor/FeedbackDetails.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react'; 2 | import Navbar from '../Basic/Navbar'; 3 | import { Row, Input, Button } from 'reactstrap' 4 | import { Link, useParams } from 'react-router-dom'; 5 | import StarPicker from 'react-star-picker'; 6 | import Spinner from "react-bootstrap/Spinner"; 7 | import axios from 'axios'; 8 | 9 | const FeedbackDetails = () => { 10 | const { id } = useParams(); 11 | const [feedback, setFeedback] = useState({}); 12 | const [isLoading, setIsLoading] = useState(true); 13 | 14 | useEffect(() => { 15 | async function init() { 16 | setIsLoading(true); 17 | const { data } = await axios.get( 18 | `${process.env.REACT_APP_SERVER_URL}/doctors/appointment/${id}` 19 | ); 20 | 21 | setFeedback(data?.feedback); 22 | 23 | setIsLoading(false); 24 | } 25 | 26 | init(); 27 | }, []) 28 | 29 | if (isLoading) { 30 | return ( 31 |
32 | 33 |
34 | 35 | Loading... 36 | 37 |
38 |
39 | ) 40 | } 41 | 42 | return (
43 | 44 |
54 | 55 | 56 | 57 | 58 | 62 | 63 | 64 | 71 | 72 | 73 | 79 | 80 | 81 | 82 | 83 |
84 |
) 85 | 86 | } 87 | 88 | export default FeedbackDetails; -------------------------------------------------------------------------------- /frontend/src/Patient/Feedback.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import Navbar from '../Basic/Navbar'; 3 | import { Row, Input, Button } from 'reactstrap' 4 | import { Link, useHistory, useParams } from 'react-router-dom'; 5 | import StarPicker from 'react-star-picker'; 6 | import axios from 'axios'; 7 | 8 | const Feedback = () => { 9 | const [rating, setRating] = useState(0); 10 | const [title, setTitle] = useState(''); 11 | const [review, setReview] = useState(''); 12 | const appointmentId = useParams(); 13 | 14 | const history = useHistory(); 15 | 16 | const onChange = (value) => { 17 | setRating(value); 18 | } 19 | 20 | const putFeedback = async () => { 21 | try { 22 | const { data } = axios.put( 23 | `${process.env.REACT_APP_SERVER_URL}/appointments/feedback/`, 24 | { 25 | appointmentId: appointmentId.id, 26 | stars: rating, 27 | title: title, 28 | review: review 29 | } 30 | ) 31 | 32 | if (data) { 33 | console.log(data) 34 | } 35 | 36 | history.push("/patient/"); 37 | } 38 | catch (err) { 39 | console.log(err); 40 | } 41 | } 42 | 43 | return (
44 | 45 |
55 |

It will be helpful if you share your Experience

56 | 57 | 58 | 59 | 60 | setTitle(e.target.value)} 63 | /> 64 | 65 | 66 | setReview(e.target.value)} 72 | /> 73 | 74 | 75 | 81 | 82 | 83 | 84 | 85 | 86 |
87 |
) 88 | 89 | } 90 | 91 | export default Feedback -------------------------------------------------------------------------------- /frontend/src/components/PhoneNumber.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import React, { useContext, useState } from 'react'; 3 | import { Redirect, useHistory } from 'react-router'; 4 | import { Row,Col, Container, FormGroup, Input, Label, Button } from 'reactstrap'; 5 | import { AuthContext } from '../Auth/AuthContext'; 6 | import Navbar from '../Basic/Navbar'; 7 | 8 | function PhoneNumber() { 9 | const [number, setNumber] = useState(); 10 | const { token, googleId } = useContext(AuthContext); 11 | const history = useHistory(); 12 | 13 | async function updatePhoneNumber() { 14 | try { 15 | const res = await axios.put(`${process.env.REACT_APP_SERVER_URL}/patients/update-phone`, 16 | { 17 | googleId: googleId, 18 | phoneNumber: number 19 | } 20 | ) 21 | // console.log(res); 22 | if (res.status === 200) { 23 | history.push('/patient') 24 | } 25 | else { 26 | console.log(res.message) 27 | } 28 | } 29 | catch(err){ 30 | console.log(err); 31 | } 32 | } 33 | 34 | if (!token) { 35 | return ( 36 | 37 | ) 38 | } 39 | 40 | return ( 41 |
42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | setNumber(e.target.value)} 59 | /> 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 |
72 | ) 73 | } 74 | 75 | export default PhoneNumber; -------------------------------------------------------------------------------- /frontend/src/Doctor/PersonalDetails.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useMemo } from "react"; 2 | import Navbar from "../Basic/Navbar"; 3 | import Leftside from "../Dashbaord/LeftsideDoctor"; 4 | import jwt_decode from "jwt-decode"; 5 | 6 | import "../Dashbaord/dashboard.css"; 7 | import { AuthContext } from "../Auth/AuthContext"; 8 | 9 | const PersonalDetails = () => { 10 | const { token } = useContext(AuthContext); 11 | const doctor = useMemo(() => jwt_decode(token), [token]); 12 | 13 | return ( 14 |
15 | 16 |
17 |
18 |
22 | 23 |
24 |
32 |
33 |

Personal Details

34 |
    35 |
  • 36 | 37 | Name: 38 | 39 | {doctor.name} 40 |
  • 41 |
  • 42 | 43 | Specialization: 44 | 45 | 46 | {doctor.specialization} 47 | 48 |
  • 49 |
  • 50 | 51 | Phone No: 52 | 53 | {doctor.phoneNumber} 54 |
  • 55 |
  • 56 | 57 | Fees Per Session: 58 | 59 | {doctor.feesPerSession} 60 |
  • 61 |
62 |
63 |
64 |
65 |
66 |
67 | ); 68 | }; 69 | export default PersonalDetails; 70 | -------------------------------------------------------------------------------- /frontend/src/Home/Card.js: -------------------------------------------------------------------------------- 1 | import { Button } from 'react-bootstrap'; 2 | import React, { useContext } from 'react'; 3 | // import GoogleLogin from 'react-google-login'; 4 | import { Link, useHistory } from "react-router-dom"; 5 | import { AuthContext } from '../Auth/AuthContext'; 6 | import axios from 'axios'; 7 | 8 | const Card = ({ login = "Doctor", Image, link }) => { 9 | const { token, googleId, setToken, setGoogleId } = useContext(AuthContext); 10 | const history = useHistory(); 11 | 12 | async function loginWithGoogle(e) { 13 | try { 14 | await window.gapi.auth2.getAuthInstance().signIn(); 15 | const auth2 = await window.gapi.auth2.getAuthInstance(); 16 | if (auth2.isSignedIn.get()) { 17 | console.log("[Google] Signed in successfully!"); 18 | var profile = auth2.currentUser.get(); 19 | console.log(profile); 20 | window.localStorage.setItem("token", profile.getAuthResponse().id_token); 21 | window.localStorage.setItem("googleId", profile.getId()); 22 | 23 | const serverRes = await axios.post( 24 | `${process.env.REACT_APP_SERVER_URL}/patients/google-login/`, 25 | { 26 | tokenId: profile.getAuthResponse().id_token, 27 | } 28 | ); 29 | 30 | if (serverRes) { 31 | console.log(serverRes.data.phoneNumberExists); 32 | 33 | setToken(profile.getAuthResponse().id_token); 34 | setGoogleId(profile.getId()); 35 | 36 | if (serverRes.data.phoneNumberExists === true) { 37 | history.push("/patient"); 38 | } else { 39 | history.push("/patient/update-phone"); 40 | } 41 | } 42 | else { 43 | const err = {err : "Server Didn't respond"} 44 | throw err; 45 | } 46 | } 47 | } catch (err) { 48 | console.log(`[Google] Some error occurred while signing in! ${err}`); 49 | } 50 | } 51 | 52 | return ( 53 |
54 | ... 55 |
56 | {((!token || googleId) && login === "Doctor") && Login As A Doctor} 57 | {((token && !googleId) && login === "Doctor") && My Dashboard} 58 | {((!googleId && login === "Patient") && )} 59 | {((token && googleId) && login === "Patient") && My Dashboard} 60 |
61 |
62 | ) 63 | } 64 | 65 | export default Card; -------------------------------------------------------------------------------- /frontend/src/calendarSampleCode/refer.js: -------------------------------------------------------------------------------- 1 | // Require google from googleapis package. 2 | const { google } = require('googleapis') 3 | 4 | // Require oAuth2 from our google instance. 5 | const { OAuth2 } = google.auth 6 | 7 | // Create a new instance of oAuth and set our Client ID & Client Secret. 8 | const oAuth2Client = new OAuth2( 9 | 'YOUR CLIENT ID GOES HERE', 10 | 'YOUR CLIENT SECRET GOES HERE' 11 | ) 12 | 13 | // Call the setCredentials method on our oAuth2Client instance and set our refresh token. 14 | oAuth2Client.setCredentials({ 15 | refresh_token: 'YOUR REFRESH TOKEN GOES HERE', 16 | }) 17 | 18 | // Create a new calender instance. 19 | const calendar = google.calendar({ version: 'v3', auth: oAuth2Client }) 20 | 21 | // Create a new event start date instance for temp uses in our calendar. 22 | const eventStartTime = new Date() 23 | eventStartTime.setDate(eventStartTime.getDay() + 2) 24 | 25 | // Create a new event end date instance for temp uses in our calendar. 26 | const eventEndTime = new Date() 27 | eventEndTime.setDate(eventEndTime.getDay() + 4) 28 | eventEndTime.setMinutes(eventEndTime.getMinutes() + 45) 29 | 30 | // Create a dummy event for temp uses in our calendar 31 | const event = { 32 | summary: `Meeting with David`, 33 | location: `3595 California St, San Francisco, CA 94118`, 34 | description: `Meet with David to talk about the new client project and how to integrate the calendar for booking.`, 35 | colorId: 1, 36 | start: { 37 | dateTime: eventStartTime, 38 | timeZone: 'America/Denver', 39 | }, 40 | end: { 41 | dateTime: eventEndTime, 42 | timeZone: 'America/Denver', 43 | }, 44 | } 45 | 46 | // Check if we a busy and have an event on our calendar for the same time. 47 | calendar.freebusy.query( 48 | { 49 | resource: { 50 | timeMin: eventStartTime, 51 | timeMax: eventEndTime, 52 | timeZone: 'America/Denver', 53 | items: [{ id: 'primary' }], 54 | }, 55 | }, 56 | (err, res) => { 57 | // Check for errors in our query and log them if they exist. 58 | if (err) return console.error('Free Busy Query Error: ', err) 59 | 60 | // Create an array of all events on our calendar during that time. 61 | const eventArr = res.data.calendars.primary.busy 62 | 63 | // Check if event array is empty which means we are not busy 64 | if (eventArr.length === 0) 65 | // If we are not busy create a new calendar event. 66 | return calendar.events.insert( 67 | { calendarId: 'primary', resource: event }, 68 | err => { 69 | // Check for errors and log them if they exist. 70 | if (err) return console.error('Error Creating Calender Event:', err) 71 | // Else log that the event was created. 72 | return console.log('Calendar event successfully created.') 73 | } 74 | ) 75 | 76 | // If event array is not empty log that we are busy. 77 | return console.log(`Sorry I'm busy...`) 78 | } 79 | ) 80 | -------------------------------------------------------------------------------- /frontend/src/Patient/Selectdate.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import Navbar from "../Basic/Navbar"; 3 | import Leftside from "../Dashbaord/LeftsidePatient"; 4 | import "react-calendar/dist/Calendar.css"; 5 | import { Button } from "reactstrap"; 6 | import { Link } from "react-router-dom"; 7 | import Calendar from "react-calendar"; 8 | 9 | const Selectdate = (props) => { 10 | const [date, setDate] = useState(new Date()); 11 | 12 | const onChange = (date) => { 13 | setDate(date); 14 | }; 15 | var pervious = new Date(); 16 | pervious.setDate(pervious.getDate() - 1); 17 | return ( 18 |
19 | 20 |
21 |
22 |
26 | 27 |
28 |
36 |
37 | {/* */} 38 |
39 | 41 | date.getDay() === 0 || date < pervious 42 | } 43 | onChange={onChange} 44 | value={date} 45 | /> 46 | {console.log(date)} 47 |

48 | {date.getFullYear().toString() + 49 | "-" + 50 | (date.getMonth() + 1).toString() + 51 | "-" + 52 | date.getDate().toString()} 53 |

54 |
55 |
56 | {/* 57 | */} 58 |
59 |
60 | 61 | 62 | 63 |
64 | {/* 65 | */} 66 |
67 | 76 | 77 | 78 |
79 | {/* 80 | */} 81 |
82 |
83 |
84 |
85 |
86 | ); 87 | }; 88 | 89 | export default Selectdate; 90 | -------------------------------------------------------------------------------- /frontend/src/Doctorlogin/LoginForm.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useState } from 'react'; 2 | import { Redirect, useHistory } from "react-router-dom"; 3 | import { Container, Row, Col, Card, Form, CardHeader, CardBody, FormGroup, CardFooter, Button, Label, Input } from 'reactstrap' 4 | import axios from 'axios'; 5 | import { AuthContext } from '../Auth/AuthContext'; 6 | 7 | const LoginForm = () => { 8 | const [username, setUsername] = useState(''); 9 | const [password, setPassword] = useState(''); 10 | const [status, setStatus] = useState(0); 11 | const { token, setToken, googleId, setGoogleId } = useContext(AuthContext); 12 | const history = useHistory(); 13 | 14 | async function login() { 15 | try { 16 | const res = await axios.post( 17 | `${process.env.REACT_APP_SERVER_URL}/doctors/login/`, 18 | { 19 | username: username, 20 | password: password 21 | } 22 | ); 23 | setStatus(res.status); 24 | 25 | const token = res.data.token; 26 | 27 | if (res.status === 200) { 28 | window.localStorage.setItem("token", token); 29 | 30 | // Remove the googleId if it exisits in the local storage 31 | window.localStorage.removeItem("googleId"); 32 | setGoogleId(null); 33 | setToken(token); 34 | history.push('/doctor'); 35 | } 36 | } catch (err) { 37 | console.log(err); 38 | } 39 | } 40 | 41 | if (token && !googleId) { 42 | return 43 | } 44 | return ( 45 | 46 | 47 | 48 | 49 |
50 | Welcome back, Doc 51 | 52 | 53 | 56 | 57 | setUsername(e.target.value)} 63 | /> 64 | 65 | 66 | 67 | 70 | 71 | setPassword(e.target.value)} 77 | onKeyPress={(target) => { 78 | if (target.charCode === 13) { 79 | login(); 80 | } 81 | } } 82 | /> 83 | 84 | 85 | {status === 201 &&

Wrong username or password! Please try again

} 86 |
87 | 88 | 91 | 92 |
93 |
94 | 95 |
96 |
97 | ); 98 | } 99 | 100 | export default LoginForm; -------------------------------------------------------------------------------- /frontend/src/Doctor/PaymentHistory.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import Axios from "axios"; 3 | import jwt_decode from "jwt-decode"; 4 | import Scrollbar from "react-scrollbars-custom"; 5 | import Navbar from "../Basic/Navbar"; 6 | import "../Dashbaord/dashboard.css"; 7 | import StarPicker from 'react-star-picker'; 8 | import Leftside from "../Dashbaord/LeftsideDoctor"; 9 | import { Link } from "react-router-dom"; 10 | 11 | const DocAppointments = () => { 12 | 13 | // console.log(decoded); 14 | 15 | const [Appointments, setAppointments] = useState([]); 16 | 17 | const fetchAppointments = async () => { 18 | 19 | var token = localStorage.getItem("token"); 20 | var decoded = jwt_decode(token); 21 | const { data } = await Axios.post( 22 | `${process.env.REACT_APP_SERVER_URL}/doctors/previous-appointments/`, 23 | { 24 | doctorId: decoded._id, 25 | } 26 | ); 27 | // console.log(data); 28 | setAppointments(data); 29 | }; 30 | 31 | useEffect(() => { 32 | fetchAppointments(); 33 | }, []); 34 | 35 | return ( 36 |
37 | 38 |
39 |
40 |
44 | 45 |
46 |
54 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | {Appointments.map((Appointment) => ( 70 | 71 | 72 | 73 | 74 | {Appointment.feedback.given ? : } 78 | 79 | ))} 80 | 81 |
DateTimePatient NameFeedback
{Appointment.date}{Appointment.slotTime}{Appointment.patientName} 75 | 76 | Details 77 | -
82 |
83 |
84 |
85 |
86 |
87 | ); 88 | }; 89 | 90 | export default DocAppointments; 91 | -------------------------------------------------------------------------------- /frontend/src/Patient/PerviousAppointments.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import Axios from "axios"; 3 | import Scrollbar from "react-scrollbars-custom"; 4 | import { BsPencilSquare } from "react-icons/bs"; 5 | import Navbar from "../Basic/Navbar"; 6 | import "../Dashbaord/dashboard.css"; 7 | 8 | import Leftside from "../Dashbaord/LeftsidePatient"; 9 | 10 | import { Link } from "react-router-dom"; 11 | 12 | const PatientAppointments = () => { 13 | const [Appointments, setAppointments] = useState([]); 14 | 15 | const fetchAppointments = async () => { 16 | 17 | const { data } = await Axios.post( 18 | `${process.env.REACT_APP_SERVER_URL}/patients/previous-appointments/`, 19 | { 20 | googleId: localStorage.getItem("googleId"), 21 | } 22 | ); 23 | // console.log(data); 24 | setAppointments(data); 25 | }; 26 | 27 | useEffect(() => { 28 | fetchAppointments(); 29 | }, []); 30 | 31 | return ( 32 |
33 | 34 |
35 |
36 |
40 | 41 |
42 |
50 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | {Appointments.map((Appointment) => ( 66 | 67 | 68 | 69 | 70 | 82 | 83 | ))} 84 | 85 |
DateTimeDoctor NameFeedback
{Appointment.date}{Appointment.slotTime}{Appointment.doctorName} 71 |
74 | 75 | 76 | 77 | {Appointment.feedback.given &&
{Appointment.feedback.stars}/5
} 80 |
81 |
86 |
87 |
88 |
89 |
90 |
91 | ); 92 | }; 93 | 94 | export default PatientAppointments; -------------------------------------------------------------------------------- /frontend/src/Doctor/BookingSlots.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import { Link } from "react-router-dom"; 3 | import Navbar from "../Basic/Navbar"; 4 | import LeftsidePatient from "../Dashbaord/LeftsidePatient"; 5 | 6 | import Axios from "axios"; 7 | 8 | const BookingSlots = (props) => { 9 | // console.log(props.location.state) 10 | const { date, doctor } = props.location.state; 11 | // console.log("Date: " + date + " DoctorId: " + doctorId); 12 | const [dateId, setdateId] = useState(); 13 | const [Slots, setSlots] = useState([]); 14 | 15 | useEffect(() => { 16 | const fetchDate = async (dateToPost) => { 17 | const { data } = await Axios.post( 18 | `${process.env.REACT_APP_SERVER_URL}/doctors/get-slots/`, 19 | { 20 | doctorId: doctor._id, 21 | date: dateToPost 22 | } 23 | ); 24 | console.log(data); 25 | setdateId(data._id); 26 | setSlots(data.slots); 27 | }; 28 | 29 | function getDateString() { 30 | let finalDate = date.getFullYear().toString() 31 | const month = date.getMonth() + 1 32 | const day = date.getDate(); 33 | 34 | if(month < 10) { 35 | finalDate += ('-0' + month.toString()) 36 | } 37 | else { 38 | finalDate += '-' + month.toString() 39 | } 40 | 41 | if(day < 10) { 42 | finalDate += ('-0' + day.toString()) 43 | } 44 | else { 45 | finalDate += '-' + day.toString() 46 | } 47 | 48 | return finalDate 49 | 50 | } 51 | const dateToSend = getDateString() 52 | fetchDate(dateToSend); 53 | }, []); 54 | 55 | return ( 56 |
57 | 58 |
59 |
60 |
61 | 62 |
63 |
71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | {Slots.map((slot) => ( 80 | 81 | 82 | {slot.isBooked ? ( 83 | 84 | ) : ( 85 | 99 | )} 100 | 101 | ))} 102 | 103 |
SlotBooking Status
{slot.time}Booked 86 | 96 | Book Now 97 | 98 |
104 |
105 |
106 |
107 |
108 | ); 109 | }; 110 | 111 | export default BookingSlots; 112 | -------------------------------------------------------------------------------- /frontend/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Create React App 2 | 3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 4 | 5 | 6 | 7 | ## To Run development server 8 | create .env file and paste contents of env-info.txt \ 9 | npm install (installs all dependancies) 10 | 11 | npm start 12 | 13 | ## Available Scripts 14 | 15 | In the project directory, you can run: 16 | 17 | ### `yarn start` 18 | 19 | Runs the app in the development mode.\ 20 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 21 | 22 | The page will reload if you make edits.\ 23 | You will also see any lint errors in the console. 24 | 25 | ### `yarn test` 26 | 27 | Launches the test runner in the interactive watch mode.\ 28 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 29 | 30 | ### `yarn build` 31 | 32 | Builds the app for production to the `build` folder.\ 33 | It correctly bundles React in production mode and optimizes the build for the best performance. 34 | 35 | The build is minified and the filenames include the hashes.\ 36 | Your app is ready to be deployed! 37 | 38 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 39 | 40 | ### `yarn eject` 41 | 42 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 43 | 44 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 45 | 46 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 47 | 48 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 49 | 50 | ## Learn More 51 | 52 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 53 | 54 | To learn React, check out the [React documentation](https://reactjs.org/). 55 | 56 | ### Code Splitting 57 | 58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) 59 | 60 | ### Analyzing the Bundle Size 61 | 62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) 63 | 64 | ### Making a Progressive Web App 65 | 66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) 67 | 68 | ### Advanced Configuration 69 | 70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) 71 | 72 | ### Deployment 73 | 74 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) 75 | 76 | ### `yarn build` fails to minify 77 | 78 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## healthcare-appointment-scheduling-app 2 | 3 | **Frontend**- https://healthcarebooking.netlify.app/ 4 | 5 | **Backend** - https://healthcare-appointment-scheduling-app.onrender.com 6 | 7 | ## Patient Guide: 8 | 9 | ### Patient Login 10 | ![Patient Login](https://github.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/blob/calendar/Software-Engineering/Screenshots/original_login%20patient.jpg) 11 | 12 | ### Patient Personal Details 13 | ![Patient Personal Details](https://github.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/blob/calendar/Software-Engineering/Screenshots/original_patient_personal%20details.png) 14 | 15 | ### Search 16 | ![Search](https://github.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/blob/calendar/Software-Engineering/Screenshots/original_search%20doctor.jpg) 17 | 18 | ### Select Date 19 | ![Select date](https://github.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/blob/calendar/Software-Engineering/Screenshots/original_select%20date.jpg) 20 | 21 | ### Select Slot 22 | ![Select Slot](https://github.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/blob/calendar/Software-Engineering/Screenshots/original_booking%20status.jpg) 23 | 24 | ### Payment 25 | ![Payment](https://github.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/blob/calendar/Software-Engineering/Screenshots/original_payment.jpg) 26 | 27 | ![Address](https://github.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/blob/calendar/Software-Engineering/Screenshots/original_address%20details.jpg) 28 | 29 | ![Card details](https://github.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/blob/calendar/Software-Engineering/Screenshots/original_card%20details.jpg) 30 | 31 | ### Appointment Status 32 | ![Appointment Status](https://github.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/blob/calendar/Software-Engineering/Screenshots/original_appointment%20status.jpg) 33 | 34 | ### Previous Appointments 35 | ![Previous Appointments](https://github.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/blob/calendar/Software-Engineering/Screenshots/original_previous%20appointments.jpg) 36 | 37 | ### Patient Feedback 38 | ![Patient Feedback](https://github.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/blob/calendar/Software-Engineering/Screenshots/original_patient%20feedback.jpg) 39 | 40 | ## Doctor Guide: 41 | ![Hompage doctor login](https://github.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/blob/calendar/Software-Engineering/Screenshots/original_login%20both.jpg) 42 | 43 | ### Doctor Login 44 | **USERNAME** : test 45 | **Password** : test 46 | 47 | ![Doctor login](https://github.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/blob/calendar/Software-Engineering/Screenshots/original_doctor%20login.jpg) 48 | 49 | ### Doctor's Today's Schedule 50 | ![Doctors today's schedule](https://github.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/blob/calendar/Software-Engineering/Screenshots/original_todays%20schedule.png) 51 | 52 | ### Doctor's Personal Details 53 | ![doctor's personal details](https://github.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/blob/calendar/Software-Engineering/Screenshots/original_doctor%20personal%20details.jpg) 54 | 55 | ### Doctor's Previous Appointments 56 | ![Doctor's previous appointments](https://github.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/blob/calendar/Software-Engineering/Screenshots/original_doctor%20previous%20appointments.png) 57 | 58 | ### Doctor View Feedback 59 | ![Doctor's View feedback](https://github.com/Project-Based-Learning-IT/healthcare-appointment-scheduling-app/blob/calendar/Software-Engineering/Screenshots/original_doctor%20feedback.jpg) 60 | -------------------------------------------------------------------------------- /backend/test/3_patients.test.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = 'test' 2 | const Patient = require('../models/patient.model'); 3 | 4 | const chai = require('chai'); 5 | const chaiHttp = require('chai-http'); 6 | const server = require('../server'); 7 | const expect = chai.expect; 8 | 9 | chai.use(chaiHttp); 10 | 11 | describe('Patients', () => { 12 | before((done) => { //Before each test we empty the database 13 | Patient.deleteMany({}, (err) => { 14 | if (err) done(err); 15 | done(); 16 | }); 17 | }); 18 | 19 | //Test GET for Patients 20 | describe('/GET Patient', () => { 21 | it('GET all the Patients', (done) => { 22 | chai.request(server) 23 | .get('/patients') 24 | .end((err, res) => { 25 | if (err) { 26 | done(err) 27 | } 28 | expect(res).to.have.status(200) 29 | expect(res.body).to.eql([]) 30 | done() 31 | }); 32 | }); 33 | }); 34 | 35 | //Test for /POST Patient/add 36 | describe('/POST Patient', () => { 37 | it('POST a Patient at patients/add', (done) => { 38 | const newPatient = new Patient({ 39 | googleId: "testGoogleId" 40 | }); 41 | 42 | chai.request(server) 43 | .post('/patients/add') 44 | .send(newPatient) 45 | .end((err, res) => { 46 | if (err) { 47 | done(err) 48 | } 49 | expect(res).to.have.status(200) 50 | done(); 51 | }); 52 | }); 53 | }); 54 | 55 | describe('/PUT', () => { 56 | it('PUT request to update the data', (done) => { 57 | chai.request(server) 58 | .put('/patients/update-phone') 59 | .send({ 60 | googleId: "testGoogleId", 61 | phoneNumber: "test37438243280432432432", 62 | }) 63 | .end((err, res) => { 64 | if (err) { 65 | console.log(err) 66 | done(err) 67 | } 68 | expect(res).to.have.status(200) 69 | done(); 70 | }); 71 | }) 72 | }) 73 | 74 | //Test for /POST Patient/add 75 | describe('/POST Patient', () => { 76 | it('POST a Patient at patients/add with a duplicate key', (done) => { 77 | const newPatient = new Patient({ 78 | googleId: "testGoogleId" 79 | }); 80 | 81 | chai.request(server) 82 | .post('/patients/add') 83 | .send(newPatient) 84 | .end((err, res) => { 85 | if (err) { 86 | // console.log(err); 87 | done(err); 88 | } 89 | expect(res).to.have.status(400); 90 | done(); 91 | }); 92 | }); 93 | }); 94 | 95 | //Test GET for Patients 96 | describe('/GET Patient', () => { 97 | it('GET all the Patients', (done) => { 98 | chai.request(server) 99 | .get('/patients') 100 | .end((err, res) => { 101 | if (err) { 102 | console.log(err) 103 | done(err); 104 | } 105 | expect(res).to.have.status(200); 106 | expect(res.body.length).eql(1); 107 | done() 108 | }); 109 | }); 110 | }); 111 | 112 | after(function() { 113 | process.exit(); 114 | }) 115 | }); -------------------------------------------------------------------------------- /backend/test/2_doctors.test.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = 'test' 2 | const Doctor = require('../models/doctor.model'); 3 | 4 | const chai = require('chai'); 5 | const chaiHttp = require('chai-http'); 6 | const server = require('../server'); 7 | const expect = chai.expect; 8 | 9 | chai.use(chaiHttp); 10 | 11 | describe('Doctors', () => { 12 | before((done) => { //Before each test we empty the database 13 | Doctor.deleteMany({}, (err) => { 14 | if (err) done(err); 15 | done(); 16 | }); 17 | }); 18 | 19 | //Test GET for Doctors 20 | describe('/GET Doctor', () => { 21 | it('GET all the Doctors', (done) => { 22 | chai.request(server) 23 | .get('/doctors') 24 | .end((err, res) => { 25 | if (err) { 26 | done(err) 27 | } 28 | expect(res).to.have.status(200); 29 | expect(res.body).to.eql([]); 30 | done(); 31 | }); 32 | }); 33 | }); 34 | 35 | //Test for /POST Doctor/add 36 | describe('/POST Doctor', () => { 37 | it('POST a Doctor at doctors/add', (done) => { 38 | const newDoctor = new Doctor({ 39 | username: "testUsername", 40 | password: "testPassword" 41 | }); 42 | 43 | chai.request(server) 44 | .post('/doctors/add') 45 | .send(newDoctor) 46 | .end((err, res) => { 47 | if (err) { 48 | done(err) 49 | } 50 | expect(res).to.have.status(200) 51 | done(); 52 | }); 53 | }); 54 | }); 55 | 56 | describe('/PUT', () => { 57 | it('PUT request to update the doctor data', (done) => { 58 | chai.request(server) 59 | .put('/doctors/update') 60 | .send({ 61 | username: "testUsername", 62 | phoneNumber: "test37438243280432432432", 63 | specialization: "testSpecialization", 64 | feesPerSession: "testfeesPerSessionTest" 65 | }) 66 | .end((err, res) => { 67 | if (err) { 68 | console.log(err) 69 | done(err) 70 | } 71 | expect(res).to.have.status(200) 72 | done(); 73 | }); 74 | }) 75 | }) 76 | 77 | // Test to add a doctor with duplicate key 78 | describe('/POST Doctor', () => { 79 | it('POST a doctor at doctors/add with a duplicate key', (done) => { 80 | const newDoctor = new Doctor({ 81 | username: "testUsername" 82 | }); 83 | 84 | chai.request(server) 85 | .post('/doctors/add') 86 | .send(newDoctor) 87 | .end((err, res) => { 88 | if (err) { 89 | done(err) 90 | } 91 | expect(res).to.have.status(400) 92 | done(); 93 | }); 94 | }); 95 | }); 96 | 97 | //Test GET for Doctors 98 | describe('/GET Doctor', () => { 99 | it('GET all the Doctors', (done) => { 100 | chai.request(server) 101 | .get('/doctors') 102 | .end((err, res) => { 103 | if (err) { 104 | console.log(err) 105 | done(err); 106 | } 107 | expect(res).to.have.status(200); 108 | expect(res.body.length).eql(1); 109 | done() 110 | }); 111 | }); 112 | }); 113 | 114 | }); -------------------------------------------------------------------------------- /frontend/src/Pages/PaitentDashboard.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from "react"; 2 | import Navbar from "../Basic/Navbar"; 3 | import Leftside from "../Dashbaord/LeftsidePatient"; 4 | import { useState, useEffect } from "react"; 5 | import Axios from "axios"; 6 | import "../Dashbaord/dashboard.css"; 7 | import { AuthContext } from "../Auth/AuthContext"; 8 | 9 | const PersonalDetails = () => { 10 | const [patient, setPatient] = useState({}); 11 | const [loading, setLoading] = useState(true); 12 | const { googleId } = useContext(AuthContext); 13 | 14 | useEffect(() => { 15 | setLoading(true); 16 | const getPatientDetails = async () => { 17 | const res = await Axios.get( 18 | `${process.env.REACT_APP_SERVER_URL}/patients/getPatientDetails/${googleId}` 19 | ); 20 | if (res.status === 200) { 21 | setPatient(res.data); 22 | window.localStorage.setItem("user", JSON.stringify(res.data)); 23 | setLoading(false); 24 | } else { 25 | console.log(res.data.message); 26 | setLoading(false); 27 | } 28 | }; 29 | getPatientDetails(); 30 | }, [googleId]); 31 | 32 | return ( 33 |
34 | 35 | {loading ? ( 36 |
37 |
42 |
43 | ) : ( 44 |
45 |
46 |
50 | 51 |
52 |
60 |
61 |
62 |
63 |

Personal Details

64 |
    65 |
  • 66 | 67 | Name: 68 | 69 | {patient.name} 70 |
  • 71 |
  • 72 | 73 | Email: 74 | 75 | {patient.email} 76 |
  • 77 |
  • 78 | 79 | Phone No: 80 | 81 | {patient.phoneNumber} 82 |
  • 83 |
84 |
85 |
86 |
87 | 94 |
95 |
96 |
97 |
98 |
99 | )} 100 |
101 | ); 102 | }; 103 | export default PersonalDetails; 104 | -------------------------------------------------------------------------------- /frontend/src/Patient/AppointmentStatus.js: -------------------------------------------------------------------------------- 1 | /* global gapi */ 2 | import React, { useState, useEffect } from "react"; 3 | import Axios from "axios"; 4 | import jwt_decode from "jwt-decode"; 5 | import Navbar from "../Basic/Navbar"; 6 | import "../Dashbaord/dashboard.css"; 7 | import Leftside from "../Dashbaord/LeftsidePatient"; 8 | 9 | const AppointmentStatus = () => { 10 | const [appointments, setAppointments] = useState([]); 11 | const [isLoading, setIsLoading] = useState() 12 | const [filteredAppointments, setFilteredAppointments] = useState() 13 | 14 | function getMeetLink(id) { 15 | if(filteredAppointments !== undefined){ 16 | const meetCode = filteredAppointments.find((apntmnt) => { 17 | return apntmnt.id === id 18 | }) 19 | 20 | return meetCode ? meetCode.hangoutLink : "#" 21 | } 22 | return '#' 23 | } 24 | 25 | useEffect(() => { 26 | setIsLoading(true) 27 | 28 | const fetchAppointments = async () => { 29 | var { data } = await Axios.post( 30 | `${process.env.REACT_APP_SERVER_URL}/patients/upcoming-appointments/`, 31 | { 32 | googleId: localStorage.getItem("googleId"), 33 | } 34 | ); 35 | 36 | // const response = await window.gapi.client.calendar.events.list({ 37 | // 'calendarId': 'primary', 38 | // 'timeMin': (new Date()).toISOString(), 39 | // 'showDeleted': false, 40 | // 'singleEvents': true, 41 | // 'maxResults': 100, 42 | // 'orderBy': 'startTime' 43 | // }) 44 | 45 | // // Filter google calendar events 46 | // const events = response.result.items 47 | // const filteredEvents = events.filter((event) => { 48 | // return data.find((it) => it._id === event.id) 49 | // }) 50 | 51 | console.log(data) 52 | setAppointments(data); 53 | // console.log(filteredEvents) 54 | // setFilteredAppointments(filteredEvents) 55 | }; 56 | 57 | fetchAppointments() 58 | setIsLoading(false) 59 | }, []); 60 | 61 | 62 | 63 | return ( 64 |
65 | 66 |
67 |
68 |
72 | 73 |
74 | {isLoading &&

Loading

} 75 | {!isLoading &&
83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | {appointments.map((Appointment) => ( 94 | 95 | 96 | 97 | 98 | 99 | 100 | ))} 101 | 102 |
DateTimeDoctor NameMeet Link
{Appointment.date}{Appointment.slotTime}{Appointment.doctorName} Join Meet
103 |
} 104 |
105 |
106 |
107 | ); 108 | }; 109 | 110 | export default AppointmentStatus; -------------------------------------------------------------------------------- /frontend/src/Basic/Navbar.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from "react"; 2 | import { Link, useHistory } from "react-router-dom"; 3 | import "bootstrap/dist/css/bootstrap.min.css"; 4 | import logo from "../image/navbaricon1.png"; 5 | import { AuthContext } from "../Auth/AuthContext"; 6 | import axios from "axios"; 7 | // import GoogleLogin from "react-google-login"; 8 | // import axios from "axios"; 9 | 10 | const Navbar = () => { 11 | const { token, setToken, setGoogleId } = useContext(AuthContext); 12 | const history = useHistory(); 13 | 14 | async function loginWithGoogle(e) { 15 | try { 16 | await window.gapi.auth2.getAuthInstance().signIn(); 17 | const auth2 = await window.gapi.auth2.getAuthInstance(); 18 | if (auth2.isSignedIn.get()) { 19 | console.log("[Google] Signed in successfully!"); 20 | var profile = auth2.currentUser.get(); 21 | console.log(profile); 22 | window.localStorage.setItem("token", profile.getAuthResponse().id_token); 23 | window.localStorage.setItem("googleId", profile.getId()); 24 | 25 | const serverRes = await axios.post( 26 | `${process.env.REACT_APP_SERVER_URL}/patients/google-login/`, 27 | { 28 | tokenId: profile.getAuthResponse().id_token, 29 | } 30 | ); 31 | 32 | if (serverRes) { 33 | console.log(serverRes.data.phoneNumberExists); 34 | 35 | setToken(profile.getAuthResponse().id_token); 36 | setGoogleId(profile.getId()); 37 | 38 | if (serverRes.data.phoneNumberExists === true) { 39 | history.push("/patient"); 40 | } else { 41 | history.push("/patient/update-phone"); 42 | } 43 | } 44 | else { 45 | const err = {err : "Server Didn't respond"} 46 | throw err; 47 | } 48 | } 49 | } catch (err) { 50 | console.log(`[Google] Some error occurred while signing in! ${JSON.stringify(err)}`); 51 | } 52 | } 53 | 54 | function signOutGoogle() { 55 | // Different logic for doctor and patient 56 | 57 | // Patient logic 58 | if (window.gapi.auth2.getAuthInstance().isSignedIn.get()) { 59 | window.gapi.auth2.getAuthInstance().signOut().then(() => { 60 | console.log("[Google] Signed out successfully!"); 61 | window.localStorage.removeItem("token"); 62 | window.localStorage.removeItem("googleId"); 63 | setToken(null); 64 | setGoogleId(null); 65 | history.push("/"); 66 | }).catch((err) => { 67 | console.log(`[Google] Some error occurred while signing out! ${err}`); 68 | }); 69 | } 70 | 71 | // Doctor logic 72 | else { 73 | window.localStorage.removeItem("token"); 74 | console.log("[Doctor] Signed out successfully!"); 75 | setToken(null); 76 | history.push("/"); 77 | } 78 | } 79 | 80 | return ( 81 | 128 | ); 129 | } 130 | 131 | export default Navbar; 132 | -------------------------------------------------------------------------------- /frontend/src/calendarSampleCode/refer2.js: -------------------------------------------------------------------------------- 1 | const {google} = require('googleapis'); 2 | require('dotenv').config(); 3 | 4 | // Provide the required configuration 5 | const CREDENTIALS = JSON.parse(process.env.CREDENTIALS); 6 | const calendarId = process.env.CALENDAR_ID; 7 | 8 | // Google calendar API settings 9 | const SCOPES = 'https://www.googleapis.com/auth/calendar'; 10 | const calendar = google.calendar({version : "v3"}); 11 | 12 | const auth = new google.auth.JWT( 13 | CREDENTIALS.client_email, 14 | null, 15 | CREDENTIALS.private_key, 16 | SCOPES 17 | ); 18 | 19 | // Your TIMEOFFSET Offset 20 | const TIMEOFFSET = '+05:30'; 21 | 22 | // Get date-time string for calender 23 | const dateTimeForCalander = () => { 24 | 25 | let date = new Date(); 26 | 27 | let year = date.getFullYear(); 28 | let month = date.getMonth() + 1; 29 | if (month < 10) { 30 | month = `0${month}`; 31 | } 32 | let day = date.getDate(); 33 | if (day < 10) { 34 | day = `0${day}`; 35 | } 36 | let hour = date.getHours(); 37 | if (hour < 10) { 38 | hour = `0${hour}`; 39 | } 40 | let minute = date.getMinutes(); 41 | if (minute < 10) { 42 | minute = `0${minute}`; 43 | } 44 | 45 | let newDateTime = `${year}-${month}-${day}T${hour}:${minute}:00.000${TIMEOFFSET}`; 46 | 47 | let event = new Date(Date.parse(newDateTime)); 48 | 49 | let startDate = event; 50 | // Delay in end time is 1 51 | let endDate = new Date(new Date(startDate).setHours(startDate.getHours()+1)); 52 | 53 | return { 54 | 'start': startDate, 55 | 'end': endDate 56 | } 57 | }; 58 | 59 | // Insert new event to Google Calendar 60 | const insertEvent = async (event) => { 61 | 62 | try { 63 | let response = await calendar.events.insert({ 64 | auth: auth, 65 | calendarId: calendarId, 66 | resource: event 67 | }); 68 | 69 | if (response['status'] == 200 && response['statusText'] === 'OK') { 70 | return 1; 71 | } else { 72 | return 0; 73 | } 74 | } catch (error) { 75 | console.log(`Error at insertEvent --> ${error}`); 76 | return 0; 77 | } 78 | }; 79 | 80 | // let dateTime = dateTimeForCalander(); 81 | 82 | // // Event for Google Calendar 83 | // let event = { 84 | // 'summary': `This is the summary.`, 85 | // 'description': `This is the description.`, 86 | // 'start': { 87 | // 'dateTime': dateTime['start'], 88 | // 'timeZone': 'Asia/Kolkata' 89 | // }, 90 | // 'end': { 91 | // 'dateTime': dateTime['end'], 92 | // 'timeZone': 'Asia/Kolkata' 93 | // } 94 | // }; 95 | 96 | // insertEvent(event) 97 | // .then((res) => { 98 | // console.log(res); 99 | // }) 100 | // .catch((err) => { 101 | // console.log(err); 102 | // }); 103 | 104 | // Get all the events between two dates 105 | const getEvents = async (dateTimeStart, dateTimeEnd) => { 106 | 107 | try { 108 | let response = await calendar.events.list({ 109 | auth: auth, 110 | calendarId: calendarId, 111 | timeMin: dateTimeStart, 112 | timeMax: dateTimeEnd, 113 | timeZone: 'Asia/Kolkata' 114 | }); 115 | 116 | let items = response['data']['items']; 117 | return items; 118 | } catch (error) { 119 | console.log(`Error at getEvents --> ${error}`); 120 | return 0; 121 | } 122 | }; 123 | 124 | // let start = '2020-10-03T00:00:00.000Z'; 125 | // let end = '2020-10-04T00:00:00.000Z'; 126 | 127 | // getEvents(start, end) 128 | // .then((res) => { 129 | // console.log(res); 130 | // }) 131 | // .catch((err) => { 132 | // console.log(err); 133 | // }); 134 | 135 | // Delete an event from eventID 136 | const deleteEvent = async (eventId) => { 137 | 138 | try { 139 | let response = await calendar.events.delete({ 140 | auth: auth, 141 | calendarId: calendarId, 142 | eventId: eventId 143 | }); 144 | 145 | if (response.data === '') { 146 | return 1; 147 | } else { 148 | return 0; 149 | } 150 | } catch (error) { 151 | console.log(`Error at deleteEvent --> ${error}`); 152 | return 0; 153 | } 154 | }; 155 | 156 | let eventId = 'hkkdmeseuhhpagc862rfg6nvq4'; 157 | 158 | deleteEvent(eventId) 159 | .then((res) => { 160 | console.log(res); 161 | }) 162 | .catch((err) => { 163 | console.log(err); 164 | }); 165 | -------------------------------------------------------------------------------- /frontend/src/App.js: -------------------------------------------------------------------------------- 1 | /* global gapi */ 2 | import React, { useEffect, useState } from "react"; 3 | import "bootstrap"; 4 | import "bootstrap/dist/css/bootstrap.css"; 5 | import "bootstrap/dist/js/bootstrap.js"; 6 | import "bootstrap/dist/css/bootstrap.min.css"; 7 | import { BrowserRouter as Router, Route, Switch } from "react-router-dom"; 8 | import "./App.css"; 9 | import Home from "./Pages/Home"; 10 | import DoctorLogin from "./Pages/DoctorLogin"; 11 | import DoctorDashboard from "./Pages/DoctorDashboard"; 12 | import PaitentDashboard from "./Pages/PaitentDashboard"; 13 | import Error from "./Pages/Error"; 14 | import { AuthContext } from "./Auth/AuthContext"; 15 | import PhoneNumber from "./components/PhoneNumber"; 16 | import PersonalDetails from "./Doctor/PersonalDetails"; 17 | import SearchDoctor from "./Patient/SearchDoctor"; 18 | import PerviousAppointments from "./Patient/PerviousAppointments"; 19 | import Spinner from "react-bootstrap/Spinner"; 20 | import Selectdate from "./Patient/Selectdate"; 21 | import BookingSlots from "./Doctor/BookingSlots"; 22 | import Payment from "./Patient/Payment"; 23 | import DocAppointments from "./Doctor/PaymentHistory"; 24 | import AppointmentStatus from "./Patient/AppointmentStatus"; 25 | import Pfeedback from './Patient/Feedback'; 26 | import FeedbackDetails from './Doctor/FeedbackDetails'; 27 | 28 | function App() { 29 | const [token, setToken] = useState(window.localStorage.getItem("token")); 30 | const [googleId, setGoogleId] = useState( 31 | window.localStorage.getItem("googleId") 32 | ); 33 | 34 | const [apiLoaded, setApiLoaded] = useState(false); 35 | 36 | // To load only when gapi is loaded 37 | useEffect(() => { 38 | if (window.gapi !== undefined) { 39 | setApiLoaded(false); 40 | window.gapi.load("client:auth2", initClient); 41 | function initClient() { 42 | window.gapi.client 43 | .init({ 44 | apiKey: process.env.REACT_APP_API_KEY, 45 | clientId: process.env.REACT_APP_CLIENT_ID, 46 | discoveryDocs: [process.env.REACT_APP_DISCOVERY_DOCS], 47 | scope: process.env.REACT_APP_SCOPE, 48 | }) 49 | .then( 50 | function () { 51 | if (window.gapi.auth2.getAuthInstance().isSignedIn.get()) { 52 | console.log( 53 | `Is signed in? ${window.gapi.auth2 54 | .getAuthInstance() 55 | .isSignedIn.get()}` 56 | ); 57 | } else { 58 | console.log("Currently Logged Out!!"); 59 | } 60 | setApiLoaded(true); 61 | }, 62 | function (error) { 63 | console.log(`error ${JSON.stringify(error)}`); 64 | setApiLoaded(true); 65 | } 66 | ); 67 | } 68 | setApiLoaded(true); 69 | } else { 70 | console.log("[Google] inside the else block line 54 App.js"); 71 | setApiLoaded(false); 72 | } 73 | 74 | }, []); 75 | 76 | return apiLoaded ? ( 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 91 | 96 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | ) : ( 116 |
117 | 118 | Loading... 119 | 120 |
121 | ); 122 | } 123 | 124 | export default App; 125 | -------------------------------------------------------------------------------- /frontend/src/Doctor/Search.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect, useMemo } from "react"; 2 | import Axios from "axios"; 3 | import Scrollbar from "react-scrollbars-custom"; 4 | // import { ListGroup, ListGroupItem } from "reactstrap"; 5 | 6 | import { 7 | Row, 8 | Col, 9 | Input, 10 | Button, 11 | InputGroup, 12 | InputGroupAddon, 13 | } from "reactstrap"; 14 | 15 | import Trie from "./Trie.js"; 16 | import specialization from "./specialization"; 17 | import { Link } from "react-router-dom"; 18 | 19 | const Search = () => { 20 | const [text, setText] = useState(); 21 | const [suggestions, setSuggestions] = useState([]); 22 | 23 | const memoized_trie = useMemo(() => { 24 | const trie = new Trie(); 25 | 26 | // Insert 27 | for (let i = 0; i < specialization.length; i++) { 28 | trie.insert(specialization[i]); 29 | } 30 | 31 | return trie; 32 | }, []); 33 | 34 | function onTextChanged(e) { 35 | let value = e.target.value; 36 | setText(value); 37 | fetchDoctor(); 38 | value = value.toLowerCase(); 39 | if (value !== "") setSuggestions(memoized_trie.find(value)); 40 | else setSuggestions([]); 41 | } 42 | 43 | function suggestionSelected(value) { 44 | setText(value); 45 | setSuggestions([]); 46 | } 47 | 48 | function renderSuggestions() { 49 | if (suggestions.length === 0) { 50 | return null; 51 | } 52 | return ( 53 | 54 |
    55 | {suggestions.map((item) => ( 56 |
  • suggestionSelected(item)} 59 | key={item} 60 | > 61 | {item} 62 |
  • 63 | ))} 64 |
65 |
66 | ); 67 | } 68 | 69 | const [Doctor, setDoctor] = useState([]); 70 | 71 | const fetchDoctor = async () => { 72 | const { data } = await Axios.get( 73 | `${process.env.REACT_APP_SERVER_URL}/doctors/` 74 | ); 75 | setDoctor(data); 76 | console.log(data); 77 | }; 78 | 79 | const UpdateDisplay = (text) => { 80 | setDoctor((Doctor) => { 81 | return Doctor.filter( 82 | (doctor) => doctor.specialization.toLowerCase() === text.toLowerCase() 83 | ); 84 | }); 85 | console.log(Doctor); 86 | }; 87 | 88 | useEffect(() => { 89 | fetchDoctor(); 90 | }, []); 91 | 92 | return ( 93 |
94 | 95 | 96 | 97 | 104 |
105 | 106 | 113 | 114 |
115 |
116 | {renderSuggestions()} 117 | 118 |
119 | 120 | {/* */} 121 | 126 |
127 | {Doctor.map((doc) => ( 128 | // 129 |
130 |
131 |
132 |
133 |
134 | Doctor Name: 135 | {doc.name} 136 |
137 |
138 |
Specialization : {doc.specialization}
139 |
Phone Number : {doc.phoneNumber}
140 |
141 |
142 | FeesPerSession: {doc.feesPerSession} 143 |
144 |
148 | 151 |
152 |
153 | 154 | {/* */} 155 |
156 |
157 |
158 | ))} 159 |
160 |
161 | {/*
*/} 162 |
163 | ); 164 | }; 165 | 166 | export default Search; 167 | -------------------------------------------------------------------------------- /backend/routes/patients.js: -------------------------------------------------------------------------------- 1 | const router = require('express').Router(); 2 | const Patient = require('../models/patient.model'); 3 | const appointmentImport = require('../models/appointment.model'); 4 | const jwt = require('jsonwebtoken'); 5 | const stripe = require("stripe")("sk_test_51IabQNSCj4BydkZ38AsoDragCM19yaMzGyBVng5KUZnCNrxCJuj308HmdAvoRcUEe2PEdoORMosOaRz1Wl8UX0Gt00FCuSwYpz") 6 | const { v4: uuidv4 } = require('uuid'); 7 | const { Appointment } = appointmentImport; 8 | 9 | // To get all the patients 10 | // ** ONLY FOR TESTING ** 11 | router.route('/').get((req, res) => { 12 | Patient.find().then(patients => { 13 | res.status(200).json(patients); 14 | }).catch((err) => { 15 | res.status(400).json(`Error : ${err}`); 16 | }) 17 | }) 18 | 19 | // To add a patient 20 | router.route('/add').post((req, res) => { 21 | const googleId = req.body.googleId; 22 | const name = req.body.name; 23 | const picture = req.body.picture; 24 | 25 | const newPatient = new Patient({ 26 | googleId, name, picture 27 | }) 28 | 29 | newPatient.save().then(() => { 30 | res.status(200).json('Patient added'); 31 | }).catch(err => { 32 | res.status(400).json(`Error : ${err}`); 33 | }) 34 | }) 35 | 36 | // To update a patient's phone number 37 | router.route('/update-phone').put((req, res) => { 38 | const googleId = req.body.googleId; 39 | 40 | Patient.findOne({ googleId: googleId }).then(patient => { 41 | if (patient) { 42 | patient.phoneNumber = req.body.phoneNumber; 43 | 44 | patient.save().then(() => { 45 | res.status(200).json('Patient\'s phone number updated'); 46 | }).catch(err => { 47 | res.status(400).json({ message: `Error : ${err}` }); 48 | }); 49 | } 50 | }) 51 | }) 52 | 53 | router.route('/google-login').post(async (req, res) => { 54 | try { 55 | const tokenId = req.body.tokenId; 56 | 57 | // Decode the jwt 58 | const decoded = jwt.decode(tokenId, process.env.KEY); 59 | const googleId = await decoded.sub; 60 | 61 | // Check if the user already exists in the database 62 | const patient = await Patient.findOne({ googleId: googleId }); 63 | 64 | // If the patient is not found 65 | if (patient === null) { 66 | const { email, name, picture } = decoded; 67 | const newPatient = new Patient({ 68 | googleId, email, name, picture 69 | }) 70 | const savedPromise = await newPatient.save(); 71 | if (savedPromise) { 72 | return res.status(200).json({ phoneNumberExists: false }); 73 | } 74 | else { 75 | throw savedPromise; 76 | } 77 | } 78 | 79 | // If the phone number is not present in the database 80 | else if (patient.phoneNumber === undefined) { 81 | return res.status(200).json({ phoneNumberExists: false }); 82 | } 83 | 84 | // Patient's phone number already exists in the database 85 | else { 86 | return res.status(200).json({ phoneNumberExists: true }) 87 | } 88 | } 89 | catch (err) { 90 | console.log(err); 91 | return res.status(400).json(err); 92 | } 93 | }) 94 | 95 | router.route('/getPatientDetails/:googleId').get(async (req, res) => { 96 | try { 97 | const googleId = req.params.googleId; 98 | const patient = await Patient.findOne({ googleId: googleId }); 99 | 100 | if (patient) { 101 | return res.status(200).json(patient); 102 | } 103 | else { 104 | return res.status(201).json({ message: "Patient not found!" }); 105 | } 106 | } 107 | catch (err) { 108 | console.log(err); 109 | res.status(400).json({ message: err }); 110 | } 111 | }) 112 | 113 | router.route('/previous-appointments').post(async (req, res) => { 114 | try { 115 | const googleId = req.body.googleId; 116 | const appointments = await Appointment.find({ patientId: googleId }); 117 | 118 | // Get current dateTime 119 | const date = new Date() 120 | let currDateTime = date.getFullYear().toString() 121 | const month = date.getMonth() + 1 122 | const day = date.getDate() 123 | const hour = date.getHours() 124 | const minutes = date.getMinutes() 125 | const seconds = date.getSeconds() 126 | 127 | currDateTime += month < 10 ? ('-0' + month.toString()) : '-' + month.toString() 128 | currDateTime += day < 10 ? ('-0' + day.toString()) : '-' + day.toString() 129 | currDateTime += hour < 10 ? ('T0' + hour.toString()) : 'T' + hour.toString() 130 | currDateTime += minutes < 10 ? (':0' + minutes.toString()) : ':' + minutes.toString() 131 | currDateTime += seconds < 10 ? (':0' + seconds.toString()) : ':' + seconds.toString() 132 | 133 | const filteredAppointments = appointments.filter((appointment) => { 134 | return Date.parse(currDateTime) >= Date.parse(appointment.date + 'T' + appointment.slotTime) 135 | }) 136 | 137 | const sortedAppointments = filteredAppointments.sort((a, b) => { 138 | return Date.parse(b.date + 'T' + b.slotTime) - Date.parse(a.date + 'T' + a.slotTime) 139 | }) 140 | 141 | res.status(200).json(sortedAppointments); 142 | } 143 | catch (err) { 144 | console.log(err) 145 | res.status(400).json(err) 146 | } 147 | }) 148 | 149 | router.route('/upcoming-appointments').post(async (req, res) => { 150 | try { 151 | const googleId = req.body.googleId; 152 | const appointments = await Appointment.find({ patientId: googleId }); 153 | 154 | // Get current dateTime 155 | const date = new Date() 156 | let currDateTime = date.getFullYear().toString() 157 | const month = date.getMonth() + 1 158 | const day = date.getDate() 159 | const hour = date.getHours() 160 | const minutes = date.getMinutes() 161 | const seconds = date.getSeconds() 162 | 163 | currDateTime += month < 10 ? ('-0' + month.toString()) : '-' + month.toString() 164 | currDateTime += day < 10 ? ('-0' + day.toString()) : '-' + day.toString() 165 | currDateTime += hour < 10 ? ('T0' + hour.toString()) : 'T' + hour.toString() 166 | currDateTime += minutes < 10 ? (':0' + minutes.toString()) : ':' + minutes.toString() 167 | currDateTime += seconds < 10 ? (':0' + seconds.toString()) : ':' + seconds.toString() 168 | 169 | const filteredAppointments = appointments.filter((appointment) => { 170 | return Date.parse(currDateTime) <= Date.parse(appointment.date + 'T' + appointment.slotTime) 171 | }) 172 | 173 | const sortedAppointments = filteredAppointments.sort((a, b) => { 174 | return Date.parse(a.date + 'T' + a.slotTime) - Date.parse(b.date + 'T' + b.slotTime) 175 | }) 176 | 177 | res.status(200).json(sortedAppointments); 178 | } 179 | catch (err) { 180 | console.log(err) 181 | res.status(400).json(err) 182 | } 183 | }) 184 | 185 | router.route("/payment").post(async (req, res) => { 186 | const { finalBalnce, token } = req.body; 187 | // console.log(product); 188 | const idempotencyKey = uuidv4(); 189 | 190 | return stripe.customers 191 | .create({ 192 | email: token.email, 193 | source: token.id 194 | }) 195 | .then(customer => { 196 | stripe.charges 197 | .create( 198 | { 199 | amount: finalBalnce * 100, 200 | currency: 'usd', 201 | customer: customer.id, 202 | receipt_email: token.email, 203 | description: `Booked Appointement Successfully`, 204 | shipping: { 205 | name: token.card.name, 206 | address: { 207 | line1: token.card.address_line1, 208 | line2: token.card.address_line2, 209 | city: token.card.address_city, 210 | country: token.card.address_country, 211 | postal_code: token.card.address_zip 212 | } 213 | } 214 | }, 215 | { 216 | idempotencyKey 217 | } 218 | ) 219 | .then(result => res.status(200).json(result)) 220 | .catch(err => { 221 | console.log(`Error : ${err}`); 222 | res.status(400).json(err); 223 | }); 224 | }) 225 | .catch((err) => { 226 | console.log(err); 227 | res.status(400).json(err); 228 | }); 229 | }) 230 | 231 | 232 | module.exports = router; -------------------------------------------------------------------------------- /frontend/src/Patient/Payment.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import Axios from "axios"; 3 | import { useHistory } from "react-router-dom"; 4 | 5 | import Navbar from "../Basic/Navbar"; 6 | import Leftside from "../Dashbaord/LeftsidePatient"; 7 | import StripeCheckoutButton from "react-stripe-checkout"; 8 | import { toast } from "react-toastify"; 9 | import axios from "axios"; 10 | // import { Toast } from "react-toastify/dist/components"; 11 | 12 | function getEndDateTime(dateTime) { 13 | const hrs = (parseInt(dateTime.split("T")[1].split(":")[0]) + 1) 14 | .toString() 15 | .padStart(2, "0"); 16 | const time = hrs + ":00:00"; 17 | const date = dateTime.split("T")[0]; 18 | return date + "T" + time; 19 | } 20 | 21 | const Payment = (props) => { 22 | const [finalBalnce, setFinalBalnce] = useState(0); 23 | const history = useHistory(); 24 | 25 | function createEvent(id, dateTime, doctorEmail) { 26 | var virtualEvent = { 27 | id: id, 28 | summary: "Appointment", 29 | location: "Virtual", 30 | description: "Doctor-Patient appointment", 31 | start: { 32 | dateTime: dateTime, 33 | timeZone: "Asia/Kolkata", 34 | }, 35 | end: { 36 | dateTime: getEndDateTime(dateTime), 37 | timeZone: "Asia/Kolkata", 38 | }, 39 | conferenceData: { 40 | createRequest: { 41 | requestId: "7qxalsvy0e", 42 | }, 43 | }, 44 | attendees: [{ email: doctorEmail }], 45 | guestsCanModify: true, 46 | reminders: { 47 | useDefault: false, 48 | overrides: [ 49 | { method: "email", minutes: 24 * 60 }, 50 | { method: "popup", minutes: 15 }, 51 | ], 52 | }, 53 | }; 54 | 55 | var request = window.gapi.client.calendar.events.insert({ 56 | calendarId: "primary", 57 | resource: virtualEvent, 58 | sendUpdates: "all", 59 | supportsAttachments: true, 60 | conferenceDataVersion: 1, 61 | }); 62 | 63 | request.execute(function (event) { 64 | console.log("Executed!"); 65 | 66 | // Add meet link 67 | if (event) { 68 | // console.log(`AddEvent link : ${event.hangoutLink}, Id : ${id}`) 69 | axios.put( 70 | `${process.env.REACT_APP_SERVER_URL}/appointments/add-meet-link`, 71 | { 72 | appointmentId: id, 73 | meetLink: event.hangoutLink 74 | } 75 | ).then((x) => { 76 | console.log(`Updated Meet Link!`); 77 | }) 78 | } 79 | }); 80 | } 81 | 82 | const { dateId, doctor, slotId } = props.location.data; 83 | 84 | const bookSlot = async () => { 85 | const { data } = await Axios.post( 86 | `${process.env.REACT_APP_SERVER_URL}/doctors/book-slot/`, 87 | { 88 | googleId: localStorage.getItem("googleId"), 89 | patientName: JSON.parse(localStorage.getItem("user")).name, 90 | slotId: slotId, 91 | dateId: dateId, 92 | doctorId: doctor._id, 93 | } 94 | ); 95 | 96 | if (data.doctorEmail) { 97 | createEvent(data._id, data.date + "T" + data.slotTime, data.doctorEmail); 98 | } 99 | }; 100 | 101 | useEffect(() => { 102 | setFinalBalnce(1.18 * doctor.feesPerSession); 103 | }, []); 104 | 105 | const makePayment = async (token) => { 106 | const { data } = await Axios.post( 107 | `${process.env.REACT_APP_SERVER_URL}/patients/payment`, 108 | { 109 | token, 110 | finalBalnce, 111 | } 112 | ); 113 | 114 | if (data) { 115 | bookSlot(); 116 | setFinalBalnce(0); 117 | toast("Appointment booked successfully", { 118 | type: "success" 119 | }) 120 | history.push("/patient"); 121 | } 122 | 123 | console.log(data); 124 | }; 125 | 126 | return ( 127 |
128 | 129 |
130 |
131 |
135 | 136 |
137 |
145 |
146 |
147 |
148 |
149 |
150 |
151 | Elf Cafe 152 |
153 | 2135 Sunset Blvd 154 |
155 | Los Angeles, CA 90026 156 |
157 | P: (213) 484-6829 158 |
159 |
160 |
161 |

162 | Date: 1st November, 2013 163 |

164 |

165 | Receipt #: 34522677W 166 |

167 |
168 |
169 |
170 |
171 |

Receipt

172 |
173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 187 | 193 | 194 | 197 | 198 | 199 | 200 | 201 | 202 | 210 | 218 | 219 | 220 | 221 | 222 | 227 | 232 | 233 | 234 |
Doctor NameSpecializationTotal
185 | {doctor.name} 186 | 191 | {doctor.specialization} 192 | 195 | {doctor.feesPerSession} 196 |
  203 |

204 | Subtotal:  205 |

206 |

207 | Tax:  208 |

209 |
211 |

212 | {doctor.feesPerSession} 213 |

214 |

215 | {0.18 * doctor.feesPerSession} 216 |

217 |
  223 |

224 | Total:  225 |

226 |
228 |

229 | {finalBalnce} 230 |

231 |
235 | 243 | 250 | 251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 | ); 260 | }; 261 | 262 | export default Payment; 263 | -------------------------------------------------------------------------------- /backend/routes/doctors.js: -------------------------------------------------------------------------------- 1 | const router = require("express").Router(); 2 | const doctors = require("../models/doctor.model"); 3 | const jwt = require("jsonwebtoken"); 4 | require("dotenv").config(); 5 | const appointmentImport = require("../models/appointment.model"); 6 | const { Doctor, Slot, DateSchedule } = doctors; 7 | const { Appointment, Feedback } = appointmentImport; 8 | const bcrypt = require('../bcrypt/bcrypt'); 9 | 10 | function createDate(date) { 11 | return new DateSchedule({ 12 | date: date, 13 | slots: [ 14 | new Slot({ 15 | time: "09:00:00", 16 | isBooked: false, 17 | }), 18 | new Slot({ 19 | time: "12:00:00", 20 | isBooked: false, 21 | }), 22 | new Slot({ 23 | time: "15:00:00", 24 | isBooked: false, 25 | }), 26 | ], 27 | }); 28 | } 29 | 30 | // To get all the doctors 31 | // **ONLY FOR TESTING** 32 | router.route("/").get((req, res) => { 33 | Doctor.find() 34 | .then((doctors) => { 35 | res.json(doctors); 36 | }) 37 | .catch((err) => { 38 | res.status(400).json(`Error : ${err}`); 39 | }); 40 | }); 41 | 42 | // To add a doctor 43 | router.route("/add").post((req, res) => { 44 | const username = req.body.username; // Required.. can't be undefined 45 | const password = req.body.password; 46 | const name = req.body.name; 47 | const phoneNumber = req.body.phoneNumber; 48 | const specialization = req.body.specialization; 49 | const feesPerSession = req.body.feesPerSession; 50 | 51 | const newDoctor = new Doctor({ 52 | username, 53 | password, 54 | name, 55 | phoneNumber, 56 | specialization, 57 | feesPerSession, 58 | }); 59 | 60 | newDoctor 61 | .save() 62 | .then(() => { 63 | res.json("Doctor added"); 64 | // console.log(`${newDoctor} added!`) 65 | }) 66 | .catch((err) => { 67 | res.status(400).json(`Error : ${err}`); 68 | // console.log(err); 69 | }); 70 | }); 71 | 72 | // To update a doctor 73 | router.route("/update").put((req, res) => { 74 | const username = req.body.username; // Required.. can't be undefined 75 | 76 | Doctor.findOne({ username: username }).then((doctor) => { 77 | if (doctor) { 78 | doctor.name = req.body.name; 79 | doctor.phoneNumber = req.body.phoneNumber; 80 | doctor.specialization = req.body.specialization; 81 | doctor.feesPerSession = req.body.feesPerSession; 82 | 83 | doctor 84 | .save() 85 | .then(() => { 86 | res.json("Doctor updated"); 87 | // console.log(`${doctor} updated!`) 88 | }) 89 | .catch((err) => { 90 | res.status(400).json(`Error : ${err}`); 91 | // console.log(err); 92 | }); 93 | } 94 | }); 95 | }); 96 | 97 | // Doctor login 98 | router.route("/login").post(async (req, res) => { 99 | try { 100 | const username = req.body.username; 101 | 102 | // Password entered by the user 103 | const plainTextPassword = req.body.password; 104 | 105 | // Password Salt for hashing purpose 106 | const passwordSalt = process.env.PASSWORD_SALT; 107 | 108 | // Encrypted password after hashing operation 109 | const encryptedPassword = bcrypt.hash(plainTextPassword, passwordSalt) 110 | 111 | const doctor = await Doctor.findOne({ 112 | username: username, 113 | password: encryptedPassword, 114 | }); 115 | 116 | console.log(doctor); 117 | 118 | if (doctor === null) { 119 | return res.status(201).json({ message: "wrong username or password" }); 120 | } 121 | 122 | // Doctor found, return the token to the client side 123 | const token = jwt.sign( 124 | JSON.stringify(doctor), 125 | process.env.KEY, 126 | { 127 | algorithm: process.env.ALGORITHM, 128 | } 129 | ); 130 | 131 | return res.status(200).json({ token: token.toString() }); 132 | 133 | } catch (err) { 134 | console.log(err); 135 | return res.status(400).json(err); 136 | } 137 | }); 138 | 139 | // To get the slots available for the date 140 | router.route("/get-slots").post(async (req, res) => { 141 | try { 142 | const id = req.body.doctorId; // Doctor's id 143 | const date = req.body.date; // Date to book 144 | 145 | const doctor = await Doctor.findOne({ _id: id }); 146 | 147 | // Doctor not found 148 | if (doctor === null) { 149 | console.log("Doctor not found in the database!"); 150 | return res.status(201).json({ 151 | message: "Doctor not found in the database!", 152 | }); 153 | } 154 | 155 | // Doctor found 156 | // Find the date 157 | let count = 0; 158 | for (const i of doctor.dates) { 159 | if (i.date === date) { 160 | return res.status(200).json(i); 161 | } 162 | count++; 163 | } 164 | 165 | const oldLength = count; 166 | 167 | // Add new slots if date not found in the db 168 | const dateSchedule = createDate(date); 169 | const updatedDoctor = await Doctor.findOneAndUpdate( 170 | { _id: doctor._id }, 171 | { $push: { dates: dateSchedule } }, 172 | { new: true } 173 | ); 174 | 175 | if (updatedDoctor) { 176 | return res.status(200).json(updatedDoctor.dates[oldLength]); 177 | } else { 178 | const err = { err: "an error occurred!" }; 179 | throw err; 180 | } 181 | } catch (err) { 182 | console.log(err); 183 | return res.status(400).json({ 184 | message: err, 185 | }); 186 | } 187 | }); 188 | 189 | router.route("/book-slot").post((req, res) => { 190 | const patientId = req.body.googleId; // Patient's google id 191 | const patientName = req.body.patientName; // Patient's name 192 | const doctorId = req.body.doctorId; // Doctor's id 606460d2e0dd28cc76d9b0f3 193 | const slotId = req.body.slotId; // Id of that particular slot 194 | const dateId = req.body.dateId; // Id of that particular date 195 | const meetLink = ""; 196 | 197 | Doctor.findOne({ _id: doctorId }).then((doctor) => { 198 | const date = doctor.dates.id(dateId); 199 | const slot = date.slots.id(slotId); 200 | slot.isBooked = true; 201 | doctor 202 | .save() 203 | .then(() => { 204 | // Create an entry in the appointment database 205 | const newAppointment = new Appointment({ 206 | doctorId, 207 | dateId, 208 | slotId, 209 | patientId, 210 | date: date.date, 211 | slotTime: slot.time, 212 | doctorName: doctor.name, 213 | doctorEmail: doctor.email, 214 | patientName: patientName, 215 | googleMeetLink: meetLink, 216 | feedback: new Feedback() 217 | }); 218 | 219 | console.log(newAppointment); 220 | 221 | newAppointment 222 | .save() 223 | .then((appointment) => { 224 | return res.status(200).json(appointment); 225 | }) 226 | .catch((err) => { 227 | console.log(err); 228 | res.status(400).json(err); 229 | }); 230 | }) 231 | .catch((err) => { 232 | console.log(err); 233 | res.status(400).json({ 234 | message: `An error occurred : ${err}`, 235 | }); 236 | }); 237 | }); 238 | }); 239 | 240 | router.route("/appointments").post(async (req, res) => { 241 | try { 242 | const doctorId = req.body.doctorId; 243 | const appointments = await Appointment.find({ 244 | doctorId: doctorId, 245 | }); 246 | // res.status(200).json(appointments); 247 | const sortedAppointments = appointments.sort((a, b) => { 248 | return ( 249 | Date.parse(b.date + "T" + b.slotTime) - 250 | Date.parse(a.date + "T" + a.slotTime) 251 | ); 252 | }); 253 | 254 | res.status(200).json(sortedAppointments); 255 | } catch (err) { 256 | console.log(err); 257 | res.status(400).json(err); 258 | } 259 | }); 260 | 261 | router.route("/appointment/:id").get(async (req, res) => { 262 | try { 263 | const appointmentId = req.params.id; 264 | const appointment = await Appointment.findOne({ 265 | _id: appointmentId, 266 | }); 267 | 268 | res.status(200).json(appointment); 269 | } catch (err) { 270 | console.log(err); 271 | res.status(400).json(err); 272 | } 273 | }); 274 | 275 | router.route('/todays-appointments').post(async (req, res) => { 276 | try { 277 | const date = new Date() 278 | let currDate = date.getFullYear().toString() 279 | const month = date.getMonth() + 1 280 | const day = date.getDate() 281 | 282 | currDate += month < 10 ? ('-0' + month.toString()) : '-' + month.toString() 283 | currDate += day < 10 ? ('-0' + day.toString()) : '-' + day.toString() 284 | 285 | const doctorId = req.body.doctorId; 286 | 287 | const appointments = await Appointment.find({ doctorId: doctorId, date: currDate }); 288 | 289 | const sortedAppointments = appointments.sort((a, b) => { 290 | return ( 291 | Date.parse(a.date + "T" + a.slotTime) - Date.parse(b.date + "T" + b.slotTime) 292 | ); 293 | }); 294 | 295 | res.status(200).json(sortedAppointments); 296 | } 297 | catch (err) { 298 | console.log(err); 299 | res.status(400).json(err); 300 | } 301 | }) 302 | 303 | router.route('/previous-appointments').post(async (req, res) => { 304 | try { 305 | const doctorId = req.body.doctorId; 306 | 307 | const appointments = await Appointment.find({ doctorId: doctorId }); 308 | 309 | // Get current dateTime 310 | const date = new Date() 311 | let currDateTime = date.getFullYear().toString() 312 | const month = date.getMonth() + 1 313 | const day = date.getDate() 314 | const hour = date.getHours() 315 | const minutes = date.getMinutes() 316 | const seconds = date.getSeconds() 317 | 318 | currDateTime += month < 10 ? ('-0' + month.toString()) : '-' + month.toString() 319 | currDateTime += day < 10 ? ('-0' + day.toString()) : '-' + day.toString() 320 | currDateTime += hour < 10 ? ('T0' + hour.toString()) : 'T' + hour.toString() 321 | currDateTime += minutes < 10 ? (':0' + minutes.toString()) : ':' + minutes.toString() 322 | currDateTime += seconds < 10 ? (':0' + seconds.toString()) : ':' + seconds.toString() 323 | 324 | const filteredAppointments = appointments.filter((appointment) => { 325 | return Date.parse(currDateTime) >= Date.parse(appointment.date + 'T' + appointment.slotTime) 326 | }) 327 | 328 | const sortedAppointments = filteredAppointments.sort((a, b) => { 329 | return Date.parse(b.date + 'T' + b.slotTime) - Date.parse(a.date + 'T' + a.slotTime) 330 | }) 331 | 332 | res.status(200).json(sortedAppointments); 333 | } 334 | catch (err) { 335 | console.log(err); 336 | res.status(400).json(err); 337 | } 338 | }) 339 | 340 | module.exports = router; 341 | --------------------------------------------------------------------------------