├── 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 |
11 |
12 | {Value}
13 |
14 |
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 |
10 | Back to Home
11 |
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 | You need to enable JavaScript to run this app.
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 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
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 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | {/*
28 |
29 |
30 |
31 | */}
32 |
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 && Logout
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 | Date
31 | Time
32 | Patient Name
33 | Meet Link
34 |
35 |
36 |
37 | {appointments.map((appointment) => (
38 |
39 | {appointment.date}
40 | {appointment.slotTime}
41 | {appointment.patientName}
42 | Join Meet
43 |
44 | ))}
45 |
46 |
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 |
34 | {/*
35 |
36 | First
37 | */}
38 |
39 |
40 |
47 | {/*
48 | Second
49 | */}
50 |
51 |
52 |
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 ()
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 ()
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 | Phone/Mobile Number
49 |
50 |
51 | setNumber(e.target.value)}
59 | />
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | Add Phone Number
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") && Login As A 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 | GO BACK
62 |
63 |
64 | {/*
65 |
*/}
66 |
67 |
76 | Confirm And Go to Next Step
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 |
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 | Date
63 | Time
64 | Patient Name
65 | Feedback
66 |
67 |
68 |
69 | {Appointments.map((Appointment) => (
70 |
71 | {Appointment.date}
72 | {Appointment.slotTime}
73 | {Appointment.patientName}
74 | {Appointment.feedback.given ?
75 |
76 | Details
77 | : - }
78 |
79 | ))}
80 |
81 |
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 | Date
59 | Time
60 | Doctor Name
61 | Feedback
62 |
63 |
64 |
65 | {Appointments.map((Appointment) => (
66 |
67 | {Appointment.date}
68 | {Appointment.slotTime}
69 | {Appointment.doctorName}
70 |
71 |
74 |
75 |
76 |
77 | {Appointment.feedback.given &&
{Appointment.feedback.stars}/5
}
80 |
81 |
82 |
83 | ))}
84 |
85 |
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 | Slot
75 | Booking Status
76 |
77 |
78 |
79 | {Slots.map((slot) => (
80 |
81 | {slot.time}
82 | {slot.isBooked ? (
83 | Booked
84 | ) : (
85 |
86 |
96 | Book Now
97 |
98 |
99 | )}
100 |
101 | ))}
102 |
103 |
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 | 
11 |
12 | ### Patient Personal Details
13 | 
14 |
15 | ### Search
16 | 
17 |
18 | ### Select Date
19 | 
20 |
21 | ### Select Slot
22 | 
23 |
24 | ### Payment
25 | 
26 |
27 | 
28 |
29 | 
30 |
31 | ### Appointment Status
32 | 
33 |
34 | ### Previous Appointments
35 | 
36 |
37 | ### Patient Feedback
38 | 
39 |
40 | ## Doctor Guide:
41 | 
42 |
43 | ### Doctor Login
44 | **USERNAME** : test
45 | **Password** : test
46 |
47 | 
48 |
49 | ### Doctor's Today's Schedule
50 | 
51 |
52 | ### Doctor's Personal Details
53 | 
54 |
55 | ### Doctor's Previous Appointments
56 | 
57 |
58 | ### Doctor View Feedback
59 | 
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 |
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 | Date
87 | Time
88 | Doctor Name
89 | Meet Link
90 |
91 |
92 |
93 | {appointments.map((Appointment) => (
94 |
95 | {Appointment.date}
96 | {Appointment.slotTime}
97 | {Appointment.doctorName}
98 | Join Meet
99 |
100 | ))}
101 |
102 |
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 |
85 |
86 |
93 | Hospital Management System
94 |
95 |
101 |
102 |
103 |
104 |
105 |
106 |
107 | {!token && (
108 |
112 | Login As A Patient
113 |
114 | )}
115 | {token && (
116 |
121 | Logout
122 |
123 | )}
124 |
125 |
126 |
127 |
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 | UpdateDisplay(text)}
110 | >
111 | Search Doctor
112 |
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 | Book
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 | Doctor Name
177 | Specialization
178 |
179 | Total
180 |
181 |
182 |
183 |
184 |
185 | {doctor.name}
186 |
187 |
191 | {doctor.specialization}
192 |
193 |
194 |
195 | {doctor.feesPerSession}
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 | Subtotal:
205 |
206 |
207 | Tax:
208 |
209 |
210 |
211 |
212 | {doctor.feesPerSession}
213 |
214 |
215 | {0.18 * doctor.feesPerSession}
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 | Total:
225 |
226 |
227 |
228 |
229 | {finalBalnce}
230 |
231 |
232 |
233 |
234 |
235 |
243 |
247 | Pay Now
248 |
249 |
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 |
--------------------------------------------------------------------------------