├── .prettierrc
├── src
├── index.css
├── assets
│ ├── images
│ │ ├── ennaime.jpeg
│ │ ├── img_back.jpg
│ │ ├── ait elkadi.jpeg
│ │ ├── logo_theracure.png
│ │ ├── logo_thercaure1.png
│ │ ├── Untitled_design-14-removebg-preview.png
│ │ ├── Premium_Vector___Healthy_logo-removebg-preview.png
│ │ ├── undraw_no_data_re_kwbl (1).svg
│ │ ├── thecure.svg
│ │ └── thecure-whitev2.svg
│ └── css
│ │ ├── footer.css
│ │ ├── profile.css
│ │ ├── login.css
│ │ ├── allDoctors.css
│ │ ├── calendar.css
│ │ ├── header.css
│ │ └── home.css
├── components
│ ├── context
│ │ └── userContext.js
│ ├── getUserId.js
│ ├── customHooks
│ │ ├── useLocalStorage.js
│ │ └── useSessionStorage.js
│ ├── home.jsx
│ ├── doctors.jsx
│ ├── footer.jsx
│ ├── login.jsx
│ ├── profile.jsx
│ ├── event.jsx
│ ├── calendar.jsx
│ ├── header.jsx
│ ├── signup.jsx
│ ├── appointments.jsx
│ └── allDoctors.jsx
├── index.jsx
└── App.jsx
├── public
├── favicon.ico
├── logo192.png
├── logo512.png
├── robots.txt
├── manifest.json
└── index.html
├── .gitignore
├── package.json
└── README.md
/.prettierrc:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | *{
2 | margin: 0;
3 | padding: 0;
4 | box-sizing: border-box;
5 | }
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AhmedEnnaime/Theracure/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AhmedEnnaime/Theracure/HEAD/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AhmedEnnaime/Theracure/HEAD/public/logo512.png
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/src/assets/images/ennaime.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AhmedEnnaime/Theracure/HEAD/src/assets/images/ennaime.jpeg
--------------------------------------------------------------------------------
/src/assets/images/img_back.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AhmedEnnaime/Theracure/HEAD/src/assets/images/img_back.jpg
--------------------------------------------------------------------------------
/src/assets/images/ait elkadi.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AhmedEnnaime/Theracure/HEAD/src/assets/images/ait elkadi.jpeg
--------------------------------------------------------------------------------
/src/assets/images/logo_theracure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AhmedEnnaime/Theracure/HEAD/src/assets/images/logo_theracure.png
--------------------------------------------------------------------------------
/src/assets/images/logo_thercaure1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AhmedEnnaime/Theracure/HEAD/src/assets/images/logo_thercaure1.png
--------------------------------------------------------------------------------
/src/components/context/userContext.js:
--------------------------------------------------------------------------------
1 | import { createContext } from "react";
2 |
3 | const userContext = createContext();
4 |
5 | export default userContext;
6 |
--------------------------------------------------------------------------------
/src/assets/images/Untitled_design-14-removebg-preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AhmedEnnaime/Theracure/HEAD/src/assets/images/Untitled_design-14-removebg-preview.png
--------------------------------------------------------------------------------
/src/assets/images/Premium_Vector___Healthy_logo-removebg-preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AhmedEnnaime/Theracure/HEAD/src/assets/images/Premium_Vector___Healthy_logo-removebg-preview.png
--------------------------------------------------------------------------------
/src/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom/client';
3 | import './index.css';
4 | import App from './App';
5 |
6 | const root = ReactDOM.createRoot(document.getElementById('root'));
7 | root.render(
8 |
9 |
10 |
11 | );
12 |
13 |
--------------------------------------------------------------------------------
/src/components/getUserId.js:
--------------------------------------------------------------------------------
1 | import jwtDecode from "jwt-decode";
2 |
3 | const getUserId = () => {
4 | const token = localStorage.getItem("jwt");
5 | if (token) {
6 | const decoded = jwtDecode(token);
7 | const userId = decoded.userId;
8 | return userId;
9 | }
10 | };
11 |
12 | export default getUserId;
13 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/src/assets/css/footer.css:
--------------------------------------------------------------------------------
1 |
2 | footer{
3 | margin-top: 30px;
4 | background-color:#DCEDFE;
5 | }
6 | .footer-head{
7 | text-align: center;
8 | margin-bottom: 50px;
9 | padding-top: 20px;
10 | }
11 | .footer-content{
12 | display: flex;
13 | justify-content: space-around;
14 | }
15 | .footer-info{
16 | margin-bottom: 20px;
17 | }
18 | .footer-title{
19 | margin-bottom: 20px;
20 | }
21 | .section_content{
22 | display: flex;
23 | flex-direction: column;
24 | gap: 20px;
25 | }
26 | .subscribe_input{
27 | width: 200px;
28 | border-radius: 10px;
29 | height: 30px;
30 | }
31 | .subscribe_btn{
32 | width: 80px;
33 | height: 30px;
34 | border-radius: 10px;
35 | border: none;
36 | color: white;
37 | background-color: black;
38 | }
39 | .social{
40 | display: flex;
41 | justify-content: space-between;
42 | }
43 | .social_link{
44 | font-size: 30px;
45 | cursor: pointer;
46 | }
--------------------------------------------------------------------------------
/src/assets/css/profile.css:
--------------------------------------------------------------------------------
1 | .profile-container{
2 | display: flex;
3 | flex-direction: column;
4 | align-items: center;
5 | gap: 20px;
6 | }
7 |
8 | .profile-head{
9 | display: flex;
10 | flex-direction: column;
11 | align-items: center;
12 | background-color: #00DCA6;
13 | border-radius: 50%;
14 | border: 1px solid black;
15 | }
16 |
17 | .profile-img{
18 | height: 130px;
19 | width: 130px;
20 | border-radius: 50%;
21 | z-index: 1;
22 | }
23 |
24 | .profile-body form{
25 | display: flex;
26 | flex-direction: column;
27 | align-items: center;
28 | gap: 30px;
29 | }
30 |
31 | .cam{
32 | position: absolute;
33 | bottom: 5px;
34 | margin-left: 40px;
35 | cursor: pointer;
36 | font-size: 30px;
37 | z-index: 99;
38 | }
39 | .image-upload > input
40 | {
41 | display: none;
42 | }
43 |
44 | .image-upload img
45 | {
46 | width: 80px;
47 | cursor: pointer;
48 | }
--------------------------------------------------------------------------------
/src/components/customHooks/useLocalStorage.js:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 |
3 | function useLocalStorage(key, initialValue) {
4 | const [storedValue, setStoredValue] = useState(() => {
5 | if (typeof window === "undefined") {
6 | return initialValue;
7 | }
8 | try {
9 | const item = window.localStorage.getItem(key);
10 | return item ? JSON.parse(item) : initialValue;
11 | } catch (error) {
12 | console.log(error);
13 | return initialValue;
14 | }
15 | });
16 |
17 | const setValue = (value) => {
18 | try {
19 | const valueToStore =
20 | value instanceof Function ? value(storedValue) : value;
21 | setStoredValue(valueToStore);
22 | if (typeof window !== "undefined") {
23 | window.localStorage.setItem(key, JSON.stringify(valueToStore));
24 | }
25 | } catch (error) {
26 | console.log(error);
27 | }
28 | };
29 | return [storedValue, setValue];
30 | }
31 |
32 | export default useLocalStorage;
33 |
--------------------------------------------------------------------------------
/src/components/customHooks/useSessionStorage.js:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 |
3 | function useSessionStorage(key, initialValue) {
4 | const [storedValue, setStoredValue] = useState(() => {
5 | if (typeof window === "undefined") {
6 | return initialValue;
7 | }
8 | try {
9 | const item = window.sessionStorage.getItem(key);
10 | return item ? JSON.parse(item) : initialValue;
11 | } catch (error) {
12 | console.log(error);
13 | return initialValue;
14 | }
15 | });
16 |
17 | const setValue = (value) => {
18 | try {
19 | const valueToStore =
20 | value instanceof Function ? value(storedValue) : value;
21 | setStoredValue(valueToStore);
22 | if (typeof window !== "undefined") {
23 | window.sessionStorage.setItem(key, JSON.stringify(valueToStore));
24 | }
25 | } catch (error) {
26 | console.log(error);
27 | }
28 | };
29 | return [storedValue, setValue];
30 | }
31 |
32 | export default useSessionStorage;
33 |
--------------------------------------------------------------------------------
/src/components/home.jsx:
--------------------------------------------------------------------------------
1 | import Calendare from "./calendar";
2 | import Doctors from "./doctors";
3 | import Appointment from "./appointments";
4 | import Header from "./header";
5 | import Footer from "./footer";
6 | import "../assets/css/home.css";
7 | import { useEffect, useState } from "react";
8 | import { useNavigate } from "react-router-dom";
9 | import getUserId from "./getUserId";
10 | import axios from "axios";
11 |
12 | const Home = ({ user }) => {
13 | const navigate = useNavigate();
14 | const url = "http://localhost/YouCode/Theracure";
15 |
16 | useEffect(() => {
17 | const check = localStorage.getItem("jwt");
18 | if (!check) {
19 | navigate("/login");
20 | }
21 | }, []);
22 |
23 | return (
24 |
25 |
26 |
27 |
28 | 👋
29 |
Welcome Back {user.name}
30 |
31 |
36 |
37 |
38 |
39 | );
40 | };
41 |
42 | export default Home;
43 |
--------------------------------------------------------------------------------
/src/assets/css/login.css:
--------------------------------------------------------------------------------
1 | /* body{
2 | background-image:linear-gradient(rgba(0, 0, 0, 0.5),
3 | rgba(0, 0, 0, 0.5)), url("../images/img_back.jpg");
4 | background-repeat: no-repeat;
5 | background-size: cover;
6 | } */
7 |
8 | .login-container{
9 | margin-top: 17%;
10 | margin-left: 40%;
11 | }
12 | .login-content{
13 | display: flex;
14 | flex-direction: column;
15 | }
16 | .login-head{
17 | display: flex;
18 | flex-direction: row;
19 | align-items: center;
20 | gap: 20px;
21 | margin-bottom: 50px;
22 | }
23 | .lock-icon{
24 | font-size: 40px;
25 | }
26 | .login-inputs form{
27 | display: flex;
28 | flex-direction: column;
29 | align-items: center;
30 | gap: 40px;
31 | margin-right: 67%;
32 | }
33 | .login-inp{
34 | height: 40px;
35 | width: 280px;
36 | border-radius: 6px;
37 | padding-left: 20px;
38 | }
39 | .login-inp::placeholder{
40 | padding-left: 40px;
41 | }
42 | .login-btn{
43 | width: 100%;
44 | height: 30px;
45 | border-radius: 6px;
46 | background-color: #00DCA6;
47 | border: none;
48 | color: black;
49 | cursor: pointer;
50 | }
51 | .signup-link{
52 | margin-top: 60px;
53 | text-decoration: underline;
54 | cursor: pointer;
55 | }
--------------------------------------------------------------------------------
/src/assets/css/allDoctors.css:
--------------------------------------------------------------------------------
1 | .title{
2 | margin: 40px;
3 | }
4 | .search-bar{
5 | display: flex;
6 | justify-content: space-around;
7 | margin-bottom: 50px;
8 | }
9 | .search-doctor{
10 | border: 1px solid black;
11 | width: 30%;
12 | height: 40px;
13 | padding-left: 20px;
14 | border-radius: 20px;
15 | }
16 | .speciality-search{
17 | width: 10%;
18 | border-radius: 10px;
19 | padding-left: 10px;
20 | }
21 | .doctors-list{
22 | display: grid;
23 | grid-template-columns: repeat(6,1fr);
24 | padding: 40px;
25 | gap: 70px 40px;
26 | }
27 | .doctor-card{
28 | display: flex;
29 | flex-direction: column;
30 | justify-content: center;
31 | align-items: center;
32 | gap: 20px;
33 | border: 1px solid black;
34 | height: 185px;
35 | border-radius: 10px;
36 | position: relative;
37 | }
38 | .img-card{
39 | border: 1px solid black;
40 | background-color: #00DCA6;
41 | border-radius: 50%;
42 | padding: 7px;
43 | display: flex;
44 | align-items: center;
45 | position: absolute;
46 | top: -50px;
47 | }
48 | .doctors-img{
49 | height: 80px;
50 | width: 80px;
51 | border-radius: 50%;
52 | }
53 |
54 | .doctors-info{
55 | display: flex;
56 | flex-direction: column;
57 | align-items: center;
58 | gap: 10px;
59 | margin-top: 30px;
60 | }
61 | .doctors-speciality{
62 | padding: 10px;
63 | }
64 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cabinet_medicale",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@fullcalendar/core": "^6.0.2",
7 | "@fullcalendar/daygrid": "^6.0.2",
8 | "@fullcalendar/interaction": "^6.0.2",
9 | "@fullcalendar/react": "^6.0.2",
10 | "@tanstack/react-query": "^4.22.0",
11 | "@testing-library/jest-dom": "^5.16.5",
12 | "@testing-library/react": "^13.4.0",
13 | "@testing-library/user-event": "^13.5.0",
14 | "axios": "^1.2.2",
15 | "js-cookie": "^3.0.1",
16 | "jwt-decode": "^3.1.2",
17 | "react": "^18.2.0",
18 | "react-calendar": "^4.0.0",
19 | "react-dom": "^18.2.0",
20 | "react-icons": "^4.7.1",
21 | "react-query": "^3.39.2",
22 | "react-router-dom": "^6.6.1",
23 | "react-scripts": "5.0.1",
24 | "web-vitals": "^2.1.4"
25 | },
26 | "scripts": {
27 | "start": "react-scripts start",
28 | "build": "react-scripts build",
29 | "test": "react-scripts test",
30 | "eject": "react-scripts eject"
31 | },
32 | "eslintConfig": {
33 | "extends": [
34 | "react-app",
35 | "react-app/jest"
36 | ]
37 | },
38 | "browserslist": {
39 | "production": [
40 | ">0.2%",
41 | "not dead",
42 | "not op_mini all"
43 | ],
44 | "development": [
45 | "last 1 chrome version",
46 | "last 1 firefox version",
47 | "last 1 safari version"
48 | ]
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/App.jsx:
--------------------------------------------------------------------------------
1 | import Home from "./components/home";
2 | import Login from "./components/login";
3 | import { BrowserRouter, Routes, Route } from "react-router-dom";
4 | import { useState, useEffect } from "react";
5 | import Signup from "./components/signup";
6 | import AllDoctors from "./components/allDoctors";
7 | import Profile from "./components/profile";
8 | import axios from "axios";
9 | import getUserId from "./components/getUserId";
10 |
11 | const App = () => {
12 | const [user, setUser] = useState({});
13 | const url = "http://localhost/YouCode/Theracure";
14 | const userId = getUserId();
15 |
16 | useEffect(() => {
17 | if (userId) {
18 | getUserLoggedIn();
19 | }
20 | }, []);
21 |
22 | const getUserLoggedIn = async () => {
23 | await axios
24 | .get(`${url}/users/getLoggedInUser/${userId}`)
25 | .then((response) => {
26 | setUser(response.data.user);
27 | })
28 | .catch((err) => {
29 | console.log(err);
30 | });
31 | };
32 |
33 | return (
34 |
35 |
36 |
37 | }>
38 | }>
39 | }>
40 | }>
41 | }>
42 |
43 |
44 |
45 | );
46 | };
47 |
48 | export default App;
49 |
--------------------------------------------------------------------------------
/src/assets/css/calendar.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --fc-border-color: none;
3 | --fc-daygrid-event-dot-width: 5px;
4 | }
5 | .fc .fc-col-header-cell-cushion {
6 | display: inline-block;
7 | padding: 5px 20px;
8 | }
9 |
10 | .fc-daygrid-day-frame:hover .fc-daygrid-event-dot{
11 | padding: 13px !important;
12 | margin-bottom: 50px !important;
13 | margin-left: 17px !important;
14 | border-radius: 50%;
15 | position: absolute !important;
16 | }
17 | .fc-daygrid-event-dot{
18 | margin-left: 28px;
19 | }
20 | /* .fc-daygrid-day-number{
21 | margin-left: 8px;
22 | } */
23 | .fc-event-title{
24 | visibility: hidden;
25 | }
26 | .fc-event{
27 | margin-left: -19px !important;
28 | }
29 | .fc-daygrid-day-frame{
30 | display: grid !important;
31 | justify-content: center !important;
32 | }
33 |
34 | .fc-button{
35 | color: black !important;
36 | }
37 | .fc-header-toolbar{
38 | padding-top: 10px;
39 | }
40 | .fc-button {
41 | background-color: transparent !important;
42 | border: none !important;
43 | }
44 | .fc-icon{
45 | color: black;
46 | }
47 |
48 | .horraires-list{
49 | display: flex;
50 | flex-direction: column;
51 | gap: 10px;
52 | justify-content: center;
53 | padding: 40px;
54 | margin-top: 40px;
55 | border-radius: 5px;
56 | background-color: #86b6e9;
57 | margin-left: 20px;
58 | margin-right: 20px;
59 | }
60 | .horraire-row{
61 | display: flex;
62 | flex-direction: row;
63 | align-items: center;
64 | gap: 20px;
65 | }
66 | .submit-btn{
67 | padding: 10px;
68 | border-radius: 8px;
69 | border: none;
70 | cursor: pointer;
71 | background-color: #00DCA6;
72 | margin-top: 20px;
73 | }
74 | .close-btn{
75 | cursor: pointer;
76 | }
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | Theracure
28 |
29 |
30 | You need to enable JavaScript to run this app.
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/assets/css/header.css:
--------------------------------------------------------------------------------
1 | .App-header{
2 | background-color: #0152A8;
3 | }
4 |
5 | .nav-list{
6 | display: flex;
7 | justify-content: space-between;
8 | }
9 | .left-header{
10 | float: left;
11 | margin-top: 10px;
12 | margin-bottom: 10px;
13 | margin-left: 20px;
14 | cursor: pointer;
15 | }
16 | .left-header-title{
17 | color: black;
18 | width: 120px;
19 | }
20 | .right-header{
21 | margin-top: 10px;
22 | margin-bottom: 10px;
23 | display: flex;
24 | }
25 | .right-header form{
26 | display: flex;
27 | align-items: center;
28 | }
29 | .user-img{
30 | border-radius: 50%;
31 | width: 40px;
32 | height: 40px;
33 | margin-right: 10px;
34 | margin-left: 20px;
35 | }
36 | .search-input{
37 | margin-right: 10px;
38 | height: 25px;
39 | width: 160px;
40 | border-radius: 30px;
41 | border: none;
42 | }
43 | .search-input::placeholder{
44 | padding-left: 10px;
45 | }
46 | .search-btn{
47 | background: none;
48 | border: none;
49 | cursor: pointer;
50 | font-size: 20px;
51 | color: white;
52 | }
53 | .profile{
54 | cursor: pointer;
55 | display: flex;
56 | color: white;
57 | }
58 | .profile h5{
59 | margin-top: 10px;
60 | }
61 | .drop-down-btn{
62 | margin-top: 10px;
63 | margin-left: 5px;
64 | margin-right: 40px;
65 | }
66 | .dropdown-content{
67 | display: flex;
68 | flex-direction: column;
69 | width: 150px;
70 | position: absolute;
71 | top: 60.5px;
72 | right: 20px;
73 | border-radius:5px;
74 | box-shadow: 10px 10px 5px 0px rgba(0,0,0,0.15);
75 | -webkit-box-shadow: 10px 10px 5px 0px rgba(0,0,0,0.15);
76 | -moz-box-shadow: 10px 10px 5px 0px rgba(0,0,0,0.15);
77 | background-color: #00DCA6;
78 | }
79 | .dropdown-link{
80 | text-align:start;
81 | padding-left: 20px;
82 | text-decoration: none;
83 | list-style: none;
84 | padding-bottom: 7px;
85 | padding-top: 7px;
86 | color: #0152A8;
87 | }
88 |
89 | .dropdown-link:hover{
90 | background-color: #56e5c1;
91 | }
--------------------------------------------------------------------------------
/src/components/doctors.jsx:
--------------------------------------------------------------------------------
1 | import doctor_img from "../assets/images/ait elkadi.jpeg";
2 | import axios from "axios";
3 | import "../assets/css/home.css";
4 | import { useState, useEffect } from "react";
5 | import { Link } from "react-router-dom";
6 |
7 | const Doctors = () => {
8 | const [doctors, setDoctors] = useState([]);
9 | const [doctorsNum, setDoctorsNum] = useState([]);
10 | useEffect(() => {
11 | requestDoctors();
12 | DoctorsNum();
13 | }, []);
14 |
15 | const url = "http://localhost/YouCode/Theracure";
16 | async function requestDoctors() {
17 | await axios
18 | .get(`${url}/doctors/getAllDoctors`)
19 | .then((response) => {
20 | setDoctors(response.data.Doctors);
21 | })
22 | .catch((err) => {
23 | console.log(err);
24 | });
25 | }
26 |
27 | async function DoctorsNum() {
28 | await axios
29 | .get(`${url}/doctors/getDoctorsNum`)
30 | .then((response) => {
31 | setDoctorsNum(response.data.doctors);
32 | })
33 | .catch((err) => {
34 | console.log(err);
35 | });
36 | }
37 |
38 | return (
39 |
40 |
41 |
Doctors
42 | {doctorsNum} doctors
43 |
44 |
45 |
46 | {doctors.slice(0, 9).map((doctor, key) => (
47 |
48 |
49 | {doctor.name}
50 | {doctor.speciality}
51 |
52 | ))}
53 |
54 |
55 |
56 |
57 |
61 |
View All Doctors
62 |
63 |
64 |
65 | );
66 | };
67 |
68 | export default Doctors;
69 |
--------------------------------------------------------------------------------
/src/components/footer.jsx:
--------------------------------------------------------------------------------
1 | import "../assets/css/footer.css";
2 | import { BsInstagram, BsFacebook, BsTwitter } from "react-icons/bs";
3 | import logo from "../assets/images/thecure.svg";
4 |
5 | const Footer = () => {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
Contact
15 |
16 |
+212682622717
17 |
ahmedennaime20@gmail.com
18 |
Ahmed Ennaime
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
Services
29 |
30 |
Medical treatment
31 |
Good care
32 |
Online appointments
33 |
34 |
35 |
36 |
37 |
Office
38 |
39 |
Address :21 rue el falah
40 |
City: Safi
41 |
Country: Morocco
42 |
43 |
44 |
45 |
46 |
Subscribe
47 |
48 |
53 | Subscribe
54 |
55 |
56 |
57 |
58 |
59 | );
60 | };
61 |
62 | export default Footer;
63 |
--------------------------------------------------------------------------------
/src/components/login.jsx:
--------------------------------------------------------------------------------
1 | import { BiLock } from "react-icons/bi";
2 | import "../assets/css/login.css";
3 | import logo from "../assets/images/thecure.svg";
4 | import { Link, useNavigate } from "react-router-dom";
5 | import { useState } from "react";
6 | import axios from "axios";
7 | import { useEffect } from "react";
8 |
9 | const Login = () => {
10 | const navigate = useNavigate();
11 | useEffect(() => {
12 | const check = localStorage.getItem("jwt");
13 | if (check) {
14 | navigate("/");
15 | }
16 | }, []);
17 | const [credentials, setCredentials] = useState({});
18 | const url = "http://localhost/YouCode/Theracure";
19 |
20 | const handleChange = (e) => {
21 | const name = e.target.name;
22 | const value = e.target.value;
23 | setCredentials((values) => ({ ...values, [name]: value }));
24 | };
25 | async function handleSubmit(e) {
26 | e.preventDefault();
27 | await axios
28 | .post(`${url}/authenticate/`, credentials, { withCredentials: true })
29 | .then((response) => {
30 | if (response.data.message === "Access allowed") {
31 | localStorage.setItem("jwt", response.data.token);
32 | navigate("/");
33 | } else {
34 | alert("Invalid credentials");
35 | }
36 | })
37 | .catch((err) => {
38 | console.log(err);
39 | });
40 | }
41 | return (
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
70 |
71 |
Don't have account ? sign up now
72 |
73 |
74 |
75 |
76 | );
77 | };
78 |
79 | export default Login;
80 |
--------------------------------------------------------------------------------
/src/assets/images/undraw_no_data_re_kwbl (1).svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/profile.jsx:
--------------------------------------------------------------------------------
1 | import Footer from "./footer";
2 | import Header from "./header";
3 | import doctor_img from "../assets/images/ait elkadi.jpeg";
4 | import { AiOutlineCamera } from "react-icons/ai";
5 | import { useState } from "react";
6 | import "../assets/css/profile.css";
7 |
8 | const Profile = ({ user }) => {
9 | const [inputs, setInputs] = useState({});
10 | const handleChange = (e) => {
11 | const name = e.target.name;
12 | const value = e.target.value;
13 | setInputs((values) => ({ ...values, [name]: value }));
14 | };
15 |
16 | const updateProfile = async () => {};
17 | return (
18 |
19 |
20 |
Profile
21 |
22 |
23 |
24 |
30 |
31 |
32 |
70 |
71 |
72 |
73 |
74 | );
75 | };
76 |
77 | export default Profile;
78 |
--------------------------------------------------------------------------------
/src/assets/css/home.css:
--------------------------------------------------------------------------------
1 | #home{
2 | margin-top: 40px;
3 | margin-bottom: 100px;
4 | }
5 | .greeting{
6 | display: flex;
7 | align-items: center;
8 | }
9 | .greeting span{
10 | font-size: 40px;
11 | padding-left: 15%;
12 | padding-right: 10px;
13 | }
14 | .cards-container{
15 | display: grid;
16 | grid-template-columns: repeat(3,1fr);
17 | margin-top: 30px;
18 | padding: 0 90px;
19 | gap: 30px;
20 |
21 | }
22 | .card{
23 | background-color: rgba(160, 160, 146, 0.067);
24 | border: 1px solid black;
25 | border-radius: 5px;
26 | width: 100%;
27 | height: fit-content;
28 | background-color: #DCEDFE;
29 | }
30 | .card-title{
31 | color: white;
32 | }
33 | .element-num{
34 | color: white;
35 | }
36 |
37 | .card-head{
38 | background-color: #0152A8;
39 | display: flex;
40 | grid-column: 1/-1;
41 | justify-content: space-between;
42 | height: 30px;
43 | width: 100%;
44 | align-items: center;
45 | padding: 0 10px;
46 | }
47 |
48 | .calendar-card{
49 | width: 390px;
50 | height: 450px;
51 | }
52 |
53 | .doctor-list{
54 | margin-top: 20px;
55 | display: grid;
56 | grid-template-columns: repeat(4,auto);
57 | gap: 20px;
58 | justify-content: center;
59 | padding-left: 50px;
60 | padding-right: 50px;
61 | list-style: none;
62 | }
63 |
64 | .card-item{
65 | text-align: center;
66 | }
67 | .card-footer{
68 | margin-top: 90px;
69 | }
70 | .card-footer p{
71 | text-align: center;
72 | cursor: pointer;
73 | margin-top: 5px;
74 | }
75 |
76 | .doctor-img{
77 | height: 80px;
78 | width: 80px;
79 | border-radius: 7px;
80 | }
81 |
82 | .appointment-list{
83 | margin-top: 20px;
84 | list-style: none;
85 | display: grid;
86 | grid-template-columns: repeat(1,auto);
87 | }
88 |
89 | .active {
90 | text-decoration: none !important;
91 | }
92 |
93 | .sides{
94 | display: flex;
95 | flex-direction: column;
96 | gap: 10px;
97 | padding: 10px;
98 | }
99 | .responsible-doctor{
100 | display: flex;
101 | align-items: center;
102 | gap: 10px;
103 | }
104 | .responsible-doctor-img{
105 | width: 40px;
106 | height: 40px;
107 | border-radius: 50%;
108 | }
109 | .appointment-date{
110 | padding-left: 50px;
111 | }
112 |
113 | .left-side{
114 | float: left;
115 | margin-left: 20px;
116 | }
117 | .right-side{
118 | float: right;
119 | margin-right: 10px;
120 | align-items: center;
121 | }
122 | .trash-icon{
123 | color: red;
124 | font-size: 22px;
125 | cursor: pointer;
126 | }
127 |
128 | .not-found{
129 | width: 280px;
130 | height: 200px;
131 | padding-left: 40px;
132 | padding-bottom: 20px;
133 | }
134 |
135 |
136 |
--------------------------------------------------------------------------------
/src/components/event.jsx:
--------------------------------------------------------------------------------
1 | import { FaTimes } from "react-icons/fa";
2 | import axios from "axios";
3 | import { useState } from "react";
4 | import { useNavigate } from "react-router-dom";
5 | import getUserId from "./getUserId";
6 |
7 | const EventItem = ({ eventDate, appointments, open }) => {
8 | const [appointmentInfo, setAppointmentInfo] = useState({});
9 | const url = "http://localhost/YouCode/Theracure";
10 | const navigate = useNavigate();
11 | const userId = getUserId();
12 |
13 | const handleChange = (e) => {
14 | const value = e.target.value;
15 | const test = {
16 | date: eventDate,
17 | user_id: userId,
18 | schedule_id: value,
19 | };
20 | setAppointmentInfo(test);
21 | };
22 |
23 | const handleSubmit = async (e) => {
24 | e.preventDefault();
25 | await axios
26 | .post(`${url}/appointments/takeAppointment/${userId}`, appointmentInfo)
27 | .then((response) => {
28 | console.log(response.data);
29 | if (response.status === 201) {
30 | console.log("appointment taken successfully");
31 | console.log(appointmentInfo);
32 | //navigate("/");
33 | } else {
34 | console.log(appointmentInfo);
35 | console.log("failed to take appointment");
36 | }
37 | })
38 | .catch((err) => {
39 | console.log(err);
40 | });
41 | };
42 |
43 | return (
44 | <>
45 |
91 | >
92 | );
93 | };
94 |
95 | export default EventItem;
96 |
--------------------------------------------------------------------------------
/src/components/calendar.jsx:
--------------------------------------------------------------------------------
1 | import { useState, useEffect, useRef } from "react";
2 | import "react-calendar/dist/Calendar.css";
3 | import FullCalendar from "@fullcalendar/react"; // must go before plugins
4 | import dayGridPlugin from "@fullcalendar/daygrid";
5 | import interactionPlugin from "@fullcalendar/interaction";
6 | import "../assets/css/calendar.css";
7 | import axios from "axios";
8 | import EventItem from "./event";
9 |
10 | const Calendare = () => {
11 | const [appointments, setAppointments] = useState([]);
12 | const [showCalendar, setShowCalendar] = useState(true);
13 | const [eventDate, setEventDate] = useState(new Date());
14 |
15 | useEffect(() => {
16 | requestAvailableAppointments();
17 | }, []);
18 |
19 | function getUniqueListBy(arr, key) {
20 | return [...new Map(arr.map((item) => [item[key], item])).values()];
21 | }
22 |
23 | const getAppointmentsDates = () => {
24 | const dates = [];
25 | appointments.forEach((appointment) => {
26 | const { date } = appointment;
27 | dates.push({ date: date }, { date: "2023-02-01", color: "#00DCA6" });
28 | });
29 | return dates;
30 | };
31 |
32 | const availableAppointments = getUniqueListBy(getAppointmentsDates(), "date");
33 | const url = "http://localhost/YouCode/Theracure";
34 | const requestAvailableAppointments = async () => {
35 | await axios
36 | .get(`${url}/available_appointments/getAppointmentsInfo`)
37 | .then((response) => {
38 | setAppointments(response.data.Appointments);
39 | })
40 | .catch((err) => {
41 | console.log(err);
42 | });
43 | };
44 |
45 | return (
46 |
47 |
48 |
Today's schedule
49 |
50 | {showCalendar ? (
51 |
{
58 | appointments.forEach((appointment, key) => {
59 | if (info.event.startStr === appointment.date) {
60 | setEventDate(info.event.startStr);
61 | setShowCalendar(false);
62 | }
63 | });
64 | }}
65 | firstDay="1"
66 | headerToolbar={{
67 | left: "prev",
68 | center: "title",
69 | right: "next",
70 | }}
71 | footerToolbar={{
72 | right: "today",
73 | left: "dayGridMonth dayGridWeek dayGridDay",
74 | }}
75 | buttonIcons={{
76 | prev: "chevrons-left",
77 | next: "chevrons-right",
78 | }}
79 | />
80 | ) : (
81 |
86 | )}
87 |
88 | );
89 | };
90 |
91 | export default Calendare;
92 |
--------------------------------------------------------------------------------
/src/components/header.jsx:
--------------------------------------------------------------------------------
1 | import { BiSearchAlt2, BiDownArrow } from "react-icons/bi";
2 | import { useState } from "react";
3 | import "../assets/css/header.css";
4 | import profile_img from "../assets/images/ennaime.jpeg";
5 | import { Link, useNavigate } from "react-router-dom";
6 | import logo from "../assets/images/thecure-whitev2.svg";
7 | import axios from "axios";
8 |
9 | const Header = ({ user }) => {
10 | const [search, setSearch] = useState("");
11 | const [toggle, setToggle] = useState(false);
12 | const url = "http://localhost/YouCode/Theracure";
13 | const navigate = useNavigate();
14 | const logout = async (e) => {
15 | e.preventDefault();
16 | localStorage.removeItem("jwt");
17 | localStorage.clear();
18 | navigate("/login");
19 | };
20 |
21 | return (
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
53 |
{
56 | setToggle(!toggle);
57 | }}
58 | >
59 | <>
60 |
61 |
66 |
{user.name}
67 |
68 |
69 | {toggle && (
70 |
71 |
72 |
Profile
73 |
74 |
75 |
Log out
76 |
77 |
78 | )}
79 | >
80 |
81 |
82 |
83 |
84 |
85 | );
86 | };
87 |
88 | export default Header;
89 |
--------------------------------------------------------------------------------
/src/components/signup.jsx:
--------------------------------------------------------------------------------
1 | import "../assets/css/login.css";
2 | import { BiLock } from "react-icons/bi";
3 | import logo from "../assets/images/thecure.svg";
4 | import { Link, useNavigate } from "react-router-dom";
5 | import { useState } from "react";
6 | import axios from "axios";
7 |
8 | const Signup = () => {
9 | const [inputs, setInputs] = useState({});
10 | const url = "http://localhost/YouCode/Theracure";
11 | const navigate = useNavigate();
12 | const handleChange = (e) => {
13 | const name = e.target.name;
14 | const value = e.target.value;
15 | setInputs((values) => ({ ...values, [name]: value }));
16 | };
17 |
18 | async function handleSubmit(e) {
19 | e.preventDefault();
20 | await axios
21 | .post(`${url}/users/signup`, inputs)
22 | .then((response) => {
23 | if (response.data) {
24 | console.log(response.data);
25 | navigate("/login");
26 | }
27 | })
28 | .catch((err) => {
29 | console.log(err);
30 | });
31 | }
32 | return (
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
94 |
95 |
Already have account ? Login now
96 |
97 |
98 |
99 |
100 | );
101 | };
102 |
103 | export default Signup;
104 |
--------------------------------------------------------------------------------
/src/components/appointments.jsx:
--------------------------------------------------------------------------------
1 | import { BsFillTrashFill } from "react-icons/bs";
2 | import doctor_img from "../assets/images/ait elkadi.jpeg";
3 | import axios from "axios";
4 | import { useState, useEffect } from "react";
5 | import getUserId from "./getUserId";
6 | import { useNavigate } from "react-router-dom";
7 | import notFound from "../assets/images/undraw_no_data_re_kwbl (1).svg";
8 |
9 | const Appointment = () => {
10 | const [appointments, setAppointments] = useState([]);
11 | const userId = getUserId();
12 | const url = "http://localhost/YouCode/Theracure";
13 | const navigate = useNavigate();
14 |
15 | useEffect(() => {
16 | getAppointments();
17 | }, []);
18 |
19 | const cancelAppointment = async (schedule_id, id) => {
20 | await axios
21 | .delete(`${url}/appointments/cancelAppointment/${schedule_id}/${id}`)
22 | .then((response) => {
23 | if (response.status === 200) {
24 | navigate("/");
25 | }
26 | })
27 | .catch((err) => {
28 | console.log(err);
29 | });
30 | };
31 |
32 | const getAppointments = async () => {
33 | await axios
34 | .get(`${url}/appointments/getLoggedInUserAppointments/${userId}`)
35 | .then((response) => {
36 | setAppointments(response.data.Appointments);
37 | })
38 | .catch((err) => {
39 | console.log(err);
40 | });
41 | };
42 | return (
43 |
44 |
45 |
Appointments
46 | {appointments.length} appointments
47 |
48 |
49 |
93 |
94 | );
95 | };
96 |
97 | export default Appointment;
98 |
--------------------------------------------------------------------------------
/src/components/allDoctors.jsx:
--------------------------------------------------------------------------------
1 | import Footer from "./footer";
2 | import Header from "./header";
3 | import axios from "axios";
4 | import { useState, useEffect } from "react";
5 | import "../assets/css/allDoctors.css";
6 | import doctor_img from "../assets/images/ait elkadi.jpeg";
7 | import getUserId from "./getUserId";
8 |
9 | const AllDoctors = ({ user }) => {
10 | const [doctors, setDoctors] = useState([]);
11 | const [searchName, setSearchName] = useState("");
12 | const [searchSpeciality, setSearchSpeciality] = useState("");
13 |
14 | useEffect(() => {
15 | requestDoctors();
16 | }, []);
17 |
18 | const url = "http://localhost/YouCode/Theracure";
19 |
20 | const requestDoctors = async () => {
21 | await axios
22 | .get(`${url}/doctors/getAllDoctors`)
23 | .then((response) => {
24 | setDoctors(response.data.Doctors);
25 | })
26 | .catch((err) => {
27 | console.log(err);
28 | });
29 | };
30 |
31 | const getSpeciality = () => {
32 | const specialities = [];
33 | doctors.forEach((doctor) => {
34 | const { speciality } = doctor;
35 | specialities.push(speciality);
36 | });
37 | return specialities;
38 | };
39 | const uniq = [...new Set(getSpeciality())];
40 |
41 | return (
42 |
43 |
44 |
Doctors
45 |
46 | setSearchName(e.target.value)}
51 | value={searchName}
52 | />
53 | setSearchSpeciality(e.target.value)}
55 | className="speciality-search"
56 | name=""
57 | id=""
58 | value={searchSpeciality}
59 | >
60 |
61 | Select a speciality
62 |
63 | {uniq.map((i, key) => (
64 |
65 | {i}
66 |
67 | ))}
68 |
69 |
70 |
71 | {doctors.length ? (
72 | doctors
73 | .filter((doctor) => {
74 | if (searchName === "" && searchSpeciality === "") {
75 | return doctor;
76 | } else if (
77 | doctor.name.includes(searchName) &&
78 | doctor.speciality.includes(searchSpeciality)
79 | ) {
80 | return doctor;
81 | }
82 | })
83 | .map((doctor, key) => (
84 |
85 |
86 |
87 |
88 |
89 |
{doctor.name}
90 |
{doctor.email}
91 |
92 |
93 |
94 | {doctor.speciality}
95 |
96 |
97 | ))
98 | ) : (
99 |
No doctor found
100 | )}
101 |
102 |
103 |
104 | );
105 | };
106 | export default AllDoctors;
107 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Getting Started with Create React App
2 |
3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
4 |
5 | ## Available Scripts
6 |
7 | In the project directory, you can run:
8 |
9 | ### `npm start`
10 |
11 | Runs the app in the development mode.\
12 | Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
13 |
14 | The page will reload when you make changes.\
15 | You may also see any lint errors in the console.
16 |
17 | ### `npm test`
18 |
19 | Launches the test runner in the interactive watch mode.\
20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
21 |
22 | ### `npm run build`
23 |
24 | Builds the app for production to the `build` folder.\
25 | It correctly bundles React in production mode and optimizes the build for the best performance.
26 |
27 | The build is minified and the filenames include the hashes.\
28 | Your app is ready to be deployed!
29 |
30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
31 |
32 | ### `npm run eject`
33 |
34 | **Note: this is a one-way operation. Once you `eject`, you can't go back!**
35 |
36 | 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.
37 |
38 | 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.
39 |
40 | 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.
41 |
42 | ## Learn More
43 |
44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
45 |
46 | To learn React, check out the [React documentation](https://reactjs.org/).
47 |
48 | ### Code Splitting
49 |
50 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
51 |
52 | ### Analyzing the Bundle Size
53 |
54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
55 |
56 | ### Making a Progressive Web App
57 |
58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
59 |
60 | ### Advanced Configuration
61 |
62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
63 |
64 | ### Deployment
65 |
66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
67 |
68 | ### `npm run build` fails to minify
69 |
70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
71 |
--------------------------------------------------------------------------------
/src/assets/images/thecure.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/assets/images/thecure-whitev2.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------