├── .env
├── .gitignore
├── README.md
├── client
├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
└── src
│ ├── App.css
│ ├── App.js
│ ├── actions
│ ├── alert.js
│ ├── appointment.js
│ ├── authDoctor.js
│ ├── authUser.js
│ ├── profile.js
│ ├── review.js
│ └── types.js
│ ├── components
│ ├── auth
│ │ ├── DoctorRegister.js
│ │ ├── LoginDoctor.js
│ │ ├── LoginUser.js
│ │ └── UserRegister.js
│ ├── bookappointment
│ │ ├── AppointmentForm.js
│ │ └── Form.js
│ ├── dashboard
│ │ ├── Dashboard.js
│ │ ├── Education.js
│ │ ├── Experience.js
│ │ ├── Graph.js
│ │ ├── Patient.js
│ │ └── Review.js
│ ├── layout
│ │ ├── Alert.js
│ │ ├── Landing.js
│ │ ├── Navbar.js
│ │ ├── Spinner.js
│ │ └── doctor (1).png
│ ├── profile-forms
│ │ ├── AddEducation.js
│ │ ├── AddExperience.js
│ │ ├── CreateProfile.js
│ │ └── EditProfile.js
│ ├── profile
│ │ ├── Profile.js
│ │ ├── ProfileAbout.js
│ │ ├── ProfileEducation.js
│ │ ├── ProfileExperience.js
│ │ ├── ProfileReview.js
│ │ ├── ProfileReviewForm.js
│ │ ├── ProfileTop.js
│ │ └── ReviewForm.js
│ ├── profiles
│ │ ├── ProfileItem.js
│ │ └── Profiles.js
│ ├── routing
│ │ ├── PrivateDoctorRoute.js
│ │ └── PrivateUserRoute.js
│ └── user
│ │ ├── AppointmentItems.js
│ │ └── Appointments.js
│ ├── img
│ ├── calendar.svg
│ ├── coughing_2.svg
│ ├── doctor.svg
│ ├── doctor4.svg
│ ├── doctor8.svg
│ ├── graduation.svg
│ ├── mention.svg
│ ├── newDoctor1.svg
│ ├── undraw_account_490v.svg
│ ├── undraw_doctor_kw5l.svg
│ ├── undraw_forms_78yw.svg
│ └── undraw_medical_research_qg4d.svg
│ ├── index.css
│ ├── index.js
│ ├── logo.svg
│ ├── reducers
│ ├── alert.js
│ ├── appointment.js
│ ├── authDoctor.js
│ ├── authUser.js
│ ├── index.js
│ ├── profile.js
│ └── review.js
│ ├── store.js
│ └── utils
│ └── setAuthToken.js
├── config
└── keys.js
├── middleware
├── authDoctor.js
└── authUser.js
├── models
├── Doctor.js
├── Profile.js
└── User.js
├── package-lock.json
├── package.json
├── routes
└── api
│ ├── appointment.js
│ ├── authDoctor.js
│ ├── authUser.js
│ ├── doctors.js
│ ├── profile.js
│ └── users.js
└── server.js
/.env:
--------------------------------------------------------------------------------
1 | jwtSecret=mysecrettoken
--------------------------------------------------------------------------------
/.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 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Doctor-Assigned
2 | > Doctor appointment booking for patients
3 |
4 | This is a MERN stack application which is based on booking appointment which includes doctor authentication, create profile,add experience, add education, dashboard with recent appointments, recent reviews and user authentication, appointment booking and cancel appointment, post review and delete review to a doctor profile by users.
5 | #### [Click Here](https://drive.google.com/drive/folders/1BplDurTpvfIIzYjeMv98YfslDRjVdf_e?usp=sharing) for screenshots
6 |
7 | ## Install server dependencies
8 | `npm install`
9 |
10 | ## Install client dependencies
11 | `cd client`
12 |
13 | `npm install`
14 |
15 | ## Run both Express & React from root
16 | `npm run dev`
17 |
18 |
19 |
--------------------------------------------------------------------------------
/client/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # misc
7 | /.pnp
8 | .pnp.js
9 |
10 | # testing
11 | /coverage
12 |
13 | # production
14 | /build
15 |
16 | # misc
17 | .DS_Store
18 | .env.local
19 | .env.development.local
20 | .env.test.local
21 | .env.production.local
22 |
23 |
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
27 |
28 |
--------------------------------------------------------------------------------
/client/README.md:
--------------------------------------------------------------------------------
1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
2 |
3 | ## Available Scripts
4 |
5 | In the project directory, you can run:
6 |
7 | ### `npm start`
8 |
9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
11 |
12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console.
14 |
15 | ### `npm test`
16 |
17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
19 |
20 | ### `npm run build`
21 |
22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance.
24 |
25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed!
27 |
28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
29 |
30 | ### `npm run eject`
31 |
32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!**
33 |
34 | 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.
35 |
36 | 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.
37 |
38 | 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.
39 |
40 | ## Learn More
41 |
42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
43 |
44 | To learn React, check out the [React documentation](https://reactjs.org/).
45 |
46 | ### Code Splitting
47 |
48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
49 |
50 | ### Analyzing the Bundle Size
51 |
52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
53 |
54 | ### Making a Progressive Web App
55 |
56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
57 |
58 | ### Advanced Configuration
59 |
60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
61 |
62 | ### Deployment
63 |
64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
65 |
66 | ### `npm run build` fails to minify
67 |
68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify
69 |
--------------------------------------------------------------------------------
/client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "client",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^4.2.4",
7 | "@testing-library/react": "^9.5.0",
8 | "@testing-library/user-event": "^7.2.1",
9 | "axios": "^0.19.2",
10 | "chart.js": "^2.9.3",
11 | "moment": "^2.27.0",
12 | "react": "^16.13.1",
13 | "react-chartjs-2": "^2.9.0",
14 | "react-dom": "^16.13.1",
15 | "react-moment": "^0.9.7",
16 | "react-preloaders": "^3.0.3",
17 | "react-redux": "^7.2.0",
18 | "react-router-dom": "^5.2.0",
19 | "react-scripts": "3.4.1",
20 | "redux-devtools-extension": "^2.13.8",
21 | "redux-thunk": "^2.3.0",
22 | "uuid": "^8.2.0"
23 | },
24 | "scripts": {
25 | "start": "react-scripts start",
26 | "build": "react-scripts build",
27 | "test": "react-scripts test",
28 | "eject": "react-scripts eject"
29 | },
30 | "eslintConfig": {
31 | "extends": "react-app"
32 | },
33 | "browserslist": {
34 | "production": [
35 | ">0.2%",
36 | "not dead",
37 | "not op_mini all"
38 | ],
39 | "development": [
40 | "last 1 chrome version",
41 | "last 1 firefox version",
42 | "last 1 safari version"
43 | ]
44 | },
45 | "proxy": "http://localhost:5000"
46 | }
47 |
--------------------------------------------------------------------------------
/client/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeevantheDev/Doctor-Assigned/87f6c1cb7e814e0c5c628d1e5393a227c9719487/client/public/favicon.ico
--------------------------------------------------------------------------------
/client/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | React App
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/client/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeevantheDev/Doctor-Assigned/87f6c1cb7e814e0c5c628d1e5393a227c9719487/client/public/logo192.png
--------------------------------------------------------------------------------
/client/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeevantheDev/Doctor-Assigned/87f6c1cb7e814e0c5c628d1e5393a227c9719487/client/public/logo512.png
--------------------------------------------------------------------------------
/client/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 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/client/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/client/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, Fragment } from 'react';
2 | import {BrowserRouter as Router, Route, Switch} from 'react-router-dom';
3 | import Alert from './components/layout/Alert';
4 | import Navbar from './components/layout/Navbar';
5 | import Landing from './components/layout/Landing';
6 | import LoginUser from './components/auth/LoginUser';
7 | import LoginDoctor from './components/auth/LoginDoctor';
8 | import DoctorRegister from './components/auth/DoctorRegister';
9 | import UserRegister from './components/auth/UserRegister';
10 | import Dashboard from './components/dashboard/Dashboard';
11 | import AddEducation from './components/profile-forms/AddEducation';
12 | import AddExperience from './components/profile-forms/AddExperience';
13 | import CreateProfile from './components/profile-forms/CreateProfile';
14 | import EditProfile from './components/profile-forms/EditProfile';
15 | import Profiles from './components/profiles/Profiles';
16 | import Profile from './components/profile/Profile';
17 | import PrivateDoctorRoute from './components/routing/PrivateDoctorRoute';
18 | import Appointment from './components/user/Appointments';
19 | import AppointmentForm from './components/bookappointment/AppointmentForm';
20 | import PrivateUserRoute from './components/routing/PrivateUserRoute';
21 | import './App.css';
22 |
23 | // Redux
24 | import {Provider} from 'react-redux';
25 | import store from './store';
26 | import { loadUser } from './actions/authUser';
27 | import { loadDoctor } from './actions/authDoctor';
28 | import setAuthToken from './utils/setAuthToken';
29 |
30 |
31 | if(localStorage.token) {
32 | setAuthToken(localStorage.token);
33 | }
34 |
35 | const App = () => {
36 | useEffect(() => {
37 | store.dispatch(loadUser());
38 | store.dispatch(loadDoctor());
39 | }, []);
40 |
41 | return (
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | );
69 | }
70 |
71 | export default App;
72 |
--------------------------------------------------------------------------------
/client/src/actions/alert.js:
--------------------------------------------------------------------------------
1 | import { v4 as uuidv4 } from 'uuid';
2 | import { SET_ALERT, REMOVE_ALERT } from './types';
3 |
4 | export const setAlert = (msg, alertType, timeOut=5000) => dispatch => {
5 | const id = uuidv4();
6 | dispatch({
7 | type: SET_ALERT,
8 | payload: { msg, alertType, id }
9 | });
10 |
11 | setTimeout(() => dispatch({ type: REMOVE_ALERT, payload: id }), timeOut);
12 | };
--------------------------------------------------------------------------------
/client/src/actions/appointment.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import {setAlert} from './alert';
3 |
4 | import {
5 | GET_APPOINTMENTS,
6 | ADD_APPOINTMENTS,
7 | UPDATE_APPOINTMENTS,
8 | APPOINTMENT_ERROR,
9 | DELETE_USER_ACCOUNT
10 | } from './types';
11 |
12 | // Get Appointments
13 | export const getAppointments = () => async dispatch => {
14 | try {
15 | const res = await axios.get('/api/authUser');
16 | dispatch({
17 | type: GET_APPOINTMENTS,
18 | payload: res.data
19 | });
20 |
21 | } catch (err) {
22 | dispatch({
23 | type: APPOINTMENT_ERROR,
24 | payload: {msg: err.response.statusText, status: err.response.status}
25 | });
26 | };
27 | };
28 |
29 | // Add appointment
30 | export const addAppointment = (doctorId, formData, history) => async dispatch => {
31 | const config = {
32 | headers: {
33 | 'Content-Type': 'application/json'
34 | }
35 | };
36 | try {
37 | const res = await axios.post(`/api/appointment/${doctorId}`,formData, config);
38 | dispatch({
39 | type: ADD_APPOINTMENTS,
40 | payload: res.data
41 | });
42 |
43 | dispatch(setAlert('Appointment booked', 'success'));
44 | history.push('/appointment');
45 |
46 | } catch (err) {
47 | dispatch({
48 | type: APPOINTMENT_ERROR,
49 | payload: { msg: err.response.statusText, status: err.response.status }
50 | });
51 | };
52 | };
53 |
54 | // Delete appointment
55 | export const deleteAppointment = (appointmentId) => async dispatch => {
56 | try {
57 | const res = await axios.delete(`/api/authUser/${appointmentId}`);
58 | dispatch({
59 | type: UPDATE_APPOINTMENTS,
60 | payload: res.data
61 | });
62 |
63 | dispatch(setAlert('Appointment removed', 'success'));
64 | } catch (err) {
65 | dispatch({
66 | type: APPOINTMENT_ERROR,
67 | payload: { msg: err.response.statusText, status: err.response.status }
68 | });
69 | };
70 | };
71 |
72 | // Delete user account
73 | export const deleteAccountUser = () => async dispatch => {
74 | if(window.confirm('Are you sure? this can not be undone!')) {
75 | try {
76 | await axios.delete('/api/authUser');
77 |
78 | dispatch({
79 | type: DELETE_USER_ACCOUNT
80 | });
81 |
82 | dispatch(setAlert("Your account has been removed", 'success'));
83 | } catch (err) {
84 | dispatch ({
85 | type: APPOINTMENT_ERROR,
86 | payload: { msg: err.response.statusText, status: err.response.status }
87 | });
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/client/src/actions/authDoctor.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import { setAlert } from './alert';
3 | import {
4 | REGISTER_DOCTOR_SUCCESS,
5 | REGISTER_DOCTOR_FAIL,
6 | DOCTOR_LOADED,
7 | AUTH_DOCTOR_ERROR,
8 | LOGIN_DOCTOR_SUCCESS,
9 | LOGIN_DOCTOR_FAIL,
10 | LOGOUT_DOCTOR,
11 | CLEAR_PROFILE
12 | } from './types';
13 | import setAuthToken from '../utils/setAuthToken';
14 |
15 | // Load Doctors
16 | export const loadDoctor = () => async dispatch => {
17 | if(localStorage.token) {
18 | setAuthToken(localStorage.token);
19 | }
20 |
21 | try {
22 | const res = await axios.get('/api/authDoctor');
23 |
24 | dispatch({
25 | type: DOCTOR_LOADED,
26 | payload: res.data
27 | });
28 | } catch (err) {
29 | dispatch({
30 | type: AUTH_DOCTOR_ERROR
31 | });
32 | }
33 | };
34 |
35 | // Register Doctor
36 | export const register = ({ name, email, password }) => async dispatch => {
37 | const config = {
38 | headers: {
39 | 'Content-Type': 'application/json'
40 | }
41 | }
42 | const body = JSON.stringify({ name, email, password });
43 | try {
44 | const res = await axios.post('/api/doctors', body, config);
45 | console.log(res);
46 |
47 | dispatch({
48 | type: REGISTER_DOCTOR_SUCCESS,
49 | payload: res.data
50 | });
51 | dispatch(loadDoctor());
52 | } catch (err) {
53 | const errors = err.response.data.errors;
54 | if(errors) {
55 | errors.forEach(error => dispatch(setAlert(error.msg, 'danger')));
56 | }
57 |
58 | dispatch({
59 | type: REGISTER_DOCTOR_FAIL
60 | });
61 | }
62 | };
63 |
64 | // Login Doctor
65 | export const login = (email, password) => async (dispatch) => {
66 | const config = {
67 | headers: {
68 | 'Content-Type': 'application/json'
69 | }
70 | }
71 | const body = JSON.stringify({ email, password });
72 | try {
73 | const res = await axios.post('/api/authDoctor', body, config);
74 |
75 | dispatch({
76 | type: LOGIN_DOCTOR_SUCCESS,
77 | payload: res.data
78 | });
79 | dispatch(loadDoctor());
80 | } catch (err) {
81 | const errors = err.response.data.errors;
82 | if(errors) {
83 | errors.forEach(error => dispatch(setAlert(error.msg, 'danger')));
84 | }
85 |
86 | dispatch({
87 | type: LOGIN_DOCTOR_FAIL
88 | });
89 | }
90 | };
91 |
92 | // Logout/ clear Profile
93 | export const logout_doctor = () => dispatch => {
94 | dispatch({
95 | type: CLEAR_PROFILE
96 | });
97 | dispatch({
98 | type: LOGOUT_DOCTOR
99 | });
100 | }
--------------------------------------------------------------------------------
/client/src/actions/authUser.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import { setAlert } from './alert';
3 | import {
4 | REGISTER_USER_SUCCESS,
5 | REGISTER_USER_FAIL,
6 | USER_LOADED,
7 | AUTH_USER_ERROR,
8 | LOGIN_USER_SUCCESS,
9 | LOGIN_USER_FAIL,
10 | LOGOUT_USER,
11 | CLEAR_USER_PROFILE
12 | } from './types';
13 | import setAuthToken from '../utils/setAuthToken';
14 |
15 | // Load User
16 | export const loadUser = () => async dispatch => {
17 | if(localStorage.token) {
18 | setAuthToken(localStorage.token);
19 | }
20 |
21 | try {
22 | const res = await axios.get('/api/authUser');
23 |
24 | dispatch({
25 | type: USER_LOADED,
26 | payload: res.data
27 | });
28 | } catch (err) {
29 | dispatch({
30 | type: AUTH_USER_ERROR
31 | });
32 | }
33 | };
34 |
35 | // Register User
36 | export const register = ({ name, email, password }) => async dispatch => {
37 | const config = {
38 | headers: {
39 | 'Content-Type': 'application/json'
40 | }
41 | }
42 | const body = JSON.stringify({ name, email, password });
43 | try {
44 | const res = await axios.post('./api/users', body, config);
45 |
46 | dispatch({
47 | type: REGISTER_USER_SUCCESS,
48 | payload: res.data
49 | });
50 | dispatch(loadUser());
51 | } catch (err) {
52 | const errors = err.response.data.errors;
53 | if(errors) {
54 | errors.forEach(error => dispatch(setAlert(error.msg, 'danger')));
55 | }
56 |
57 | dispatch({
58 | type: REGISTER_USER_FAIL
59 | });
60 | }
61 | };
62 |
63 | // Login User
64 | export const login = (email, password) => async (dispatch) => {
65 | const config = {
66 | headers: {
67 | 'Content-Type': 'application/json'
68 | }
69 | }
70 | const body = JSON.stringify({ email, password });
71 | try {
72 | const res = await axios.post('/api/authUser', body, config);
73 |
74 | dispatch({
75 | type: LOGIN_USER_SUCCESS,
76 | payload: res.data
77 | });
78 | dispatch(loadUser());
79 | } catch (err) {
80 | const errors = err.response.data.errors;
81 | if(errors) {
82 | errors.forEach(error => dispatch(setAlert(error.msg, 'danger')));
83 | }
84 |
85 | dispatch({
86 | type: LOGIN_USER_FAIL
87 | });
88 | }
89 | };
90 |
91 | // Logout/ clear Profile
92 | export const logout_user = () => dispatch => {
93 | dispatch({
94 | type: CLEAR_USER_PROFILE
95 | });
96 | dispatch({
97 | type: LOGOUT_USER
98 | });
99 | }
--------------------------------------------------------------------------------
/client/src/actions/profile.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import {setAlert} from './alert';
3 |
4 | import {
5 | GET_PROFILE,
6 | GET_PROFILE_BY_ID,
7 | GET_PROFILES,
8 | UPDATE_PROFILE,
9 | PROFILE_ERROR,
10 | CLEAR_PROFILE,
11 | ADD_REVIEW,
12 | ADD_REVIEW_ERROR,
13 | REMOVE_REVIEW,
14 | DELETE_ACCOUNT
15 | } from './types';
16 |
17 | // Get current doctors profile
18 | export const getCurrentProfile = () => async dispatch => {
19 | try {
20 | const res = await axios.get('/api/profile/me');
21 | dispatch({
22 | type: GET_PROFILE,
23 | payload: res.data
24 | });
25 | } catch (err) {
26 | dispatch({
27 | type: PROFILE_ERROR,
28 | payload: { msg: err.response.statusText, status: err.response.status }
29 | });
30 |
31 | }
32 | };
33 | // Get all profiles
34 | export const getProfiles = () => async dispatch => {
35 | try {
36 | const res = await axios.get('/api/profile');
37 |
38 | dispatch({
39 | type: GET_PROFILES,
40 | payload: res.data
41 | });
42 | } catch (err) {
43 | dispatch({
44 | type: PROFILE_ERROR,
45 | payload: { msg: err.response.statusText, status: err.response.status }
46 | });
47 | }
48 | };
49 |
50 | // Get profiles by doctor id
51 | export const getProfileById = doctorId => async dispatch => {
52 | try {
53 | const res = await axios.get(`/api/profile/doctor/${doctorId}`);
54 | dispatch({
55 | type: GET_PROFILE_BY_ID,
56 | payload: res.data
57 | });
58 | } catch (err) {
59 | dispatch({
60 | type: PROFILE_ERROR,
61 | payload: { msg: err.response.statusText, status: err.response.status }
62 | });
63 | }
64 | };
65 |
66 | // Create / Update a profile
67 | export const createProfile = (formData, history, edit=false) => async dispatch => {
68 | try {
69 | const config = {
70 | headers: {
71 | 'Content-Type': 'application/json'
72 | }
73 | }
74 | const res = await axios.post('api/profile', formData, config);
75 | dispatch({
76 | type: GET_PROFILE,
77 | payload: res.data
78 | });
79 | dispatch(setAlert(edit ? 'Profile Updated' : 'Profile Created', 'success'));
80 |
81 | if(!edit) {
82 | history.push('/dashboard');
83 | }
84 | } catch (err) {
85 | const errors = err.response.data.errors;
86 | if(errors) {
87 | errors.forEach(error => dispatch(setAlert(error.msg, 'danger')));
88 | }
89 |
90 | dispatch({
91 | type: PROFILE_ERROR,
92 | payload: { msg: err.response.statusText, status: err.response.status }
93 | });
94 | }
95 | };
96 |
97 | // ADD Experience
98 | export const addExperience = (formData, history) => async dispatch => {
99 | try {
100 | const config = {
101 | headers: {
102 | 'Content-Type': 'application/json'
103 | }
104 | }
105 | const res = await axios.put('api/profile/experience', formData, config);
106 | dispatch({
107 | type: UPDATE_PROFILE,
108 | payload: res.data
109 | });
110 | dispatch(setAlert("Experience added", 'success'));
111 | history.push('/dashboard');
112 | } catch (err) {
113 | const errors = err.response.data.errors;
114 | if(errors) {
115 | errors.forEach(error => dispatch(setAlert(error.msg, 'danger')));
116 | }
117 |
118 | dispatch({
119 | type: PROFILE_ERROR,
120 | payload: { msg: err.response.statusText, status: err.response.status }
121 | });
122 | }
123 | };
124 | // ADD Education
125 | export const addEducation = (formData, history) => async dispatch => {
126 | try {
127 | const config = {
128 | headers: {
129 | 'Content-Type': 'application/json'
130 | }
131 | }
132 | const res = await axios.put('api/profile/education', formData, config);
133 | dispatch({
134 | type: UPDATE_PROFILE,
135 | payload: res.data
136 | });
137 | dispatch(setAlert("Education added", 'success'));
138 | console.log(history);
139 |
140 | history.push('/dashboard');
141 | } catch (err) {
142 | const errors = err.response.data.errors;
143 | if(errors) {
144 | errors.forEach(error => dispatch(setAlert(error.msg, 'danger')));
145 | }
146 |
147 | dispatch({
148 | type: PROFILE_ERROR,
149 | payload: { msg: err.response.statusText, status: err.response.status }
150 | });
151 | }
152 | };
153 |
154 | // Delete experience
155 | export const deleteExperience = exp_id => async dispatch => {
156 | try {
157 | const res = await axios.delete(`api/profile/experience/${exp_id}`);
158 | dispatch({
159 | type: UPDATE_PROFILE,
160 | payload: res.data
161 | });
162 | dispatch(setAlert("Experience Removed", 'success'));
163 | } catch (err) {
164 | dispatch ({
165 | type: PROFILE_ERROR,
166 | payload: { msg: err.response.statusText, status: err.response.status }
167 | });
168 | }
169 | };
170 | // Delete education
171 | export const deleteEducation = edu_id => async dispatch => {
172 | try {
173 | const res = await axios.delete(`api/profile/education/${edu_id}`);
174 | dispatch({
175 | type: UPDATE_PROFILE,
176 | payload: res.data
177 | });
178 | dispatch(setAlert("Education Removed", 'success'));
179 | } catch (err) {
180 | dispatch ({
181 | type: PROFILE_ERROR,
182 | payload: { msg: err.response.statusText, status: err.response.status }
183 | });
184 | }
185 | };
186 |
187 | // Add review
188 | export const addReview = (doctorId, formData) => async dispatch => {
189 | const config = {
190 | headers: {
191 | 'Content-Type': 'application/json'
192 | }
193 | };
194 | try {
195 | const res = await axios.post(`/api/profile/doctor/:${doctorId}`, formData, config);
196 | dispatch({
197 | type: ADD_REVIEW,
198 | payload: res.data
199 | });
200 |
201 | dispatch(setAlert('Review Added', 'success'))
202 | } catch (err) {
203 | dispatch ({
204 | type: ADD_REVIEW_ERROR,
205 | payload: { msg: err.response.statusText, status: err.response.status }
206 | });
207 | }
208 | };
209 |
210 | // Delete Review
211 | export const deleteReview = (doctorId, reviewId) => async dispatch => {
212 | try {
213 | await axios.delete(`/api/profile/doctor/${doctorId}/${reviewId}`);
214 |
215 | dispatch({
216 | type: REMOVE_REVIEW,
217 | payload: reviewId
218 | });
219 |
220 | dispatch(setAlert('Comment removed', 'success'));
221 | } catch (err) {
222 | dispatch ({
223 | type: ADD_REVIEW_ERROR,
224 | payload: { msg: err.response.statusText, status: err.response.status }
225 | });
226 | }
227 | };
228 |
229 | // Delete account and profile
230 | export const deleteAccount = () => async dispatch => {
231 | if(window.confirm('Are you sure? this can not be undone!')) {
232 | try {
233 | await axios.delete('/api/profile');
234 |
235 | dispatch({
236 | type: CLEAR_PROFILE
237 | });
238 | dispatch({
239 | type: DELETE_ACCOUNT
240 | });
241 |
242 | dispatch(setAlert("Your Account has been Removed", 'success'));
243 | } catch (err) {
244 | dispatch ({
245 | type: PROFILE_ERROR,
246 | payload: { msg: err.response.statusText, status: err.response.status }
247 | });
248 | }
249 | }
250 | };
251 |
--------------------------------------------------------------------------------
/client/src/actions/review.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import {setAlert} from './alert';
3 |
4 | import {
5 | ADD_REVIEW,
6 | ADD_REVIEW_ERROR,
7 | REMOVE_REVIEW
8 | } from './types';
9 |
10 | // Add review
11 | export const addReview = (doctorId, formData) => async dispatch => {
12 | const config = {
13 | headers: {
14 | 'Content-Type': 'application/json'
15 | }
16 | };
17 | try {
18 | const res = await axios.post(`/api/profile/doctor/${doctorId}`, formData, config);
19 |
20 | dispatch({
21 | type: ADD_REVIEW,
22 | payload: res.data.review
23 | });
24 |
25 | dispatch(setAlert('Review Added', 'success'))
26 | } catch (err) {
27 | dispatch ({
28 | type: ADD_REVIEW_ERROR,
29 | payload: { msg: err.response.statusText, status: err.response.status }
30 | });
31 | }
32 | };
33 |
34 | // Delete Review
35 | export const deleteReview = (doctorId, reviewId) => async dispatch => {
36 | try {
37 | await axios.delete(`/api/profile/doctor/${doctorId}/${reviewId}`);
38 | dispatch({
39 | type: REMOVE_REVIEW,
40 | payload: reviewId
41 | });
42 |
43 | dispatch(setAlert('Comment removed', 'success'));
44 | } catch (err) {
45 | dispatch ({
46 | type: ADD_REVIEW_ERROR,
47 | payload: { msg: err.response.statusText, status: err.response.status }
48 | });
49 | }
50 | };
--------------------------------------------------------------------------------
/client/src/actions/types.js:
--------------------------------------------------------------------------------
1 | export const SET_ALERT = 'SET_ALERT';
2 | export const REMOVE_ALERT = 'REMOVE_ALERT';
3 |
4 | // Doctor action types
5 | export const REGISTER_DOCTOR_SUCCESS = 'REGISTER_DOCTOR_SUCCESS';
6 | export const REGISTER_DOCTOR_FAIL = 'REGISTER_DOCTOR_FAIL';
7 | export const DOCTOR_LOADED = 'DOCTOR_LOADED';
8 | export const AUTH_DOCTOR_ERROR = 'AUTH_DOCTOR_ERROR';
9 | export const LOGIN_DOCTOR_SUCCESS = 'LOGIN_DOCTOR_SUCCESS';
10 | export const LOGIN_DOCTOR_FAIL = 'LOGIN_DOCTOR_FAIL';
11 | export const LOGOUT_DOCTOR = 'LOGOUT_DOCTOR';
12 | export const GET_PROFILE = 'GET_PROFILE';
13 | export const GET_PROFILE_BY_ID = 'GET_PROFILE_BY_ID';
14 | export const GET_PROFILES = 'GET_PROFILES';
15 | export const UPDATE_PROFILE = 'UPDATE_PROFILE';
16 | export const CLEAR_PROFILE = 'CLEAR_PROFILE';
17 | export const PROFILE_ERROR = 'PROFILE_ERROR';
18 | export const DELETE_ACCOUNT = 'DELETE_ACCOUNT';
19 |
20 | // User action types
21 | export const REGISTER_USER_SUCCESS = 'REGISTER_USER_SUCCESS';
22 | export const REGISTER_USER_FAIL = 'REGISTER_USER_FAIL';
23 | export const USER_LOADED = 'USER_LOADED';
24 | export const AUTH_USER_ERROR = 'AUTH_USER_ERROR';
25 | export const LOGIN_USER_SUCCESS = 'LOGIN_USER_SUCCESS';
26 | export const LOGIN_USER_FAIL = 'LOGIN_USER_FAIL';
27 | export const LOGOUT_USER = 'LOGOUT_USER';
28 | export const GET_APPOINTMENTS = 'GET_APPOINTMENTS';
29 | export const ADD_APPOINTMENTS = 'ADD_APPOINTMENTS';
30 | export const APPOINTMENT_ERROR = 'APPOINTMENT_ERROR';
31 | export const UPDATE_APPOINTMENTS = 'UPDATE_APPOINTMENTS';
32 | export const ADD_REVIEW = 'ADD_REVIEW';
33 | export const ADD_REVIEW_ERROR = 'ADD_REVIEW_ERROR';
34 | export const REMOVE_REVIEW = 'REMOVE_REVIEW';
35 | export const CLEAR_USER_PROFILE = 'CLEAR_USER_PROFILE';
36 | export const DELETE_USER_ACCOUNT = 'DELETE_USER_ACCOUNT';
--------------------------------------------------------------------------------
/client/src/components/auth/DoctorRegister.js:
--------------------------------------------------------------------------------
1 | import React, { useState,Fragment } from 'react';
2 | import {Redirect} from 'react-router-dom';
3 | import {setAlert} from '../../actions/alert';
4 | import { register} from '../../actions/authDoctor';
5 | import PropTypes from 'prop-types';
6 | import {connect} from 'react-redux';
7 |
8 |
9 | const DoctorRegister = ({ setAlert, register, isDoctorAuthenticated }) => {
10 | const [formData, setFormData] = useState({
11 | name: '',
12 | email: '',
13 | password: '',
14 | password2: ''
15 | });
16 |
17 | const {name, email, password, password2} = formData;
18 | const onChange = e => setFormData({
19 | ...formData,
20 | [e.target.name]: e.target.value
21 | });
22 | const onSubmit = async e => {
23 | e.preventDefault();
24 | if(password !== password2) {
25 | setAlert('Password do not match', 'danger');
26 | } else {
27 | register({ name, email, password });
28 | }
29 | }
30 | if(isDoctorAuthenticated) {
31 | return
32 | }
33 |
34 | return (
35 |
36 |
37 |
38 |
39 |
40 |
41 |
Doctor
42 |
43 |
44 |
45 |
93 |
94 |
95 |
})
96 |
97 |
98 |
99 |
100 |
101 | );
102 | };
103 |
104 | DoctorRegister.propTypes = {
105 | setAlert: PropTypes.func.isRequired,
106 | register: PropTypes.func.isRequired,
107 | isDoctorAuthenticated: PropTypes.bool
108 | }
109 |
110 | const mapStateToProps =state => ({
111 | isDoctorAuthenticated: state.authDoctor.isDoctorAuthenticated
112 | });
113 |
114 | export default connect(mapStateToProps, {setAlert, register})(DoctorRegister);
115 |
--------------------------------------------------------------------------------
/client/src/components/auth/LoginDoctor.js:
--------------------------------------------------------------------------------
1 | import React, { useState, Fragment } from 'react';
2 | import {Link, Redirect} from 'react-router-dom';
3 | import {connect} from 'react-redux';
4 | import PropTypes from 'prop-types';
5 | import {login} from '../../actions/authDoctor';
6 |
7 | const LoginDoctor = ({ login, isDoctorAuthenticated }) => {
8 | const [formData, setFormData] = useState({
9 | email: '',
10 | password: ''
11 | });
12 |
13 | const {email, password} = formData;
14 | const onChange = e => setFormData({
15 | ...formData,
16 | [e.target.name]: e.target.value
17 | });
18 | const onSubmit = async e => {
19 | e.preventDefault();
20 | login(email,password);
21 | }
22 |
23 | // Redirect if login
24 | if(isDoctorAuthenticated) {
25 | return
26 | }
27 |
28 | return (
29 |
30 |
31 |
32 |
33 |
34 |
35 |
Log in Doctor
36 |
37 |
38 |
39 |
69 |
70 |
71 |
})
72 |
73 |
74 |
75 |
76 |
77 | );
78 | };
79 |
80 | LoginDoctor.propTypes ={
81 | login: PropTypes.func.isRequired,
82 | isDoctorAuthenticated: PropTypes.bool
83 | };
84 | const mapStateToProps = state => ({
85 | isDoctorAuthenticated: state.authDoctor.isDoctorAuthenticated
86 | });
87 |
88 | export default connect(mapStateToProps, {login})(LoginDoctor);
89 |
--------------------------------------------------------------------------------
/client/src/components/auth/LoginUser.js:
--------------------------------------------------------------------------------
1 | import React, { useState, Fragment } from 'react';
2 | import {Link, Redirect} from 'react-router-dom';
3 | import {connect} from 'react-redux';
4 | import PropTypes from 'prop-types';
5 | import {login} from '../../actions/authUser';
6 |
7 | const LoginUser = ({ login, isUserAuthenticated }) => {
8 | const [formData, setFormData] = useState({
9 | email: '',
10 | password: ''
11 | });
12 |
13 | const {email, password} = formData;
14 | const onChange = e => setFormData({
15 | ...formData,
16 | [e.target.name]: e.target.value
17 | });
18 | const onSubmit = async e => {
19 | e.preventDefault();
20 | login(email,password);
21 | }
22 |
23 | // Redirect if login
24 | if(isUserAuthenticated) {
25 | return
26 | }
27 |
28 | return (
29 |
30 |
31 |
32 |
33 |
34 |
35 |
Log in User{' '}
36 |
37 |
38 |
39 |
69 |
70 |
71 |
})
72 |
73 |
74 |
75 |
76 |
77 | );
78 | };
79 |
80 | LoginUser.propTypes ={
81 | login: PropTypes.func.isRequired,
82 | isUserAuthenticated: PropTypes.bool
83 | };
84 | const mapStateToProps = state => ({
85 | isUserAuthenticated: state.authUser.isUserAuthenticated
86 | });
87 |
88 | export default connect(mapStateToProps, {login})(LoginUser);
89 |
--------------------------------------------------------------------------------
/client/src/components/auth/UserRegister.js:
--------------------------------------------------------------------------------
1 | import React, { useState, Fragment } from 'react';
2 | import {Redirect} from 'react-router-dom';
3 | import {setAlert} from '../../actions/alert';
4 | import { register} from '../../actions/authUser';
5 | import PropTypes from 'prop-types';
6 | import {connect} from 'react-redux';
7 |
8 |
9 | const UserRegister = ({ setAlert, register, isUserAuthenticated }) => {
10 | const [formData, setFormData] = useState({
11 | name: '',
12 | email: '',
13 | password: '',
14 | password2: ''
15 | });
16 |
17 | const {name, email, password, password2} = formData;
18 | const onChange = e => setFormData({
19 | ...formData,
20 | [e.target.name]: e.target.value
21 | });
22 | const onSubmit = async e => {
23 | e.preventDefault();
24 | if(password !== password2) {
25 | setAlert('Password do not match', 'danger');
26 | } else {
27 | register({ name, email, password });
28 | }
29 | }
30 | if(isUserAuthenticated) {
31 | return
32 | }
33 |
34 | return (
35 |
36 |
37 |
38 |
39 |
40 |
41 |
User
42 |
43 |
44 |
45 |
93 |
94 |
95 |
})
96 |
97 |
98 |
99 |
100 |
101 | );
102 | };
103 |
104 | UserRegister.propTypes = {
105 | setAlert: PropTypes.func.isRequired,
106 | register: PropTypes.func.isRequired,
107 | isUserAuthenticated: PropTypes.bool.isRequired
108 | }
109 |
110 | const mapStateToProps =state => ({
111 | isUserAuthenticated: state.authUser.isUserAuthenticated
112 | });
113 |
114 | export default connect(mapStateToProps, {setAlert, register})(UserRegister);
115 |
--------------------------------------------------------------------------------
/client/src/components/bookappointment/AppointmentForm.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState, Fragment } from 'react';
2 | import PropTypes from 'prop-types';
3 | import {connect} from 'react-redux';
4 | import {getProfileById} from '../../actions/profile';
5 | import Form from './Form';
6 | import { withRouter } from 'react-router-dom';
7 |
8 | const AppointmentForm = ({
9 | getProfileById,
10 | profile: {profileById},
11 | match,
12 | history
13 | }) => {
14 | useEffect(() => {
15 | getProfileById(match.params.id)
16 | },[getProfileById, match.params.id]);
17 |
18 | return (
19 |
20 |
21 |
22 |
23 |
24 | {
25 | profileById !== null ?
26 | (
27 |
28 | ) : (
29 | ""
30 | )
31 | }
32 |
33 |
34 |
})
35 |
36 |
37 |
38 |
39 |
40 | );
41 | };
42 |
43 | AppointmentForm.propTypes = {
44 | getProfileById: PropTypes.func.isRequired,
45 | profile: PropTypes.object.isRequired
46 | };
47 |
48 | const mapStateToProps = state => ({
49 | profile: state.profile,
50 | });
51 |
52 | export default connect(mapStateToProps, {getProfileById})(withRouter(AppointmentForm));
53 |
--------------------------------------------------------------------------------
/client/src/components/bookappointment/Form.js:
--------------------------------------------------------------------------------
1 | import React, { Fragment, useState } from 'react';
2 | import PropTypes from 'prop-types';
3 | import {connect} from 'react-redux';
4 | import {addAppointment} from '../../actions/appointment';
5 | import { Link } from 'react-router-dom';
6 |
7 |
8 | const Form = ({profile, doctorId,history, addAppointment}) => {
9 |
10 | const [formData, setFormData] = useState({
11 | patientname: '',
12 | fathername: '',
13 | age:'',
14 | status:'',
15 | date:'',
16 | description:''
17 | });
18 |
19 | const {
20 | patientname,
21 | fathername,
22 | age,
23 | status,
24 | date,
25 | description
26 | } = formData;
27 |
28 | const onChange = e => setFormData({
29 | ...formData,
30 | [e.target.name]: e.target.value
31 | });
32 | return (
33 |
34 |
35 |
36 |
Book Appointment
37 |
38 |
39 | Provide your details correctly and book your appointment.
40 |
41 |
42 |

43 |
{profile.name}
44 |
45 |
46 |
110 |
111 |
112 | );
113 | };
114 |
115 | Form.propTypes = {
116 | addAppointment: PropTypes.func.isRequired
117 | }
118 |
119 | export default connect(null, {addAppointment})(Form);
120 |
--------------------------------------------------------------------------------
/client/src/components/dashboard/Dashboard.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, Fragment } from 'react';
2 | import PropTypes from 'prop-types';
3 | import {connect} from 'react-redux';
4 | import Spinner from '../layout/Spinner';
5 | import Experience from './Experience';
6 | import Education from './Education';
7 | import Patient from './Patient';
8 | import Review from './Review';
9 | import {getCurrentProfile, deleteAccount} from '../../actions/profile';
10 | import {Link} from 'react-router-dom';
11 |
12 |
13 | const Dashboard = ({
14 | getCurrentProfile,
15 | deleteAccount,
16 | authDoctor: {doctor},
17 | profile: {profile, loading}
18 | }) => {
19 | useEffect(() => {
20 | getCurrentProfile();
21 | }, [getCurrentProfile]);
22 |
23 | return loading && profile == null ? (
24 |
25 | ) : (
26 |
27 |
28 |
29 |
30 |
Dashboard
31 | Welcome {doctor && doctor.name}
32 |
33 |
34 | {profile !== null ? (
35 |
36 | {profile.patients !== null && profile.patients.length > 0 ?
37 | (
38 |
39 | ) : (
40 | No Appointments yet..
41 | )
42 | }
43 |
44 |
45 |
46 |
51 |
52 | ) : (
53 |
54 | You have not any Profile add your Profile..
55 |
56 | Create Profile
57 |
58 |
59 | )}
60 |
61 |
62 |
63 |
64 | );
65 | };
66 |
67 | Dashboard.propTypes = {
68 | getCurrentProfile: PropTypes.func.isRequired,
69 | deleteAccount: PropTypes.func.isRequired,
70 | authDoctor: PropTypes.object.isRequired,
71 | profile: PropTypes.object.isRequired
72 | }
73 | const mapStateToProps = state => ({
74 | authDoctor: state.authDoctor,
75 | profile: state.profile
76 | });
77 |
78 | export default connect(mapStateToProps, {getCurrentProfile, deleteAccount})(Dashboard);
79 |
--------------------------------------------------------------------------------
/client/src/components/dashboard/Education.js:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 | import PropTypes from 'prop-types';
3 | import Moment from 'react-moment';
4 | import {connect} from 'react-redux';
5 | import {deleteEducation} from '../../actions/profile';
6 |
7 | const Education = ({education, deleteEducation}) => {
8 | const educations = education.map(edu => (
9 |
10 | {edu.school} |
11 | {edu.degree} |
12 |
13 | {edu.from} - {' '}
14 | {edu.to === null ? (
15 | 'Now'
16 | ) : (
17 | {edu.to}
18 | )}
19 | |
20 |
21 |
26 | |
27 |
28 | ));
29 | return (
30 |
31 |
32 |
Education Credentials
33 |
34 |
35 |
36 |
37 | School |
38 | Degree |
39 | Years |
40 | |
41 |
42 | {educations}
43 |
44 |
45 |
46 |
47 |
48 | );
49 | };
50 |
51 | Education.propTypes = {
52 | education: PropTypes.array.isRequired,
53 | deleteEducation: PropTypes.func.isRequired,
54 | }
55 |
56 | export default connect(null, {deleteEducation})(Education);
57 |
--------------------------------------------------------------------------------
/client/src/components/dashboard/Experience.js:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 | import PropTypes from 'prop-types';
3 | import Moment from 'react-moment';
4 | import {connect} from 'react-redux';
5 | import {deleteExperience} from '../../actions/profile';
6 |
7 | const Experience = ({experience, deleteExperience}) => {
8 | const experiences = experience.map(exp => (
9 |
10 | {exp.medical} |
11 | {exp.position} |
12 |
13 | {exp.from} - {' '}
14 | {exp.to === null ? (
15 | 'Now'
16 | ) : (
17 | {exp.to}
18 | )}
19 | |
20 |
21 |
26 | |
27 |
28 | ));
29 | return (
30 |
31 |
32 |
Experience Credentials
33 |
34 |
35 |
36 |
37 | Hospital |
38 | Postion |
39 | Years |
40 | |
41 |
42 | {experiences}
43 |
44 |
45 |
46 |
47 |
48 | );
49 | };
50 |
51 | Experience.propTypes = {
52 | experience: PropTypes.array.isRequired,
53 | deleteExperience: PropTypes.func.isRequired,
54 | }
55 |
56 | export default connect(null, {deleteExperience})(Experience);
57 |
--------------------------------------------------------------------------------
/client/src/components/dashboard/Graph.js:
--------------------------------------------------------------------------------
1 | import React, {Fragment, useState, useEffect} from 'react';
2 | import {Line, Bar} from 'react-chartjs-2';
3 | import PropTypes from 'prop-types';
4 |
5 | const Graph = ({patient}) => {
6 | const [chartData, setChartData] = useState([]);
7 |
8 | const chart = () => {
9 | const patientData = [];
10 | const jan = [0];
11 | const feb = [0];
12 | const mar = [0];
13 | const apr = [0];
14 | const may = [0];
15 | const jun = [0];
16 | const jul = [0];
17 | const aug = [0];
18 | const sep = [0];
19 | const oct = [0];
20 | const nov = [0];
21 | const dec = [0];
22 |
23 | patient.forEach(pat => {
24 | if(new Date(pat.date).getMonth() === 0) {
25 | return jan.push(jan[0]+1);
26 | } else if(new Date(pat.date).getMonth() === 1) {
27 | return feb.push(feb[0]+1);
28 | } else if(new Date(pat.date).getMonth() === 2) {
29 | return mar.push(mar[0]+1);
30 | } else if(new Date(pat.date).getMonth() === 3) {
31 | return apr.push(apr[0]+1);
32 | } else if(new Date(pat.date).getMonth() === 4) {
33 | return may.push(may[0]+1);
34 | } else if(new Date(pat.date).getMonth() === 5) {
35 | return jun.push(jun[0]+1);
36 | } else if(new Date(pat.date).getMonth() === 6) {
37 | return jul.push(jul[0]+1);
38 | } else if(new Date(pat.date).getMonth() === 7) {
39 | return aug.push(aug[0]+1);
40 | } else if(new Date(pat.date).getMonth() === 8) {
41 | return sep.push(sep[0]+1);
42 | } else if(new Date(pat.date).getMonth() === 9) {
43 | return oct.push(oct[0]+1);
44 | } else if(new Date(pat.date).getMonth() === 10) {
45 | return nov.push(nov[0]+1);
46 | } else if(new Date(pat.date).getMonth() === 11) {
47 | return dec.push(dec[0]+1);
48 | } else {
49 | }
50 | });
51 |
52 | var janData = jan.reduce( (a, b) => a+b, jan[0]);
53 | var febData = feb.reduce( (a, b) => a+b, feb[0]);
54 | var marData = mar.reduce( (a, b) => a+b, mar[0]);
55 | var aprData = apr.reduce( (a, b) => a+b, apr[0]);
56 | var mayData = may.reduce( (a, b) => a+b, may[0]);
57 | var junData = jun.reduce( (a, b) => a+b, jun[0]);
58 | var julData = jul.reduce( (a, b) => a+b, jul[0]);
59 | var augData = aug.reduce( (a, b) => a+b, aug[0]);
60 | var sepData = sep.reduce( (a, b) => a+b, sep[0]);
61 | var octData = oct.reduce( (a, b) => a+b, oct[0]);
62 | var novData = nov.reduce( (a, b) => a+b, nov[0]);
63 | var decData = dec.reduce( (a, b) => a+b, dec[0]);
64 |
65 | patientData.push(janData);
66 | patientData.push(febData);
67 | patientData.push(marData);
68 | patientData.push(aprData);
69 | patientData.push(mayData);
70 | patientData.push(junData);
71 | patientData.push(julData);
72 | patientData.push(augData);
73 | patientData.push(sepData);
74 | patientData.push(octData);
75 | patientData.push(novData);
76 | patientData.push(decData);
77 |
78 | console.log(patientData);
79 |
80 | setChartData({
81 | labels: [
82 | "January",
83 | "February",
84 | "March",
85 | "April",
86 | "May",
87 | "June",
88 | "July",
89 | "August",
90 | "September",
91 | "October",
92 | "November",
93 | "December"
94 | ],
95 | datasets: [
96 | {
97 | label: "level of patients",
98 | data: patientData,
99 | borderColor: [
100 | "#17a2b8"
101 | ],
102 | pointBorderColor: [
103 | "#17a2b8",
104 | "#17a2b8",
105 | "#17a2b8",
106 | "#17a2b8",
107 | "#17a2b8",
108 | "#17a2b8",
109 | "#17a2b8",
110 | "#17a2b8",
111 | "#17a2b8",
112 | "#17a2b8",
113 | "#17a2b8",
114 | "#17a2b8",
115 | ],
116 | borderWidth: 3
117 | }
118 | ]
119 | });
120 | };
121 | useEffect(() => {
122 | chart();
123 | }, []);
124 |
125 | return (
126 |
127 |
128 |
159 |
160 |
161 | );
162 | };
163 |
164 | Graph.propTypes = {
165 | patient: PropTypes.array.isRequired,
166 | }
167 |
168 | export default Graph;
169 |
--------------------------------------------------------------------------------
/client/src/components/dashboard/Patient.js:
--------------------------------------------------------------------------------
1 | import React, { Fragment,useState } from 'react';
2 | import PropTypes from 'prop-types';
3 | import Moment from 'react-moment';
4 | import {connect} from 'react-redux';
5 |
6 | const Patient = ({patient}) => {
7 |
8 | const [value,setValue] = useState([]);
9 |
10 | const modalBody = patient.map(pat => (
11 |
12 | {pat.patientname}
13 | Father's name: {pat.fathername}
14 | Age: {pat.age}
15 | Status: {pat.status}
16 | Date: {pat.date}
17 | Booking ID: {pat.bookingId}
18 |
19 | ));
20 | const patients = patient.map(ptn => (
21 |
22 | {ptn.bookingId} |
23 | {ptn.patientname} |
24 |
25 | {ptn.date}
26 | |
27 |
28 |
35 |
36 |
37 |
38 |
39 | Patient Details
40 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | {
50 | modalBody.map(modal => value === modal.key ?
51 | modal.props.children : "")
52 | }
53 |
54 |
55 |
56 | Description: {ptn.description}
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | |
68 |
69 | ));
70 |
71 | return (
72 |
73 |
74 |
Patient Credentials
75 |
76 |
77 |
78 |
79 |
80 |
81 | Booking ID |
82 | Patient's Name |
83 | Date |
84 | |
85 |
86 |
87 |
88 | {patients}
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 | );
97 | };
98 |
99 | Patient.propTypes = {
100 | patient: PropTypes.array.isRequired,
101 | }
102 |
103 | export default connect(null)(Patient);
104 |
--------------------------------------------------------------------------------
/client/src/components/dashboard/Review.js:
--------------------------------------------------------------------------------
1 | import React, { Fragment, useState, useEffect } from 'react';
2 | import PropTypes from 'prop-types';
3 | import Moment from 'react-moment';
4 | import {connect} from 'react-redux';
5 | import Graph from './Graph';
6 |
7 | const Review = ({review, patient}) => {
8 | const reviews = review.map(rev => (
9 |
10 |

11 |
12 |
{rev.text}
13 |
posted on
14 | {' '}{rev.date}
15 |
16 |
{rev.name}
17 |
18 |
19 | ));
20 | return (
21 |
22 |
23 |
24 |
Users Reviews
25 |
26 |
27 |
28 | { review.length === 0 ? "No Reviews Yet" : reviews }
29 |
30 |
31 |
32 |
33 |
Total Appointments
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | );
43 | };
44 |
45 | Review.propTypes = {
46 | patient: PropTypes.array.isRequired,
47 | }
48 |
49 | export default connect(null)(Review);
50 |
--------------------------------------------------------------------------------
/client/src/components/layout/Alert.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import { connect } from 'react-redux';
4 |
5 | const Alert = ({ alerts }) => alerts !== null && alerts.length > 0 && alerts.map(alert => (
6 |
7 | {alert.msg}
8 |
9 | ));
10 |
11 | Alert.propTypes = {
12 | alerts: PropTypes.array.isRequired
13 | }
14 |
15 | const mapStateToProps = state => ({
16 | alerts: state.alert
17 | });
18 |
19 | export default connect(mapStateToProps)(Alert);
20 |
--------------------------------------------------------------------------------
/client/src/components/layout/Landing.js:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 | import { Link, Redirect } from 'react-router-dom';
3 | import {connect} from 'react-redux';
4 | import PropTypes from 'prop-types';
5 |
6 | import '../../App.css';
7 |
8 | const Landing = ({isDoctorAuthenticated, isUserAuthenticated}) => {
9 | if(isDoctorAuthenticated){
10 | return
11 | } else if(isUserAuthenticated) {
12 | return
13 | }
14 |
15 | return (
16 |
17 |
18 |
19 |
20 |
Find Your Best Doctor &
21 | Book Your Appointment.
22 |
23 |
24 |
25 |
For Doctors
26 |
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Vel itaque quae delectus veritatis consequatur hic!
27 |
Sign Up
28 |
29 |
30 |
For Users
31 |
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Vel itaque quae delectus veritatis consequatur hic!
32 |
Sign Up
33 |
34 |
35 |
36 |
37 |
38 |
})
39 |
40 |
41 |
42 |
43 |
44 |
45 | );
46 | };
47 | Landing.propTypes = {
48 | isDoctorAuthenticated: PropTypes.bool.isRequired,
49 | isUserAuthenticated: PropTypes.bool.isRequired
50 | }
51 |
52 | const mapStateToProps = state => ({
53 | isDoctorAuthenticated: state.authDoctor.isDoctorAuthenticated,
54 | isUserAuthenticated: state.authUser.isUserAuthenticated
55 | });
56 |
57 | export default connect(mapStateToProps)(Landing);
58 |
--------------------------------------------------------------------------------
/client/src/components/layout/Navbar.js:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 | import {Link} from 'react-router-dom';
3 | import {connect} from 'react-redux';
4 | import PropTypes from 'prop-types';
5 | import { logout_user } from '../../actions/authUser';
6 | import { logout_doctor } from '../../actions/authDoctor';
7 |
8 | import '../../App.css';
9 |
10 | const Navbar = (
11 | {
12 | authUser: { isUserAuthenticated, loadingUser, user}, logout_user,
13 | authDoctor: {isDoctorAuthenticated, loadingDoctor, doctor}, logout_doctor
14 | }
15 | ) => {
16 |
17 | const authUserLinks = (
18 |
19 |
20 | Cure
21 |
22 |
26 |
43 |
44 | );
45 | const authDoctorLinks = (
46 |
47 |
48 | Cure
49 |
50 |
54 |
80 |
81 | )
82 | const guestLinks = (
83 |
84 |
85 | Cure
86 |
87 |
91 |
116 |
117 | )
118 |
119 | return (
120 |
139 | );
140 | };
141 | Navbar.propTypes = {
142 | logout_user: PropTypes.func.isRequired,
143 | logout_doctor: PropTypes.func.isRequired,
144 | authUser: PropTypes.object.isRequired,
145 | authDoctor: PropTypes.object.isRequired
146 | };
147 |
148 | const mapStateToProps = state => ({
149 | authUser: state.authUser,
150 | authDoctor: state.authDoctor
151 | });
152 |
153 | export default connect(mapStateToProps, {logout_user, logout_doctor})(Navbar);
154 |
--------------------------------------------------------------------------------
/client/src/components/layout/Spinner.js:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 |
3 | export default () => (
4 |
5 |
6 |
13 | Loading...
14 |
15 |
16 |
17 | );
--------------------------------------------------------------------------------
/client/src/components/layout/doctor (1).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeevantheDev/Doctor-Assigned/87f6c1cb7e814e0c5c628d1e5393a227c9719487/client/src/components/layout/doctor (1).png
--------------------------------------------------------------------------------
/client/src/components/profile-forms/AddEducation.js:
--------------------------------------------------------------------------------
1 | import React, {Fragment, useState} from 'react';
2 | import {Link, withRouter} from 'react-router-dom';
3 | import PropTypes from 'prop-types';
4 | import {connect} from 'react-redux';
5 | import {addEducation} from '../../actions/profile';
6 |
7 |
8 | const AddEducation = ({addEducation, history}) => {
9 | const [formData, setFormdata] = useState({
10 | school: '',
11 | degree: '',
12 | fieldofstudy: '',
13 | from:'',
14 | to:'',
15 | current: false,
16 | description: ''
17 | });
18 |
19 | const [toDateDisabled, toggleDisabled] = useState(false);
20 |
21 | const {school, degree, fieldofstudy, from, to, current, description} = formData;
22 |
23 | const onChange = e => setFormdata({
24 | ...formData,
25 | [e.target.name]: e.target.value
26 | });
27 |
28 | return (
29 |
30 |
119 |
120 | );
121 | };
122 |
123 | AddEducation.propTypes = {
124 | addEducation: PropTypes.func.isRequired
125 | }
126 |
127 | export default connect(null, {addEducation})(withRouter(AddEducation));
128 |
--------------------------------------------------------------------------------
/client/src/components/profile-forms/AddExperience.js:
--------------------------------------------------------------------------------
1 | import React, {Fragment, useState} from 'react';
2 | import {Link, withRouter} from 'react-router-dom';
3 | import PropTypes from 'prop-types';
4 | import {connect} from 'react-redux';
5 | import {addExperience} from '../../actions/profile';
6 |
7 | const AddExperience = ({addExperience, history}) => {
8 | const [formData, setFormData] = useState({
9 | medical: '',
10 | position: '',
11 | location: '',
12 | from: '',
13 | to: '',
14 | current: false,
15 | description: ''
16 | });
17 |
18 | const [toDateDisabled, toggleDisabled] = useState(false);
19 |
20 | const {medical, position, location, from, to, current, description} = formData;
21 |
22 | const onChange = e => setFormData({
23 | ...formData,
24 | [e.target.name]: e.target.value
25 | });
26 | return (
27 |
120 | )
121 | };
122 | AddExperience.propTypes = {
123 | addExperience: PropTypes.func.isRequired
124 | }
125 |
126 | export default connect(null, {addExperience})(withRouter(AddExperience));
127 |
--------------------------------------------------------------------------------
/client/src/components/profile/Profile.js:
--------------------------------------------------------------------------------
1 | import React, {Fragment, useEffect} from 'react';
2 | import PropTypes from 'prop-types';
3 | import {connect} from 'react-redux';
4 | import Spinner from '../layout/Spinner';
5 | import {getProfileById} from '../../actions/profile';
6 | import ProfileTop from './ProfileTop';
7 | import ProfileAbout from './ProfileAbout';
8 | import ProfileExperience from './ProfileExperience';
9 | import ProfileEducation from './ProfileEducation';
10 | import ProfileReview from './ProfileReview';
11 | import ReviewForm from '../profile/ReviewForm';
12 | import { Link } from 'react-router-dom';
13 |
14 | const Profile = ({
15 | getProfileById,
16 | profile: {profileById, loading}, authDoctor,authUser, match
17 | }) => {
18 | useEffect(() => {
19 | getProfileById(match.params.id);
20 | },[getProfileById, match.params.id]);
21 |
22 | return (
23 |
24 | {profileById === null || loading ? (
25 |
26 | ) : (
27 |
28 |
29 |
30 |
31 |
32 |
Back to Profiles
33 | {authUser.isUserAuthenticated ? (
34 |
35 | Book Appointment
36 |
37 | ) : (
38 |
39 |
40 | Book Appointment
41 |
42 |
43 | )
44 | }
45 | {authDoctor.isDoctorAuthenticated &&
46 | authDoctor.loadingDoctor === false &&
47 | authDoctor.doctor._id === profileById.doctor._id && (
48 |
49 |
50 |
51 | )}
52 |
53 |
54 |
55 |
56 |
57 |
Experience
58 | {profileById.experience.length > 0 ? (
59 |
60 | {profileById.experience.map(experience => (
61 |
62 | ))}
63 |
64 | ) : (
65 |
No Experience credentials
66 | )
67 | }
68 |
69 |
70 |
Education
71 | {profileById.education.length > 0 ? (
72 |
73 | {profileById.education.map(education => (
74 |
75 | ))}
76 |
77 | ) : (
78 |
No education credentials
79 | )
80 | }
81 |
82 |
83 |
84 |
Patient Reviews
85 | { authUser.isUserAuthenticated ?
86 | (
87 |
88 | ) : ""
89 | }
90 | {
91 | profileById.review.map(rev => (
92 |
93 | ))
94 | }
95 |
96 |
97 |
98 |
99 |
100 | )}
101 |
102 | );
103 | };
104 |
105 | Profile.propTypes = {
106 | getProfileById: PropTypes.func.isRequired,
107 | profile: PropTypes.object.isRequired,
108 | authDoctor: PropTypes.object.isRequired,
109 | authUser: PropTypes.object.isRequired
110 | };
111 |
112 | const mapStateToProps = state => ({
113 | profile: state.profile,
114 | authDoctor: state.authDoctor,
115 | authUser: state.authUser
116 | });
117 |
118 | export default connect(mapStateToProps, {getProfileById})(Profile);
119 |
--------------------------------------------------------------------------------
/client/src/components/profile/ProfileAbout.js:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | const ProfileAbout = ({
5 | profile: {
6 | bio,
7 | timing,
8 | doctor: {name}
9 | }
10 | }) => {
11 | return (
12 |
13 |
14 |
15 |
Dr. {(name.split(' ')[1])}'s Bio
16 |
{bio}
17 |
18 |
19 |
20 |
Timing
21 |
{timing}
22 |
23 |
24 |
25 |
26 | )
27 | };
28 |
29 | ProfileAbout.propTypes = {
30 | profile: PropTypes.object.isRequired
31 | };
32 |
33 | export default ProfileAbout;
34 |
--------------------------------------------------------------------------------
/client/src/components/profile/ProfileEducation.js:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 | import PropTypes from 'prop-types';
3 | import Moment from 'react-moment';
4 |
5 | const ProfileEducation = ({
6 | education : {
7 | school, degree, fieldofstudy,from, to, description
8 | }
9 | }) => {
10 | return (
11 |
12 |
13 |
{school}
14 |
{from} -
15 | {
16 | !to ? 'Now' : {to}
17 | }
18 |
19 |
Degree: {degree}
20 |
Field of Study: {fieldofstudy}
21 |
Description: {description}
22 |
23 |
24 |
25 | )
26 | };
27 |
28 | ProfileEducation.propTypes = {
29 | education: PropTypes.array.isRequired
30 | };
31 |
32 | export default ProfileEducation;
33 |
--------------------------------------------------------------------------------
/client/src/components/profile/ProfileExperience.js:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 | import PropTypes from 'prop-types';
3 | import Moment from 'react-moment';
4 |
5 | const ProfileExperience = ({
6 | experience: {
7 | medical, position, location ,from, to, description
8 | }
9 | }) => {
10 | return (
11 |
12 |
13 |
{medical}
14 |
15 | {from} - {
16 | !to ? 'Now' : {to}
17 | }
18 |
19 |
Position: {position}
20 |
Location: {location}
21 |
Description: {description}
22 |
23 |
24 |
25 | )
26 | };
27 |
28 | ProfileExperience.propTypes = {
29 | experience: PropTypes.array.isRequired
30 | };
31 |
32 | export default ProfileExperience;
33 |
--------------------------------------------------------------------------------
/client/src/components/profile/ProfileReview.js:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 | import PropTypes from 'prop-types';
3 | import Moment from 'react-moment';
4 | import {deleteReview} from '../../actions/profile';
5 | import { connect } from 'react-redux';
6 |
7 | const ProfileReview = ({
8 | doctorId,
9 | review: { _id, text, name, avatar, date, user},
10 | authUser,
11 | deleteReview
12 | }) => {
13 |
14 | return (
15 |
16 |
17 |
18 |

19 |
{name}
20 |
21 |
22 |
{text}
23 |
24 | Posted on {date}
25 |
26 | {
27 | authUser.user !== null && user === authUser.user._id && (
28 |
31 | )}
32 |
33 |
34 |
35 | )
36 | };
37 |
38 | ProfileReview.propTypes = {
39 | profileId: PropTypes.number.isRequired,
40 | review: PropTypes.object.isRequired,
41 | authUser: PropTypes.object.isRequired,
42 | deleteReview: PropTypes.func.isRequired
43 | };
44 | const mapStateToProps = state => ({
45 | authUser: state.authUser
46 | });
47 |
48 | export default connect(mapStateToProps, {deleteReview})(ProfileReview);
49 |
--------------------------------------------------------------------------------
/client/src/components/profile/ProfileReviewForm.js:
--------------------------------------------------------------------------------
1 | import React, {useState} from 'react';
2 | import PropTypes from 'prop-types';
3 | import {connect} from 'react-redux';
4 | import {addReview} from '../../actions/profile';
5 |
6 | const ProfileReviewForm = () => {
7 | return (
8 |
9 |
10 |
11 | )
12 | }
13 |
14 | export default ProfileReviewForm
15 |
--------------------------------------------------------------------------------
/client/src/components/profile/ProfileTop.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | const ProfileTop = ({profile: {
5 | doctor: { name, avatar },
6 | clinic,
7 | location,
8 | specialists,
9 | ruppess,
10 | website,
11 | social
12 | }
13 | }) => {
14 | return (
15 |
16 |
17 |
18 |

19 |
20 |
21 |
{name}
22 |
23 |
{specialists}
24 |
25 |
{clinic}, {location}
26 |
{ruppess} Consultation Fee
27 |
28 | {website && (
29 |
30 |
31 |
32 | )}
33 | { social && social.twitter && (
34 |
35 |
36 |
37 | )}
38 | { social && social.facebook && (
39 |
40 |
41 |
42 | )}
43 | { social && social.instagram && (
44 |
45 |
46 |
47 | )}
48 | { social && social.youtube && (
49 |
50 |
51 |
52 | )}
53 |
54 |
55 |
56 |
57 |
})
58 |
59 |
60 | )
61 | };
62 |
63 | ProfileTop.propTypes = {
64 | profile: PropTypes.object.isRequired
65 | };
66 |
67 | export default ProfileTop;
68 |
--------------------------------------------------------------------------------
/client/src/components/profile/ReviewForm.js:
--------------------------------------------------------------------------------
1 | import React, {Fragment, useState } from 'react';
2 | import PropTypes from 'prop-types';
3 | import {connect} from 'react-redux';
4 | import {addReview} from '../../actions/review';
5 |
6 | const ReviewForm = ({ doctorId, addReview }) => {
7 | const [text, setText] = useState('');
8 |
9 | return (
10 |
11 |
12 |
28 |
29 |
30 | );
31 | };
32 |
33 | ReviewForm.propTypes = {
34 | addReview: PropTypes.func.isRequired
35 | };
36 |
37 | export default connect(null, {addReview})(ReviewForm);
38 |
--------------------------------------------------------------------------------
/client/src/components/profiles/ProfileItem.js:
--------------------------------------------------------------------------------
1 | import React, { Fragment, useState } from 'react';
2 | import {Link} from 'react-router-dom';
3 | import PropTypes from 'prop-types';
4 | import {connect} from 'react-redux';
5 |
6 |
7 | const ProfileItem = ({
8 | profile: {
9 | doctor: {_id, name, avatar },
10 | clinic,
11 | location,
12 | specialists,
13 | ruppess
14 | },
15 | authUser
16 | }) => {
17 |
18 | return (
19 |
20 |
21 |
22 |

23 |
24 |
25 |
26 |
{name}
27 |
{specialists}
28 |
{clinic} {location}
29 |
{ruppess} Consultation fee at clinic
30 |
31 |
32 |
33 | {authUser.isUserAuthenticated ? (
34 |
35 | Book Appointment
36 |
37 | ) : (
38 |
39 |
42 |
43 | )
44 | }
45 | View Profile
46 |
47 |
48 |
49 | )
50 | };
51 |
52 | ProfileItem.propTypes ={
53 | profile: PropTypes.object.isRequired,
54 | authUser: PropTypes.object.isRequired
55 | };
56 | const mapStateToProps =state => ({
57 | authUser: state.authUser
58 | });
59 |
60 | export default connect(mapStateToProps)(ProfileItem);
61 |
--------------------------------------------------------------------------------
/client/src/components/profiles/Profiles.js:
--------------------------------------------------------------------------------
1 | import React, {Fragment, useEffect} from 'react';
2 | import PropTypes from 'prop-types';
3 | import {connect} from 'react-redux';
4 | import Spinner from '../layout/Spinner';
5 | import {Dots} from 'react-preloaders';
6 | import ProfileItem from './ProfileItem';
7 | import {getProfiles} from '../../actions/profile';
8 |
9 | const Profiles = ({getProfiles, profile: { profiles,loading }}) => {
10 | useEffect(() => {
11 | getProfiles();
12 | },[getProfiles]);
13 |
14 | return (
15 |
16 | { loading ? :
17 |
18 |
19 |
20 |
21 |
Doctor Profiles
22 |
23 |
Book your Appointments
24 |
25 | {
26 | profiles != null ? (
27 | profiles.map(profile => (
28 |
29 | ))
30 | ) :
No Profiles found..
31 | }
32 |
33 |
34 |
35 | }
36 |
37 | )
38 | };
39 |
40 | Profiles.propTypes = {
41 | getProfiles: PropTypes.func.isRequired,
42 | profile: PropTypes.object.isRequired
43 | };
44 |
45 | const mapStateToProps = state => ({
46 | profile: state.profile
47 | });
48 |
49 | export default connect(mapStateToProps, {getProfiles})(Profiles);
50 |
--------------------------------------------------------------------------------
/client/src/components/routing/PrivateDoctorRoute.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Route, Redirect} from 'react-router-dom';
3 | import PropTypes from 'prop-types';
4 | import {connect} from 'react-redux';
5 |
6 |
7 | const PrivateDoctorRoute = ({component: Component,
8 | authDoctor: {isDoctorAuthenticated, loadingDoctor},
9 | ...rest}) => (
10 |
13 | !isDoctorAuthenticated && !loadingDoctor ? (
14 |
15 | ) : (
16 |
17 | )
18 | }
19 | />
20 | );
21 |
22 | PrivateDoctorRoute.propTypes = {
23 | authDoctor: PropTypes.object.isRequired
24 | }
25 | const mapStateToProps = state => ({
26 | authDoctor: state.authDoctor
27 | });
28 |
29 | export default connect(mapStateToProps)(PrivateDoctorRoute);
30 |
--------------------------------------------------------------------------------
/client/src/components/routing/PrivateUserRoute.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Route, Redirect} from 'react-router-dom';
3 | import PropTypes from 'prop-types';
4 | import {connect} from 'react-redux';
5 |
6 |
7 | const PrivateUserRoute = ({component: Component,
8 | authUser: {isUserAuthenticated, loadingUser},
9 | ...rest}) => (
10 |
13 | !isUserAuthenticated && !loadingUser ? (
14 |
15 | ) : (
16 |
17 | )
18 | }
19 | />
20 | );
21 |
22 | PrivateUserRoute.propTypes = {
23 | authUser: PropTypes.object.isRequired
24 | }
25 | const mapStateToProps = state => ({
26 | authUser: state.authUser
27 | });
28 |
29 | export default connect(mapStateToProps)(PrivateUserRoute);
30 |
--------------------------------------------------------------------------------
/client/src/components/user/AppointmentItems.js:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 | import {Link} from 'react-router-dom';
3 | import PropTypes from 'prop-types';
4 | import {connect} from 'react-redux';
5 | import Moment from 'react-moment';
6 | import {deleteAppointment} from '../../actions/appointment';
7 |
8 | const AppointmentItems = ({
9 | appointment, deleteAppointment,
10 | }) => {
11 |
12 | const appointments = appointment.map(appnt => (
13 |
14 |
15 |
16 |

17 |
18 |
{appnt.name}
19 |
20 |
21 |
22 |
{appnt.patientname}
23 |
Father's name: {appnt.fathername}
24 |
Age: {appnt.age}
25 |
Status: {appnt.status}
26 |
Date: {appnt.date}
27 |
Booking ID: {appnt.bookingId}
28 |
29 |
30 |
31 |
Description: {appnt.description}
32 |
33 |
34 |
35 | ));
36 | return (
37 |
38 | {appointments}
39 |
40 | );
41 | };
42 |
43 | AppointmentItems.propTypes = {
44 | appointment: PropTypes.array.isRequired,
45 | deleteAppointment: PropTypes.func.isRequired
46 | }
47 |
48 | export default connect(null, {deleteAppointment})(AppointmentItems);
49 |
--------------------------------------------------------------------------------
/client/src/components/user/Appointments.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, Fragment } from 'react';
2 | import PropTypes from 'prop-types';
3 | import {connect} from 'react-redux';
4 | import Spinner from '../layout/Spinner';
5 | import {Dots} from 'react-preloaders';
6 | import AppointmentItems from './AppointmentItems';
7 | import {getAppointments, deleteAccountUser} from '../../actions/appointment';
8 |
9 | const Appointments = ({
10 | getAppointments,
11 | deleteAccountUser,
12 | authUser: {user},
13 | appointment: {appointments, loading}
14 | }) => {
15 | useEffect(() => {
16 | getAppointments();
17 | }, [getAppointments])
18 |
19 | return (
20 |
21 | { loading && appointments !== null ? :
22 |
23 |
24 |
25 |
26 |
Appointments
27 |
{' '}
28 | {user && (user.name.split(' ')[0].toLocaleUpperCase())}'s appointments
29 |
30 |
34 |
35 |
36 |
37 |
38 | {appointments !== null && appointments.appointments.length !== 0 ? (
39 |
44 | ) : (
45 |
No Appointments found...
46 | )
47 | }
48 |
49 |
50 |
51 |
52 | }
53 |
54 | )
55 | }
56 |
57 | Appointments.propTypes = {
58 | getAppointments: PropTypes.func.isRequired,
59 | deleteAccountUser: PropTypes.func.isRequired,
60 | authUser: PropTypes.object.isRequired,
61 | appointment: PropTypes.object.isRequired
62 | }
63 |
64 | const mapStateToProps = state => ({
65 | authUser: state.authUser,
66 | appointment: state.appointment
67 | });
68 |
69 | export default connect(mapStateToProps, {getAppointments, deleteAccountUser})(Appointments);
70 |
--------------------------------------------------------------------------------
/client/src/img/doctor8.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/client/src/img/undraw_account_490v.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/client/src/img/undraw_forms_78yw.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/client/src/img/undraw_medical_research_qg4d.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/client/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 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 |
6 | ReactDOM.render(
7 |
8 |
9 | ,
10 | document.getElementById('root')
11 | );
12 |
--------------------------------------------------------------------------------
/client/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/client/src/reducers/alert.js:
--------------------------------------------------------------------------------
1 | import { SET_ALERT, REMOVE_ALERT } from '../actions/types';
2 |
3 | const initialState = [];
4 |
5 | export default function( state = initialState, action) {
6 | const {type, payload} = action;
7 | switch (type) {
8 | case SET_ALERT:
9 | return [...state, payload];
10 | case REMOVE_ALERT:
11 | return state.filter(alert => alert.id !== payload);
12 | default:
13 | return state;
14 | }
15 | }
--------------------------------------------------------------------------------
/client/src/reducers/appointment.js:
--------------------------------------------------------------------------------
1 | import {
2 | GET_APPOINTMENTS,
3 | ADD_APPOINTMENTS,
4 | UPDATE_APPOINTMENTS,
5 | APPOINTMENT_ERROR,
6 | } from '../actions/types';
7 |
8 | const initalState = {
9 | appointments: null,
10 | loading: true,
11 | error: {}
12 | }
13 |
14 | export default function(state=initalState, action) {
15 | const {type, payload} = action;
16 |
17 | switch(type) {
18 | case GET_APPOINTMENTS:
19 | return {
20 | ...state,
21 | appointments: payload,
22 | loading: false
23 | };
24 | case ADD_APPOINTMENTS:
25 | return {
26 | ...state,
27 | appointments: payload,
28 | loading: false
29 | };
30 | case UPDATE_APPOINTMENTS:
31 | return {
32 | ...state,
33 | appointments: payload,
34 | loading: false
35 | }
36 | case APPOINTMENT_ERROR:
37 | return {
38 | ...state,
39 | error: payload,
40 | loading: false
41 | };
42 | default:
43 | return state;
44 | }
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/client/src/reducers/authDoctor.js:
--------------------------------------------------------------------------------
1 | import {
2 | REGISTER_DOCTOR_SUCCESS,
3 | REGISTER_DOCTOR_FAIL,
4 | DOCTOR_LOADED,
5 | AUTH_DOCTOR_ERROR,
6 | LOGIN_DOCTOR_SUCCESS,
7 | LOGIN_DOCTOR_FAIL,
8 | LOGOUT_DOCTOR,
9 | DELETE_ACCOUNT
10 |
11 | } from '../actions/types';
12 |
13 | const initialState = {
14 | token: localStorage.getItem('token'),
15 | isDoctorAuthenticated: null,
16 | loadingDoctor: true,
17 | doctor: null
18 | }
19 |
20 | export default function(state = initialState, action) {
21 | const {type, payload} = action;
22 | switch (type) {
23 | case DOCTOR_LOADED:
24 | return {
25 | ...state,
26 | isDoctorAuthenticated: true,
27 | loadingDoctor: false,
28 | doctor: payload
29 | };
30 | case REGISTER_DOCTOR_SUCCESS:
31 | case LOGIN_DOCTOR_SUCCESS:
32 | localStorage.setItem('token', payload.token);
33 | return {
34 | ...state,
35 | ...payload,
36 | isDoctorAuthenticated: true,
37 | loadingDoctor: false
38 | };
39 | case REGISTER_DOCTOR_FAIL:
40 | case LOGIN_DOCTOR_FAIL:
41 | case DELETE_ACCOUNT:
42 | localStorage.removeItem('token');
43 | return {
44 | ...state,
45 | token: null,
46 | isDoctorAuthenticated: false,
47 | loadingDoctor: false
48 | };
49 | case LOGOUT_DOCTOR:
50 | case AUTH_DOCTOR_ERROR:
51 | localStorage.removeItem('token');
52 | return {
53 | ...state,
54 | token: null,
55 | isDoctorAuthenticated: false,
56 | loadingDoctor: false
57 | };
58 | default:
59 | return state;
60 | }
61 | }
--------------------------------------------------------------------------------
/client/src/reducers/authUser.js:
--------------------------------------------------------------------------------
1 | import {
2 | REGISTER_USER_SUCCESS,
3 | REGISTER_USER_FAIL,
4 | USER_LOADED,
5 | AUTH_USER_ERROR,
6 | LOGIN_USER_SUCCESS,
7 | LOGIN_USER_FAIL,
8 | LOGOUT_USER,
9 | DELETE_USER_ACCOUNT
10 | } from '../actions/types';
11 |
12 | const initialState = {
13 | token: localStorage.getItem('token'),
14 | isUserAuthenticated: null,
15 | loadingUser: true,
16 | user: null
17 | }
18 |
19 | export default function(state = initialState, action) {
20 | const {type, payload} = action;
21 | switch (type) {
22 | case USER_LOADED:
23 | return {
24 | ...state,
25 | isUserAuthenticated: true,
26 | loadingUser: false,
27 | user: payload
28 | };
29 | case REGISTER_USER_SUCCESS:
30 | case LOGIN_USER_SUCCESS:
31 | localStorage.setItem('token', payload.token);
32 | return {
33 | ...state,
34 | ...payload,
35 | isUserAuthenticated: true,
36 | loadingUser: false
37 | };
38 | case REGISTER_USER_FAIL:
39 | case LOGIN_USER_FAIL:
40 | localStorage.removeItem('token');
41 | return {
42 | ...state,
43 | token: null,
44 | isUserAuthenticated: false,
45 | loadingUser: false
46 | };
47 | case AUTH_USER_ERROR:
48 | case LOGOUT_USER:
49 | case DELETE_USER_ACCOUNT:
50 | localStorage.removeItem('token');
51 | return {
52 | ...state,
53 | token: null,
54 | isUserAuthenticated: false,
55 | loadingUser: false
56 | };
57 | default:
58 | return state;
59 | }
60 | }
--------------------------------------------------------------------------------
/client/src/reducers/index.js:
--------------------------------------------------------------------------------
1 | import {combineReducers} from 'redux';
2 | import alert from './alert';
3 | import authDoctor from './authDoctor';
4 | import authUser from './authUser';
5 | import profile from './profile';
6 | import appointment from './appointment';
7 |
8 | export default combineReducers({
9 | alert,
10 | authDoctor,
11 | authUser,
12 | profile,
13 | appointment
14 | });
15 |
--------------------------------------------------------------------------------
/client/src/reducers/profile.js:
--------------------------------------------------------------------------------
1 | import {
2 | GET_PROFILE,
3 | GET_PROFILE_BY_ID,
4 | GET_PROFILES,
5 | UPDATE_PROFILE,
6 | PROFILE_ERROR,
7 | CLEAR_PROFILE,
8 | ADD_REVIEW,
9 | ADD_REVIEW_ERROR,
10 | REMOVE_REVIEW
11 | } from '../actions/types';
12 |
13 | const initialState = {
14 | profileById: null,
15 | profile: null,
16 | profiles: [],
17 | loading: true,
18 | error: {}
19 | }
20 |
21 | export default function( state = initialState, action) {
22 | const {type, payload} = action;
23 |
24 | switch (type) {
25 | case GET_PROFILE:
26 | case UPDATE_PROFILE:
27 | return {
28 | ...state,
29 | profile: payload,
30 | loading: false
31 | };
32 | case GET_PROFILE_BY_ID:
33 | return {
34 | ...state,
35 | profileById: payload,
36 | loading: false
37 | };
38 |
39 | case ADD_REVIEW:
40 | return {
41 | ...state,
42 | profileById: { ...state.profileById, review: payload },
43 | loading: false
44 | };
45 | case REMOVE_REVIEW:
46 | return {
47 | ...state,
48 | profileById: {
49 | ...state.profileById,
50 | review: state.profileById.review.filter(comment => comment._id !== payload)
51 | },
52 | loading: false
53 | };
54 | case GET_PROFILES:
55 | return {
56 | ...state,
57 | profiles: payload,
58 | loading: false
59 | };
60 | case PROFILE_ERROR:
61 | case ADD_REVIEW_ERROR:
62 | return {
63 | ...state,
64 | error: payload,
65 | loading: false
66 | };
67 | case CLEAR_PROFILE:
68 | return {
69 | ...state,
70 | profile: null,
71 | loading: false
72 | };
73 |
74 | default:
75 | return state;
76 | }
77 | }
--------------------------------------------------------------------------------
/client/src/reducers/review.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeevantheDev/Doctor-Assigned/87f6c1cb7e814e0c5c628d1e5393a227c9719487/client/src/reducers/review.js
--------------------------------------------------------------------------------
/client/src/store.js:
--------------------------------------------------------------------------------
1 | import { createStore, applyMiddleware } from 'redux';
2 | import { composeWithDevTools } from 'redux-devtools-extension';
3 | import thunk from 'redux-thunk';
4 | import rootReducer from './reducers';
5 |
6 | const initialState = {};
7 |
8 | const middleWare = [thunk];
9 |
10 | const store = createStore(rootReducer, initialState, composeWithDevTools(applyMiddleware(...middleWare)));
11 |
12 | export default store;
--------------------------------------------------------------------------------
/client/src/utils/setAuthToken.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 |
3 | const setAuthToken = token => {
4 | if(token) {
5 | axios.defaults.headers.common['x-auth-token'] = token;
6 | } else {
7 | delete axios.defaults.headers.common['x-auth-token'];
8 | }
9 | }
10 |
11 | export default setAuthToken;
--------------------------------------------------------------------------------
/config/keys.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | mongoURI: "mongodb://localhost:27017/doctorconnectorDB"
3 | };
--------------------------------------------------------------------------------
/middleware/authDoctor.js:
--------------------------------------------------------------------------------
1 | require('dotenv').config();
2 | const jwt = require('jsonwebtoken');
3 |
4 | module.exports = function(req, res, next) {
5 | // Get token from the header
6 | const token = req.header('x-auth-token');
7 |
8 | // Check if no token
9 | if(!token) {
10 | return res.status(401).json({msg: "No token"});
11 | }
12 |
13 | // Verify token
14 | try {
15 | const decoded = jwt.verify(token, process.env.jwtSecret);
16 |
17 | req.doctor = decoded.doctor;
18 | next();
19 | } catch (err) {
20 | res.status(401).json({ msg: "token is not valid " });
21 | }
22 | }
--------------------------------------------------------------------------------
/middleware/authUser.js:
--------------------------------------------------------------------------------
1 | require('dotenv').config();
2 | const jwt = require('jsonwebtoken');
3 |
4 | module.exports = function(req, res, next) {
5 | // Get token from the header
6 | const token = req.header('x-auth-token');
7 |
8 | // Check if no token
9 | if(!token) {
10 | return res.status(401).json({msg: "No token"});
11 | }
12 |
13 | // Verify token
14 | try {
15 | const decoded = jwt.verify(token, process.env.jwtSecret);
16 |
17 | req.user = decoded.user;
18 | next();
19 | } catch (err) {
20 | res.status(401).json({ msg: "token is not valid " });
21 | }
22 | }
--------------------------------------------------------------------------------
/models/Doctor.js:
--------------------------------------------------------------------------------
1 | const mongoose = require ('mongoose');
2 |
3 | const DoctorSchema = new mongoose.Schema({
4 | name: {
5 | type: String,
6 | required: true
7 | },
8 | email: {
9 | type: String,
10 | required: true,
11 | unique: true
12 | },
13 | password: {
14 | type: String,
15 | required: true
16 | },
17 | avatar: {
18 | type: String
19 | },
20 | date: {
21 | type: Date,
22 | default: Date.now
23 | }
24 | });
25 |
26 | module.exports = Doctor = mongoose.model('doctor', DoctorSchema);
--------------------------------------------------------------------------------
/models/Profile.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 | const Schema = mongoose.Schema;
3 |
4 | const ProfileSchema = new mongoose.Schema({
5 | doctor: {
6 | type: mongoose.Schema.Types.ObjectId,
7 | ref: 'doctor'
8 | },
9 | clinic: {
10 | type: String
11 | },
12 | website: {
13 | type: String
14 | },
15 | location: {
16 | type: String
17 | },
18 | timing: {
19 | type: String,
20 | required: true
21 | },
22 | status: {
23 | type: String,
24 | required: true
25 | },
26 | specialists: {
27 | type: String
28 | },
29 | ruppess: {
30 | type: String
31 | },
32 | bio: {
33 | type: String
34 | },
35 | patients: [
36 | {
37 | user: {
38 | type: Schema.Types.ObjectId,
39 | ref: 'users'
40 | },
41 | bookingId: {
42 | type: Number
43 | },
44 | patientname: {
45 | type: String,
46 | required: true
47 | },
48 | fathername: {
49 | type: String,
50 | },
51 | status: {
52 | type: String,
53 | },
54 | age: {
55 | type: Number,
56 |
57 | },
58 | date: {
59 | type: Date,
60 | },
61 | description: {
62 | type: String,
63 | required: true
64 | },
65 | name: {
66 | type: String
67 | },
68 | avatar: {
69 | type: String
70 | },
71 | date: {
72 | type: Date,
73 | default: Date.now
74 | }
75 | }
76 | ],
77 | review: [
78 | {
79 | user: {
80 | type: Schema.Types.ObjectId,
81 | ref: 'users'
82 | },
83 | text: {
84 | type: String,
85 | require: true
86 | },
87 | name: {
88 | type: String
89 | },
90 | avatar: {
91 | type: String
92 | },
93 | date: {
94 | type: Date,
95 | default: Date.now
96 | }
97 | }
98 | ],
99 | experience : [
100 | {
101 | position: {
102 | type: String,
103 | required: true
104 | },
105 | medical: {
106 | type: String,
107 | required: true
108 | },
109 | location: {
110 | type: String
111 | },
112 | from: {
113 | type: Date,
114 | required: true
115 | },
116 | to: {
117 | type: Date
118 | },
119 | current: {
120 | type: Boolean,
121 | default: false
122 | },
123 | description: {
124 | type: String
125 | }
126 | }
127 | ],
128 | education: [
129 | {
130 | school: {
131 | type: String,
132 | required: true
133 | },
134 | degree: {
135 | type: String,
136 | required: true
137 | },
138 | fieldofstudy: {
139 | type: String,
140 | required: true
141 | },
142 | from: {
143 | type: Date,
144 | required: true
145 | },
146 | to: {
147 | type: Date
148 | },
149 | current: {
150 | type: Boolean,
151 | default: false
152 | },
153 | description: {
154 | type: String
155 | }
156 | }
157 | ],
158 | social: {
159 | youtube: {
160 | type: String
161 | },
162 | twitter: {
163 | type: String
164 | },
165 | facebook: {
166 | type: String
167 | },
168 | instagram: {
169 | type: String
170 | }
171 | },
172 | date: {
173 | type: Date,
174 | default: Date.now
175 | }
176 | });
177 |
178 | module.exports = Profile = mongoose.model('profile', ProfileSchema);
179 |
--------------------------------------------------------------------------------
/models/User.js:
--------------------------------------------------------------------------------
1 | const mongoose = require ('mongoose');
2 | const Schema = mongoose.Schema;
3 |
4 | const UserSchema = new mongoose.Schema({
5 | name: {
6 | type: String,
7 | required: true
8 | },
9 | email: {
10 | type: String,
11 | required: true,
12 | unique: true
13 | },
14 | password: {
15 | type: String,
16 | required: true
17 | },
18 | avatar: {
19 | type: String
20 | },
21 | appointments: [
22 | {
23 | doctor: {
24 | type: Schema.Types.ObjectId,
25 | ref: 'doctors'
26 | },
27 | bookingId: {
28 | type: Number
29 | },
30 | patientname: {
31 | type: String,
32 | required: true
33 | },
34 | fathername: {
35 | type: String,
36 | },
37 | status: {
38 | type: String,
39 | },
40 | age: {
41 | type: Number,
42 | },
43 | date: {
44 | type: Date,
45 | },
46 | description: {
47 | type: String,
48 | required: true
49 | },
50 | name: {
51 | type: String
52 | },
53 | avatar: {
54 | type: String
55 | },
56 | date: {
57 | type: Date,
58 | default: Date.now
59 | }
60 | }
61 | ],
62 | date: {
63 | type: Date,
64 | default: Date.now
65 | }
66 | });
67 |
68 | module.exports = User = mongoose.model('user', UserSchema);
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "doctor_connector",
3 | "version": "1.0.0",
4 | "description": "By Jeevan Jyoti Dash",
5 | "main": "server.js",
6 | "scripts": {
7 | "start": "node server.js",
8 | "server": "nodemon server.js",
9 | "client": "npm start --prefix client",
10 | "dev": "concurrently \"npm run server\" \"npm run client\""
11 | },
12 | "author": "JeevanTheDev",
13 | "license": "ISC",
14 | "dependencies": {
15 | "bcryptjs": "^2.4.3",
16 | "body-parser": "^1.19.0",
17 | "bootstrap": "^4.5.0",
18 | "chart.js": "^2.9.3",
19 | "config": "^3.3.1",
20 | "dotenv": "^8.2.0",
21 | "express": "^4.17.1",
22 | "express-validator": "^6.6.0",
23 | "gravatar": "^1.8.0",
24 | "jsonwebtoken": "^8.5.1",
25 | "moment": "^2.27.0",
26 | "mongoose": "^5.9.21",
27 | "passport": "^0.4.1",
28 | "passport-jwt": "^4.0.0",
29 | "react-bootstrap": "^1.1.1",
30 | "react-chartjs-2": "^2.9.0",
31 | "react-router-redux": "^4.0.8",
32 | "redux": "^4.0.5",
33 | "request": "^2.88.2",
34 | "validator": "^13.1.1"
35 | },
36 | "devDependencies": {
37 | "concurrently": "^5.2.0",
38 | "nodemon": "^2.0.4"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/routes/api/appointment.js:
--------------------------------------------------------------------------------
1 | require('dotenv').config();
2 | const express = require('express');
3 | const router = express.Router();
4 | const { check, validationResult } = require('express-validator');
5 |
6 | const authUser = require('../../middleware/authUser');
7 |
8 | const User = require('../../models/User');
9 | const Doctor = require('../../models/Doctor');
10 | const Profile = require('../../models/Profile');
11 |
12 |
13 | // @route Post api/appointment/:doctor_id
14 | // @desc Create a user appointment
15 | // @access Private
16 | router.post('/:doctor_id', [authUser,
17 | [
18 | check('patientname', 'Patient name is required')
19 | .not()
20 | .isEmpty(),
21 | check('fathername', 'Father name is required')
22 | .not()
23 | .isEmpty(),
24 | check('age', 'Age is required')
25 | .not()
26 | .isEmpty(),
27 | check('description', 'Description is required')
28 | .not()
29 | .isEmpty()
30 | ]
31 | ], async (req, res) => {
32 | const errors = validationResult(req);
33 | if(!errors.isEmpty()) {
34 | return res.status(400).json({ errors: errors.array() });
35 | }
36 | try {
37 | const user = await User.findById(req.user.id).select('-password');
38 | const doctor = await Doctor.findById(req.params.doctor_id).select('-password');
39 | const profile = await Profile.findOne({ doctor: req.params.doctor_id });
40 |
41 | // Create booking id
42 | function appointmentGenerator() {
43 |
44 | this.length = 8;
45 | this.timestamp = +new Date;
46 |
47 | var _getRandomInt = function( min, max ) {
48 | return Math.floor( Math.random() * ( max - min + 1 ) ) + min;
49 | }
50 |
51 | this.generate = function() {
52 | var ts = this.timestamp.toString();
53 | var parts = ts.split( "" ).reverse();
54 | var id = "";
55 |
56 | for( var i = 0; i < this.length; ++i ) {
57 | var index = _getRandomInt( 0, parts.length - 1 );
58 | id += parts[index];
59 | }
60 |
61 | return id;
62 | }
63 | }
64 |
65 | const create_id = new appointmentGenerator();
66 | const appointmentId = create_id.generate();
67 |
68 | const newPatient = {
69 | bookingId: appointmentId,
70 | patientname: req.body.patientname,
71 | fathername: req.body.fathername,
72 | status: req.body.status,
73 | age: req.body.age,
74 | date: req.body.date,
75 | description: req.body.description,
76 | avatar: user.avatar,
77 | name: user.name,
78 | user: req.user.id
79 | }
80 |
81 | const newAppointment = {
82 | bookingId: appointmentId,
83 | patientname: req.body.patientname,
84 | fathername: req.body.fathername,
85 | status: req.body.status,
86 | age: req.body.age,
87 | date: req.body.date,
88 | description: req.body.description,
89 | avatar: doctor.avatar,
90 | name: doctor.name,
91 | doctor: doctor.id
92 | }
93 |
94 | profile.patients.unshift(newPatient);
95 |
96 | await profile.save();
97 |
98 | user.appointments.unshift(newAppointment);
99 | await user.save();
100 |
101 | res.json(user);
102 | } catch (err) {
103 | console.error(err.message);
104 | res.status(500).send("Server error");
105 | }
106 | });
107 |
108 | // // @route Delete api/appointment/:appointment_id
109 | // // @desc Delete a appointment
110 | // // @access Private
111 | // router.delete('/:appointment_id', authUser, async (req, res) => {
112 | // try {
113 | // const user = await User.findById(req.user.id).select('-password');
114 |
115 | // const doctorId = user.appointments
116 | // .map(item => {
117 | // if(item.id === req.params.appointment_id) {
118 | // return item.doctor;
119 | // }
120 | // })
121 | // const profile = await Profile.findOne({ doctor: doctorId[0]});
122 |
123 | // // Get the remove index for user
124 | // const removeIndexUser = user.appointments
125 | // .map(item => item.id)
126 | // .indexOf(req.params.appointment_id);
127 |
128 | // user.appointments.splice(removeIndexUser, 1);
129 | // await user.save();
130 |
131 | // // Get the remove index for doctor
132 | // const removeIndexDoctor = profile.patients
133 | // .map(item => item.id)
134 | // .indexOf(req.params.appointment_id);
135 |
136 | // profile.patients.splice(removeIndexDoctor, 1);
137 | // await profile.save();
138 |
139 | // // Return user
140 | // res.json(user);
141 | // } catch (err) {
142 |
143 | // }
144 | // });
145 |
146 |
147 | module.exports = router;
--------------------------------------------------------------------------------
/routes/api/authDoctor.js:
--------------------------------------------------------------------------------
1 | require('dotenv').config();
2 | const express = require('express');
3 | const router = express.Router();
4 | const { check, validationResult } = require('express-validator');
5 | const jwt = require('jsonwebtoken');
6 | const bcrypt = require('bcryptjs');
7 | const authDoctor = require('../../middleware/authDoctor');
8 |
9 | const Doctor = require('../../models/Doctor');
10 |
11 | // @route GET api/authDoctor
12 | // @desc Tests auth Doctor route
13 | // @access Public
14 | router.get('/', authDoctor, async(req, res) => {
15 | try {
16 | const doctor = await Doctor.findById(req.doctor.id).select('-password');
17 | res.json(doctor);
18 | } catch (err) {
19 | console.error(err.message);
20 | res.status(500).send("Server Error");
21 | }
22 | });
23 |
24 | // @route post api/authDoctor
25 | // @desc Authenticate Doctor and get Token
26 | // @access Public
27 | router.post('/',
28 | [
29 | check('email', 'Please include a valid email').isEmail(),
30 | check('password', 'Password required').exists()
31 | ],
32 | async (req, res) => {
33 | const errors = validationResult(req);
34 | if(!errors.isEmpty()) {
35 | return res.status(400).json({ errors: errors.array() });
36 | }
37 |
38 | const {email, password} = req.body;
39 |
40 | try {
41 | // If Doctor exists
42 | let doctor = await Doctor.findOne({ email });
43 |
44 | if(!doctor) {
45 | return res.status(400).json({ errors: [{ msg: 'Invalid cridentials' }] });
46 | }
47 |
48 | const isMatch = await bcrypt.compare(password, doctor.password);
49 |
50 | if(!isMatch) {
51 | return res.status(400).json({ errors: [{ msg: 'Invalid cridentials' }] });
52 | }
53 |
54 | // Return jsonwebtoken
55 |
56 | const payload = {
57 | doctor: {
58 | id: doctor.id
59 | }
60 | }
61 |
62 | jwt.sign(payload, process.env.jwtSecret,
63 | {expiresIn: 36000},
64 | (err, token) => {
65 | if(err) throw err;
66 | res.json({ token });
67 | });
68 |
69 | } catch (err) {
70 | console.error(err.message);
71 | res.status(500).send('Server error');
72 | }
73 | });
74 |
75 | module.exports = router;
--------------------------------------------------------------------------------
/routes/api/authUser.js:
--------------------------------------------------------------------------------
1 | require('dotenv').config();
2 | const express = require('express');
3 | const router = express.Router();
4 | const { check, validationResult } = require('express-validator');
5 | const jwt = require('jsonwebtoken');
6 | const bcrypt = require('bcryptjs');
7 | const authUser = require('../../middleware/authUser');
8 |
9 | const User = require('../../models/User');
10 | const Doctor = require('../../models/Doctor');
11 | const Profile = require('../../models/Profile');
12 |
13 | // @route GET api/authUser
14 | // @desc Tests auth User route
15 | // @access Public
16 | router.get('/', authUser, async(req, res) => {
17 | try {
18 | const user = await User.findById(req.user.id).select('-password');
19 | res.json(user);
20 | } catch (err) {
21 | console.error(err.message);
22 | res.status(500).send("Server Error");
23 | }
24 | });
25 |
26 | // @route post api/authUser
27 | // @desc Authenticate User and get Token
28 | // @access Public
29 | router.post('/',
30 | [
31 | check('email', 'Please include a valid email').isEmail(),
32 | check('password', 'Password required').exists()
33 | ],
34 | async (req, res) => {
35 | const errors = validationResult(req);
36 | if(!errors.isEmpty()) {
37 | return res.status(400).json({ errors: errors.array() });
38 | }
39 |
40 | const {email, password} = req.body;
41 |
42 | try {
43 | // If User exists
44 | let user = await User.findOne({ email });
45 |
46 | if(!user) {
47 | return res.status(400).json({ errors: [{ msg: 'Invalid cridentials' }] });
48 | }
49 |
50 | const isMatch = await bcrypt.compare(password, user.password);
51 |
52 | if(!isMatch) {
53 | return res.status(400).json({ errors: [{ msg: 'Invalid cridentials' }] });
54 | }
55 |
56 | // Return jsonwebtoken
57 |
58 | const payload = {
59 | user: {
60 | id: user.id
61 | }
62 | }
63 |
64 | jwt.sign(payload, process.env.jwtSecret,
65 | {expiresIn: 36000},
66 | (err, token) => {
67 | if(err) throw err;
68 | res.json({ token });
69 | });
70 |
71 | } catch (err) {
72 | console.error(err.message);
73 | res.status(500).send('Server error');
74 | }
75 | });
76 |
77 | // @route Delete api/authUser/:appointment_id
78 | // @desc Delete a appointment
79 | // @access Private
80 | router.delete('/:appointment_id', authUser, async (req, res) => {
81 | try {
82 | const user = await User.findById(req.user.id).select('-password');
83 |
84 | const doctorId = user.appointments
85 | .map(item => (
86 | item.id === req.params.appointment_id
87 | ) ? item.doctor : null
88 | );
89 |
90 | const newId = doctorId.filter( doctor => doctor !== null);
91 |
92 | const profile = await Profile.findOne({ doctor: newId[0]});
93 |
94 | // Get the remove index for user
95 | const removeIndexUser = user.appointments
96 | .map(item => item.id)
97 | .indexOf(req.params.appointment_id);
98 |
99 | const removeIndex = user.appointments[removeIndexUser].bookingId;
100 | user.appointments.splice(removeIndexUser, 1);
101 |
102 | await user.save();
103 |
104 | if(profile !== null) {
105 | const indexDoctor = profile.patients
106 | .map(item => item.bookingId)
107 | .indexOf(removeIndex);
108 |
109 | profile.patients.splice(indexDoctor, 1);
110 |
111 | await profile.save();
112 |
113 | } else {
114 | console.log("No Dcotor exist");
115 | }
116 |
117 | // Return user
118 | res.json(user);
119 | } catch (err) {
120 | console.error(err.message);
121 | res.status(500).send("Server error");
122 | }
123 | });
124 |
125 | // @route Delete api/authUser
126 | // @desc Delete profile, doctor
127 | // @access Private
128 | router.delete('/', authUser, async (req, res) => {
129 | try {
130 | // Remove user
131 | await User.findOneAndRemove({ _id: req.user.id });
132 | res.json({ msg: "User deleted" });
133 | } catch (err) {
134 | console.error(err.message);
135 | res.status(500).send('Server error');
136 | }
137 | });
138 |
139 | module.exports = router;
--------------------------------------------------------------------------------
/routes/api/doctors.js:
--------------------------------------------------------------------------------
1 | require('dotenv').config();
2 | const express = require('express');
3 | const router = express.Router();
4 | const gravtar = require('gravatar');
5 | const { check, validationResult } = require('express-validator');
6 | const bcrypt = require('bcryptjs');
7 | const jwt = require('jsonwebtoken');
8 | const Doctor = require('../../models/Doctor');
9 |
10 | // @route Post api/doctors
11 | // @desc Register Doctor
12 | // @access Public
13 | router.post('/',
14 | [
15 | check('name', 'Name is required')
16 | .not()
17 | .isEmpty(),
18 | check('email', 'Please include a valid email').isEmail(),
19 | check('password', 'Please enter a password min 6 to 10 charcters').isLength({ min: 6 })
20 | ],
21 | async (req, res) => {
22 | const errors = validationResult(req);
23 | if(!errors.isEmpty()) {
24 | return res.status(400).json({ errors: errors.array() });
25 | }
26 | const { name, email, password } = req.body;
27 |
28 | try {
29 | // See if user exists
30 | let doctor = await Doctor.findOne({ email });
31 |
32 | if(doctor) {
33 | return res.status(400).json({ errors: [{ msg: 'Doctor already exists' }] });
34 | }
35 |
36 | // Get doctors gravtar
37 |
38 | const avatar = gravtar.url(email, {
39 | s: '200',
40 | r: 'pg',
41 | d: 'mm'
42 | });
43 |
44 | doctor = new Doctor({
45 | name,
46 | email,
47 | avatar,
48 | password
49 | });
50 |
51 | // Encrypt password
52 |
53 | const salt = await bcrypt.genSalt(10);
54 |
55 | doctor.password = await bcrypt.hash(password, salt);
56 |
57 | await doctor.save();
58 |
59 | //Return jsonwebtoken
60 |
61 | const payload = {
62 | doctor: {
63 | id: doctor.id
64 | }
65 | }
66 |
67 | jwt.sign(payload, process.env.jwtSecret,
68 | { expiresIn: 360000 },
69 | (err, token) => {
70 | if (err) throw err;
71 | res.json({ token });
72 | });
73 |
74 | } catch (err) {
75 | console.error(err.message);
76 | res.status(500).send('Server error');
77 | }
78 | });
79 |
80 | module.exports = router;
--------------------------------------------------------------------------------
/routes/api/profile.js:
--------------------------------------------------------------------------------
1 | require('dotenv').config();
2 | const express = require('express');
3 | const request = require('request');
4 | const router = express.Router();
5 | const authDoctor = require('../../middleware/authDoctor');
6 | const authUser = require('../../middleware/authUser');
7 | const { check, validationResult} = require('express-validator');
8 |
9 | const Doctor = require('../../models/Doctor');
10 | const User = require('../../models/User');
11 | const Profile = require('../../models/Profile');
12 |
13 | // @route GET api/profile/me
14 | // @desc Get current doctor profile
15 | // @access Private
16 | router.get('/me', authDoctor, async (req, res) => {
17 | try {
18 | const profile = await Profile.findOne({ doctor: req.doctor.id }).populate('doctor', ['name', 'avatar']);
19 | if(!profile) {
20 | return res.status(400).json({ msg: "No Profile for this doctor "});
21 | }
22 |
23 | res.json(profile);
24 | } catch (err) {
25 | console.error(err.message);
26 | res.status(500).send("Server error");
27 | }
28 | });
29 |
30 | // @route Post api/profile
31 | // @desc Create or update a doctor profile
32 | // @access Private
33 | router.post('/',
34 | [
35 | authDoctor,
36 | [
37 | check('status', 'Status is required')
38 | .not()
39 | .isEmpty()
40 | ]
41 | ],
42 | async (req, res) => {
43 | const errors = validationResult(req);
44 | if(!errors.isEmpty()) {
45 | return res.status(400).json({ errors: errors.array() });
46 | }
47 |
48 | const {
49 | clinic,
50 | website,
51 | location,
52 | timing,
53 | bio,
54 | status,
55 | specialists,
56 | ruppess,
57 | youtube,
58 | facebook,
59 | twitter,
60 | instagram,
61 | } = req.body;
62 |
63 | // Build profile object
64 | const profileFields = {};
65 | profileFields.doctor = req.doctor.id;
66 | if(clinic) profileFields.clinic = clinic;
67 | if(website) profileFields.website = website;
68 | if(location) profileFields.location = location;
69 | if(timing) profileFields.timing = timing;
70 | if(bio) profileFields.bio = bio;
71 | if(status) profileFields.status = status;
72 | if(specialists) profileFields.specialists = specialists;
73 | if(ruppess) profileFields.ruppess = ruppess;
74 |
75 | //Build social objects
76 | profileFields.social = {}
77 | if (youtube) profileFields.social.youtube = req.body.youtube;
78 | if (twitter) profileFields.social.twitter = req.body.twitter;
79 | if (facebook) profileFields.social.facebook = req.body.facebook;
80 | if (instagram) profileFields.social.instagram = req.body.instagram;
81 |
82 | try {
83 | let profile = await Profile.findOne({ doctor: req.doctor.id });
84 |
85 | if(profile) {
86 | // Update
87 | profile = await Profile.findOneAndUpdate(
88 | { doctor: req.doctor.id },
89 | { $set: profileFields },
90 | { new: true }
91 | );
92 |
93 | return res.json(profile);
94 | }
95 |
96 | // Create
97 | profile = new Profile(profileFields);
98 | await profile.save();
99 | res.json(profile);
100 | } catch (err) {
101 | console.error(err.message);
102 | res.status(500).send("Server error");
103 | }
104 | });
105 |
106 | // @route Get api/profile
107 | // @desc Get all profiles
108 | // @access Public
109 |
110 | router.get('/', async (req, res) => {
111 | try {
112 | const profiles = await Profile.find().populate('doctor', ['name', 'avatar']);
113 | res.json(profiles);
114 | } catch (err) {
115 | console.error(err.message);
116 | res.status(500).send('Server error');
117 |
118 | }
119 | });
120 |
121 | // @route Get api/profile/doctor/:doctor_id
122 | // @desc Get profile by doctor id
123 | // @access Public
124 |
125 | router.get('/doctor/:doctor_id', async (req, res) => {
126 | try {
127 | const profile = await Profile.findOne({ doctor: req.params.doctor_id }).populate('doctor', ['name', 'avatar']);
128 | if(!profile) {
129 | return res.status(400).json({ msg: "There is no profile" });
130 | }
131 | res.json(profile);
132 | } catch (err) {
133 | console.error(err.message);
134 | if(err.kind === 'ObjectId') {
135 | return res.status(400).json({ msg: "There is no profile" });
136 | }
137 | res.status(500).send('Server error');
138 | }
139 | });
140 |
141 | // @route Post api/profile/doctor/:doctor_id
142 | // @desc Comment on a profile
143 | // @access Private
144 | router.post('/doctor/:doctor_id', [authUser,
145 | [
146 | check('text', 'Text is required').not().isEmpty()
147 | ]
148 | ], async (req, res) => {
149 | const errors = validationResult(req);
150 | if(!errors.isEmpty()) {
151 | return res.status(400).json({ errors: errors.array() });
152 | }
153 | try {
154 | const user = await User.findById(req.user.id).select('-password');
155 | const profile = await Profile.findOne({ doctor: req.params.doctor_id });
156 |
157 | const newReview = {
158 | text: req.body.text,
159 | name: user.name,
160 | avatar: user.avatar,
161 | user: req.user.id
162 | };
163 |
164 | profile.review.unshift(newReview);
165 |
166 | await profile.save();
167 | res.json(profile);
168 | } catch (err) {
169 | console.error(err.message);
170 | res.status(500).send("Server error");
171 | }
172 | });
173 |
174 | // @route Delete api/profile/doctor/:doctor_id/:review_id
175 | // @desc Delete comment on a profile
176 | // @access Private
177 | router.delete('/doctor/:doctor_id/:review_id', authUser, async (req, res) => {
178 | try {
179 | const profile = await Profile.findOne({ doctor: req.params.doctor_id });
180 |
181 | // Pill out review
182 | const review = profile.review.find(review => review.id === req.params.review_id);
183 |
184 | const text = review.text;
185 |
186 | // Make sure review exists
187 | if(!review) {
188 | return res.status(404).json({ msg: "Review not exist "});
189 | }
190 | // Check user
191 | if(review.user.toString() !== req.user.id) {
192 | return res.status(404).json({ msg: "User not autherized" });
193 | }
194 |
195 | // get remove index
196 | const removeIndex = profile.review.map( review => review.text).indexOf(text);
197 |
198 | profile.review.splice(removeIndex, 1);
199 |
200 | await profile.save();
201 | res.json(profile);
202 | } catch (err) {
203 | console.error(err.message);
204 | res.status(500).send("Server error");
205 | }
206 | });
207 |
208 | // @route Delete api/profile
209 | // @desc Delete profile, doctor
210 | // @access Private
211 | router.delete('/', authDoctor, async (req, res) => {
212 | try {
213 | // Remove profile
214 | await Profile.findOneAndRemove({ doctor: req.doctor.id });
215 | // Remove doctor
216 | await Doctor.findOneAndRemove({ _id: req.doctor.id });
217 | res.json({ msg: "Doctor deleted" });
218 | } catch (err) {
219 | console.error(err.message);
220 | res.status(500).send('Server error');
221 | }
222 | });
223 |
224 | // @route Put api/profile/experience
225 | // @desc Add profile, experience
226 | // @access Private
227 | router.put('/experience', [authDoctor,
228 | [
229 | check('position', 'Position is required')
230 | .not()
231 | .isEmpty(),
232 | check('medical', 'Medical is required')
233 | .not()
234 | .isEmpty(),
235 | check('from', 'From date is required')
236 | .not()
237 | .isEmpty()
238 | ]
239 | ], async (req, res) => {
240 | const errors = validationResult(req);
241 | if(!errors.isEmpty()) {
242 | return res.status(400).json({ errors: errors.array() });
243 | }
244 |
245 | const {
246 | position,
247 | medical,
248 | location,
249 | from,
250 | to,
251 | current,
252 | description
253 | } = req.body;
254 |
255 | const newExp = {
256 | position,
257 | medical,
258 | location,
259 | from,
260 | to,
261 | current,
262 | description
263 | }
264 | try {
265 | const profile = await Profile.findOne({ doctor: req.doctor.id });
266 | profile.experience.unshift(newExp);
267 | await profile.save();
268 |
269 | res.json(profile);
270 | } catch (err) {
271 | console.error(err.message);
272 | res.status(500).send('Server error');
273 | }
274 | });
275 |
276 | // @route Delete api/profile/experience/:exp_id
277 | // @desc Delete experience from profile
278 | // @access Private
279 | router.delete('/experience/:exp_id', authDoctor, async (req, res) => {
280 | try {
281 | const profile = await Profile.findOne({ doctor: req.doctor.id });
282 | // Get remove index
283 | const removeIndex = profile.experience
284 | .map(item => item.id)
285 | .indexOf(req.params.exp_id);
286 |
287 | profile.experience.splice(removeIndex, 1);
288 | await profile.save();
289 | res.json(profile);
290 |
291 | } catch (err) {
292 | console.error(err.message);
293 | res.status(500).send('Server error');
294 | }
295 | });
296 |
297 | // @route PUT api/profile/education
298 | // @desc Add profile education
299 | // @access Private
300 | router.put('/education', [
301 | authDoctor,
302 | [
303 | check('school', 'School is required').not().isEmpty(),
304 | check('degree', 'Degree is required').not().isEmpty(),
305 | check('fieldofstudy', 'Field of study is required').not().isEmpty(),
306 | check('from', 'From date is required and needs to be from the past')
307 | .not()
308 | .isEmpty()
309 | ]
310 | ], async (req, res) => {
311 | const errors = validationResult(req);
312 | if(!errors.isEmpty()) {
313 | return res.status(400).json({ errors: errors.array() });
314 | }
315 |
316 | const {
317 | school,
318 | degree,
319 | fieldofstudy,
320 | from,
321 | to,
322 | current,
323 | description
324 | } = req.body;
325 |
326 | const newEdu = {
327 | school,
328 | degree,
329 | fieldofstudy,
330 | from,
331 | to,
332 | current,
333 | description
334 | };
335 |
336 | try {
337 | const profile = await Profile.findOne({ doctor: req.doctor.id });
338 |
339 | profile.education.unshift(newEdu);
340 |
341 | await profile.save();
342 |
343 | res.json(profile);
344 | } catch (err) {
345 | console.error(err.message);
346 | res.status(500).send('Server Error');
347 | }
348 | });
349 |
350 | // @route DELETE api/profile/education/:edu_id
351 | // @desc Delete education from profile
352 | // @access Private
353 |
354 | router.delete('/education/:edu_id', authDoctor, async (req, res) => {
355 | try {
356 | const foundProfile = await Profile.findOne({ doctor: req.doctor.id });
357 | foundProfile.education = foundProfile.education.filter(
358 | (edu) => edu._id.toString() !== req.params.edu_id
359 | );
360 | await foundProfile.save();
361 | return res.status(200).json(foundProfile);
362 | } catch (error) {
363 | console.error(error);
364 | return res.status(500).json({ msg: 'Server error' });
365 | }
366 | });
367 |
368 | module.exports = router;
--------------------------------------------------------------------------------
/routes/api/users.js:
--------------------------------------------------------------------------------
1 | require('dotenv').config();
2 | const express = require('express');
3 | const router = express.Router();
4 | const gravtar = require('gravatar');
5 | const { check, validationResult } = require('express-validator');
6 | const bcrypt = require('bcryptjs');
7 | const jwt = require('jsonwebtoken');
8 |
9 | const User = require('../../models/User');
10 |
11 | // @route Post api/user
12 | // @desc Register USer
13 | // @access Public
14 | router.post('/',
15 | [
16 | check('name', 'Name is required')
17 | .not()
18 | .isEmpty(),
19 | check('email', 'Please include a valid email').isEmail(),
20 | check('password', 'Please enter a password min 6 to 10 charcters').isLength({ min: 6 })
21 | ],
22 | async (req, res) => {
23 | const errors = validationResult(req);
24 | if(!errors.isEmpty()) {
25 | return res.status(400).json({ errors: errors.array() });
26 | }
27 | const { name, email, password } = req.body;
28 |
29 | try {
30 | // See if user exists
31 | let user = await User.findOne({ email });
32 |
33 | if(user) {
34 | return res.status(400).json({ errors: [{ msg: 'User already exists' }] });
35 | }
36 |
37 | // Get User gravtar
38 |
39 | const avatar = gravtar.url(email, {
40 | s: '200',
41 | r: 'pg',
42 | d: 'mm'
43 | });
44 |
45 | user = new User({
46 | name,
47 | email,
48 | avatar,
49 | password
50 | });
51 |
52 | // Encrypt password
53 |
54 | const salt = await bcrypt.genSalt(10);
55 |
56 | user.password = await bcrypt.hash(password, salt);
57 |
58 | await user.save();
59 |
60 | //Return jsonwebtoken
61 |
62 | const payload = {
63 | user: {
64 | id: user.id
65 | }
66 | }
67 |
68 | jwt.sign(payload, process.env.jwtSecret,
69 | { expiresIn: 360000 },
70 | (err, token) => {
71 | if (err) throw err;
72 | res.json({ token });
73 | });
74 |
75 | } catch (err) {
76 | console.error(err.message);
77 | res.status(500).send('Server error');
78 | }
79 | });
80 |
81 | module.exports = router;
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const mongoose = require("mongoose");
3 | const doctors = require('./routes/api/doctors');
4 | const authsDoctor = require('./routes/api/authDoctor');
5 | const users = require('./routes/api/users');
6 | const authsUser = require('./routes/api/authUser');
7 | const profile = require('./routes/api/profile');
8 | const appointment = require('./routes/api/appointment');
9 |
10 | const app = express();
11 |
12 | // DB config
13 | const db = require('./config/keys').mongoURI;
14 |
15 | // connect to MongoDB;
16 | mongoose
17 | .connect(db, { useNewUrlParser: true, useUnifiedTopology: true, useFindAndModify: false })
18 | .then(() => console.log("MongoDB Connected"))
19 | .catch(err => console.log(err));
20 |
21 | //Init Middleware
22 | app.use(express.json({ extended: false}));
23 |
24 | app.get('/', (req, res) => res.send("Welcome Jeevan Joti Dash"));
25 |
26 | // Use Routes
27 | app.use('/api/doctors', doctors);
28 | app.use('/api/authDoctor', authsDoctor);
29 | app.use('/api/users', users);
30 | app.use('/api/authUser', authsUser);
31 | app.use('/api/profile', profile);
32 | app.use('/api/appointment', appointment);
33 |
34 |
35 |
36 | const port = process.env.PORT || 5000;
37 | app.listen(port , () => console.log(`Server running on port ${port}`));
--------------------------------------------------------------------------------