├── .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 |
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 | You need to enable JavaScript to run this app.
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 |
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 |
setSideToggle(!sideToggle)}>
47 |
48 |
49 |
50 |
51 |
52 |
53 |
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 |
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 | Name
90 | Description
91 | Price
92 | Action
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 | {name}
103 | {des ? des : "Nothing"}
104 | ${price}
105 |
106 | checkPermission(_id, 'edit')}>
107 |
108 | Edit
109 | checkPermission(_id, 'delete')}>
110 |
111 | Delete
112 |
113 |
114 | )
115 | })
116 | }
117 |
118 |
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 | Name
34 | Email ID
35 | Service
36 | Status
37 |
38 |
39 |
40 | {
41 | orders.map(order => )
42 | }
43 |
44 |
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 |
Log out
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 |
21 |
22 |
23 | setTitle('Profile')} activeclassname="activePage" exact to="/dashboard/profile">
24 |
25 | Profile
26 |
27 |
28 | {admin ?
29 | <>
30 |
31 | setTitle('Order List')} activeclassname="activePage" to="/dashboard/orderList">
32 |
33 | Order list
34 |
35 |
36 |
37 | setTitle('Add Service')} activeclassname="activePage" to="/dashboard/addService">
38 |
39 | Add Service
40 |
41 |
42 |
43 | setTitle('Make Admin')} activeclassname="activePage" to="/dashboard/makeAdmin">
44 |
45 | Make Admin
46 |
47 |
48 |
49 | setTitle('Manage Services')} activeclassname="activePage" to="/dashboard/manageServices">
50 |
51 | Manage Services
52 |
53 |
54 | >
55 | :
56 | <>
57 |
58 | setTitle('Book')} activeclassname="activePage" exact to="/dashboard/book">
59 |
60 | Book
61 |
62 |
63 |
64 | setTitle('Booking List')} activeclassname="activePage" to="/dashboard/booking">
65 |
66 | Booking List
67 |
68 |
69 |
70 | setTitle('Review')} activeclassname="activePage" to="/dashboard/review">
71 |
72 | Review
73 |
74 |
75 | >
76 | }
77 |
78 |
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 |
Edit
74 |
handleDelete(_id)}> Delete
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 |
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 |
50 | {selectedService.name &&
51 | {selectedService.name}
52 | }
53 | {
54 | services?.map(({id, name}) => {name} )
55 | }
56 |
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 |
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 |
69 |
70 |
{serviceName}
71 |
{description}
72 |
handleDelete(_id, status)}>
73 |
74 | { status === 'Done' ? 'Remove':'Cancel'}
75 |
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 | learn More
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 |
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 |
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 |
63 | Start now
64 |
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 |
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 |
Book Now
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 |
61 |
62 |
63 |
64 |
65 |
New here ?
66 |
Lorem ipsum dolor sit amet consectetur adipisicing elit. Sequi beatae quas magnam!
67 |
setSignUp(true)}>Sign Up
68 |
69 |
70 |
71 |
72 |
73 |
74 |
One of us ?
75 |
Lorem ipsum dolor sit amet consectetur adipisicing elit. Sequi beatae quas magnam!
76 |
setSignUp(false)}>Sign In
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 |
38 |
39 | window['scrollTo']({ top: 0, behavior: 'smooth' })}>Home
40 |
41 |
42 | Services
43 |
44 |
45 | Reviews
46 |
47 |
48 | Contact Us
49 |
50 |
51 | Dashboard
52 |
53 |
54 | {
55 | user.email ?
56 | :
59 |
60 | Login
61 |
62 | }
63 |
64 |
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 |
Log out
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 &&
25 | {/* */}
26 | Button
27 |
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 |
--------------------------------------------------------------------------------