├── .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 ├── App.test.js ├── Assets │ ├── 404.svg │ ├── about.svg │ ├── bg.png │ ├── contact.svg │ ├── footerbg.png │ ├── info.svg │ ├── log.svg │ ├── register.svg │ ├── s1.png │ ├── s2.png │ ├── s3.png │ ├── s4.png │ ├── s5.png │ ├── s6.png │ └── user.svg ├── component │ ├── Dashoboard │ │ ├── AddService │ │ │ ├── AddService.css │ │ │ └── AddService.jsx │ │ ├── AdminDashboard │ │ │ └── AdminDashboard.jsx │ │ ├── Dashboard │ │ │ ├── Dashboard.css │ │ │ └── Dashboard.jsx │ │ ├── MakeAdmin │ │ │ └── MakeAdmin.jsx │ │ ├── ManageServices │ │ │ └── ManageServices.jsx │ │ ├── OrderList │ │ │ ├── Order.css │ │ │ ├── Order.jsx │ │ │ ├── OrderList.css │ │ │ └── OrderList.jsx │ │ ├── Profile │ │ │ ├── Profile.css │ │ │ └── Profile.jsx │ │ ├── Sidebar │ │ │ ├── Sidebar.css │ │ │ └── Sidebar.jsx │ │ └── UserDashboard │ │ │ ├── AddReview │ │ │ ├── Review.css │ │ │ ├── Review.jsx │ │ │ └── ReviewFrom.jsx │ │ │ ├── Book │ │ │ ├── Book.css │ │ │ ├── Book.jsx │ │ │ └── Checkout.jsx │ │ │ ├── BookList │ │ │ ├── BookList.css │ │ │ └── BookList.jsx │ │ │ └── UserDashboard │ │ │ └── UserDashboard.jsx │ ├── FooterData.jsx │ ├── Home │ │ ├── About │ │ │ └── About.jsx │ │ ├── BrowserSupport │ │ │ └── BrowserSupport.jsx │ │ ├── BuildTools │ │ │ └── BuildTools.jsx │ │ ├── Contact │ │ │ ├── Contact.css │ │ │ └── Contact.jsx │ │ ├── Footer │ │ │ ├── Footer.css │ │ │ ├── Footer.jsx │ │ │ ├── FooterCol.jsx │ │ │ └── FooterInfo.jsx │ │ ├── HappyClient │ │ │ ├── HappyClient.css │ │ │ └── HappyClient.jsx │ │ ├── Header │ │ │ ├── Header.css │ │ │ └── Header.jsx │ │ ├── Hero │ │ │ └── Hero.jsx │ │ ├── Home │ │ │ └── Home.jsx │ │ ├── Pricing │ │ │ ├── Pricing.css │ │ │ ├── Pricing.jsx │ │ │ └── PricingCard.jsx │ │ ├── Reviews │ │ │ ├── Review.jsx │ │ │ ├── Reviews.css │ │ │ └── Reviews.jsx │ │ └── Services │ │ │ ├── Service.css │ │ │ ├── Service.jsx │ │ │ └── Services.jsx │ ├── Login │ │ ├── LoginManager.jsx │ │ ├── LoginModal.css │ │ ├── LoginModal.jsx │ │ ├── PrivateRoute.jsx │ │ ├── SignInForm.jsx │ │ ├── SignUpForm.jsx │ │ └── SocialMedia.jsx │ ├── NotFound.jsx │ ├── PricingData.jsx │ └── Shared │ │ ├── Navbar │ │ ├── Navbar.css │ │ └── Navbar.jsx │ │ ├── PopOver │ │ ├── PopOver.css │ │ └── PopOver.jsx │ │ ├── ScrollTop │ │ ├── ScrollTop.css │ │ └── ScrollTop.jsx │ │ ├── Spinner │ │ └── Spinner.jsx │ │ └── TableOrder │ │ ├── ListSkeleton.jsx │ │ └── TableOrder.jsx ├── context │ ├── actionTypes.js │ ├── app-context.js │ ├── index.js │ └── reducer.js ├── firebaseBaseConfig.js ├── index.css ├── index.js ├── logo.svg ├── reportWebVitals.js └── setupTests.js └── yarn.lock /.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 | 2 |
3 |
4 | 5 | Logo 6 | 7 | 8 |

Easy Consulting

9 | 10 |

11 | A Technonogly agency fullstack website build in react, mui , bootstrap and nodejs 12 |
13 | Explore the code here » 14 |
15 | Backend code here » 16 |
17 | View Demo 18 | · 19 | Report Bug 20 | · 21 | Request Feature 22 |

23 |
24 | 25 | 26 | ## Tech Stack 27 | - [React](https://facebook.github.io/react/) 28 | - [JavaScripp(ES6)](https://facebook.github.io/react/) 29 | - [Firebase](https://firebase.google.com/) 30 | - [Firestore](https://firebase.google.com/docs/firestore) 31 | - [Firebase Authentication](https://firebase.google.com/docs/auth) 32 | - [Material-UI](https://material-ui.com/) 33 | - [Webpack](https://webpack.js.org/) 34 | - [FileSaver](https://www.npmjs.com/package/file-saver) 35 | - [React-Bootstrape](#) 36 | - [Context API](#) 37 | - [stripe](#) 38 | - [React-router-dom v-6](#) 39 | - [Express](#) 40 | - [MongoDb](#) 41 | - [Node.js](#) 42 | - [More...](#) 43 | 44 | ### Installation 45 | 46 | _Below is an example of how you can instruct your audience on installing and setting up your app. This template doesn't rely on any external dependencies or services._ 47 | 48 | 1. Clone the repo 49 | ```sh 50 | git clone https://github.com/Ujjalzaman/Easy-Consulting-react 51 | ``` 52 | 2. Install NPM packages 53 | ```sh 54 | npm install 55 | ``` 56 | or 57 | ```sh 58 | yarn add 59 | ``` 60 | 61 | 3. Start the project 62 | ```sh 63 | npm start 64 | ``` 65 | or 66 | ```sh 67 | yarn start 68 | ``` 69 |

For this project you have to create firebase console for authentication , mongodb for database and stripe for payment gateway.

70 |

After then put all the credential env file respectly for backend keep them in root folder

71 |

create a jsx file in root and add here firbase config info

72 |

eventully if you having any issues startin this project fill free to contact me. love to help you.

73 | 74 | 75 | 76 | ## Contributing 77 | 78 | Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**. 79 | 80 | If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". 81 | Don't forget to give the project a star! Thanks again! 82 | 83 | 1. Fork the Project 84 | 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`) 85 | 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`) 86 | 4. Push to the Branch (`git push origin feature/AmazingFeature`) 87 | 5. Open a Pull Request 88 | 89 | 90 | ## Features 91 | This is fullstack softawre agency project. i have build this site in my leisure time only cool. that's why did'nt have much time added much functionalilty. but in future i will try add here more things. 92 | here i have implement context api for data handling. my plan was using redux or graphql using. but this is only testing project and i have time conflict that's why can't add that features. 93 | also love to add typeScript. right now my machine taking little time while compile typescript file, it's too hard me that using that site without typescript. 94 | 95 | What you get here: 96 | * implement responsive ui with first loading including backend 97 | * * MUI provides styling and building Material-UI components quickly and easily 98 | * Most of the UI created react-bootstrap as well row css. 99 | * Few cases used MUI but in future i will add more MUI features here.:smile: 100 | * Responsive landing page. 101 | * user can give review, can purchase a product and see there status. 102 | * there most interting part is Login Page. this is amazing design and authentication system. 103 | * job portal site. 104 | * all the input are have to validate. 105 | * authenttication system(login, logout, signup, reset email, OTP, subscribe). 106 | * payement system(here used only Stripe in near will add more payment gateway) 107 | * Deffrent for Dasboard(Admin and User) 108 | * in dashboard Admin has all kinds of access(CRUD operations, add admin, manage orders and many more) 109 | 110 | ## Contact 111 | 112 | ujjal zaman - [Linkdeind](www.linkedin.com/in/ujjal-zaman) 113 | 114 | Project Link: [https://github.com/Ujjalzaman/Easy-Consulting-react](https://github.com/Ujjalzaman/Easy-Consulting-react) 115 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "client", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@emotion/react": "^11.6.0", 7 | "@emotion/styled": "^11.6.0", 8 | "@fortawesome/fontawesome-svg-core": "^1.2.36", 9 | "@fortawesome/free-brands-svg-icons": "^5.15.4", 10 | "@fortawesome/free-regular-svg-icons": "^5.15.4", 11 | "@fortawesome/free-solid-svg-icons": "^5.15.4", 12 | "@fortawesome/react-fontawesome": "^0.1.16", 13 | "@mui/icons-material": "^5.1.1", 14 | "@mui/material": "^5.1.1", 15 | "@stripe/react-stripe-js": "^1.6.0", 16 | "@stripe/stripe-js": "^1.21.1", 17 | "@testing-library/jest-dom": "^5.11.4", 18 | "@testing-library/react": "^11.1.0", 19 | "@testing-library/user-event": "^12.1.10", 20 | "axios": "^0.24.0", 21 | "bootstrap": "^5.1.3", 22 | "firebase": "^9.4.1", 23 | "jwt-decode": "^3.1.2", 24 | "react": "^17.0.2", 25 | "react-bootstrap": "^2.0.2", 26 | "react-content-loader": "^6.0.3", 27 | "react-countup": "^6.1.0", 28 | "react-dom": "^17.0.2", 29 | "react-hook-form": "^7.19.5", 30 | "react-hot-toast": "^2.1.1", 31 | "react-lazy-load-image-component": "^1.5.1", 32 | "react-loader-spinner": "^4.0.0", 33 | "react-reveal": "^1.2.2", 34 | "react-router-dom": "^6.0.2", 35 | "react-scripts": "4.0.3", 36 | "react-syntax-highlighter": "^15.4.5", 37 | "react-typed": "^1.2.0", 38 | "swal": "^0.1.0", 39 | "sweetalert": "^2.1.2", 40 | "sweetalert2": "^11.1.10", 41 | "swiper": "6.8.4", 42 | "web-vitals": "^1.0.1" 43 | }, 44 | "scripts": { 45 | "start": "react-scripts start", 46 | "build": "react-scripts build", 47 | "test": "react-scripts test", 48 | "eject": "react-scripts eject" 49 | }, 50 | "eslintConfig": { 51 | "extends": [ 52 | "react-app", 53 | "react-app/jest" 54 | ] 55 | }, 56 | "browserslist": { 57 | "production": [ 58 | ">0.2%", 59 | "not dead", 60 | "not op_mini all" 61 | ], 62 | "development": [ 63 | "last 1 chrome version", 64 | "last 1 firefox version", 65 | "last 1 safari version" 66 | ] 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Honestdev125/react-full/fa254b27b61db9f7d62f1c1fcc827c29ae81d7e9/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Honestdev125/react-full/fa254b27b61db9f7d62f1c1fcc827c29ae81d7e9/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Honestdev125/react-full/fa254b27b61db9f7d62f1c1fcc827c29ae81d7e9/public/logo512.png -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import Home from "../src/component/Home/Home/Home"; 2 | import { Routes, Route } from "react-router-dom"; 3 | import React, { createContext } from "react"; 4 | import About from "./component/Home/About/About"; 5 | import Dashboard from "./component/Dashoboard/Dashboard/Dashboard"; 6 | import LoginModal from "./component/Login/LoginModal"; 7 | import PrivateRoute from "./component/Login/PrivateRoute"; 8 | import NotFound from "./component/NotFound"; 9 | export const UserContext = createContext(); 10 | 11 | const App = () => { 12 | return ( 13 |
14 | 15 | } /> 16 | } /> 17 | } /> 18 | 22 | 23 | 24 | } 25 | /> 26 | } /> 27 | 28 |
29 | ); 30 | }; 31 | 32 | export default App; 33 | -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /src/Assets/404.svg: -------------------------------------------------------------------------------- 1 | page not found -------------------------------------------------------------------------------- /src/Assets/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Honestdev125/react-full/fa254b27b61db9f7d62f1c1fcc827c29ae81d7e9/src/Assets/bg.png -------------------------------------------------------------------------------- /src/Assets/contact.svg: -------------------------------------------------------------------------------- 1 | online discussion -------------------------------------------------------------------------------- /src/Assets/footerbg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Honestdev125/react-full/fa254b27b61db9f7d62f1c1fcc827c29ae81d7e9/src/Assets/footerbg.png -------------------------------------------------------------------------------- /src/Assets/info.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 7 | 8 | 16 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/Assets/s1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Honestdev125/react-full/fa254b27b61db9f7d62f1c1fcc827c29ae81d7e9/src/Assets/s1.png -------------------------------------------------------------------------------- /src/Assets/s2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Honestdev125/react-full/fa254b27b61db9f7d62f1c1fcc827c29ae81d7e9/src/Assets/s2.png -------------------------------------------------------------------------------- /src/Assets/s3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Honestdev125/react-full/fa254b27b61db9f7d62f1c1fcc827c29ae81d7e9/src/Assets/s3.png -------------------------------------------------------------------------------- /src/Assets/s4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Honestdev125/react-full/fa254b27b61db9f7d62f1c1fcc827c29ae81d7e9/src/Assets/s4.png -------------------------------------------------------------------------------- /src/Assets/s5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Honestdev125/react-full/fa254b27b61db9f7d62f1c1fcc827c29ae81d7e9/src/Assets/s5.png -------------------------------------------------------------------------------- /src/Assets/s6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Honestdev125/react-full/fa254b27b61db9f7d62f1c1fcc827c29ae81d7e9/src/Assets/s6.png -------------------------------------------------------------------------------- /src/Assets/user.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/component/Dashoboard/AddService/AddService.css: -------------------------------------------------------------------------------- 1 | .addServiceForm{ 2 | background: white; 3 | box-shadow: 0 2px 5px 1px rgb(64 60 67 / 4%); 4 | padding: 2rem; 5 | border-radius: 1rem; 6 | margin: 2.5rem 0; 7 | } 8 | 9 | .uploadBtn { 10 | color: #6544f8; 11 | border: 1px solid #5c38ff; 12 | background-color: rgba(147, 123, 255, 0.227); 13 | padding: 8px 20px; 14 | border-radius: 0.5rem; 15 | font-size: 1rem; 16 | font-weight: 500; 17 | outline: 0; 18 | width: 250px; 19 | transition: 0.4s; 20 | } 21 | 22 | .uploadBtn:hover { 23 | color: #6544f8; 24 | border: 1px solid #5c38ff; 25 | background-color: rgba(147, 123, 255, 0.384); 26 | } 27 | 28 | .form-label { 29 | margin-bottom: .6rem!important; 30 | } 31 | -------------------------------------------------------------------------------- /src/component/Dashoboard/AddService/AddService.jsx: -------------------------------------------------------------------------------- 1 | import { faCloudUploadAlt } from '@fortawesome/free-solid-svg-icons'; 2 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; 3 | import axios from 'axios'; 4 | import React, { useState, useEffect } from 'react'; 5 | import { Button, Col, Form, Row } from 'react-bootstrap'; 6 | import { useForm } from 'react-hook-form'; 7 | import toast from 'react-hot-toast'; 8 | import swal from 'sweetalert'; 9 | import './AddService.css' 10 | 11 | const AddService = ({edit, setEdit, services}) => { 12 | const { register, handleSubmit, reset } = useForm(); 13 | const [imgURL, setImgURL] = useState(null); 14 | const [service, setService] = useState({}) 15 | const [isDisabled, setIsDisabled] = useState(false); 16 | const {name, price, description, img} = service || {}; 17 | 18 | useEffect(() => { 19 | const getService = services?.find(({_id}) => _id === edit); 20 | setService(getService) 21 | }, [edit, services]) 22 | 23 | const onSubmit = data => { 24 | const loading = toast.loading('Uploading...'); 25 | const serviceInfo = { 26 | ...data, 27 | img: imgURL || img 28 | } 29 | 30 | if(edit){ 31 | axios.patch(`https://immense-river-40491.herokuapp.com/updateService/${edit}`, serviceInfo) 32 | .then(res =>{ 33 | toast.dismiss(loading) 34 | if( data.name === name && 35 | data.price === price && 36 | data.description === description){ 37 | toast.error("You haven't change anything") 38 | } 39 | else{ 40 | toast.success('Service updated successfully') 41 | } 42 | setEdit(null) 43 | }) 44 | }else{ 45 | axios.post('https://immense-river-40491.herokuapp.com/addService', serviceInfo) 46 | .then(res => { 47 | toast.dismiss(loading) 48 | if(res.data){ 49 | swal('Success!', 'One new service added successfully', 'success') 50 | reset() 51 | } 52 | }) 53 | .catch( error => { 54 | toast.dismiss(loading) 55 | toast.error(error.message) 56 | }); 57 | } 58 | } 59 | 60 | const handleImgUpload = event => { 61 | const loading = toast.loading('Image uploading...'); 62 | setIsDisabled(true) 63 | const imgData = new FormData(); 64 | imgData.set('key', 'd397289afc04f776659233bc4fe00dbc'); 65 | imgData.append('image', event.target.files[0]) 66 | axios.post('https://api.imgbb.com/1/upload', imgData) 67 | .then( response => { 68 | toast.dismiss(loading) 69 | toast.success('Image successfully uploaded') 70 | setImgURL(response.data.data.url) 71 | setIsDisabled(false) 72 | }) 73 | .catch( error => { 74 | toast.dismiss(loading) 75 | toast.error(error.message) 76 | }); 77 | } 78 | return ( 79 |
80 |
81 | 82 | 83 | Service Name 84 | 89 | 90 | 91 | Price 92 | 97 | 98 | 99 | Description 100 | 107 | 108 | 109 | {edit ? "Change Image": "Add Image"} 110 | 117 | 125 |
126 | 127 |
128 |
129 |
130 | ); 131 | }; 132 | 133 | export default AddService; -------------------------------------------------------------------------------- /src/component/Dashoboard/AdminDashboard/AdminDashboard.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Route, Routes } from 'react-router-dom'; 3 | import Profile from '../Profile/Profile'; 4 | import OrderList from '../OrderList/OrderList'; 5 | import AddService from '../AddService/AddService'; 6 | import MakeAdmin from '../MakeAdmin/MakeAdmin'; 7 | import ManageServices from '../ManageServices/ManageServices'; 8 | 9 | const AdminDashboard = () => { 10 | return ( 11 | 12 | } /> 13 | } /> 14 | } /> 15 | } /> 16 | } /> 17 | 18 | ); 19 | }; 20 | 21 | export default AdminDashboard; -------------------------------------------------------------------------------- /src/component/Dashoboard/Dashboard/Dashboard.css: -------------------------------------------------------------------------------- 1 | #dashboard { 2 | display: flex; 3 | width: 100%; 4 | min-height: 100vh; 5 | align-items: stretch; 6 | perspective: 1500px; 7 | background: #f4f7fc; 8 | font-family: 'Poppins', sans-serif; 9 | } 10 | 11 | #sidebar { 12 | min-width: 300px; 13 | max-width: 300px; 14 | height: 100vh; 15 | position: sticky; 16 | top: 0; 17 | background: white; 18 | color: #878787; 19 | transition: all 0.6s cubic-bezier( 0.55, 0.055, 0.675, 0.19 ) ; 20 | padding-bottom: 0.5rem; 21 | } 22 | #sidebar.active { 23 | margin-left: -300px; 24 | transform: rotateY(100deg); 25 | } 26 | 27 | .sidebarContent { 28 | position: relative; 29 | height: 100%; 30 | width: 100%; 31 | } 32 | 33 | .backBtnBox { 34 | position: absolute; 35 | bottom: 0; 36 | padding: 0.2rem; 37 | width: 100%; 38 | } 39 | 40 | .backBtnBox .backBtn { 41 | display: block; 42 | width: 100%; 43 | text-transform: uppercase; 44 | background: #7254F6; 45 | border: none; 46 | font-size: 1rem; 47 | transition: 0.3s; 48 | padding: 0.4rem; 49 | font-weight: 500; 50 | color: #fff; 51 | border-radius: 0.3rem; 52 | } 53 | 54 | .backBtnBox .backBtn:hover{ 55 | background: #4C25F5; 56 | } 57 | 58 | .backBtnBox a:hover { 59 | text-decoration: none; 60 | } 61 | 62 | #pageContent { 63 | width: 100%; 64 | min-height: 100vh; 65 | transition: all 0.3s; 66 | padding: 1rem; 67 | } 68 | 69 | .dashBoardHeader { 70 | display: flex; 71 | justify-content: space-between; 72 | padding: 0.6rem 2rem 0.6rem 1.3rem; 73 | margin-bottom: 1rem; 74 | background: #FFFFFF; 75 | align-items: center; 76 | border-radius: 0.2rem; 77 | box-shadow: 0 2px 5px 1px rgb(64 60 67 / 16%); 78 | transition: 0.4s; 79 | transform: button; 80 | } 81 | 82 | .dashBoardHeader h3 { 83 | font-size: 1.2rem; 84 | font-weight: 600; 85 | margin: 0; 86 | text-transform: uppercase; 87 | } 88 | 89 | .sideToggleBtn { 90 | width: 40px; 91 | height: 40px; 92 | background: #f5f5f5; 93 | cursor: pointer; 94 | outline: none; 95 | border: none; 96 | } 97 | 98 | /* Menu Hamburger Icon Animation */ 99 | 100 | #nav-icon { 101 | width: 40px; 102 | height: 34px; 103 | position: relative; 104 | -webkit-transform: rotate(0deg); 105 | -moz-transform: rotate(0deg); 106 | -o-transform: rotate(0deg); 107 | transform: rotate(0deg); 108 | -webkit-transition: .7s ease-in-out; 109 | -moz-transition: .7s ease-in-out; 110 | -o-transition: .7s ease-in-out; 111 | transition: .7s ease-in-out; 112 | cursor: pointer; 113 | border-radius: 0.133rem; 114 | margin-right: 0.5rem; 115 | background: #eff2f7; 116 | } 117 | 118 | #nav-icon span { 119 | display: block; 120 | position: absolute; 121 | height: 3px; 122 | width: 50%; 123 | background: #696969; 124 | opacity: 1; 125 | -webkit-transform: rotate(0deg); 126 | -moz-transform: rotate(0deg); 127 | -o-transform: rotate(0deg); 128 | transform: rotate(0deg); 129 | -webkit-transition: .25s ease-in-out; 130 | -moz-transition: .25s ease-in-out; 131 | -o-transition: .25s ease-in-out; 132 | transition: .25s ease-in-out; 133 | } 134 | 135 | #nav-icon span:nth-child(even) { 136 | left: 35%; 137 | border-radius: 0 5px 5px 0; 138 | } 139 | 140 | #nav-icon span:nth-child(odd) { 141 | left: 0.4rem; 142 | border-radius: 5px 0 0 5px; 143 | } 144 | 145 | #nav-icon span:nth-child(1), #nav-icon span:nth-child(2) { 146 | top: 7px; 147 | } 148 | 149 | #nav-icon span:nth-child(3), #nav-icon span:nth-child(4) { 150 | top: 15px; 151 | } 152 | 153 | #nav-icon span:nth-child(5), #nav-icon span:nth-child(6) { 154 | top: 23px; 155 | } 156 | 157 | #nav-icon.open span:nth-child(1),#nav-icon.open span:nth-child(6) { 158 | -webkit-transform: rotate(45deg); 159 | -moz-transform: rotate(45deg); 160 | -o-transform: rotate(45deg); 161 | transform: rotate(45deg); 162 | } 163 | 164 | #nav-icon.open span:nth-child(2),#nav-icon.open span:nth-child(5) { 165 | -webkit-transform: rotate(-45deg); 166 | -moz-transform: rotate(-45deg); 167 | -o-transform: rotate(-45deg); 168 | transform: rotate(-45deg); 169 | } 170 | 171 | #nav-icon.open span:nth-child(1) { 172 | left: 10px; 173 | top: 14px; 174 | } 175 | 176 | #nav-icon.open span:nth-child(2) { 177 | left: calc(50% - 10px); 178 | top: 14px; 179 | } 180 | 181 | #nav-icon.open span:nth-child(3) { 182 | left: -50%; 183 | opacity: 0; 184 | } 185 | 186 | #nav-icon.open span:nth-child(4) { 187 | left: 100%; 188 | opacity: 0; 189 | } 190 | 191 | #nav-icon.open span:nth-child(5) { 192 | left: 10px; 193 | top: 15px; 194 | } 195 | 196 | #nav-icon.open span:nth-child(6) { 197 | left: calc(50% - 10px); 198 | top: 15px; 199 | } 200 | 201 | .adminBtn { 202 | margin-top: 1.8rem; 203 | margin-left: -1rem; 204 | } 205 | 206 | .makeAdmin { 207 | background: #FFFFFF; 208 | border-radius: 1rem; 209 | padding: 3rem 2rem 8rem; 210 | margin-top: 2rem; 211 | box-shadow: 0 2px 5px 1px rgb(64 60 67 / 4%); 212 | } 213 | -------------------------------------------------------------------------------- /src/component/Dashoboard/Dashboard/Dashboard.jsx: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import React, { useEffect, useState } from 'react'; 3 | import { Link } from 'react-router-dom'; 4 | import PopOver from '../../Shared/PopOver/PopOver'; 5 | import AdminDashboard from '../AdminDashboard/AdminDashboard'; 6 | import Sidebar from '../Sidebar/Sidebar'; 7 | import UserDashboard from '../UserDashboard/UserDashboard/UserDashboard'; 8 | import './Dashboard.css'; 9 | import { faSignOutAlt } from '@fortawesome/free-solid-svg-icons'; 10 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; 11 | import { SET_ADMIN, useAppContext } from '../../../context'; 12 | 13 | const Dashboard = () => { 14 | const { state: { user, admin }, dispatch } = useAppContext() 15 | const [sideToggle, setSideToggle] = useState(false) 16 | const [title, setTitle] = useState('Easy Consulting') 17 | 18 | useEffect(() => { 19 | axios.get(`https://immense-river-40491.herokuapp.com/admin?email=${user.email}`) 20 | .then(res => { 21 | if(res.data.length > 0){ 22 | dispatch({type: SET_ADMIN, payload: true}) 23 | } 24 | }) 25 | },[dispatch, user.email]) 26 | 27 | return ( 28 |
29 | 41 |
42 |
43 |
44 | 54 |

{title}

55 |
56 | 57 |
58 | { 59 | admin ? : 60 | } 61 |
62 |
63 | ) 64 | } 65 | 66 | export default Dashboard 67 | -------------------------------------------------------------------------------- /src/component/Dashoboard/MakeAdmin/MakeAdmin.jsx: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import React from 'react'; 3 | import { Col, Form, Row } from 'react-bootstrap'; 4 | import { useForm } from 'react-hook-form'; 5 | import toast from 'react-hot-toast'; 6 | import swal from 'sweetalert'; 7 | import { useAppContext } from '../../../context'; 8 | 9 | const MakeAdmin = () => { 10 | const { state:{ user: {email}}} = useAppContext() 11 | const { register, handleSubmit, formState: { errors }, reset} = useForm(); 12 | 13 | const onSubmit = data => { 14 | const loading = toast.loading('Please wait...') 15 | if(email === "test@admin.com"){ 16 | toast.dismiss(loading) 17 | swal("Permission restriction!", "As a test admin, You haven't permission to add a new admin", "info"); 18 | } else { 19 | axios.post('https://immense-river-40491.herokuapp.com/addAdmin',{email: data.email}) 20 | .then(res => { 21 | toast.dismiss(loading) 22 | toast.success('One admin added successfully') 23 | reset(); 24 | }) 25 | .catch(err => { 26 | toast.dismiss(loading) 27 | toast.error(err.message) 28 | }) 29 | } 30 | }; 31 | return ( 32 |
33 |
34 | 35 | 36 | 37 | Email 38 | 43 | {errors.email && This field is required} 44 | 45 | 46 | 47 | 48 | 49 | 50 |
51 |
52 | ) 53 | }; 54 | 55 | export default MakeAdmin; -------------------------------------------------------------------------------- /src/component/Dashoboard/ManageServices/ManageServices.jsx: -------------------------------------------------------------------------------- 1 | import { faTrashAlt } from '@fortawesome/free-regular-svg-icons'; 2 | import { faEdit } from '@fortawesome/free-solid-svg-icons'; 3 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; 4 | import axios from 'axios'; 5 | import React, { useEffect, useState } from 'react'; 6 | import { Table, Button } from 'react-bootstrap'; 7 | import toast from 'react-hot-toast'; 8 | import swal from 'sweetalert'; 9 | import { useAppContext } from '../../../context'; 10 | import TableLoader from '../../Shared/TableOrder/TableOrder'; 11 | import AddService from '../AddService/AddService'; 12 | 13 | const ManageServices = () => { 14 | const { state: { email }} = useAppContext() 15 | const [services, setServices] = useState([]) 16 | const [isUpdated, setIsUpdated] = useState(false) 17 | const [edit, setEdit] = useState(null); 18 | 19 | useEffect(() => { 20 | axios.get('https://immense-river-40491.herokuapp.com/services') 21 | .then(res => { 22 | setServices(res.data); 23 | setIsUpdated(false) 24 | }) 25 | }, [isUpdated, edit]) 26 | 27 | const checkPermission = (id, action) => { 28 | const getMainServices = services.slice(0, 6) 29 | const getService = getMainServices.find(({_id}) => id === _id) 30 | 31 | if(getService && email === "test@admin.com"){ 32 | swal("Permission restriction!","As a test admin, you can't edit or delete the main six services. You can only edit or delete your added services", "info" ) 33 | } else { 34 | if(action === 'edit'){ 35 | setEdit(id) 36 | } else { 37 | handleDelete(id) 38 | } 39 | } 40 | } 41 | 42 | const handleDelete = (id) => { 43 | setIsUpdated(false) 44 | swal({ 45 | title: "Are you sure?", 46 | text: "Are you sure! you want to delete this service?", 47 | icon: "warning", 48 | buttons: true, 49 | dangerMode: true, 50 | }) 51 | .then( wantDelete => { 52 | if (wantDelete) { 53 | const loading = toast.loading('deleting...Please wait!') 54 | axios.delete(`https://immense-river-40491.herokuapp.com/delete/${id}`) 55 | .then(res => { 56 | toast.dismiss(loading) 57 | if(res){ 58 | setIsUpdated(true); 59 | toast.success('Service has been deleted successfully!'); 60 | } 61 | else{ 62 | toast.error('Something went wrong, please try again'); 63 | } 64 | }) 65 | .catch(err => { 66 | toast.dismiss(loading) 67 | swal({ 68 | title: "Failed!", 69 | text: 'Something went wrong, please try again', 70 | icon: "error", 71 | }); 72 | }) 73 | } 74 | }) 75 | } 76 | 77 | return ( 78 | <> 79 | { edit ? 80 | 81 | : 82 | services.length === 0 ? 83 | 84 | : 85 |
86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | { 97 | services.map(({_id, name, price, description}) => { 98 | let des = description 99 | // let shortDes = des.split(' ').slice(0,5).join(' ') 100 | return( 101 | 102 | 103 | 104 | 105 | 113 | 114 | ) 115 | }) 116 | } 117 | 118 |
NameDescriptionPriceAction
{name}{des ? des : "Nothing"}${price} 106 | 109 | 112 |
119 |
120 | } 121 | 122 | ); 123 | }; 124 | 125 | export default ManageServices; -------------------------------------------------------------------------------- /src/component/Dashoboard/OrderList/Order.css: -------------------------------------------------------------------------------- 1 | #statusBtn { 2 | border: none; 3 | outline: none; 4 | } 5 | #pending { 6 | color: white; 7 | background: rgb(255 78 96); 8 | } 9 | #pending:hover{ 10 | background: rgb(228 72 88); 11 | } 12 | #ongoing { 13 | color: white; 14 | background: rgb(73 146 255); 15 | } 16 | #ongoing:hover{ 17 | background: #4185e2; 18 | } 19 | #done { 20 | color: white; 21 | background: rgb(31 204 123); 22 | } 23 | #done:hover{ 24 | background: rgb(31 177 109); 25 | } 26 | .dropdown-menu{ 27 | padding: 1px!important; 28 | border: 1px solid black!important; 29 | } 30 | 31 | #dropdown-basic-button .btn { 32 | border: none; 33 | box-shadow: none; 34 | } -------------------------------------------------------------------------------- /src/component/Dashoboard/OrderList/Order.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Dropdown } from 'react-bootstrap'; 3 | import './Order.css' 4 | 5 | const Order = ({order, handleAction}) => { 6 | const {_id, name, email, serviceName, status} = order; 7 | const setBackground = { 8 | color: '#FFFFFF', 9 | background: status === 'Pending' ? 'rgb(255 78 96)' : status === 'On going' ? 'rgb(73 146 255)' :'rgb(31 204 123)' 10 | } 11 | return ( 12 | 13 | {name} 14 | {email} 15 | {serviceName} 16 | 17 | 18 | 19 | {status} 20 | 21 | 22 | handleAction(_id, "Pending")} id="pending">Pending 23 | handleAction(_id, "On going")} id="ongoing">On going 24 | handleAction(_id, "Done")} id="done">Done 25 | 26 | 27 | 28 | 29 | 30 | ); 31 | }; 32 | 33 | export default Order; -------------------------------------------------------------------------------- /src/component/Dashoboard/OrderList/OrderList.css: -------------------------------------------------------------------------------- 1 | .orderList{ 2 | background: white; 3 | box-shadow: 0 2px 5px 1px rgb(64 60 67 / 4%); 4 | padding: 2rem; 5 | border-radius: 1rem; 6 | width: 100%; 7 | margin-top: 2.5rem; 8 | } 9 | .tableTitle { 10 | background: #efefef; 11 | border-radius: 0.4rem; 12 | padding: 0.2rem 1rem; 13 | } 14 | .tableTitle p { 15 | margin-bottom: 0; 16 | font-weight: 500; 17 | } 18 | 19 | .table-hover tbody tr:hover { 20 | color: #212529; 21 | background-color: #fcfcfc!important; 22 | } 23 | 24 | .table td, .table th { 25 | border-top: 0!important; 26 | } 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/component/Dashoboard/OrderList/OrderList.jsx: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import React, { useEffect, useState } from 'react'; 3 | import { Table } from 'react-bootstrap'; 4 | import TableLoader from '../../Shared/TableOrder/TableOrder'; 5 | import Order from './Order'; 6 | import './OrderList.css' 7 | 8 | const OrderList = () => { 9 | const [orders, setOrders] = useState([]); 10 | const [isUpdated, setIsUpdated] = useState(false); 11 | 12 | useEffect(() => { 13 | axios.get('https://immense-river-40491.herokuapp.com/orders') 14 | .then(res => setOrders(res.data)) 15 | },[isUpdated]) 16 | 17 | const handleAction = (id, status) => { 18 | setIsUpdated(true) 19 | axios.patch(`https://immense-river-40491.herokuapp.com/statusUpdate/${id}`, {status: status }) 20 | .then(res => res.data && setIsUpdated(false)) 21 | } 22 | 23 | return ( 24 |
25 | { 26 | orders.length === 0 ? 27 | 28 | : 29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | { 41 | orders.map(order => ) 42 | } 43 | 44 |
NameEmail IDServiceStatus
45 |
46 | } 47 | 48 |
49 | ); 50 | }; 51 | 52 | export default OrderList; -------------------------------------------------------------------------------- /src/component/Dashoboard/Profile/Profile.css: -------------------------------------------------------------------------------- 1 | .profile { 2 | box-shadow: 0 2px 5px 1px rgb(64 60 67 / 16%); 3 | background: #fff; 4 | text-align: center; 5 | margin: 2.5rem auto; 6 | border-radius: 0.3rem; 7 | max-width: 500px; 8 | } 9 | 10 | .profile h2 { 11 | font-size: 35px; 12 | font-weight: 500; 13 | padding: 0.5rem 0; 14 | margin-bottom: 0; 15 | background-color: #EFF2F7; 16 | } 17 | 18 | .profile img { 19 | height: 120px; 20 | width: 120px; 21 | border-radius: 50%; 22 | margin: 1rem 0; 23 | } 24 | 25 | .profile h3 { 26 | font-size: 1.5rem; 27 | margin: 0.6rem 0; 28 | } 29 | 30 | .profile h5 { 31 | font-size: 1.1rem; 32 | color: rgba(0,0,0,.7); 33 | } 34 | 35 | .profileInfo { 36 | padding: 1.3rem; 37 | } 38 | 39 | .mainBtn { 40 | background: #7355F7; 41 | padding: 13px 36px; 42 | display: inline-block; 43 | border-radius: 50px; 44 | font-size: 15px; 45 | font-weight: 500; 46 | line-height: 1.2; 47 | text-transform: uppercase; 48 | border: none; 49 | color: #fff; 50 | transition: 0.4s; 51 | cursor: pointer; 52 | } 53 | .mainBtn:hover { 54 | background-color: #4C25F5; 55 | } -------------------------------------------------------------------------------- /src/component/Dashoboard/Profile/Profile.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Col } from 'react-bootstrap'; 3 | import toast from 'react-hot-toast'; 4 | import './Profile.css' 5 | import userimg from '../../../Assets/user.svg'; 6 | import { handleSignOut } from '../../Login/LoginManager'; 7 | import { SET_USER, useAppContext } from '../../../context'; 8 | const Profile = () => { 9 | const { state:{user: { name, email, img }}, dispatch} = useAppContext() 10 | const signOut = () => { 11 | const loading = toast.loading('Please wait...'); 12 | handleSignOut() 13 | .then(res => { 14 | toast.dismiss(loading); 15 | dispatch({type: SET_USER, payload: res}) 16 | toast.error('Logged Out!'); 17 | }) 18 | } 19 | return ( 20 | 21 |
22 |

Profile

23 |
24 | 25 |

26 | {name} 27 |

28 |
29 | {email} 30 |
31 | 34 |
35 |
36 | 37 | ); 38 | }; 39 | 40 | export default Profile; -------------------------------------------------------------------------------- /src/component/Dashoboard/Sidebar/Sidebar.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Poppins&family=Roboto&display=swap'); 2 | 3 | .sideBox{ 4 | height: 100%; 5 | } 6 | 7 | 8 | #sideNavbar { 9 | font-family: 'Poppins', sans-serif; 10 | transition: 0.4s; 11 | } 12 | #sideNavbar ul { 13 | margin: 0; 14 | padding: 0.5rem 0 0.5rem 2rem; 15 | list-style: none; 16 | } 17 | #sideNavbar ul li a { 18 | padding: 0.6rem 0.8rem; 19 | display: block; 20 | font-size: 1.1rem; 21 | color: #878787; 22 | border-left: 3px solid transparent; 23 | } 24 | #sideNavbar ul li a:hover { 25 | text-decoration: none; 26 | color: #000; 27 | background-color: #EFF2F7; 28 | } 29 | 30 | .activePage{ 31 | color: #000!important; 32 | background-color: #f1eeff!important; 33 | border-left: 3px solid #7255F6!important; 34 | } 35 | .activePage:hover { 36 | color: #000!important; 37 | background-color: #f1eeff!important; 38 | border-left: 3px solid #7255F6!important; 39 | } 40 | .iconC { 41 | margin-right: 5px; 42 | } 43 | 44 | .sideBrand { 45 | color: #000; 46 | text-align: center; 47 | margin-top: 0.5rem; 48 | margin-bottom: 1.5rem; 49 | display: flex; 50 | align-items: center; 51 | justify-content: center; 52 | } 53 | .sideBrand h2 { 54 | font-weight: 700; 55 | font-size: 1.5rem; 56 | margin-bottom: 0; 57 | } 58 | .sideBrnIcon { 59 | font-size: 2.5rem; 60 | font-weight: 700; 61 | color: #7255F6; 62 | margin-right: 5px; 63 | } -------------------------------------------------------------------------------- /src/component/Dashoboard/Sidebar/Sidebar.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { NavLink } from 'react-router-dom'; 3 | import './Sidebar.css'; 4 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' 5 | import { faShoppingCart, faCommentAlt, faUserPlus, faCog, faFileMedical, faList, faUserCircle} from '@fortawesome/free-solid-svg-icons' 6 | import { faBuffer } from '@fortawesome/free-brands-svg-icons'; 7 | import { useAppContext } from '../../../context'; 8 | 9 | const Sidebar = ({setTitle}) => { 10 | const { state: { admin } } = useAppContext() 11 | 12 | return ( 13 |
14 |
15 |
16 | 17 |
18 |

Easy Consulting

19 |
20 | 79 |
80 | ) 81 | } 82 | 83 | export default Sidebar 84 | -------------------------------------------------------------------------------- /src/component/Dashoboard/UserDashboard/AddReview/Review.css: -------------------------------------------------------------------------------- 1 | .userReviewBox { 2 | background: #f1ecff; 3 | padding: 2.5rem 5rem; 4 | border-radius: 0.6rem; 5 | text-align: center; 6 | min-height: 100vh; 7 | } 8 | .userReviewBox button { 9 | margin: 0 0.5rem; 10 | } 11 | .reviewForm { 12 | background: white; 13 | box-shadow: 0 2px 5px 1px rgb(64 60 67 / 4%); 14 | padding: 2rem; 15 | border-radius: 1rem; 16 | width: 100%; 17 | margin: 2.5rem 0; 18 | } -------------------------------------------------------------------------------- /src/component/Dashoboard/UserDashboard/AddReview/Review.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react'; 2 | import { Button } from 'react-bootstrap'; 3 | import ReviewForm from './ReviewFrom'; 4 | import './Review.css'; 5 | import { Link } from 'react-router-dom'; 6 | import userImg from '../../../../Assets/user.svg'; 7 | import axios from 'axios'; 8 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; 9 | import { faTrashAlt } from '@fortawesome/free-solid-svg-icons'; 10 | import { faEdit } from '@fortawesome/free-regular-svg-icons'; 11 | import toast from 'react-hot-toast'; 12 | import swal from 'sweetalert'; 13 | import { useAppContext } from '../../../../context'; 14 | 15 | 16 | const Review = () => { 17 | const { state: { user: { email, img } } } = useAppContext(); 18 | const [review, setReview] = useState({}); 19 | const [isUpdated, setIsUpdated] = useState(false) 20 | const {_id, name, address, description} = review || {}; 21 | useEffect(() => { 22 | axios(`https://immense-river-40491.herokuapp.com/userReview?email=${email}`) 23 | .then(res => { 24 | setReview(res.data[0]); 25 | }) 26 | }, [email, isUpdated]) 27 | 28 | const handleDelete = (id) => { 29 | setIsUpdated(false) 30 | swal({ 31 | title: "Are you sure?", 32 | text: "Are you sure! you want to delete the review?", 33 | icon: "warning", 34 | buttons: true, 35 | dangerMode: true, 36 | }) 37 | .then( wantDelete => { 38 | if (wantDelete) { 39 | const loading = toast.loading('deleting...Please wait!') 40 | axios.delete(`https://immense-river-40491.herokuapp.com/deleteReview/${id}`) 41 | .then(res => { 42 | toast.dismiss(loading) 43 | if(res){ 44 | setIsUpdated(true); 45 | toast.success('Your review has been deleted successfully!'); 46 | } 47 | else{ 48 | toast.error('Something went wrong, please try again'); 49 | } 50 | }) 51 | .catch(err => { 52 | toast.dismiss(loading) 53 | swal({ 54 | title: "Failed!", 55 | text: 'Something went wrong, please try again', 56 | icon: "error", 57 | }); 58 | }) 59 | } 60 | }); 61 | } 62 | return ( 63 |
64 | { description ? 65 |
66 |
67 | { img ? : 68 | } 69 |
{name}
70 |
{address}
71 |

{description}

72 |
73 | 74 | 75 |
76 | : 77 | 78 | } 79 |
80 | ); 81 | }; 82 | 83 | export default Review; -------------------------------------------------------------------------------- /src/component/Dashoboard/UserDashboard/AddReview/ReviewFrom.jsx: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import React, { useState } from 'react'; 3 | import { useEffect } from 'react'; 4 | import { useForm } from 'react-hook-form'; 5 | import { useParams,useNavigate } from 'react-router-dom'; 6 | import toast from 'react-hot-toast'; 7 | import { Button, Col, Form, Row } from 'react-bootstrap'; 8 | import swal from 'sweetalert'; 9 | import { useAppContext } from '../../../../context'; 10 | 11 | const ReviewForm = ({setIsUpdated}) => { 12 | const {state:{user: {email, img}}} = useAppContext() 13 | const {id} = useParams(); 14 | const { register, handleSubmit, reset } = useForm(); 15 | const [review, setReview] = useState({}); 16 | const {name, address, description} = review; 17 | useEffect(() => { 18 | axios(`https://immense-river-40491.herokuapp.com/userReview/${id}`) 19 | .then(res => { 20 | setReview(res.data[0]); 21 | }) 22 | }, [id]) 23 | 24 | const history = useNavigate (); 25 | const onSubmit = data => { 26 | const loading = toast.loading('Uploading...Please wait!'); 27 | const reviewData = {...data}; 28 | reviewData.email = review.email || email; 29 | reviewData.img = review.img || img; 30 | if(id){ 31 | axios.patch(`https://immense-river-40491.herokuapp.com/updateReview/${id}`, reviewData) 32 | 33 | .then(res => { 34 | if(res){ 35 | toast.dismiss(loading); 36 | if( 37 | data.name === name && 38 | data.address === address && 39 | data.description === description 40 | ){ 41 | toast.error("You haven't changed anything") 42 | }else{ 43 | toast.success('your review was successful updated!'); 44 | } 45 | history('/dashboard/review'); 46 | } 47 | }) 48 | }else { 49 | setIsUpdated(false) 50 | axios.post('https://immense-river-40491.herokuapp.com/addReview', reviewData) 51 | .then(res => { 52 | if(res){ 53 | setIsUpdated(true) 54 | toast.dismiss(loading); 55 | swal("Success!", "Your review has been submitted successfully. We appreciate your contirbution.", "success"); 56 | } 57 | }) 58 | } 59 | reset(); 60 | } 61 | return ( 62 |
63 |
64 |
65 | 66 | 67 | Your Name 68 | 73 | 74 | 75 | Address 76 | 81 | 82 | 83 | Description 84 | 91 | 92 | 93 |
94 | 97 |
98 |
99 |
100 |
101 | ); 102 | }; 103 | 104 | export default ReviewForm; -------------------------------------------------------------------------------- /src/component/Dashoboard/UserDashboard/Book/Book.css: -------------------------------------------------------------------------------- 1 | .bookForm { 2 | background: #fff; 3 | padding: 2rem 3rem; 4 | margin: 2.5rem 1rem; 5 | border-radius: 1rem; 6 | position: relative; 7 | } 8 | 9 | .form-select:focus, 10 | .form-control:focus { 11 | border-color: #8468ff!important; 12 | box-shadow: 0 0 0 0.2rem rgb(4 0 255 / 26%)!important; 13 | } 14 | 15 | .priceInput { 16 | display: block; 17 | width: 100%; 18 | height: calc(1.5em + .75rem + 2px); 19 | padding: .375rem .75rem; 20 | font-size: 1rem; 21 | font-weight: 400; 22 | line-height: 1.5; 23 | color: #495057; 24 | background-color: #fff; 25 | background-clip: padding-box; 26 | border: 1px solid #ced4da; 27 | border-radius: .25rem; 28 | } 29 | 30 | .activeService { 31 | background: #66b0ffbe; 32 | color: #fff; 33 | } 34 | 35 | .toastIcon { 36 | height: 1.2rem; 37 | } 38 | 39 | .bookToast { 40 | position: absolute; 41 | right: 0; 42 | top: 1.5rem; 43 | z-index: 111; 44 | background: #fff; 45 | } -------------------------------------------------------------------------------- /src/component/Dashoboard/UserDashboard/Book/Book.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react'; 2 | import {Elements} from '@stripe/react-stripe-js'; 3 | import {loadStripe} from '@stripe/stripe-js'; 4 | import { Form, Col, Row, Toast } from 'react-bootstrap'; 5 | import './Book.css' 6 | import axios from 'axios'; 7 | import ifoIcon from '../../../../Assets/info.svg'; 8 | import Checkout from './Checkout'; 9 | import { SET_SELECTED_SERVICE, useAppContext } from '../../../../context'; 10 | 11 | const Book = () => { 12 | const { state: { selectedService }, dispatch} = useAppContext() 13 | const [services, setServices] = useState([]); 14 | const [show, setShow] = useState(true); 15 | 16 | useEffect(() => { 17 | axios.get(`https://immense-river-40491.herokuapp.com/services`) 18 | .then(res => { 19 | setServices(res.data) 20 | if(!selectedService.name){ 21 | dispatch({type: SET_SELECTED_SERVICE, payload: res.data[0]}) 22 | } 23 | }) 24 | }, [selectedService.name, dispatch]) 25 | 26 | const handleSelection = e => { 27 | const getService = services.find(({name}) => e.target.value === name) 28 | dispatch({type: SET_SELECTED_SERVICE, payload: getService}) 29 | } 30 | 31 | const stripePromise = loadStripe('pk_test_51Ii2KaCKKXM4eFaOJWCOr8pS4GVkoCerGCRHefo7hDpLYMcjpGqPNpoeydvFApWXDSSMnfXNzdtwRcF1o8XmTk3H00xDH8wKZc'); 32 | setTimeout(() => { 33 | setShow(false); 34 | }, 7000) 35 | 36 | return ( 37 |
38 | setShow(!show)} className="bookToast"> 39 | 40 | 41 | Info 42 | 02 seconds ago 43 | 44 | 4242 4242 4242 4242 you can use this card number for testing 45 | 46 | 47 | 48 | Service 49 | 57 | 58 | 59 | Price 60 |
61 | {selectedService.price} 62 |
63 | 64 |
65 | 66 | 67 | 68 | 69 |
70 | ); 71 | }; 72 | 73 | export default Book; -------------------------------------------------------------------------------- /src/component/Dashoboard/UserDashboard/Book/Checkout.jsx: -------------------------------------------------------------------------------- 1 | import React, { useMemo } from 'react' 2 | import { 3 | useStripe, 4 | useElements, 5 | CardNumberElement, 6 | CardCvcElement, 7 | CardExpiryElement 8 | } from '@stripe/react-stripe-js'; 9 | import swal from 'sweetalert'; 10 | import { Form, Col, Row } from 'react-bootstrap'; 11 | import { useForm } from 'react-hook-form'; 12 | import toast from 'react-hot-toast'; 13 | import axios from 'axios'; 14 | import { useAppContext } from '../../../../context'; 15 | 16 | 17 | const useOptions = () => { 18 | const options = useMemo(() => ({ 19 | style: { 20 | base: { 21 | fontSize: "1.2rem", 22 | lineHeight: "2", 23 | color: "#495057", 24 | letterSpacing: "0.025em", 25 | "::placeholder": { 26 | color: "#aab7c4" 27 | } 28 | }, 29 | invalid: { 30 | color: "#9e2146" 31 | } 32 | } 33 | }), []); 34 | return options; 35 | }; 36 | 37 | const Checkout = () => { 38 | const { state: { user, selectedService: { name, img, _id, description, price } } } = useAppContext(); 39 | const stripe = useStripe(); 40 | const elements = useElements(); 41 | const options = useOptions(); 42 | const { register, handleSubmit, reset } = useForm(); 43 | const onSubmit = async data => { 44 | if (!stripe || !elements) { 45 | return; 46 | } 47 | const loading = toast.loading('Please wait...!'); 48 | 49 | const { error, paymentMethod } = await stripe.createPaymentMethod({ 50 | type: "card", 51 | card: elements.getElement(CardNumberElement) 52 | }); 53 | 54 | if (error) { 55 | toast.dismiss(loading); 56 | return swal("Failed!", error.message, "error", { dangerMode: true }); 57 | } 58 | else { 59 | const orderData = { 60 | ...data, 61 | paymentMethod: "card", 62 | paymentId: paymentMethod.id, 63 | status: "Pending", 64 | serviceId: _id, 65 | serviceName: name, 66 | description: description, 67 | img: img, 68 | price: price 69 | } 70 | axios.post('https://immense-river-40491.herokuapp.com/addOrder', orderData) 71 | .then(res => { 72 | toast.dismiss(loading); 73 | swal("Congratulation!", "Your order has been placed successfully", "success"); 74 | reset(); 75 | }) 76 | .catch(err => { 77 | toast.dismiss(loading); 78 | swal("Failed!", "Something went wrong! please try again", "error") 79 | }) 80 | } 81 | }; 82 | 83 | return ( 84 |
85 | 86 | 87 | 88 | Your Name 89 | 94 | 95 | 96 | 97 | Email 98 | 103 | 104 | 105 | 106 | Address 107 | 111 | 112 | 113 | 114 |
115 | Card Number 116 | 117 |
118 |
119 | Expiration Date 120 | 121 |
122 |
123 | CVC 124 | 125 |
126 | 127 |
128 |
129 | 130 |
131 |
132 | ); 133 | }; 134 | 135 | export default Checkout; -------------------------------------------------------------------------------- /src/component/Dashoboard/UserDashboard/BookList/BookList.css: -------------------------------------------------------------------------------- 1 | .bookingList { 2 | background: white; 3 | box-shadow: 0 2px 5px 1px rgb(64 60 67 / 4%); 4 | padding: 1.5rem; 5 | margin: 0.9rem 0; 6 | border-radius: 0.5rem; 7 | } 8 | .bookingList img{ 9 | height: 70px; 10 | border-radius: 0.3rem; 11 | padding: 0.2rem 0.5rem; 12 | background: #D5C4FF; 13 | margin-bottom: 0.5rem; 14 | } 15 | .bookingList h6{ 16 | margin: 0.5rem 0; 17 | color: #263179; 18 | font-size: 1.2rem; 19 | font-weight: 600; 20 | } 21 | .serviceState { 22 | padding: 0.5rem 1rem; 23 | border-radius: 0.3rem; 24 | } 25 | -------------------------------------------------------------------------------- /src/component/Dashoboard/UserDashboard/BookList/BookList.jsx: -------------------------------------------------------------------------------- 1 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; 2 | import axios from 'axios'; 3 | import { Button } from 'react-bootstrap'; 4 | import React, { useEffect, useState } from 'react'; 5 | import toast from 'react-hot-toast'; 6 | import swal from 'sweetalert'; 7 | import './BookList.css' 8 | import { faTimesCircle } from '@fortawesome/free-solid-svg-icons'; 9 | import ListSkeleton from '../../../Shared/TableOrder/ListSkeleton'; 10 | import { useAppContext } from '../../../../context'; 11 | 12 | const BookList = () => { 13 | const { state:{user} } =useAppContext(); 14 | const [bookings, setBookings] = useState([]); 15 | const [isUpdated, setIsUpdated] = useState(false); 16 | 17 | useEffect(() => { 18 | axios.get(`https://immense-river-40491.herokuapp.com/bookingList?email=${user.email}`) 19 | .then(res => setBookings(res.data)) 20 | },[user.email, isUpdated]) 21 | 22 | const handleDelete = (id, status) => { 23 | setIsUpdated(false) 24 | swal({ 25 | title: `${status === 'Done' ? "Remove" : "Cancel"} Booking?`, 26 | text: `Are you sure! you want to ${status === 'Done' ? "remove booking from your booking List" : "cancel"}?`, 27 | icon: "warning", 28 | buttons: true, 29 | dangerMode: true, 30 | }) 31 | .then( wantDelete => { 32 | if (wantDelete) { 33 | const loading = toast.loading('deleting...Please wait!') 34 | axios.delete(`https://immense-river-40491.herokuapp.com/deleteOrder/${id}`) 35 | .then(res => { 36 | toast.dismiss(loading) 37 | if(res){ 38 | setIsUpdated(true); 39 | toast.success('Your Booking is successfully canceled!'); 40 | } 41 | else{ 42 | toast.error('Something went wrong, please try again'); 43 | } 44 | }) 45 | .catch(err => { 46 | toast.dismiss(loading) 47 | swal({ 48 | title: "Failed!", 49 | text: 'Something went wrong, please try again', 50 | icon: "error", 51 | }); 52 | }) 53 | } 54 | }); 55 | } 56 | return ( 57 |
58 | {bookings.length === 0 && } 59 |
60 | { 61 | bookings.map(({_id, serviceName,status,description,img}) => { 62 | return(
63 |
64 |
65 | 66 |
67 |

{status}

68 |
69 |
70 |
{serviceName}
71 |

{description}

72 | 76 |
77 |
) 78 | }) 79 | } 80 |
81 |
82 | ); 83 | }; 84 | 85 | export default BookList; -------------------------------------------------------------------------------- /src/component/Dashoboard/UserDashboard/UserDashboard/UserDashboard.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Profile from '../../Profile/Profile' 3 | import { Routes, Route } from 'react-router-dom' 4 | import BookList from '../BookList/BookList' 5 | import Book from '../Book/Book' 6 | import Review from '../AddReview/Review'; 7 | import ReviewForm from '../AddReview/ReviewFrom' 8 | const UserDashboard = () => { 9 | return ( 10 | 11 | } /> 12 | } /> 13 | } /> 14 | } /> 15 | } /> 16 | } /> 17 | 18 | ) 19 | } 20 | 21 | export default UserDashboard 22 | -------------------------------------------------------------------------------- /src/component/FooterData.jsx: -------------------------------------------------------------------------------- 1 | import { faMobileAlt, faMapMarkedAlt } from '@fortawesome/free-solid-svg-icons'; 2 | import { faBuffer } from '@fortawesome/free-brands-svg-icons' 3 | 4 | export const usefulLink = [ 5 | {name: 'Home', id: 1}, 6 | {name: 'About us', id: 2}, 7 | {name: 'Services', id: 3}, 8 | {name: 'Team', id: 4}, 9 | {name: 'Blog', id: 5} 10 | ] 11 | export const ourServices = [ 12 | {name: 'Strategy & Research', id: 6}, 13 | {name: 'Web Design', id: 7}, 14 | {name: 'Web Development', id: 8}, 15 | {name: 'Digital Marketing', id: 9}, 16 | {name: 'Graphic Design', id: 10} 17 | ] 18 | export const otherLinks = [ 19 | {name: 'FAQ', id: 11}, 20 | {name: 'Portfolio', id: 12}, 21 | {name: 'Privacy Policy', id: 13}, 22 | {name: 'Terms & Conditions', id: 14}, 23 | {name: 'Support', id: 15}, 24 | ] 25 | 26 | export const footerInfo = [ 27 | {icon: faBuffer, info1: 'EASY CONSULTING', id: 1}, 28 | {icon: faMobileAlt, info1: '+13322176301', info2: 'ujjalzaman@gmail.com', id: 2}, 29 | {icon: faMapMarkedAlt, info1: 'bronx,new york, USA', info2: 'Nevada,USA', id: 3} 30 | ]; -------------------------------------------------------------------------------- /src/component/Home/About/About.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import teamPic from '../../../Assets/about.svg'; 3 | import Fade from 'react-reveal/Fade'; 4 | 5 | const About = () => { 6 | return ( 7 |
8 |
9 |
10 |
11 | 12 | 13 | 14 |
15 |
16 | 17 |

about us

18 |

HOW WE CAN HELP YOUR BUSINESS GOAL

19 |

Choosing a suitable theme for your business isn’t hard if you know what to look for. A solid bundled contact form plugin enables customers to make contact with you, and a means of displaying your business and location information prominently is also essential.

20 | 21 |
22 |
23 |
24 |
25 |
26 | ); 27 | }; 28 | 29 | export default About; -------------------------------------------------------------------------------- /src/component/Home/BrowserSupport/BrowserSupport.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Box from '@mui/material/Box'; 3 | import Typography from '@mui/material/Typography'; 4 | import Avatar from '@mui/material/Avatar'; 5 | import Grid from '@mui/material/Grid'; 6 | 7 | const data = [ 8 | { 9 | title: 'Google Chrome', 10 | subtitle: 11 | 'Google Chrome is a cross-platform web browser developed by Google.', 12 | icon: 'https://assets.maccarianagency.com/browsers/chrome.png', 13 | }, 14 | { 15 | title: 'Safari', 16 | subtitle: 17 | 'Safari is a graphical web browser developed by Apple, based on the WebKit engine.', 18 | icon: 'https://assets.maccarianagency.com/browsers/safari.png', 19 | }, 20 | { 21 | title: 'Microsoft Edge', 22 | subtitle: 23 | 'Microsoft Edge is a web browser developed by Microsoft. It was first released for Windows 10.', 24 | icon: 'https://assets.maccarianagency.com/browsers/edge.png', 25 | }, 26 | { 27 | title: 'Mozilla Firefox', 28 | subtitle: 29 | 'Mozilla Firefox, or simply Firefox, is a free and web browser developed by the Mozilla.', 30 | icon: 'https://assets.maccarianagency.com/browsers/firefox.png', 31 | }, 32 | ]; 33 | 34 | const BrowserSupport = () => { 35 | return ( 36 | 37 | 38 | 46 | Compatibility 47 | 48 | 49 | Compatible with all major browsers 50 | 51 | 52 | 53 | {data.map((item, i) => ( 54 | 55 | 63 | 68 | 75 | 81 | {item.title} 82 | 83 | 84 | {item.subtitle} 85 | 86 | 87 | 88 | 89 | ))} 90 | 91 | 92 | ) 93 | } 94 | 95 | export default BrowserSupport 96 | -------------------------------------------------------------------------------- /src/component/Home/BuildTools/BuildTools.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import SyntaxHighlighter from 'react-syntax-highlighter'; 3 | import { vs2015 } from 'react-syntax-highlighter/dist/cjs/styles/hljs'; 4 | import Box from '@mui/material/Box'; 5 | import Typography from '@mui/material/Typography'; 6 | import { useTheme } from '@mui/material/styles'; 7 | 8 | const BuildTools = () => { 9 | const theme = useTheme(); 10 | 11 | return ( 12 | 13 | 14 | 15 | 24 | Build tools and full documention 25 | 26 | 33 | Components, plugins, and build tools are all thoroughly documented 34 | with live examples and markup for easier use and customization. 35 | 36 | 37 | 38 | 39 | 50 | {` 51 | > $ yarn install 52 | // Or 53 | > $ npm install 54 | 55 | // Everything installed! 56 | 57 | 58 | > $ yarn start 59 | // Or 60 | > $ npm run start 61 | 62 | // LiveReload started. Opening localhost:3000 63 | `} 64 | 65 | 66 | 67 | ) 68 | } 69 | 70 | export default BuildTools 71 | -------------------------------------------------------------------------------- /src/component/Home/Contact/Contact.css: -------------------------------------------------------------------------------- 1 | #contact { 2 | padding: 7rem 0 6rem; 3 | overflow: hidden; 4 | } 5 | .sectionTitle { 6 | margin: 0.5rem 0 3rem; 7 | font-size: 2rem; 8 | font-weight: 700; 9 | position: relative; 10 | display: inline-block; 11 | padding-bottom: 0.6rem; 12 | } 13 | .sectionTitle::after { 14 | content: ""; 15 | position: absolute; 16 | left: 0; 17 | bottom: -2px; 18 | width: 100px; 19 | border-radius: 70px; 20 | height: 4px; 21 | background: #7355F7; 22 | } 23 | 24 | .contactForm { 25 | padding: 1rem; 26 | } 27 | .contactForm input, 28 | .contactForm textarea { 29 | width: 100%; 30 | margin: 0.5rem 0; 31 | padding: 1rem 0.8rem; 32 | border-radius: 0.3rem; 33 | border: 1px solid #bebebe; 34 | color: #000; 35 | } 36 | .contactForm input:focus, 37 | .contactForm textarea:focus { 38 | outline: none !important; 39 | border: 1px solid #7054F2; 40 | background-color: rgb(243, 240, 255); 41 | } 42 | .contactForm textarea { 43 | height: 120px; 44 | } -------------------------------------------------------------------------------- /src/component/Home/Contact/Contact.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Col, Row } from 'react-bootstrap'; 3 | import './Contact.css'; 4 | import contactImg from '../../../Assets/contact.svg'; 5 | // import swal from 'sweetalert' 6 | import Fade from 'react-reveal/Fade'; 7 | 8 | const Contact = () => { 9 | const handleSubmit = event => { 10 | event.preventDefault(); 11 | event.target.reset(); 12 | // swal("Thank You!", "We appreciate you contacting us!", "success"); 13 | } 14 | return ( 15 |
16 | 17 | 18 | 19 | 20 |
21 |

CONTACT US

22 |
GET IN TOUCH
23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 |
39 |
40 | 41 | 42 | 43 | 44 | 45 | 46 |
47 | 48 |
49 | ); 50 | }; 51 | 52 | export default Contact; -------------------------------------------------------------------------------- /src/component/Home/Footer/Footer.css: -------------------------------------------------------------------------------- 1 | .footer { 2 | background: #7355F7; 3 | background-image: url('../../../Assets/footerbg.png'); 4 | width: 100%; 5 | font-family: 'Poppins', sans-serif; 6 | margin: 0!important; 7 | } 8 | .footerBox .footerLogo { 9 | background-color: #fff; 10 | border-radius: 3px; 11 | box-shadow: 0 0px 60px 0 rgb(0 0 0 / 20%); 12 | height: 70px; 13 | padding: 0.5rem; 14 | } 15 | .linkIcon { 16 | color: #6F53EF; 17 | font-size: 2rem; 18 | cursor: pointer; 19 | background: white; 20 | padding: 5px; 21 | margin: 0 0.5rem; 22 | border-radius: 0.3rem; 23 | } 24 | .footerLink, 25 | .fAboutUs { 26 | padding: 1.5rem 2rem; 27 | } 28 | 29 | .footerLink h5, 30 | .fAboutUs h5 { 31 | color: rgba(240, 255, 255, 0.925); 32 | padding-top: 0.5rem; 33 | font-weight: 400; 34 | display: inline-block; 35 | position: relative; 36 | } 37 | .footerLink h5 { 38 | padding-bottom: 0.5rem; 39 | } 40 | .footerLink h5::after { 41 | content: ""; 42 | position: absolute; 43 | left: 0; 44 | bottom: -2px; 45 | width: 60px; 46 | border-radius: 70px; 47 | height: 4px; 48 | background: rgba(240, 255, 255, 0.925);; 49 | } 50 | .footerLink > .aboutUsDes { 51 | color: rgba(255, 255, 255, 0.6); 52 | font-weight: 400; 53 | } 54 | .footerLink li { 55 | list-style: none; 56 | color: rgba(255, 255, 255, 0.6); 57 | font-size: 1rem; 58 | transition: 0.4s; 59 | margin: 1.1rem 0; 60 | font-weight: 400; 61 | } 62 | .footerLink li:hover { 63 | margin-left: 0.7rem; 64 | color: #fff; 65 | } 66 | 67 | .footerLink a { 68 | color: rgba(255, 255, 255, 0.6); 69 | text-decoration: none; 70 | } 71 | .footerLink a:hover { 72 | text-decoration: none; 73 | } 74 | .footArrowIcon { 75 | font-size: 0.9rem; 76 | } 77 | 78 | .fAboutUs p { 79 | color: rgba(255, 255, 255, 0.699); 80 | font-weight: 400; 81 | margin: 1rem 0; 82 | 83 | } 84 | .fAboutUs ul { 85 | margin: 0; 86 | padding: 0; 87 | } 88 | .fAboutUs li { 89 | list-style: none; 90 | float: left; 91 | } 92 | .fAboutUs li a { 93 | display: block; 94 | width: 2.5rem; 95 | height: 2.5rem; 96 | border-radius: 50%; 97 | text-align: center; 98 | line-height: 2.5rem; 99 | background: #fff; 100 | margin-right: 5px; 101 | color:#7355F7; 102 | transition: 0.4s; 103 | } 104 | .fAboutUs li a:hover{ 105 | background: #4B24F5; 106 | color: #fff; 107 | } 108 | 109 | .copyRight { 110 | background-color: #2608AB; 111 | color: rgba(255, 255, 255, 0.692); 112 | font-weight: 400; 113 | font-size: 0.911rem; 114 | text-align: center; 115 | margin-bottom: 0; 116 | padding: 1rem 0; 117 | } 118 | .copyRight > .fHighlight { 119 | color: #fff; 120 | font-weight: 400; 121 | font-size: 1rem; 122 | } 123 | 124 | 125 | /* FooterInfo */ 126 | 127 | .footerInfo { 128 | width: 100%; 129 | border-bottom: 1px solid rgba(255, 255, 255, 0.6); 130 | padding: 3rem 0 2rem; 131 | } 132 | 133 | .fContactInfo p { 134 | color: rgba(255, 255, 255, 0.6); 135 | font-size: 1rem; 136 | margin-bottom: 0.2rem; 137 | margin-left: 0.7rem; 138 | } 139 | .fContactIcon { 140 | font-size: 2.5rem; 141 | color: rgba(255, 255, 255, 0.822); 142 | } 143 | 144 | .fContactInfo1 p { 145 | color: #fff!important; 146 | font-weight: 500; 147 | font-size: 1.5rem!important; 148 | } 149 | .fContactInfo1 .fContactIcon { 150 | color: #fff; 151 | font-weight: 500; 152 | font-size: 3rem; 153 | } 154 | 155 | 156 | /* Animation border */ 157 | 158 | .animate-border { 159 | position: relative; 160 | display: block; 161 | width: 115px; 162 | height: 3px; 163 | background: #2608AB; 164 | } 165 | 166 | .animate-border:after { 167 | position: absolute; 168 | content: ""; 169 | width: 35px; 170 | height: 3px; 171 | left: 0; 172 | bottom: 0; 173 | border-left: 20px solid #fff; 174 | -webkit-animation: animborder 3s linear infinite; 175 | animation: animborder 3s linear infinite; 176 | } 177 | 178 | @-webkit-keyframes animborder { 179 | 0% { 180 | -webkit-transform: translateX(0px); 181 | transform: translateX(0px); 182 | } 183 | 100% { 184 | -webkit-transform: translateX(81px); 185 | transform: translateX(81px); 186 | } 187 | } 188 | 189 | @keyframes animborder { 190 | 0% { 191 | -webkit-transform: translateX(0px); 192 | transform: translateX(0px); 193 | } 194 | 100% { 195 | -webkit-transform: translateX(81px); 196 | transform: translateX(81px); 197 | } 198 | } -------------------------------------------------------------------------------- /src/component/Home/Footer/Footer.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Col, Row } from 'react-bootstrap'; 3 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' 4 | import { faFacebook, faInstagram, faLinkedinIn, faTwitter } from '@fortawesome/free-brands-svg-icons' 5 | import FooterCol from './FooterCol'; 6 | import './Footer.css'; 7 | import { usefulLink, ourServices, otherLinks, footerInfo } from '../../FooterData'; 8 | import FooterInfo from './FooterInfo'; 9 | import { Link } from 'react-router-dom'; 10 | import { scrollUP } from '../../Shared/ScrollTop/ScrollTop'; 11 | 12 | 13 | const Footer = () => { 14 | return ( 15 |
16 | 17 | 18 | { 19 | footerInfo.map(data => ) 20 | } 21 | 22 | 23 |
ABOUT US
24 | 25 |

Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolor, voluptate quod facere quas rem quaerat.

26 |
    27 |
  • 28 | 29 | 30 | 31 |
  • 32 |
  • 33 | 34 | 35 | 36 |
  • 37 |
  • 38 | 39 | 40 | 41 |
  • 42 |
  • 43 | 44 | 45 | 46 |
  • 47 |
48 | 49 | 50 | 51 | 52 |
53 |

Copyright © 2021 Ujjal zaman. All rights reserved.

54 |
55 | ); 56 | }; 57 | 58 | export default Footer; -------------------------------------------------------------------------------- /src/component/Home/Footer/FooterCol.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link } from 'react-router-dom'; 3 | import { Col } from 'react-bootstrap'; 4 | // import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; 5 | // import { faAngleDoubleRight } from '@fortawesome/free-solid-svg-icons'; 6 | import { scrollUP } from '../../Shared/ScrollTop/ScrollTop'; 7 | 8 | const FooterCol = (props) => { 9 | return ( 10 | 11 |
{props.title? props.title : ''}
12 | { 13 | props.menuItems?.map(({name, id}) =>
  • 14 | {/* */} 16 | {name}
  • ) 17 | } 18 | {props.children && props.children} 19 | 20 | ); 21 | }; 22 | 23 | export default FooterCol; -------------------------------------------------------------------------------- /src/component/Home/Footer/FooterInfo.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; 3 | import { Col } from 'react-bootstrap'; 4 | 5 | const FooterInfo = ({data: {icon, info1, info2, id}}) => { 6 | return ( 7 | 8 |
    9 | 10 |
    11 |

    {info1}

    12 | {info2 &&

    {info2}

    } 13 |
    14 |
    15 | 16 | ); 17 | }; 18 | 19 | export default FooterInfo; -------------------------------------------------------------------------------- /src/component/Home/HappyClient/HappyClient.css: -------------------------------------------------------------------------------- 1 | .ourValue { 2 | background: #7355F7; 3 | padding: 2rem; 4 | } 5 | .ourValueDetails { 6 | background-color: #fff; 7 | border-radius: 0.25rem; 8 | box-shadow: 0 0px 60px 0 rgb(0 0 0 / 10%); 9 | padding: 1.3rem 1rem 1rem; 10 | transition: all 1s; 11 | text-align: center; 12 | } 13 | .valueIcon { 14 | padding: 0.4rem 0.8rem; 15 | font-size: 3rem; 16 | color: #fff; 17 | border-radius: 0.25rem 18 | } 19 | .valueIcon1 { 20 | background: #029e76; 21 | box-shadow: 0 2px 15px rgb(2 158 118 / 50%); 22 | } 23 | .valueIcon2 { 24 | box-shadow: 0 2px 15px rgb(255 168 8 / 50%); 25 | background-color: #ffa808; 26 | } 27 | .valueIcon3 { 28 | box-shadow: 0 2px 15px rgb(85 67 209 / 50%); 29 | background-color: #5543d1; 30 | } 31 | .valueIcon4 { 32 | box-shadow: 0 2px 15px rgb(255 88 110 / 50%); 33 | background-color: #ff586e; 34 | } 35 | .ourValueNumber { 36 | font-weight: 700; 37 | font-size: 2.4rem; 38 | color: #7355F7; 39 | } 40 | .ourValueTitle { 41 | color: #777777; 42 | margin: 1.5rem 0 1rem 0; 43 | font-weight: 500; 44 | font-size: 1.2rem; 45 | } 46 | 47 | @media (max-width: 981px) { 48 | .ourValueDetails{ 49 | margin-top: 1rem; 50 | } 51 | } -------------------------------------------------------------------------------- /src/component/Home/HappyClient/HappyClient.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import './HappyClient.css'; 3 | // import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; 4 | // import { faSmileBeam, faTasks, faHeadset, faUsers } from '@fortawesome/free-solid-svg-icons'; 5 | import CountUp from 'react-countup'; 6 | const HappyClient = () => { 7 | const workDetails = [ 8 | { title: 'Happy Clients', number: 542, id: 1 }, 9 | { title: 'Projects', number: 623, id: 2 }, 10 | { title: 'Hours of Support', number: 1634, id: 3 }, 11 | { title: 'Hard Workers', number: 31, id: 4 } 12 | ] 13 | return ( 14 |
    15 |
    16 | { 17 | workDetails.map(({ title, number, icon, id }) => { 18 | return (
    19 |
    20 | 21 | {/* */} 22 | 23 |
    24 |

    {title}

    25 |

    26 | 31 |

    32 |
    33 |
    34 |
    ) 35 | }) 36 | } 37 |
    38 |
    39 | ) 40 | } 41 | 42 | export default HappyClient 43 | -------------------------------------------------------------------------------- /src/component/Home/Header/Header.css: -------------------------------------------------------------------------------- 1 | .header { 2 | background: white; 3 | height: 100vh; 4 | background-image: url('../../../Assets/bg.png'); 5 | background-repeat: no-repeat; 6 | background-position: right; 7 | width: 100%; 8 | overflow: hidden; 9 | } 10 | .titleArea { 11 | padding: 1rem; 12 | } 13 | .miniTitle { 14 | font-size: 22px; 15 | font-weight: 600; 16 | margin-bottom: 5px; 17 | color: #777777; 18 | text-transform: uppercase; 19 | } 20 | .headerTitle{ 21 | margin-bottom: 10px; 22 | font-size: 60px; 23 | font-weight: 800; 24 | font-family: sans-serif!important; 25 | } 26 | 27 | .headerContent { 28 | font-size: 18px; 29 | line-height: 1.5; 30 | color: #5e5e5e; 31 | font-weight: 400; 32 | font-family: 'Poppins', sans-serif; 33 | margin: 0.5rem 0 1rem 34 | } 35 | .branBtn { 36 | background: #7355F7; 37 | padding: 18px 35px; 38 | display: inline-block; 39 | border-radius: 50px; 40 | font-size: 15px; 41 | font-weight: 500; 42 | line-height: 1.2; 43 | text-transform: uppercase; 44 | border: none; 45 | color: #fff; 46 | transition: 0.4s; 47 | } 48 | .branBtn:hover { 49 | color: #fff; 50 | background-color: #4B24F5; 51 | } 52 | .headerHighlight { 53 | color: #7355F7; 54 | } 55 | 56 | @media (max-width: 981px) { 57 | .header{ 58 | overflow: visible; 59 | height: 100%; 60 | } 61 | .headerTitle{ 62 | margin-bottom: 10px; 63 | font-size: 40px; 64 | font-weight: 700; 65 | font-family: sans-serif!important; 66 | } 67 | } -------------------------------------------------------------------------------- /src/component/Home/Header/Header.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import NavBar from '../../Shared/Navbar/Navbar'; 3 | import './Header.css' 4 | import Hero from '../Hero/Hero'; 5 | 6 | const Header = () => { 7 | return ( 8 |
    9 | 10 | 11 |
    12 | ); 13 | }; 14 | 15 | export default Header; -------------------------------------------------------------------------------- /src/component/Home/Hero/Hero.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { LazyLoadImage } from 'react-lazy-load-image-component'; 3 | import { alpha, useTheme } from '@mui/material/styles'; 4 | import useMediaQuery from '@mui/material/useMediaQuery'; 5 | import Box from '@mui/material/Box'; 6 | import Typography from '@mui/material/Typography'; 7 | import Button from '@mui/material/Button'; 8 | import Grid from '@mui/material/Grid'; 9 | import Typed from 'react-typed'; 10 | 11 | const Hero = () => { 12 | const theme = useTheme(); 13 | 14 | const isMd = useMediaQuery(theme.breakpoints.up('md'), { 15 | defaultMatches: true, 16 | }); 17 | return ( 18 | 19 | 20 | 21 | 22 | 27 | Easy Consulting{' '}
    28 | Start Your {' '} 29 | 37 | 42 | 43 |
    44 |
    45 | 46 | 47 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Illum, delectus. 48 |
    49 | Lorem ipsum dolor sit amet. 50 |
    51 |
    52 | 57 | 65 | 74 | Learn more 75 | 76 | 77 |
    78 |
    79 | 90 | 104 | 105 |
    106 | ) 107 | } 108 | 109 | export default Hero 110 | -------------------------------------------------------------------------------- /src/component/Home/Home/Home.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import About from '../About/About'; 3 | import BrowserSupport from '../BrowserSupport/BrowserSupport'; 4 | import BuildTools from '../BuildTools/BuildTools'; 5 | import Contact from '../Contact/Contact'; 6 | import Footer from '../Footer/Footer'; 7 | import HappyClient from '../HappyClient/HappyClient'; 8 | import Header from '../Header/Header'; 9 | import Pricing from '../Pricing/Pricing'; 10 | import Reviews from '../Reviews/Reviews'; 11 | import Services from '../Services/Services'; 12 | 13 | const Home = () => { 14 | return ( 15 |
    16 |
    17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
    26 | {/* */} 27 |
    28 | ); 29 | }; 30 | 31 | export default Home; -------------------------------------------------------------------------------- /src/component/Home/Pricing/Pricing.css: -------------------------------------------------------------------------------- 1 | .pricing{ 2 | padding: 7rem 0 6rem; 3 | font-family: 'Poppins', sans-serif; 4 | } 5 | .pricingNav { 6 | display: flex; 7 | justify-content: space-between; 8 | padding: 0 1rem; 9 | } 10 | 11 | .pricingNav img { 12 | width: 50%; 13 | position: absolute; 14 | top: 50%; 15 | left: 50%; 16 | transform: translate(-50%, -50%); 17 | } 18 | 19 | .pricingNav .nav-link { 20 | position: relative; 21 | height: 90px; 22 | width: 90px; 23 | border-radius: 50%; 24 | transition: 0.3s; 25 | } 26 | 27 | .priceLink1 > .nav-link { 28 | border: 7px solid #ffccd3; 29 | } 30 | .priceLink2 > .nav-link { 31 | border: 7px solid #a2ffd2; 32 | } 33 | .priceLink3 > .nav-link { 34 | border: 7px solid #fdd2ff; 35 | } 36 | .priceLink4 > .nav-link { 37 | border: 7px solid #CBEDFF; 38 | } 39 | .priceLink5 > .nav-link { 40 | border: 7px solid #dfdaff; 41 | } 42 | .priceLink6 > .nav-link { 43 | border: 7px solid #ffeb94; 44 | } 45 | 46 | .priceLink1 > a:hover, 47 | .priceLink1 > .nav-link.active { 48 | background: #FF4F66; 49 | } 50 | .priceLink2 > a:hover, 51 | .priceLink2 > .nav-link.active { 52 | background: #4ED797; 53 | 54 | } 55 | .priceLink3 > a:hover, 56 | .priceLink3 > .nav-link.active { 57 | background: #F78CFF; 58 | } 59 | .priceLink4 > a:hover, 60 | .priceLink4 > .nav-link.active { 61 | background: #76CDFF; 62 | } 63 | .priceLink5 > a:hover, 64 | .priceLink5 > .nav-link.active { 65 | background: #755BFF; 66 | } 67 | .priceLink6 > a:hover, 68 | .priceLink6 > .nav-link.active { 69 | background: #ffd30f; 70 | } 71 | 72 | 73 | /* Pricing Card Component Design */ 74 | 75 | .pricingCard { 76 | box-shadow: 1px 0 50px rgb(0 0 0 / 9%); 77 | border-radius: 0.26rem !important; 78 | transition: all 1s; 79 | background-color: #fff; 80 | padding: 1rem 2rem; 81 | margin-top: 2.5rem; 82 | } 83 | 84 | .pricingBox { 85 | text-align: center; 86 | border-bottom: 1px solid rgba(119, 119, 119, 0.322); 87 | margin-bottom: 0.8rem; 88 | } 89 | 90 | .pricingBox h4 { 91 | font-weight: 700; 92 | padding: 0.5 0; 93 | margin-bottom: 0; 94 | } 95 | .pricingBox h5 { 96 | font-weight: 700; 97 | font-size: 1rem; 98 | } 99 | 100 | .pricingBox .pricePlan { 101 | font-weight: 600; 102 | margin: 0.7rem 0; 103 | } 104 | 105 | .planDescription{ 106 | font-size: 15px; 107 | color: #777; 108 | line-height: 1.8; 109 | } 110 | .pricingCard li { 111 | list-style: none; 112 | margin: 0.2rem 0; 113 | } 114 | .ph1, 115 | .ph2, 116 | .ph3, 117 | .ph4, 118 | .ph5, 119 | .ph6 { 120 | font-size: 1.6rem; 121 | font-weight: 700; 122 | } 123 | .pricingCard1 { 124 | background: #FFD2C4; 125 | } 126 | .ph1, 127 | .pricingCard1 > li > .checkIcon { 128 | color: #FF4F66; 129 | } 130 | 131 | .pricingCard2 { 132 | background: #D0FFE7; 133 | } 134 | .ph2, 135 | .pricingCard2 > li > .checkIcon { 136 | color: #11d87b; 137 | } 138 | 139 | .pricingCard3 { 140 | background: #fce1ff; 141 | } 142 | .ph3, 143 | .pricingCard3 > li > .checkIcon { 144 | color: #f565ff; 145 | } 146 | 147 | .pricingCard4 { 148 | background: #d2efff; 149 | } 150 | .ph4, 151 | .pricingCard4 > li > .checkIcon { 152 | color: #5bc5ff; 153 | } 154 | 155 | .pricingCard5 { 156 | background: #ded9ff; 157 | } 158 | .ph5, 159 | .pricingCard5 > li > .checkIcon { 160 | color: #755BFF; 161 | } 162 | 163 | .pricingCard6 { 164 | background: #fff1d5; 165 | } 166 | .ph6, 167 | .pricingCard6 > li > .checkIcon { 168 | color: #f5c800; 169 | } 170 | 171 | 172 | @media (max-width: 768px) { 173 | .pricingNav { 174 | display: flex; 175 | } 176 | } -------------------------------------------------------------------------------- /src/component/Home/Pricing/Pricing.jsx: -------------------------------------------------------------------------------- 1 | import { Col, Container, Nav, Row, Tab } from 'react-bootstrap'; 2 | import React from 'react'; 3 | import PricingCard from './PricingCard'; 4 | import './Pricing.css'; 5 | import { PricingData } from '../../PricingData'; 6 | import sPic1 from '../../../Assets/s1.png'; 7 | import sPic2 from '../../../Assets/s2.png'; 8 | import sPic3 from '../../../Assets/s3.png'; 9 | import sPic4 from '../../../Assets/s4.png'; 10 | import sPic5 from '../../../Assets/s5.png'; 11 | import sPic6 from '../../../Assets/s6.png'; 12 | import Spinner from '../../Shared/Spinner/Spinner'; 13 | const Pricing = () => { 14 | return ( 15 |
    16 |

    Pricing

    17 |
    18 |

    CHOOSE PLAN

    19 |
    20 | 21 | 22 | 23 | 24 | 56 | 57 | 58 | { 59 | PricingData.length === 0 ? 60 |
    : 61 | PricingData.map((data, index) => ) 62 | } 63 |
    64 |
    65 |
    66 |
    67 |
    68 | ); 69 | }; 70 | 71 | export default Pricing; -------------------------------------------------------------------------------- /src/component/Home/Pricing/PricingCard.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Col, Row, Tab } from 'react-bootstrap'; 3 | // import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; 4 | // import { faCheckCircle } from '@fortawesome/free-solid-svg-icons'; 5 | import Fade from 'react-reveal/Fade'; 6 | 7 | const PricingCard = ({data, id}) => { 8 | return ( 9 | 10 | 11 | { 12 | data.map(({title, name, price}, index) => { 13 | return( 14 | 15 | 16 |
    17 |
    18 |

    {title}

    19 |

    20 | ${price}/month 21 |

    22 |
    {name}
    23 |

    Pellentesque nibh. Aenean quam. In scelerisque sem at dolor. Maecenas mattis. Sed convallis tristique sem.

    24 |
    25 |
  • 26 | 27 | {/* */} 28 | UI/UX Design. 29 |
  • 30 |
  • 31 | 32 | {/* */} 33 | Related statistics. 34 |
  • 35 |
  • 36 | 37 | {/* */} 38 | Business Analysis. 39 |
  • 40 |
    41 |
    42 | 43 | ) 44 | }) 45 | } 46 |
    47 |
    48 | ); 49 | }; 50 | 51 | export default PricingCard; -------------------------------------------------------------------------------- /src/component/Home/Reviews/Review.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import userImg from '../../../Assets/user.svg'; 3 | import './Reviews.css'; 4 | import Fade from 'react-reveal/Fade'; 5 | 6 | const Review = ({review}) => { 7 | const {name, address, description, img} = review; 8 | return ( 9 | 10 |
    11 | { img ? : 12 | } 13 |
    {name}
    14 |
    {address}
    15 |

    {description}

    16 |
    17 |
    18 | ); 19 | }; 20 | 21 | export default Review; -------------------------------------------------------------------------------- /src/component/Home/Reviews/Reviews.css: -------------------------------------------------------------------------------- 1 | #testimonial { 2 | padding: 7rem 0 6rem; 3 | background: #F8F5FF; 4 | } 5 | .review{ 6 | box-shadow: 1px 0 20px rgb(0 0 0 / 10%); 7 | padding: 1rem; 8 | border-radius: 0.3rem; 9 | margin: 5rem 0 1rem 0; 10 | text-align: center; 11 | background: #fff; 12 | max-width: 550px; 13 | } 14 | .review > img { 15 | height: 90px; 16 | width: 90px; 17 | border-radius: 50%; 18 | margin-top: -4rem; 19 | border: 5px solid #fff; 20 | } 21 | .review > .testimonialName { 22 | font-weight: 600; 23 | font-size: 22px; 24 | font-family: sans-serif; 25 | color: #000; 26 | line-height: 26px; 27 | margin: 0.8rem 0 0.4rem 0; 28 | } 29 | .review > .testimonialAddress { 30 | font-size: 15px; 31 | color: #7053F1; 32 | } 33 | .review > p { 34 | color: #777; 35 | margin-top: 0.8rem; 36 | font-size: 1rem; 37 | font-weight: 400; 38 | font-family: sans-serif; 39 | } 40 | .rate { 41 | color:#FFBE5B; 42 | } 43 | :root { 44 | --swiper-theme-color: #7053F1!important; 45 | } -------------------------------------------------------------------------------- /src/component/Home/Reviews/Reviews.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react'; 2 | import { Col } from 'react-bootstrap'; 3 | import Review from './Review'; 4 | import { Swiper, SwiperSlide } from "swiper/react"; 5 | import 'swiper/swiper-bundle.min.css' 6 | import 'swiper/swiper.min.css' 7 | import SwiperCore, { Autoplay, Pagination } from 'swiper/core' 8 | import Spinner from '../../Shared/Spinner/Spinner'; 9 | 10 | const Reviews = () => { 11 | SwiperCore.use([Pagination, Autoplay]); 12 | const [reviews, setReviews] = useState([]) 13 | useEffect(() => { 14 | fetch('https://immense-river-40491.herokuapp.com/reviews') 15 | .then(res => res.json()) 16 | .then(data => { 17 | setReviews(data); 18 | }) 19 | }, []) 20 | return ( 21 |
    22 |

    TESTIMONIALS

    23 |
    24 |

    WHAT OUR CLIENTS SAY’S

    25 |
    26 | 27 | 50 | 51 | { 52 | reviews.length === 0 ? 53 |
    54 | 55 |
    : 56 | reviews.map((review, id) => { 57 | return( 58 | 59 | 60 | 61 | ) 62 | }) 63 | } 64 |
    65 | 66 |
    67 | ); 68 | }; 69 | 70 | export default Reviews; -------------------------------------------------------------------------------- /src/component/Home/Services/Service.css: -------------------------------------------------------------------------------- 1 | .services { 2 | padding: 7rem 0 6rem; 3 | width: 100%; 4 | background-color: #FAF8FF; 5 | font-family: 'Poppins', sans-serif; 6 | } 7 | .service { 8 | margin: 1.5rem 0; 9 | } 10 | .service-card{ 11 | box-shadow: 0 0px 60px 0 rgb(0 0 0 / 2%); 12 | padding: 1rem; 13 | border-radius: 0.5rem; 14 | position: relative; 15 | background: white; 16 | text-align: center; 17 | z-index: 1; 18 | } 19 | 20 | .service-card:hover { 21 | box-shadow: 0 8px 6px -5px rgb(161, 161, 161); 22 | margin-top: -1rem; 23 | } 24 | .service-card:hover .serviceImg{ 25 | height: 70px; 26 | } 27 | .service-card:hover .bookingBox { 28 | display: block; 29 | margin-bottom: -2rem; 30 | transition: 0.4s; 31 | } 32 | .service-card:hover .serviceName { 33 | padding: 0.2rem 0 0.2rem; 34 | } 35 | .service-card:hover .serviceDes { 36 | line-height: 1.5; 37 | } 38 | .service-card:hover::before { 39 | transform: scaleY(1); 40 | } 41 | 42 | .service-card::before{ 43 | content: ""; 44 | position: absolute; 45 | top: 0; 46 | left: 0; 47 | width: 100%; 48 | height: 100%; 49 | z-index: -1; 50 | transition: transform 300ms ease-out; 51 | transform: scaleY(0); 52 | border-radius: 0.5rem; 53 | background-color: #E2DEF9; 54 | } 55 | .serviceImg { 56 | height: 90px; 57 | background-color: rgb(213 196 255); 58 | padding: 0.2rem 0.5rem; 59 | border-radius: 0.5rem; 60 | transition: 0.4s; 61 | } 62 | 63 | .serviceDes { 64 | color: #666; 65 | font-weight: 500; 66 | line-height: 1.9; 67 | font-family: sans-serif; 68 | font-size: 1rem; 69 | margin-bottom: 0; 70 | } 71 | .serviceName { 72 | font-weight: 700; 73 | font-size: 1.4rem; 74 | padding: 1rem 0; 75 | margin-bottom: 0; 76 | } 77 | .bookingBox { 78 | display: none; 79 | transition: 2s; 80 | } 81 | .bookingBtn { 82 | border-radius: 1.8rem; 83 | font-weight: 500; 84 | font-size: 1rem; 85 | outline: none; 86 | color: #fff; 87 | border: none; 88 | padding: 0.5rem 1rem; 89 | background: #7355F7; 90 | margin-top: 0.3rem; 91 | } 92 | 93 | .servicePrice { 94 | color: #755BFF; 95 | font-size: 1.6rem; 96 | font-weight: 700; 97 | margin-bottom: 0; 98 | } 99 | 100 | .bookingBtn:hover { 101 | background: #4B24F5; 102 | } -------------------------------------------------------------------------------- /src/component/Home/Services/Service.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link } from 'react-router-dom'; 3 | import './Service.css' 4 | import Fade from 'react-reveal/Fade'; 5 | import './Service.css'; 6 | import { useAppContext } from '../../../context'; 7 | 8 | const Service = ({service}) => { 9 | const { state:{ admin}, dispatch } = useAppContext() 10 | const {name, price, description, img} = service; 11 | 12 | const handleSelectedService = (service) => { 13 | dispatch({type: 'SELECTED_SERVICE', payload: service}) 14 | } 15 | 16 | return ( 17 |
    18 | 19 |
    20 |
    21 | 22 |
    23 |

    {name}

    24 |

    {description}

    25 |
    26 |

    ${price}

    27 | 28 | 31 | 32 |
    33 |
    34 |
    35 |
    36 | ); 37 | }; 38 | 39 | export default Service; -------------------------------------------------------------------------------- /src/component/Home/Services/Services.jsx: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import React, { useEffect, useState } from 'react'; 3 | import Service from './Service'; 4 | import Spinner from '../../Shared/Spinner/Spinner'; 5 | 6 | const Services = () => { 7 | const [services, setServices] = useState([]) 8 | 9 | useEffect(() => { 10 | axios.get('https://immense-river-40491.herokuapp.com/services') 11 | .then(res => setServices(res.data)) 12 | }, []) 13 | 14 | return ( 15 |
    16 |

    SERVICES

    17 |
    18 |
    PROVIDE AWESOME SERVICE
    19 |
    20 | {services.length === 0 &&
    } 21 |
    22 | { 23 | services?.map((service, id) => ) 24 | } 25 |
    26 |
    27 | ); 28 | }; 29 | 30 | export default Services; -------------------------------------------------------------------------------- /src/component/Login/LoginManager.jsx: -------------------------------------------------------------------------------- 1 | // import firebase from 'firebase/app'; 2 | // import * as firebase from "firebase/app" 3 | import firebase from 'firebase/compat/app'; //v9 4 | import 'firebase/compat/auth'; //v9 5 | // import "firebase/auth"; 6 | import firebaseConfig from "../../firebaseBaseConfig"; 7 | import jwt_decode from "jwt-decode"; 8 | import userImg from '../../Assets/user.svg'; 9 | 10 | if(!firebase.apps.length){ 11 | firebase.initializeApp(firebaseConfig); 12 | } 13 | 14 | const setToken = () => { 15 | firebase.auth().currentUser.getIdToken(true) 16 | .then(function(idToken) { 17 | localStorage.setItem('token', idToken); 18 | }) 19 | } 20 | 21 | export const loginWithProvider = (provider) => { 22 | return firebase.auth().signInWithPopup(provider) 23 | .then( res => { 24 | setToken(); 25 | return handleResponse(res); 26 | }).catch( error => { 27 | const message = { 28 | error: error.message 29 | } 30 | return message; 31 | }); 32 | }; 33 | 34 | export const createAccount = (email, password) => { 35 | return firebase.auth().createUserWithEmailAndPassword(email, password) 36 | .then( res => { 37 | setToken(); 38 | return handleResponse(res); 39 | }) 40 | .catch( error => { 41 | const message = { 42 | error: error.message 43 | } 44 | return message; 45 | }); 46 | } 47 | 48 | export const loginWithEmail = (email, password) =>{ 49 | return firebase.auth().signInWithEmailAndPassword(email, password) 50 | .then( res => { 51 | setToken(); 52 | return handleResponse(res); 53 | }) 54 | .catch( error => { 55 | const message = { 56 | error: error.message 57 | } 58 | return message; 59 | }); 60 | } 61 | 62 | const defaultName = (str) => { 63 | let myStr = str 64 | let firstWord = myStr.substring(0, 4) 65 | return firstWord; 66 | } 67 | 68 | const handleResponse = (res) => { 69 | const {displayName, email, photoURL} = res.user; 70 | const userInfo = { 71 | isSignedIn: true, 72 | name: displayName || defaultName(email), 73 | email: email, 74 | img: photoURL || userImg, 75 | } 76 | return userInfo; 77 | } 78 | 79 | export const getDecodedUser = () => { 80 | const token = localStorage.getItem('token'); 81 | if (!token) { 82 | return {}; 83 | } 84 | const { name, picture, email } = jwt_decode(token); 85 | const decodedUser = { 86 | isSignedIn: true, 87 | name: name || defaultName(email), 88 | email: email, 89 | img: picture || userImg, 90 | } 91 | return decodedUser; 92 | } 93 | 94 | export const handleSignOut = () => { 95 | return firebase.auth().signOut() 96 | .then(() => { 97 | localStorage.removeItem('token'); 98 | const signedOutUser = { 99 | isSignedIn: false, 100 | name: '', 101 | email: '', 102 | img: '' 103 | } 104 | return signedOutUser; 105 | }) 106 | } 107 | -------------------------------------------------------------------------------- /src/component/Login/LoginModal.css: -------------------------------------------------------------------------------- 1 | .fContainer{ 2 | position: relative; 3 | width: 100%; 4 | min-height: 100vh; 5 | overflow: hidden; 6 | font-family: 'Poppins', sans-serif; 7 | } 8 | 9 | .pageCloseBtn { 10 | position: absolute; 11 | top: 3px; 12 | right: 3px; 13 | cursor: pointer; 14 | height: 1.5rem; 15 | width: 1.5rem; 16 | border-radius: 50%; 17 | z-index: 33; 18 | color: #000; 19 | background: #F0F0F0; 20 | border: 1px solid #ACACAC; 21 | text-align: center; 22 | transition: 0.3s; 23 | } 24 | .pageCloseBtn:hover { 25 | background: #d6d6d6;; 26 | } 27 | 28 | .signInToast { 29 | position: absolute; 30 | top: 20%; 31 | right: 0; 32 | z-index: 123; 33 | background: #fff; 34 | } 35 | 36 | .signInToast .toastIcon { 37 | height: 1.2rem; 38 | } 39 | 40 | .fContainer::before { 41 | content: ""; 42 | position: absolute; 43 | width: 2000px; 44 | height: 2000px;border-radius: 50%; 45 | background: linear-gradient(-45deg, #795cf9, #7355F7); 46 | top: -10%; 47 | right: 48%; 48 | transform: translateY(-50%); 49 | z-index: 6; 50 | transition: 1.8s ease-in-out; 51 | } 52 | 53 | .forms-container { 54 | position: absolute; 55 | width: 100%; 56 | height: 100%; 57 | top: 0; 58 | left: 0; 59 | } 60 | 61 | .signIn-singUp { 62 | position: absolute; 63 | top: 50%; 64 | left: 75%; 65 | transform: translate(-50%, -50%); 66 | width: 50%; 67 | display: grid; 68 | grid-template-columns: 1fr; 69 | z-index: 5; 70 | transition: 1s 0.7s ease-in-out; 71 | } 72 | 73 | .fContainer form { 74 | display: flex; 75 | align-items: center; 76 | justify-content:center; 77 | flex-direction: column; 78 | overflow: hidden; 79 | grid-column: 1/2; 80 | grid-row: 1/2; 81 | transition: 0.2s 0.7s ease-in-out; 82 | } 83 | 84 | .fContainer form.sign-in-form { 85 | z-index: 2; 86 | } 87 | 88 | .fContainer form.sign-up-form { 89 | z-index: 1; 90 | opacity: 0; 91 | } 92 | 93 | .fContainer .title { 94 | font-size: 2.2rem; 95 | color: #444; 96 | margin-bottom: 1rem; 97 | font-weight: 600; 98 | } 99 | 100 | .input-field { 101 | max-width: 380px; 102 | width: 100%; 103 | background-color: #f0f0f0; 104 | margin: 10px 0; 105 | height: 55px; 106 | border-radius: 55px; 107 | display: grid; 108 | grid-template-columns: 15% 85%; 109 | padding: 0 0.4rem; 110 | position: relative; 111 | } 112 | 113 | .input-field .fIcon { 114 | text-align: center; 115 | line-height: 55px; 116 | color: #acacac; 117 | transition: 0.5s; 118 | font-size: 1.1rem; 119 | } 120 | 121 | .input-field input { 122 | padding-right: 0.5rem; 123 | background-color: #F0F0F0!important; 124 | border-radius: 55px; 125 | outline: none; 126 | border: none; 127 | line-height: 1; 128 | font-weight: 500; 129 | font-size: 1.1rem; 130 | color: #333; 131 | width: 100%; 132 | } 133 | 134 | .social-icon { 135 | height: 46px; 136 | width: 46px; 137 | display: flex; 138 | justify-content: center; 139 | align-items: center; 140 | margin: 0 0.45rem; 141 | color: #333; 142 | border-radius: 50%; 143 | border: 1px solid #333; 144 | background: #fff; 145 | outline: none; 146 | font-size: 1.1rem; 147 | transition: 0.3s; 148 | cursor: pointer; 149 | } 150 | 151 | .social-icon:hover { 152 | border: 1px solid #6e4dff; 153 | color: #6e4dff; 154 | } 155 | 156 | .input-field input::placeholder { 157 | color: #aaa; 158 | font-weight: 500; 159 | } 160 | 161 | .iBtn { 162 | width: 160px; 163 | height: 49px; 164 | border: none; 165 | outline: none; 166 | border-radius: 50px; 167 | cursor: pointer; 168 | background-color: #7355F7; 169 | color: #fff; 170 | text-transform: uppercase; 171 | font-weight: 600; 172 | font-size: 1rem; 173 | margin: 10px 0; 174 | transition: .5s; 175 | } 176 | .iBtn:hover{ 177 | background: #4C25F5; 178 | } 179 | 180 | .social-text { 181 | padding: 0.7rem 0; 182 | font-size: 1rem; 183 | margin-bottom: 0 184 | } 185 | 186 | .social-media { 187 | display: flex; 188 | justify-content: center; 189 | } 190 | 191 | .panels-container { 192 | position: absolute; 193 | width: 100%; 194 | height: 100%; 195 | top: 0; 196 | left: 0; 197 | display: grid; 198 | grid-template-columns: repeat(2, 1fr); 199 | } 200 | 201 | .panel { 202 | display: flex; 203 | flex-direction: column; 204 | align-items: flex-end; 205 | justify-content: space-around; 206 | text-align:center; 207 | z-index: 7; 208 | } 209 | 210 | .panel .content { 211 | color: #fff; 212 | transition: .9s .6s ease-in-out; 213 | } 214 | 215 | .panel h3 { 216 | font-weight: 600; 217 | line-height:1; 218 | font-size: 1.5rem; 219 | } 220 | 221 | .panel p { 222 | font-size: 0.95rem; 223 | padding: 0.7rem 0; 224 | } 225 | 226 | .iBtn.transparent { 227 | margin: 0; 228 | background:none; 229 | border: 2px solid #fff; 230 | width: 130px; 231 | height: 41px; 232 | font-weight: 600; 233 | font-size: 0.8rem; 234 | } 235 | 236 | .left-panel { 237 | pointer-events: all; 238 | padding: 3rem 17% 2rem 12%; 239 | } 240 | 241 | .right-panel { 242 | pointer-events: none; 243 | padding: 3rem 12% 2rem 17%; 244 | } 245 | 246 | .pImg { 247 | width: 100%; 248 | transition: 1.1s .4s ease-in-out; 249 | } 250 | 251 | .right-panel .content, 252 | .right-panel .pImg { 253 | transform: translateX(800px); 254 | } 255 | 256 | 257 | /* Animation */ 258 | 259 | .fContainer.sign-up-mode::before{ 260 | transform: translate(100%, -50%); 261 | right: 52%; 262 | } 263 | 264 | .fContainer.sign-up-mode .left-panel .pImg, 265 | .fContainer.sign-up-mode .left-panel .content { 266 | transform: translateX(-800px) 267 | } 268 | 269 | .fContainer.sign-up-mode .right-panel .content, 270 | .fContainer.sign-up-mode .right-panel .pImg { 271 | transform: translateX(0px) 272 | } 273 | 274 | .fContainer.sign-up-mode .left-panel { 275 | pointer-events: none; 276 | } 277 | 278 | .fContainer.sign-up-mode .right-panel { 279 | pointer-events:all; 280 | } 281 | 282 | .fContainer.sign-up-mode .signIn-singUp { 283 | left: 25%; 284 | } 285 | 286 | .fContainer.sign-up-mode form.sign-in-form { 287 | z-index: 1; 288 | opacity: 0; 289 | } 290 | 291 | .fContainer.sign-up-mode form.sign-up-form { 292 | z-index: 2; 293 | opacity: 1; 294 | } 295 | 296 | @media (max-width: 870px) { 297 | .fContainer { 298 | min-height: 800px; 299 | height: 100vh; 300 | } 301 | .signIn-singUp { 302 | width: 100%; 303 | top: 95%; 304 | transform: translate(-50%, -100%); 305 | transition: 1s 0.8s ease-in-out; 306 | } 307 | 308 | .signIn-singUp, 309 | .fContainer.sign-up-mode .signIn-singUp { 310 | left: 50%; 311 | } 312 | 313 | .panels-container { 314 | grid-template-columns: 1fr; 315 | grid-template-rows: 1fr 2fr 1fr; 316 | } 317 | 318 | .panel { 319 | flex-direction: row; 320 | justify-content: space-around; 321 | align-items: center; 322 | padding: 2.5rem 8%; 323 | grid-column: 1 / 2; 324 | } 325 | 326 | .right-panel { 327 | grid-row: 3 / 4; 328 | } 329 | 330 | .left-panel { 331 | grid-row: 1 / 2; 332 | } 333 | 334 | .pImg { 335 | width: 200px; 336 | transition: transform 0.9s ease-in-out; 337 | transition-delay: 0.6s; 338 | } 339 | 340 | .panel .content { 341 | padding-right: 15%; 342 | transition: transform 0.9s ease-in-out; 343 | transition-delay: 0.8s; 344 | } 345 | 346 | .panel h3 { 347 | font-size: 1.2rem; 348 | } 349 | 350 | .panel p { 351 | font-size: 0.7rem; 352 | padding: 0.5rem 0; 353 | } 354 | 355 | .btn.transparent { 356 | width: 110px; 357 | height: 35px; 358 | font-size: 0.7rem; 359 | } 360 | 361 | .fContainer::before { 362 | width: 1500px; 363 | height: 1500px; 364 | transform: translateX(-50%); 365 | left: 30%; 366 | bottom: 68%; 367 | right: initial; 368 | top: initial; 369 | transition: 2s ease-in-out; 370 | } 371 | 372 | .fContainer.sign-up-mode:before { 373 | transform: translate(-50%, 100%); 374 | bottom: 32%; 375 | right: initial; 376 | } 377 | 378 | .fContainer.sign-up-mode .left-panel .pImg, 379 | .fContainer.sign-up-mode .left-panel .content { 380 | transform: translateY(-300px); 381 | } 382 | 383 | .fContainer.sign-up-mode .right-panel .pImg, 384 | .fContainer.sign-up-mode .right-panel .content { 385 | transform: translateY(0px); 386 | } 387 | 388 | .right-panel .pImg, 389 | .right-panel .content { 390 | transform: translateY(300px); 391 | } 392 | 393 | .fContainer.sign-up-mode .signIn-singUp { 394 | top: 5%; 395 | transform: translate(-50%, 0); 396 | } 397 | } 398 | 399 | @media (max-width: 570px) { 400 | form { 401 | padding: 0 1.5rem; 402 | } 403 | 404 | .pImg { 405 | display: none; 406 | } 407 | .panel .content { 408 | padding: 0.5rem 1rem; 409 | } 410 | .fContainer { 411 | padding: 1.5rem; 412 | } 413 | 414 | .fContainer:before { 415 | bottom: 72%; 416 | left: 50%; 417 | } 418 | 419 | .fContainer.sign-up-mode::before { 420 | bottom: 28%; 421 | left: 50%; 422 | } 423 | } 424 | 425 | -------------------------------------------------------------------------------- /src/component/Login/LoginModal.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link, useNavigate, useLocation } from 'react-router-dom'; 3 | import './LoginModal.css'; 4 | import "firebase/compat/auth"; 5 | import log from '../../Assets/log.svg'; 6 | import desk from '../../Assets/register.svg'; 7 | import { useState } from 'react'; 8 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; 9 | import { faTimes } from '@fortawesome/free-solid-svg-icons'; 10 | import SignInForm from './SignInForm'; 11 | import SignUpForm from './SignUpForm'; 12 | import toast from 'react-hot-toast'; 13 | import swal from 'sweetalert'; 14 | import { handleSignOut } from './LoginManager'; 15 | import { SET_USER, useAppContext } from '../../context'; 16 | 17 | const Form = () => { 18 | const { dispatch } = useAppContext() 19 | const [isSignUp, setSignUp] = useState(false); 20 | 21 | const history = useNavigate(); 22 | const location = useLocation(); 23 | let { from } = location.state || { from: { pathname: "/" }}; 24 | 25 | const handleResponse = (res) => { 26 | dispatch({type: SET_USER, payload: res}) 27 | if(!res.error){ 28 | toast.success('Successfully Logged In!'); 29 | history(from); 30 | } 31 | if (res.email === "admin@mail.com") { 32 | swal({ 33 | title: "Warning!", 34 | text: "You have entered the admin panel for testing. Please don't abuse this facility!", 35 | icon: "warning", 36 | buttons: true, 37 | dangerMode: true, 38 | }).then(ok => { 39 | if (!ok) { 40 | handleSignOut() 41 | .then(res => { 42 | dispatch({type: SET_USER, payload: res}) 43 | toast.error('Logged Out!'); 44 | }) 45 | } 46 | }); 47 | } 48 | } 49 | 50 | return ( 51 |
    52 | 53 | 54 | 55 |
    56 |
    57 | 58 | 59 |
    60 |
    61 | 62 |
    63 |
    64 |
    65 |

    New here ?

    66 |

    Lorem ipsum dolor sit amet consectetur adipisicing elit. Sequi beatae quas magnam!

    67 | 68 |
    69 | 70 |
    71 | 72 |
    73 |
    74 |

    One of us ?

    75 |

    Lorem ipsum dolor sit amet consectetur adipisicing elit. Sequi beatae quas magnam!

    76 | 77 |
    78 | 79 |
    80 |
    81 |
    82 | ); 83 | }; 84 | 85 | export default Form; -------------------------------------------------------------------------------- /src/component/Login/PrivateRoute.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { 3 | Navigate, 4 | } from "react-router-dom"; 5 | import { useAppContext } from '../../context'; 6 | const PrivateRoute = ({ children,redirectTo }) => { 7 | const { state: { user: { isSignedIn } } } = useAppContext() 8 | return isSignedIn ? children : ; 9 | } 10 | 11 | export default PrivateRoute 12 | -------------------------------------------------------------------------------- /src/component/Login/SignInForm.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useForm } from 'react-hook-form'; 3 | import { loginWithEmail } from './LoginManager'; 4 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; 5 | import { faEnvelope, faLock } from '@fortawesome/free-solid-svg-icons'; 6 | import SocialMedia from './SocialMedia'; 7 | import toast from 'react-hot-toast'; 8 | 9 | 10 | const SignInForm = ({handleResponse}) => { 11 | const { register, handleSubmit, formState: { errors } } = useForm(); 12 | 13 | const onSubmit = ({email, password}) => { 14 | const loading = toast.loading('Please wait...'); 15 | loginWithEmail(email, password) 16 | .then(res => { 17 | if(res.error){ 18 | toast.dismiss(loading); 19 | toast.error(res.error) 20 | } 21 | handleResponse(res) 22 | toast.dismiss(loading); 23 | }) 24 | } 25 | return ( 26 |
    27 |

    Sign in

    28 |
    29 | 30 | 31 |
    32 | {errors.email && This field is required} 33 |
    34 | 35 | 36 |
    37 | {errors.password && This field is required} 38 | 39 |

    Or Sign in with social platforms

    40 | 41 | 42 | ); 43 | }; 44 | 45 | export default SignInForm; -------------------------------------------------------------------------------- /src/component/Login/SignUpForm.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useForm } from 'react-hook-form'; 3 | import { createAccount } from './LoginManager'; 4 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; 5 | import { faEnvelope, faLock, faUser } from '@fortawesome/free-solid-svg-icons'; 6 | import SocialMedia from './SocialMedia'; 7 | import toast from 'react-hot-toast'; 8 | 9 | const SignUpForm = ({handleResponse}) => { 10 | const { register, handleSubmit, formState: { errors } } = useForm(); 11 | 12 | const onSubmit = ({email, password}) => { 13 | const loading = toast.loading('Please wait...'); 14 | createAccount(email, password) 15 | .then(res => { 16 | if(res.error){ 17 | toast.dismiss(loading); 18 | toast.error(res.error) 19 | } 20 | handleResponse(res) 21 | toast.dismiss(loading); 22 | }) 23 | } 24 | return ( 25 |
    26 |

    Sign Up

    27 |
    28 | 29 | 30 |
    31 |
    32 | 33 | 34 |
    35 | {errors.email && This field is required} 36 |
    37 | 38 | 39 |
    40 | 41 |

    Or Sign up with social account

    42 | 43 | 44 | ); 45 | }; 46 | 47 | export default SignUpForm; -------------------------------------------------------------------------------- /src/component/Login/SocialMedia.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import firebase from "firebase/compat/app"; 3 | import "firebase/compat/auth"; 4 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; 5 | import { faFacebook, faGithub, faGoogle } from '@fortawesome/free-brands-svg-icons'; 6 | import { loginWithProvider } from './LoginManager'; 7 | import toast from 'react-hot-toast'; 8 | 9 | const SocialMedia = ({handleResponse}) => { 10 | const googleProvider = new firebase.auth.GoogleAuthProvider(); 11 | const fbProvider = new firebase.auth.FacebookAuthProvider(); 12 | const ghProvider = new firebase.auth.GithubAuthProvider(); 13 | const handleSignIn = (provider) => { 14 | const loading = toast.loading('Please wait...'); 15 | loginWithProvider(provider) 16 | .then(res => { 17 | if(res.error){ 18 | toast.dismiss(loading); 19 | toast.error(res.error) 20 | } 21 | handleResponse(res) 22 | toast.dismiss(loading); 23 | }) 24 | } 25 | return ( 26 |
    27 |
    handleSignIn(googleProvider)} className="social-icon"> 28 | 29 |
    30 |
    handleSignIn(fbProvider)} className="social-icon"> 31 | 32 |
    33 |
    handleSignIn(ghProvider)} className="social-icon"> 34 | 35 |
    36 |
    37 | ); 38 | }; 39 | 40 | export default SocialMedia; -------------------------------------------------------------------------------- /src/component/NotFound.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import NotFoundImg from '../Assets/404.svg'; 3 | 4 | const NotFound = () => { 5 | return ( 6 |
    7 | 8 |
    9 | ) 10 | } 11 | 12 | export default NotFound 13 | -------------------------------------------------------------------------------- /src/component/PricingData.jsx: -------------------------------------------------------------------------------- 1 | export const PricingData = [ 2 | [ 3 | {title: 'Basic' ,name: 'Web Design', price: 48}, 4 | {title: 'Standard' ,name: 'Web Design', price: 78}, 5 | {title: 'Premium' ,name: 'Web Design', price: 98}, 6 | ], 7 | [ 8 | {title: 'Basic' ,name: 'Email Marketing', price: 39}, 9 | {title: 'Standard' ,name: 'Email Marketing', price: 79}, 10 | {title: 'Premium' ,name: 'Email Marketing', price: 99}, 11 | ], 12 | [ 13 | {title: 'Basic' ,name: 'Graphic Design', price: 36}, 14 | {title: 'Standard' ,name: 'Graphic Design', price: 56}, 15 | {title: 'Premium' ,name: 'Graphic Design', price: 86}, 16 | ], 17 | [ 18 | {title: 'Basic' ,name: 'Web Development', price: 49}, 19 | {title: 'Standard' ,name: 'Web Development', price: 69}, 20 | {title: 'Premium' ,name: 'Web Development', price: 89}, 21 | ], 22 | [ 23 | {title: 'Basic' ,name: 'SEO', price: 44}, 24 | {title: 'Standard' ,name: 'SEO', price: 77}, 25 | {title: 'Premium' ,name: 'SEO', price: 88}, 26 | ], 27 | [ 28 | {title: 'Basic' ,name: 'UI Design', price: 45}, 29 | {title: 'Standard' ,name: 'UI Design', price: 75}, 30 | {title: 'Premium' ,name: 'UI Design', price: 95}, 31 | ] 32 | ] -------------------------------------------------------------------------------- /src/component/Shared/Navbar/Navbar.css: -------------------------------------------------------------------------------- 1 | .navStyle { 2 | box-shadow: 0 2px 5px 1px rgb(64 60 67 / 16%); 3 | background: white; 4 | position: fixed!important; 5 | width: 100%; 6 | z-index: 99!important; 7 | transition: 0.5s!important; 8 | font-family: 'Poppins', sans-serif; 9 | } 10 | .navDefault { 11 | transition: 0.5s!important; 12 | padding: 25px 0 40px 0!important; 13 | margin-bottom: 2rem; 14 | } 15 | 16 | .mainNav .nav-link { 17 | color: #070120!important; 18 | margin: 0.5rem 1.2rem!important; 19 | font-weight: 500!important; 20 | transition: 0.3s; 21 | font-size: 1.1rem; 22 | font-family: 'Poppins', sans-serif; 23 | } 24 | .mainNav .nav-link:after { 25 | content: ''; 26 | display: block; 27 | margin: auto; 28 | height: 3px; 29 | width: 0px; 30 | background: transparent; 31 | transition: width .5s ease, background-color .5s ease; 32 | } 33 | .mainNav .nav-link:hover:after { 34 | width: 100%; 35 | background: #4C25F5; 36 | } 37 | 38 | .navBrn { 39 | font-weight: 700; 40 | font-size: 1.5rem; 41 | } 42 | .brnIcon, 43 | .navHighlight { 44 | color: #7456F7;; 45 | } 46 | .brnIcon { 47 | font-weight: 800; 48 | font-size: 1.6rem 49 | } 50 | 51 | .loginBtn { 52 | outline: none; 53 | border: none; 54 | border-radius: 50px; 55 | font-weight: 500; 56 | color:#fff; 57 | background: #7355F7; 58 | padding: 0.5rem 1.5rem; 59 | margin: 0.5rem 1rem; 60 | transition: 0.4s; 61 | } 62 | .loginBtn:hover { 63 | background : #4B24F5 64 | } 65 | .navActiveClass{ 66 | color:"red"; 67 | font-weight:900; 68 | } 69 | 70 | @media (max-width: 981px) { 71 | .navDefault { 72 | background: white; 73 | padding: 0.8rem 0.5rem!important; 74 | width: 100%; 75 | z-index: 99!important; 76 | transition: 0.5s!important; 77 | text-align: center; 78 | } 79 | .navStyle{ 80 | text-align: center; 81 | } 82 | } -------------------------------------------------------------------------------- /src/component/Shared/Navbar/Navbar.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link } from "react-router-dom"; 3 | import './Navbar.css'; 4 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; 5 | import { faBuffer } from '@fortawesome/free-brands-svg-icons'; 6 | import { useState } from 'react'; 7 | import { useEffect } from 'react'; 8 | import { Container, Nav, Navbar } from 'react-bootstrap'; 9 | import PopOver from '../PopOver/PopOver'; 10 | import { useAppContext } from '../../../context'; 11 | 12 | 13 | const NavBar = () => { 14 | const { state: { user } } = useAppContext() 15 | const [isSticky, setSticky] = useState(false) 16 | 17 | useEffect(() => { 18 | window.addEventListener("scroll", () => { 19 | if (window.scrollY > 50) { 20 | setSticky(true) 21 | } else { 22 | setSticky(false) 23 | } 24 | }) 25 | }, []) 26 | 27 | const scrollTop = () => window['scrollTo']({ top: 0, behavior: 'smooth' }); 28 | return ( 29 | 30 | 31 | 32 | Easy Consulting 33 | 34 | 35 | 36 | 37 | 65 | 66 | 67 | 68 | ); 69 | }; 70 | 71 | export default NavBar; -------------------------------------------------------------------------------- /src/component/Shared/PopOver/PopOver.css: -------------------------------------------------------------------------------- 1 | .popImg { 2 | height: 45px; 3 | border-radius: 50%; 4 | cursor: pointer!important; 5 | margin: 0.2rem 0 0 0.7rem; 6 | } 7 | .popUserImg { 8 | height: 60px; 9 | border-radius: 50%; 10 | margin-bottom: 8px; 11 | } 12 | .userName, 13 | .userEmail{ 14 | margin-bottom: 0; 15 | font-size: 1rem; 16 | font-weight: 700; 17 | } 18 | .userEmail { 19 | margin: 0.1rem 0 0.5rem; 20 | font-weight: 600; 21 | font-size: 0.9rem; 22 | color: rgba(0,0,0,.7); 23 | } -------------------------------------------------------------------------------- /src/component/Shared/PopOver/PopOver.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useState } from 'react'; 3 | import { useRef } from 'react'; 4 | import { Button, Overlay } from 'react-bootstrap'; 5 | import Popover from 'react-bootstrap/Popover' 6 | import './PopOver.css'; 7 | import toast from 'react-hot-toast'; 8 | import { handleSignOut } from '../../Login/LoginManager'; 9 | import { SET_USER, useAppContext } from '../../../context'; 10 | 11 | const PopOver = () => { 12 | const { state:{user: { name, email, img }}, dispatch} = useAppContext() 13 | const [show, setShow] = useState(false); 14 | const [target, setTarget] = useState(null); 15 | const ref = useRef(null); 16 | const handleClick = (event) => { 17 | setShow(!show); 18 | setTarget(event.target); 19 | }; 20 | const signOut = () => { 21 | const loading = toast.loading('Please wait...'); 22 | handleSignOut() 23 | .then(res => { 24 | toast.dismiss(loading); 25 | console.log(res); 26 | dispatch({type: SET_USER, payload: res}) 27 | toast.error('Logged Out!'); 28 | }) 29 | } 30 | return ( 31 |
    32 | 33 | 40 | 41 |
    42 | 43 |

    {`${name}`}

    44 |

    {email}

    45 | 46 |
    47 |
    48 |
    49 |
    50 | ); 51 | }; 52 | 53 | export default PopOver; -------------------------------------------------------------------------------- /src/component/Shared/ScrollTop/ScrollTop.css: -------------------------------------------------------------------------------- 1 | .scrollBtn { 2 | position: fixed; 3 | bottom: 1rem; 4 | right: 1rem; 5 | cursor: pointer; 6 | font-weight: 400; 7 | color: #fff; 8 | z-index: 112; 9 | display: inline-block; 10 | height: 2.4rem; 11 | width: 2.4rem; 12 | background: #7154F3; 13 | border-radius: 50%; 14 | transition: 0.3s; 15 | border: none; 16 | box-shadow: 0 2px 15px rgb(88 69 206 / 70%); 17 | } 18 | .scrollBtn:hover { 19 | background-color: #4B24F5; 20 | } -------------------------------------------------------------------------------- /src/component/Shared/ScrollTop/ScrollTop.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | // import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' 3 | // import { faAngleUp } from '@fortawesome/free-solid-svg-icons' 4 | import { useEffect } from 'react'; 5 | import './ScrollTop.css' 6 | 7 | export const scrollUP = () => { 8 | window['scrollTo']({top: 0, behavior: 'smooth'}) 9 | } 10 | const ScrollTop = () => { 11 | const [isTrue, setIsTrue] = useState(false) 12 | useEffect(() => { 13 | window.addEventListener("scroll", () => { 14 | if (window.scrollY > 50) { 15 | setIsTrue(true) 16 | } else { 17 | setIsTrue(false) 18 | } 19 | }) 20 | }, [isTrue]) 21 | return ( 22 |
    23 | { 24 | isTrue && 28 | } 29 |
    30 | ); 31 | }; 32 | 33 | export default ScrollTop; -------------------------------------------------------------------------------- /src/component/Shared/Spinner/Spinner.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Loader from 'react-loader-spinner'; 3 | import "react-loader-spinner/dist/loader/css/react-spinner-loader.css"; 4 | 5 | const Spinner = () => { 6 | return ( 7 | 13 | ); 14 | }; 15 | 16 | export default Spinner; -------------------------------------------------------------------------------- /src/component/Shared/TableOrder/ListSkeleton.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ContentLoader from 'react-content-loader' 3 | 4 | const ListSkeleton = props => ( 5 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ) 22 | 23 | export default ListSkeleton -------------------------------------------------------------------------------- /src/component/Shared/TableOrder/TableOrder.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ContentLoader from 'react-content-loader' 3 | 4 | const TableLoader = props => ( 5 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 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 | export default TableLoader -------------------------------------------------------------------------------- /src/context/actionTypes.js: -------------------------------------------------------------------------------- 1 | export const SET_USER = "SET USER"; 2 | export const SET_ADMIN = "SET ADMIN"; 3 | export const SET_SELECTED_SERVICE = "SET SELECTED SERVICE"; 4 | -------------------------------------------------------------------------------- /src/context/app-context.js: -------------------------------------------------------------------------------- 1 | import { useReducer } from "react"; 2 | import { useContext } from "react"; 3 | import { createContext } from "react"; 4 | import { getDecodedUser } from "../component/Login/LoginManager"; 5 | import { reducer } from "./reducer"; 6 | 7 | const AppContext = createContext(); 8 | 9 | const initialState = { 10 | user: getDecodedUser(), 11 | admin: false, 12 | selectedService: {}, 13 | }; 14 | 15 | export const AppProvider = ({ children }) => { 16 | const [state, dispatch] = useReducer(reducer, initialState); 17 | return ( 18 | 19 | {children} 20 | 21 | ); 22 | }; 23 | 24 | export const useAppContext = () => { 25 | return useContext(AppContext); 26 | }; 27 | -------------------------------------------------------------------------------- /src/context/index.js: -------------------------------------------------------------------------------- 1 | export * from "./app-context"; 2 | export * from "./actionTypes"; 3 | export * from "./reducer"; 4 | -------------------------------------------------------------------------------- /src/context/reducer.js: -------------------------------------------------------------------------------- 1 | import { SET_ADMIN, SET_SELECTED_SERVICE, SET_USER } from "./actionTypes"; 2 | 3 | export const reducer = (state, action) => { 4 | switch (action.type) { 5 | case SET_USER: 6 | return { ...state, user: action.payload }; 7 | case SET_ADMIN: 8 | return { ...state, admin: action.payload }; 9 | case SET_SELECTED_SERVICE: 10 | return { ...state, selectedService: action.payload }; 11 | default: 12 | return state; 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /src/firebaseBaseConfig.js: -------------------------------------------------------------------------------- 1 | const firebaseConfig = { 2 | apiKey: "AIzaSyAwR_WCLK2e_x5NK_I2yCdSNnJQC1rPxL8", 3 | authDomain: "easy-consulting-react.firebaseapp.com", 4 | projectId: "easy-consulting-react", 5 | storageBucket: "easy-consulting-react.appspot.com", 6 | messagingSenderId: "471032014480", 7 | appId: "1:471032014480:web:cbd7dc3d102ddd71d55a15" 8 | };export default firebaseConfig; -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import "./index.css"; 4 | import App from "./App"; 5 | import reportWebVitals from "./reportWebVitals"; 6 | import "bootstrap/dist/css/bootstrap.min.css"; 7 | import { BrowserRouter as Router } from "react-router-dom"; 8 | import { AppProvider } from "./context"; 9 | 10 | ReactDOM.render( 11 | 12 | 13 | 14 | 15 | 16 | 17 | , 18 | document.getElementById("root") 19 | ); 20 | 21 | reportWebVitals(); 22 | -------------------------------------------------------------------------------- /src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | --------------------------------------------------------------------------------