├── src
├── components
│ ├── 404
│ │ └── 404.jsx
│ ├── user
│ │ ├── Navbar
│ │ │ └── Navbar.css
│ │ ├── categorylist.css
│ │ ├── servicesPage
│ │ │ └── ServicesPage.js
│ │ ├── home
│ │ │ ├── home.css
│ │ │ ├── specialCards.jsx
│ │ │ └── home.js
│ │ ├── advt
│ │ │ └── advt.jsx
│ │ ├── Chat
│ │ │ └── chatButton.jsx
│ │ ├── Hero
│ │ │ ├── hero.jsx
│ │ │ └── hero.css
│ │ ├── login
│ │ │ ├── login.css
│ │ │ ├── login.jsx
│ │ │ └── Register.js
│ │ ├── payment
│ │ │ └── Payment.jsx
│ │ ├── Categorylist.jsx
│ │ ├── Ratings
│ │ │ └── Ratings.jsx
│ │ ├── Profile
│ │ │ └── profile.jsx
│ │ ├── Bookings
│ │ │ ├── Bookings.jsx
│ │ │ └── BookingDetails.jsx
│ │ ├── singleservice
│ │ │ └── SingleService.jsx
│ │ ├── BookNow
│ │ │ └── BookNow.jsx
│ │ ├── ServiceCard
│ │ │ └── ServiceCard.jsx
│ │ ├── Footer
│ │ │ └── Footer.jsx
│ │ └── Checkouts
│ │ │ ├── Address.jsx
│ │ │ └── TimeShedule.jsx
│ ├── admin
│ │ ├── Support
│ │ │ ├── Support.jsx
│ │ │ ├── chatSidebar.jsx
│ │ │ └── chat.jsx
│ │ ├── Services
│ │ │ ├── Services.css
│ │ │ ├── addservice.css
│ │ │ └── addServices.jsx
│ │ ├── Dashboard
│ │ │ ├── table.jsx
│ │ │ ├── dashboard.jsx
│ │ │ ├── chart.jsx
│ │ │ ├── columnChart.jsx
│ │ │ └── StatCard.jsx
│ │ ├── Login
│ │ │ ├── login.css
│ │ │ └── login.js
│ │ ├── Media
│ │ │ ├── Banner.jsx
│ │ │ ├── Advertisement.jsx
│ │ │ ├── EditMedia
│ │ │ │ ├── Advt.jsx
│ │ │ │ ├── banner.jsx
│ │ │ │ └── Cards.jsx
│ │ │ └── MediaCards.jsx
│ │ ├── City
│ │ │ ├── addCity.jsx
│ │ │ └── city.jsx
│ │ ├── category
│ │ │ ├── addCategory.jsx
│ │ │ ├── editCategory.jsx
│ │ │ └── Category.jsx
│ │ ├── users
│ │ │ └── users.jsx
│ │ ├── Bookings
│ │ │ └── bookings.jsx
│ │ └── AdminNavbar
│ │ │ └── AdminNavbar.jsx
│ ├── Provider
│ │ ├── register.css
│ │ ├── Bookings
│ │ │ ├── Upcoming.jsx
│ │ │ ├── Completed.jsx
│ │ │ ├── Requests.jsx
│ │ │ └── BookingCards.jsx
│ │ ├── dashboard.jsx
│ │ ├── login.jsx
│ │ ├── sidebar.jsx
│ │ ├── Profile
│ │ │ └── Profile.jsx
│ │ └── Navbar.jsx
│ ├── Loader.jsx
│ └── comfirmations
│ │ ├── Deleteservice.jsx
│ │ ├── DeleteCategory.jsx
│ │ ├── DeleteCity.jsx
│ │ ├── BlockUser.jsx
│ │ └── StartJobModal.jsx
├── config
│ └── config.js
├── index.css
├── axios.js
├── redux
│ ├── Slice
│ │ ├── userSlice.js
│ │ ├── serviceSlice.js
│ │ ├── locationSlice.js
│ │ ├── serviceEditSlice.js
│ │ └── cartSlice.js
│ └── Store.js
├── index.js
├── App.css
├── Auth
│ ├── userAuth.jsx
│ ├── adminAuth.jsx
│ └── providerAuth.jsx
├── App.js
├── validateForm.js
├── Api
│ ├── providerAPI.js
│ └── userAPI.js
└── Routes
│ ├── providerRoute.jsx
│ ├── adminRoute.jsx
│ └── userRoute.jsx
├── public
├── _redirects
├── favicon.ico
└── index.html
├── postcss.config.js
├── .env
├── tailwind.config.js
├── .gitignore
├── package.json
└── README.md
/src/components/user/Navbar/Navbar.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/admin/Support/Support.jsx:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/_redirects:
--------------------------------------------------------------------------------
1 | /* /index.html 200
2 | /admin/* /index.html 200
3 | /provider/* /index.html 200
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/muhammedsouban/QuickServe-frontend/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
--------------------------------------------------------------------------------
/src/config/config.js:
--------------------------------------------------------------------------------
1 | const BASE_URL = 'https://quickserve-backend-production.up.railway.app';
2 | export default BASE_URL;
3 |
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
1 | API_BASE_URL= '${BASE_URL}'
2 | RAZORPAY_API_KEY="rzp_test_FtVK05Td5kBCzd"
3 | RAZORPAY_API_SECRET='PEYuPWhyBGcmOWSl2MmWPpVW'
--------------------------------------------------------------------------------
/src/components/user/categorylist.css:
--------------------------------------------------------------------------------
1 | .slick-prev:before {
2 | color: black;
3 | }
4 | .slick-next:before {
5 | color: black;
6 | }
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | body {
6 | background-color: #E8F5FF;
7 | min-height: 100vh;
8 | }
9 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: ['./src/**/*.{js,jsx,ts,tsx}'],
4 | theme: {
5 | extend: {},
6 | },
7 | plugins: [
8 | require('tailwind-scrollbar')
9 | ],
10 | };
--------------------------------------------------------------------------------
/src/components/admin/Services/Services.css:
--------------------------------------------------------------------------------
1 | .modal-overlay {
2 | position: fixed;
3 | top: 0;
4 | left: 0;
5 | width: 100%;
6 | height: 100%;
7 | background-color: rgba(0, 0, 0, 0.7);
8 | display: flex;
9 | z-index: 10;
10 | justify-content: center;
11 | align-items: center;
12 | }
13 |
14 |
--------------------------------------------------------------------------------
/src/components/user/servicesPage/ServicesPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ServiceCard from '../ServiceCard/ServiceCard';
3 | import CategorySlider from '../Categorylist'
4 | function ServicesPage() {
5 | return (
6 | <>
7 |
8 |
9 | >
10 | )
11 | }
12 |
13 | export default ServicesPage
--------------------------------------------------------------------------------
/src/axios.js:
--------------------------------------------------------------------------------
1 | import BASE_URL from "./config/config";
2 |
3 | import Axios from "axios";
4 |
5 | const Axiosuser = Axios.create({
6 | baseURL: BASE_URL,
7 | });
8 |
9 | const Axiosadmin = Axios.create({
10 | baseURL: `${BASE_URL}/admin/`,
11 | });
12 |
13 | const AxiosProvider = Axios.create({
14 | baseURL: `${BASE_URL}/provider/`
15 | })
16 |
17 | export { Axiosuser, Axiosadmin, AxiosProvider };
--------------------------------------------------------------------------------
/src/components/404/404.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import BASE_URL from '../../config/config';
3 |
4 | function Error() {
5 | return (
6 |
7 |
12 |
13 | );
14 | }
15 |
16 | export default Error;
17 |
--------------------------------------------------------------------------------
/.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 | #
12 |
13 | # production
14 | /build
15 |
16 | # misc
17 | .DS_Store
18 | .env.local
19 | .env.development.local
20 | .env.test.local
21 | .env.production.local
22 |
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
--------------------------------------------------------------------------------
/src/components/user/home/home.css:
--------------------------------------------------------------------------------
1 | .navbar {
2 | display: flex;
3 | position: sticky;
4 | top: 0;
5 | justify-content: space-between;
6 | background: linear-gradient(45deg, #000235, #020073);
7 | }
8 |
9 | .sidebar {
10 | background: linear-gradient(180deg, #000235, #020073);
11 | /* width: 300px; */
12 |
13 | }
14 |
15 | /* @media (max-width:400px){
16 | .sidebar {
17 | width: 50px;
18 |
19 | }
20 | } */
21 |
--------------------------------------------------------------------------------
/src/components/Provider/register.css:
--------------------------------------------------------------------------------
1 | .Register-container {
2 | display: flex;
3 | justify-content: center;
4 | align-items: center;
5 | overflow-y: scroll;
6 | background-color: #E8F5FF;
7 | height: 85vh;
8 | scrollbar-width: thin;
9 | scrollbar-color: transparent transparent;
10 | }
11 |
12 | .Register-center {
13 | width: 100%;
14 | max-width: 800px;
15 | padding: 2rem;
16 | height: 100%;
17 | }
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/redux/Slice/userSlice.js:
--------------------------------------------------------------------------------
1 | import { createSlice } from "@reduxjs/toolkit";
2 |
3 | const initialState = {
4 | data: []
5 | };
6 |
7 | const userSlice = createSlice({
8 | name: "user",
9 | initialState,
10 | reducers: {
11 | userData: (state, action) => {
12 | const { field, value } = action.payload;
13 | state[field] = value;
14 | },
15 | resetUserState: () => initialState
16 | }
17 | });
18 |
19 | export const { userData, resetUserState } = userSlice.actions;
20 | export default userSlice.reducer;
21 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom/client';
3 | import './index.css';
4 | import App from './App';
5 | import { Provider } from "react-redux";
6 | import { PersistGate } from "redux-persist/integration/react";
7 | import { store, persistor } from "./redux/Store";
8 |
9 | const root = ReactDOM.createRoot(document.getElementById('root'));
10 | root.render(
11 |
12 |
13 |
14 |
15 |
16 |
17 | );
18 |
--------------------------------------------------------------------------------
/src/redux/Slice/serviceSlice.js:
--------------------------------------------------------------------------------
1 | import { createSlice } from "@reduxjs/toolkit";
2 |
3 | const initialState = {
4 | servicename: "",
5 | category: "",
6 | description: "",
7 | serviceincludes: "",
8 | price: '',
9 | image: ''
10 | };
11 |
12 | const serviceSlice = createSlice({
13 | name: "service",
14 | initialState,
15 | reducers: {
16 | addService: (state, action) => {
17 | const { field, value } = action.payload;
18 | state[field] = value;
19 | },
20 | },
21 | });
22 |
23 | export const { addService } = serviceSlice.actions;
24 | export default serviceSlice.reducer;
25 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 | QuickServe
14 |
15 |
16 | You need to enable JavaScript to run this app.
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/components/user/advt/advt.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-router-dom'
3 | import BASE_URL from '../../../config/config';
4 | function Advt({ data }) {
5 | return (
6 |
7 |
8 |
9 |
14 |
15 |
16 |
17 | );
18 | }
19 |
20 | export default Advt;
21 |
--------------------------------------------------------------------------------
/src/components/Loader.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ThreeCircles } from 'react-loader-spinner';
3 |
4 | const Loader = () => {
5 | return (
6 |
17 | );
18 | };
19 |
20 | export default Loader;
21 |
--------------------------------------------------------------------------------
/src/redux/Slice/locationSlice.js:
--------------------------------------------------------------------------------
1 | import { createSlice } from "@reduxjs/toolkit";
2 |
3 | const initialState = {
4 | data: {
5 | city:'',
6 | data:[]
7 | }
8 | };
9 |
10 | const locationSlice = createSlice({
11 | name: "location",
12 | initialState,
13 | reducers: {
14 | Location: (state, action) => {
15 | const { field, value } = action.payload;
16 | state.data[field] = value;
17 |
18 | }, UpdateCity: (state, action) => {
19 | state.data = { ...state.data, city: action.payload };
20 | }
21 | },
22 | });
23 |
24 | export const { Location,UpdateCity } = locationSlice.actions;
25 | export default locationSlice.reducer;
26 |
--------------------------------------------------------------------------------
/src/components/user/Chat/chatButton.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
3 | import { faComments } from '@fortawesome/free-solid-svg-icons';
4 | import Chat from './chat';
5 |
6 | const ChatButton = ({action}) => {
7 | return (
8 | <>
9 |
10 | action())} className="bg-blue-500 hover:bg-blue-600 text-white rounded-full w-16 h-16 flex items-center justify-center focus:outline-none">
11 |
12 |
13 |
14 | >
15 | );
16 | };
17 |
18 | export default ChatButton;
19 |
--------------------------------------------------------------------------------
/src/redux/Slice/serviceEditSlice.js:
--------------------------------------------------------------------------------
1 | import { createSlice } from "@reduxjs/toolkit";
2 |
3 | const initialState = {
4 | servicename: "",
5 | category: "",
6 | description: "",
7 | serviceincludes: "",
8 | price: "",
9 | image: "",
10 | };
11 |
12 | const serviceEditSlice = createSlice({
13 | name: "editservice",
14 | initialState,
15 | reducers: {
16 | EditService: (state, action) => {
17 | const { field, value } = action.payload;
18 | state[field] = value;
19 | },
20 | UpdateService: (state, action) => {
21 | return initialState;
22 | },
23 | },
24 | });
25 |
26 | export const { EditService, UpdateService } = serviceEditSlice.actions;
27 | export default serviceEditSlice.reducer;
28 |
--------------------------------------------------------------------------------
/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/components/user/Hero/hero.jsx:
--------------------------------------------------------------------------------
1 | import './hero.css'
2 |
3 | import React from 'react'
4 | import BASE_URL from '../../../config/config'
5 | import { Link } from 'react-router-dom'
6 | function Hero({data}) {
7 | return (
8 | <>
9 |
10 |
12 |
13 |
14 |
Bringing skilled Professionals To You
15 |
16 | Explore Now
17 |
18 |
19 |
20 | >
21 | )
22 | }
23 |
24 | export default Hero
--------------------------------------------------------------------------------
/src/Auth/userAuth.jsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react';
2 | import { useLocation, Navigate, Outlet } from 'react-router-dom';
3 | import Loader from '../components/Loader';
4 |
5 | function UserAuth() {
6 | const user = localStorage.getItem("userToken");
7 | const location = useLocation();
8 | const [isLoading, setIsLoading] = useState(true);
9 |
10 | useEffect(() => {
11 | const timer = setTimeout(() => {
12 | setIsLoading(false);
13 | }, 1000);
14 |
15 | return () => clearTimeout(timer);
16 | }, []);
17 |
18 | if (isLoading) {
19 | return ;
20 | } else {
21 | return (
22 | user ?
23 | :
24 | );
25 | }
26 | }
27 |
28 | export default UserAuth
--------------------------------------------------------------------------------
/src/Auth/adminAuth.jsx:
--------------------------------------------------------------------------------
1 | import { useLocation, Navigate, Outlet } from 'react-router-dom';
2 | import { useState, useEffect } from 'react';
3 | import Loader from '../components/Loader';
4 |
5 |
6 | function AdminAuth() {
7 | const [isLoading, setIsLoading] = useState(true);
8 | const admin = localStorage.getItem("token");
9 | const location = useLocation();
10 |
11 | useEffect(() => {
12 | const timer = setTimeout(() => {
13 | setIsLoading(false);
14 | }, 1000);
15 |
16 | return () => clearTimeout(timer);
17 | }, []);
18 |
19 | if (isLoading) {
20 | return ;
21 | }else{
22 | return (
23 | admin ?
24 | :
25 |
26 | );
27 | }
28 |
29 | }
30 |
31 | export default AdminAuth
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import { BrowserRouter, Routes, Route } from "react-router-dom";
2 |
3 | import "./App.css";
4 | import ProviderRoute from "./Routes/providerRoute";
5 | import UserRoute from "./Routes/userRoute";
6 | import AdminRoute from "./Routes/adminRoute";
7 | import { Toaster } from "react-hot-toast";
8 | import Error from "./components/404/404";
9 |
10 | function App() {
11 |
12 | return (
13 | <>
14 |
15 |
16 |
17 | } />
18 | } />
19 | } />
20 | {/* } /> */}
21 |
22 |
23 | >
24 |
25 | );
26 | }
27 |
28 | export default App;
29 |
--------------------------------------------------------------------------------
/src/Auth/providerAuth.jsx:
--------------------------------------------------------------------------------
1 | import { useLocation, Navigate, Outlet } from 'react-router-dom';
2 | import Loader from '../components/Loader';
3 | import { useEffect, useState } from 'react';
4 | function ProviderAuth() {
5 | const provider = localStorage.getItem("ProviderToken");
6 | const location = useLocation();
7 | const [isLoading, setIsLoading] = useState(true);
8 |
9 | useEffect(() => {
10 | const timer = setTimeout(() => {
11 | setIsLoading(false);
12 | }, 1000);
13 |
14 | return () => clearTimeout(timer);
15 | }, []);
16 |
17 | if (isLoading) {
18 | return ;
19 | } else {
20 | return (
21 | provider ?
22 | :
23 |
24 | );
25 | }
26 | }
27 |
28 | export default ProviderAuth
--------------------------------------------------------------------------------
/src/components/Provider/Bookings/Upcoming.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState,useEffect } from 'react'
2 | import BookingsCard from './BookingCards';
3 | import { acceptRequest, bookingRequests, upcoming } from '../../../Api/providerAPI';
4 |
5 | function Upcoming() {
6 |
7 | const headers = { Authorization: `Bearer ${localStorage.getItem('ProviderToken')}` };
8 |
9 | const [booking, setBooking] = useState([])
10 | const [action,setAction]=useState(false)
11 | useEffect(() => {
12 | upcoming(headers).then((res) => {
13 | setBooking(res.data);
14 | });
15 | }, [action]);
16 |
17 | const handleAction=(()=>{
18 | setAction(true)
19 | })
20 |
21 | return (
22 | <>
23 |
24 | >
25 | )
26 | }
27 |
28 | export default Upcoming
--------------------------------------------------------------------------------
/src/validateForm.js:
--------------------------------------------------------------------------------
1 | export const validatePassword = (password) => {
2 | const uppercaseRegex = /[A-Z]/;
3 | const symbolRegex = /[!@#$%^&*()]/;
4 | const numberRegex = /[0-9]/;
5 |
6 | if (password.length < 6) {
7 | return false;
8 | }
9 |
10 | if (!uppercaseRegex.test(password)) {
11 | return false;
12 | }
13 |
14 | if (!symbolRegex.test(password)) {
15 | return false;
16 | }
17 |
18 | if (!numberRegex.test(password)) {
19 | return false;
20 | }
21 |
22 | return true;
23 | };
24 |
25 | export const validateEmail = (email) => {
26 | const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
27 | return emailRegex.test(email);
28 | };
29 |
30 | export const validateMobileNumber = (mobileNumber) => {
31 | const mobileRegex = /^\d{10}$/;
32 | return mobileRegex.test(mobileNumber);
33 | };
--------------------------------------------------------------------------------
/src/components/user/login/login.css:
--------------------------------------------------------------------------------
1 | .form{
2 | background-color: white;
3 | border-radius: 5px;
4 | width: 550px;
5 | margin: 20px auto;
6 | padding: 20px;
7 | /* height: 600px; */
8 | }
9 |
10 | .form-body{
11 | text-align: left;
12 | padding: 20px 10px;
13 | }
14 |
15 | .form-body > *{
16 | padding: 5px;
17 | }
18 |
19 | .form__label{
20 | width: 40%;
21 | }
22 |
23 | .form_input{
24 | width: 60%;
25 | }
26 |
27 | .footer{
28 | text-align: center;
29 | }
30 | /*
31 | .Register-container {
32 | display: flex;
33 | justify-content: center;
34 | align-items: center;
35 | overflow-y: scroll;
36 | background-color: #fff;
37 | height: 100vh;
38 | scrollbar-width: thin;
39 | scrollbar-color: transparent transparent;
40 | }
41 |
42 | .Register-center {
43 | width: 100%;
44 | max-width: fit-content;
45 | padding: 2rem;
46 | height: 100%;
47 | } */
48 |
49 |
50 |
--------------------------------------------------------------------------------
/src/components/Provider/Bookings/Completed.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState,useEffect } from 'react'
2 | import BookingsCard from './BookingCards';
3 | import { acceptRequest, bookingRequests, completed, upcoming } from '../../../Api/providerAPI';
4 |
5 | function Completed() {
6 |
7 | const headers = { Authorization: `Bearer ${localStorage.getItem('ProviderToken')}` };
8 |
9 | const [booking, setBooking] = useState([])
10 | useEffect(() => {
11 | completed(headers).then((res) => {
12 | setBooking(res.data);
13 | });
14 | }, []);
15 | const handleAccept = ((services, booking) => {
16 |
17 | const data = {
18 | services: services,
19 | bookingId: booking
20 | }
21 | acceptRequest(data, headers)
22 | })
23 |
24 |
25 | return (
26 | <>
27 |
28 | >
29 | )
30 | }
31 |
32 | export default Completed
--------------------------------------------------------------------------------
/src/redux/Store.js:
--------------------------------------------------------------------------------
1 | import { configureStore, combineReducers } from "@reduxjs/toolkit";
2 | import { persistReducer, persistStore } from "redux-persist";
3 | import storage from "redux-persist/lib/storage";
4 |
5 | import userReducer from "./Slice/userSlice";
6 | import serviceReducer from "./Slice/serviceSlice";
7 | import ServiceEditReducer from "./Slice/serviceEditSlice";
8 | import cartReducer from "./Slice/cartSlice";
9 | import locationReducer from "./Slice/locationSlice";
10 | const persistConfig = {
11 | key: "root",
12 | storage,
13 | whitelist: ["user","location"],
14 | };
15 |
16 | const rootReducer = combineReducers({
17 | service: serviceReducer,
18 | editservice: ServiceEditReducer,
19 | user: userReducer,
20 | cart:cartReducer,
21 | location:locationReducer
22 | });
23 |
24 | const persistedReducer = persistReducer(persistConfig, rootReducer);
25 |
26 | const store = configureStore({
27 | reducer: persistedReducer,
28 | });
29 |
30 | const persistor = persistStore(store);
31 |
32 | export { store, persistor };
33 |
--------------------------------------------------------------------------------
/src/components/Provider/Bookings/Requests.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react'
2 | import BookingsCard from './BookingCards';
3 | import { acceptRequest, bookingRequests } from '../../../Api/providerAPI';
4 | import { toast } from 'react-hot-toast';
5 |
6 | function Requests() {
7 |
8 | const headers = { Authorization: `Bearer ${localStorage.getItem('ProviderToken')}` };
9 |
10 | const [booking, setBooking] = useState([])
11 | const [action, setAction] = useState(false)
12 | useEffect(() => {
13 | bookingRequests(headers).then((res) => {
14 | setBooking(res.data);
15 | });
16 | }, [action]);
17 |
18 | const handleAccept = ((services, booking) => {
19 | const data = {
20 | services: services,
21 | bookingId: booking
22 | }
23 | acceptRequest(data, headers).then((res) => {
24 | toast.success('Booking accepted Successfully')
25 | setAction(true)
26 | })
27 |
28 | })
29 |
30 |
31 | return (
32 | <>
33 |
34 | >
35 | )
36 | }
37 |
38 | export default Requests
--------------------------------------------------------------------------------
/src/components/user/home/specialCards.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-router-dom';
3 | // import { StarIcon, HeartIcon } from '@heroicons/react/solid';
4 | import BASE_URL from '../../../config/config';
5 |
6 | const MyCard = ({ data }) => {
7 | return (
8 | <>
9 |
10 |
{data?.title}
11 |
12 |
13 |
14 | {data?.images.length > 0 ? (
15 | data.images.map((service) => (
16 |
17 |
22 |
23 | ))
24 | ) : (
25 | ''
26 | )}
27 |
28 |
29 | >
30 | );
31 | };
32 |
33 | export default MyCard;
34 |
--------------------------------------------------------------------------------
/src/components/user/Hero/hero.css:
--------------------------------------------------------------------------------
1 | .hero {
2 | position: relative;
3 | height: 500px;
4 | }
5 |
6 | .hero img {
7 | object-fit: cover;
8 | width: 100%;
9 | height: 100%;
10 | }
11 |
12 | .hero-text {
13 | position: absolute;
14 | top: 50%;
15 | left: 30%;
16 | transform: translate(-30%, -50%);
17 | color: rgb(0, 0, 0);
18 | text-align: start;
19 | }
20 |
21 | .hero-text h1 {
22 | font-size: 48px;
23 | margin-bottom: 10px;
24 | width: 70%;
25 | }
26 |
27 | .hero-text button {
28 | display: inline-block;
29 | padding: 7px 40px;
30 | background-color: #000000;
31 | color: white;
32 | font-size: 20px;
33 | text-transform: uppercase;
34 | border-radius: 13px;
35 | transition: background-color 0.3s ease;
36 | }
37 |
38 | .hero-text a:hover {
39 | background-color: #ffffff;
40 | color: #000000;
41 | }
42 |
43 | /* Media Queries for Responsive Font Sizes */
44 |
45 | @media (max-width: 915px) {
46 | .hero-text h1 {
47 | font-size: 36px;
48 | width: 80%;
49 |
50 |
51 | }
52 |
53 | .hero-text input {
54 | font-size: 16px;
55 | }
56 | }
57 |
58 | @media (max-width: 480px) {
59 | .hero-text h1 {
60 | font-size: 24px;
61 | width: 100%;
62 | }
63 |
64 | .hero-text input {
65 | font-size: 14px;
66 | }
67 | }
--------------------------------------------------------------------------------
/src/components/admin/Support/chatSidebar.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from "react";
2 |
3 | const Sidebar = ({ Users, selectuser }) => {
4 |
5 | const userSelect = (userId,username) => {
6 | selectuser(userId,username);
7 | };
8 |
9 | return (
10 |
11 |
12 |
13 | QuickServe
14 | Support Panel
15 |
16 |
17 |
18 | {Users &&
19 | Users.map((item) => (
20 | userSelect(item._id,item.username)}
23 | className="flex items-center my-2 py-2 mr-2 rounded-r-lg bg-black text-white"
24 | >
25 |
30 | {item.username}
31 |
32 | ))}
33 |
34 |
35 |
36 |
37 |
38 | );
39 | };
40 |
41 | export default Sidebar;
42 |
--------------------------------------------------------------------------------
/src/Api/providerAPI.js:
--------------------------------------------------------------------------------
1 | import { AxiosProvider } from "../axios";
2 |
3 | export const Register = async (formData) => {
4 | const res = await AxiosProvider.post('/register', formData)
5 | return res
6 | }
7 | export const Login = async (email, password) => {
8 | const res = await AxiosProvider.post('/login', { email, password })
9 | return res
10 | }
11 | export const bookingRequests = async (headers) => {
12 | const res = await AxiosProvider.get('/bookingRequests', { headers })
13 | return res
14 | }
15 |
16 | export const getProviderprofile = async (headers) => {
17 | const res = await AxiosProvider.get('/profile', { headers })
18 | return res
19 | }
20 | export const acceptRequest = async (data, headers) => {
21 | const res = await AxiosProvider.put('/acceptBooking', { data }, { headers })
22 | return res
23 | }
24 |
25 | export const upcoming = async (headers) => {
26 | const res = await AxiosProvider.get('/upcoming', { headers })
27 | return res
28 | }
29 |
30 | export const completed = async (headers) => {
31 | const res = await AxiosProvider.get('/completed', { headers })
32 | return res
33 | }
34 |
35 | export const startJob = async (data, headers) => {
36 | const res = await AxiosProvider.post('/start-job', { data }, { headers })
37 | return res
38 | }
39 |
40 | export const providerDashboard = async (headers) => {
41 | const res = await AxiosProvider.get('/dashboard', { headers })
42 | return res
43 | }
--------------------------------------------------------------------------------
/src/components/user/home/home.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import "../../../components/user/home/home.css";
3 | import Hero from "../Hero/hero";
4 | import CategorySlider from "../Categorylist";
5 | import MyCard from "./specialCards";
6 | import Advt from "../advt/advt";
7 | import { getMedia } from "../../../Api/userAPI";
8 | import Loader from "../../Loader";
9 | function Home() {
10 | const [media, setMedia] = useState(null);
11 | const [loading, setLoading] = useState(true);
12 |
13 | useEffect(() => {
14 | const fetchMedia = async () => {
15 | try {
16 | await getMedia().then(response => {
17 | setMedia(response.data);
18 | setLoading(false)
19 | });
20 | } catch (error) {
21 | console.log(error);
22 | }
23 | };
24 |
25 | fetchMedia();
26 | }, []);
27 |
28 | return (
29 | <>
30 | {loading ?
31 |
32 | :
33 | {media && (
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | )}
46 |
}
47 | >
48 | );
49 | }
50 |
51 | export default Home;
52 |
--------------------------------------------------------------------------------
/src/components/admin/Dashboard/table.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import moment from 'moment';
3 |
4 | const DashboardTable = ({ value }) => {
5 |
6 | return (
7 |
8 |
Upcoming Bookings
9 |
10 |
11 |
12 |
13 | Service Name
14 | Date
15 | Start Time
16 |
17 |
18 |
19 | {value && value.length > 0 ? (
20 | value.map((booking) => (
21 |
22 | {booking.services.map((service) => (
23 |
24 | {service.serviceData.servicename}
25 |
26 | ))}
27 | {/* {booking.user} */}
28 |
29 | {moment(booking.date).format("MMMM Do, YYYY")}
30 | {booking.startTime}
31 |
32 | ))
33 | ) : (
34 |
35 | No bookings found.
36 |
37 | )}
38 |
39 |
40 |
41 |
42 |
43 | );
44 | };
45 |
46 | export default DashboardTable;
47 |
--------------------------------------------------------------------------------
/src/components/comfirmations/Deleteservice.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { deleteService } from '../../Api/AdminAPI';
3 |
4 | function Deleteservice({open,serviceId}) {
5 |
6 | const close = () => {
7 | open(false);
8 | };
9 | const headers = { Authorization: `Bearer ${localStorage.getItem('token')}` };
10 | const Delete = () => {
11 | deleteService(serviceId,headers).then((data)=>{
12 | if (data) {
13 | open(false);
14 | }
15 | })
16 | };
17 |
18 | return (
19 |
23 |
24 |
25 | Are you sure you want to delete SERVICE ?
26 |
27 |
28 |
32 | cancel
33 |
34 |
38 | delete
39 |
40 |
41 |
42 |
43 | )
44 | }
45 |
46 | export default Deleteservice
--------------------------------------------------------------------------------
/src/redux/Slice/cartSlice.js:
--------------------------------------------------------------------------------
1 | import { createSlice } from "@reduxjs/toolkit";
2 |
3 | const initialState = {
4 | cartItems: [],
5 | };
6 |
7 | export const cartSlice = createSlice({
8 | name: "cart",
9 | initialState,
10 | reducers: {
11 | addCartItem: (state, action) => {
12 | action.payload.forEach((item) => {
13 | const existingItem = state.cartItems.find((cartItem) => cartItem._id === item._id);
14 | if (!existingItem) {
15 | const total = item.price * item.qty;
16 | state.cartItems.push({ ...item, qty: 1, total });
17 | }
18 | });
19 | },
20 | deleteCartItem: (state, action) => {
21 | const index = state.cartItems.findIndex((el) => el._id === action.payload);
22 | if (index !== -1) {
23 | state.cartItems.splice(index, 1);
24 | }
25 | },
26 | increaseQty: (state, action) => {
27 | const index = state.cartItems.findIndex((el) => el._id === action.payload);
28 | if (index !== -1) {
29 | state.cartItems[index].qty += 1;
30 | state.cartItems[index].total = state.cartItems[index].price * state.cartItems[index].qty;
31 | }
32 | },
33 | decreaseQty: (state, action) => {
34 | const index = state.cartItems.findIndex((el) => el._id === action.payload);
35 | if (index !== -1 && state.cartItems[index].qty > 1) {
36 | state.cartItems[index].qty -= 1;
37 | state.cartItems[index].total = state.cartItems[index].price * state.cartItems[index].qty;
38 | }
39 | },
40 | clearCart: (state, action) => {
41 | state.cartItems = [];
42 | },
43 | },
44 | });
45 |
46 | export const {
47 | addCartItem,
48 | deleteCartItem,
49 | increaseQty,
50 | decreaseQty,
51 | clearCart,
52 | } = cartSlice.actions;
53 |
54 | export default cartSlice.reducer;
55 |
--------------------------------------------------------------------------------
/src/components/admin/Dashboard/dashboard.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import StatCard from './StatCard';
3 | import MainChart from './chart';
4 | import ColumnChart from './columnChart';
5 | import { AdminDashboard } from '../../../Api/AdminAPI';
6 | import Loader from '../../Loader';
7 |
8 | const Dashboard = () => {
9 | const [data, setData] = useState([]);
10 | const [mChartData, setMChartData] = useState();
11 | const [CChartData, setCChartData] = useState();
12 | const [loading, setLoading] = useState(true);
13 |
14 |
15 | const headers = { Authorization: `Bearer ${localStorage.getItem('token')}` };
16 |
17 | useEffect(() => {
18 | AdminDashboard(headers).then((res) => {
19 | setLoading(false)
20 |
21 | const { users, providers,totalBookings,earnings } = res.data;
22 | const namedData = [
23 | { name: 'Earnings', count: earnings },
24 | { name: 'Bookings', count: totalBookings },
25 | { name: 'Users', count: users },
26 | { name: 'Providers', count: providers }
27 | ];
28 | setData(namedData);
29 | setMChartData(res.data.earningsByMonth)
30 | setCChartData(res.data.bookingsCountByMonth)
31 | });
32 | }, []);
33 |
34 | return (
35 | <>
36 |
37 | {loading ?
38 |
:
39 |
40 |
Dashboard
41 |
42 |
43 |
44 |
45 |
46 |
47 |
}
48 |
49 | >
50 | );
51 | };
52 |
53 | export default Dashboard;
54 |
--------------------------------------------------------------------------------
/src/components/Provider/dashboard.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react'
2 | import StatCard from '../admin/Dashboard/StatCard'
3 | import MainChart from '../admin/Dashboard/chart'
4 | import DashboardTable from '../admin/Dashboard/table'
5 | import { providerDashboard, upcoming } from '../../Api/providerAPI'
6 | import Loader from '../Loader'
7 | function Dashboard() {
8 | const [data, setData] = useState([]);
9 | const [mChartData, setMChartData] = useState();
10 | const [upcomingBookings, setUpcomingBookings] = useState([])
11 | const [loading, setLoading] = useState(true);
12 |
13 |
14 | const headers = { Authorization: `Bearer ${localStorage.getItem('ProviderToken')}` };
15 |
16 | useEffect(() => {
17 | providerDashboard(headers).then((res) => {
18 | setLoading(false)
19 | const { Upcoming, Requests, completed, earnings,earningsByMonth } = res.data;
20 | const namedData = [
21 | { name: 'Earnings', count: earnings },
22 | { name: 'Completed', count: completed },
23 | { name: 'Upcomings', count: Upcoming },
24 | { name: 'Requests', count: Requests },
25 | ];
26 | setData(namedData);
27 | setMChartData(earningsByMonth)
28 | upcoming(headers).then((res) => {
29 | setUpcomingBookings(res.data)
30 | })
31 |
32 | })
33 | }, [])
34 |
35 | return (
36 | <>
37 |
38 | {loading ?
39 |
:
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
}
48 |
49 |
50 | >
51 | )
52 | }
53 |
54 | export default Dashboard
--------------------------------------------------------------------------------
/src/components/comfirmations/DeleteCategory.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { deleteCategory } from '../../Api/AdminAPI';
3 |
4 | function DeleteCategory({ open, Id }) {
5 |
6 | const close = () => {
7 | open(false);
8 | };
9 | const headers = { Authorization: `Bearer ${localStorage.getItem('token')}` };
10 | const Delete = () => {
11 | const res = deleteCategory(Id, headers)
12 | if (res) {
13 | open(false);
14 | }
15 | };
16 |
17 | return (
18 |
22 |
23 |
24 | Are you sure you want to delete Category ?
25 |
26 |
27 |
31 | cancel
32 |
33 |
37 | delete
38 |
39 |
40 |
41 |
42 | )
43 | }
44 |
45 | export default DeleteCategory
--------------------------------------------------------------------------------
/src/Routes/providerRoute.jsx:
--------------------------------------------------------------------------------
1 | import { Routes, Route, useLocation } from "react-router-dom";
2 | import ProviderNavbar from "../components/Provider/Navbar";
3 | import ProviderDashboard from "../components/Provider/dashboard";
4 | import Profile from "../components/Provider/Profile/Profile";
5 | import Requests from "../components/Provider/Bookings/Requests";
6 | import Upcoming from "../components/Provider/Bookings/Upcoming";
7 | import Completed from "../components/Provider/Bookings/Completed";
8 | import ProviderLanding from "../components/Provider/home";
9 | import ProviderLogin from "../components/Provider/login";
10 | import ProviderAuth from "../Auth/providerAuth";
11 | import Error from "../components/404/404";
12 |
13 | function ProviderRoute() {
14 | const location = useLocation();
15 | const excludeNavbarRoutes = ["/provider/login", "/provider/register"];
16 | const shouldRenderNavbar = !excludeNavbarRoutes.includes(location.pathname);
17 |
18 | return (
19 | <>
20 | {shouldRenderNavbar && }
21 |
22 |
23 | } />
24 | } />
25 | }>
26 | } />
27 | } />
28 | } />
29 | } />
30 | } />
31 |
32 | } />
33 |
34 |
35 |
36 | >
37 | );
38 | }
39 |
40 | export default ProviderRoute;
41 |
--------------------------------------------------------------------------------
/src/components/comfirmations/DeleteCity.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {deleteCity } from '../../Api/AdminAPI';
3 | import { toast } from 'react-hot-toast';
4 |
5 | function DeleteCity({ open, cityId }) {
6 |
7 | const close = () => {
8 | open(false);
9 | };
10 | const headers = { Authorization: `Bearer ${localStorage.getItem('token')}` };
11 | const Delete = () => {
12 | const res = deleteCity(cityId, headers)
13 | if (res) {
14 | toast.success('city deleted successfully')
15 | open(false);
16 | }
17 | };
18 |
19 | return (
20 |
24 |
25 |
26 | Are you sure you want to delete City ?
27 |
28 |
29 |
33 | cancel
34 |
35 |
39 | delete
40 |
41 |
42 |
43 |
44 | )
45 | }
46 |
47 | export default DeleteCity
--------------------------------------------------------------------------------
/src/components/comfirmations/BlockUser.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { HandleUserblock} from '../../Api/AdminAPI';
3 |
4 | function BlockUser({ open, userId, block }) {
5 | const close = () => {
6 | open(false);
7 | };
8 |
9 | const headers = { Authorization: `Bearer ${localStorage.getItem('token')}` };
10 | const performAction = async () => {
11 | try {
12 | await HandleUserblock(userId,block, headers);
13 | open(false);
14 | } catch (error) {
15 | console.log(error);
16 | }
17 | };
18 |
19 | return (
20 |
24 |
25 |
26 | {block ? 'Are you sure you want to Unblock this user?' : 'Are you sure you want to Block this user?'}
27 |
28 |
29 |
33 | Cancel
34 |
35 |
39 | {block ? 'Block':'Unblock'}
40 |
41 |
42 |
43 |
44 | );
45 | }
46 |
47 |
48 | export default BlockUser
--------------------------------------------------------------------------------
/src/components/user/payment/Payment.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import { useNavigate } from 'react-router-dom';
3 | import toast from 'react-hot-toast';
4 | const Payment = ({ shedule, payment, price, status }) => {
5 |
6 | const navigate = useNavigate()
7 | const options = {
8 | key: 'rzp_test_FtVK05Td5kBCzd',
9 | amount: price * 100,
10 | name: 'QuickServe',
11 | description: 'some description',
12 | image: 'https://cdn.razorpay.com/logos/7K3b6d18wHwKzL_medium.png',
13 | handler: function (response) {
14 | if (response) {
15 | toast.success('payment Successful');
16 | payment()
17 | status()
18 | navigate('/bookings')
19 | }
20 | },
21 | prefill: {
22 | name: '',
23 | contact: '',
24 | email: '',
25 | },
26 | notes: {
27 | address: '',
28 | },
29 | theme: {
30 | color: '#020073',
31 | hide_topbar: false,
32 | },
33 |
34 | };
35 |
36 | const openPayModal = () => {
37 | if (window.Razorpay) {
38 | const rzp1 = new window.Razorpay(options);
39 | rzp1.open();
40 | }
41 | };
42 |
43 | useEffect(() => {
44 | shedule();
45 | const script = document.createElement('script');
46 | script.src = 'https://checkout.razorpay.com/v1/checkout.js';
47 | script.async = true;
48 | script.onload = openPayModal;
49 | document.body.appendChild(script);
50 |
51 | return () => {
52 | document.body.removeChild(script);
53 | payment();
54 | };
55 | }, []);
56 |
57 | return (
58 | <>
59 |
60 |
61 | {/* Payment modal content */}
62 |
63 |
64 | >
65 | );
66 | };
67 |
68 | export default Payment;
69 |
--------------------------------------------------------------------------------
/src/Routes/adminRoute.jsx:
--------------------------------------------------------------------------------
1 | import { Routes, Route, useLocation } from "react-router-dom";
2 | import Services from "../components/admin/Services/Services";
3 | import AdminNavbar from "../components/admin/AdminNavbar/AdminNavbar";
4 | import Dashboard from "../components/admin/Dashboard/dashboard";
5 | import ProviderCard from "../components/admin/Providers/ProviderList";
6 | import Category from "../components/admin/category/Category";
7 | import UserList from "../components/admin/users/users";
8 | import City from "../components/admin/City/city";
9 | import AdminLogin from '../components/admin/Login/login'
10 | import Bookings from "../components/admin/Bookings/bookings";
11 | import Media from "../components/admin/Media/Media";
12 | import AdminChat from "../components/admin/Support/chat";
13 | import AdminAuth from "../Auth/adminAuth";
14 | import Error from "../components/404/404";
15 |
16 | function AdminRoute() {
17 | const location = useLocation();
18 | const excludeNavbarRoutes = ["/admin/chat", "/admin/*", "/admin/login"];
19 |
20 | const shouldRenderNavbar = !excludeNavbarRoutes.includes(location.pathname);
21 |
22 | return (
23 | <>
24 | {shouldRenderNavbar && }
25 |
26 |
27 | } />
28 | }>
29 | } />
30 | } />
31 | } />
32 | } />
33 | } />
34 | } />
35 | } />
36 | } />
37 | } />
38 |
39 | } />
40 |
41 |
42 |
43 | >
44 | );
45 | }
46 |
47 | export default AdminRoute;
48 |
--------------------------------------------------------------------------------
/src/components/admin/Dashboard/chart.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Chart from "react-apexcharts";
3 |
4 | const MainChart = ({value}) => {
5 | const data = {
6 | series: [
7 | {
8 | name: "Rupees",
9 | data: value,
10 | },
11 | ],
12 | options: {
13 | chart: {
14 | type: "area",
15 | height: "auto",
16 | toolbar: {
17 | tools: {
18 | download: false,
19 | selection: false,
20 | zoom: false,
21 | zoomin: true,
22 | zoomout: true,
23 | pan: false,
24 | reset: true | ' ',
25 | },
26 | },
27 | },
28 | fill: {
29 | colors: ["#1891c3"],
30 | type: "gradient",
31 | },
32 | dataLabels: {
33 | enabled: false,
34 | },
35 | stroke: {
36 | curve: "smooth",
37 | colors: ["#1891c3"],
38 | },
39 |
40 | grid: {
41 | show: false,
42 | },
43 | xaxis: {
44 | type: "month",
45 | categories: [
46 | "Jan",
47 | "feb",
48 | "mar",
49 | "Apr",
50 | "May",
51 | "June",
52 | "July",
53 | "Aug",
54 | "Sep",
55 | "Oct",
56 | "Nov",
57 | "Dec"
58 | ],
59 | },
60 | yaxis: {
61 | show: false,
62 | },
63 | },
64 | };
65 |
66 | return (
67 |
68 |
69 |
70 | );
71 | };
72 |
73 | export default MainChart;
74 |
--------------------------------------------------------------------------------
/src/components/admin/Dashboard/columnChart.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Chart from "react-apexcharts";
3 |
4 | const ColumnChart = ({value}) => {
5 | const data = {
6 | series: [
7 | {
8 | name: "Bookings",
9 | data: value,
10 | },
11 | ],
12 | options: {
13 | chart: {
14 | type: "area",
15 | height: "auto",
16 | toolbar: {
17 | tools: {
18 | download: false,
19 | selection: false,
20 | zoom: false,
21 | zoomin: true,
22 | zoomout: true,
23 | pan: false,
24 | reset: true | ' ',
25 | },
26 | },
27 | },
28 | fill: {
29 | colors: ["#1891c3"],
30 | type: "gradient",
31 | },
32 | dataLabels: {
33 | enabled: false,
34 | },
35 | stroke: {
36 | curve: "smooth",
37 | colors: ["#1891c3"],
38 | },
39 |
40 | grid: {
41 | show: false,
42 | },
43 | xaxis: {
44 | type: "month",
45 | categories: [
46 | "Jan",
47 | "feb",
48 | "mar",
49 | "Apr",
50 | "May",
51 | "June",
52 | "July",
53 | "Aug",
54 | "Sep",
55 | "Oct",
56 | "Nov",
57 | "Dec"
58 | ],
59 | },
60 | yaxis: {
61 | show: false,
62 | },
63 | },
64 | };
65 |
66 | return (
67 |
68 |
69 |
70 | );
71 | };
72 |
73 | export default ColumnChart;
74 |
--------------------------------------------------------------------------------
/src/components/user/Categorylist.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import { Link } from 'react-router-dom'
3 | import Slider from 'react-slick';
4 | import 'slick-carousel/slick/slick.css';
5 | import 'slick-carousel/slick/slick-theme.css';
6 | import './categorylist.css'
7 | import { getCategories } from '../../Api/AdminAPI';
8 | import BASE_URL from '../../config/config';
9 | const CategorySlider = () => {
10 | const [category, setCategory] = useState([])
11 |
12 | useEffect(() => {
13 | getCategories().then((data) => {
14 | setCategory(data);
15 | });
16 | }, []);
17 |
18 | const settings = {
19 | dots: false,
20 | arrows: true,
21 | infinite: true,
22 | speed: 500,
23 | slidesToShow: 4,
24 | slidesToScroll: 1,
25 | responsive: [
26 | {
27 | breakpoint: 1024,
28 | settings: {
29 | slidesToShow: 4,
30 | },
31 | },
32 | {
33 | breakpoint: 768,
34 | settings: {
35 | slidesToShow: 3,
36 | arrows: true,
37 | },
38 | },
39 | {
40 | breakpoint: 480,
41 | settings: {
42 | slidesToShow: 2,
43 | arrows: true,
44 | },
45 | },
46 | ],
47 | };
48 |
49 | return (
50 |
51 |
52 |
53 | {category.map((category) => (
54 |
55 |
56 |
57 |
62 |
{category.categoryName}
63 |
64 |
65 |
66 | ))}
67 |
68 |
69 |
70 | );
71 | };
72 |
73 | export default CategorySlider;
74 |
--------------------------------------------------------------------------------
/src/components/admin/Login/login.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Noto+Sans:wght@700&family=Poppins:wght@400;500;600&display=swap');
2 |
3 |
4 | .center1 {
5 | position: absolute;
6 | top: 50%;
7 | left: 50%;
8 | transform: translate(-50%, -50%);
9 | background-color: #fff;;
10 | border-radius: 10px;
11 | box-shadow: 10px 10px 15px rgba(0, 0, 0, 0.05);
12 | }
13 |
14 | .center1 h1 {
15 | text-align: center;
16 | padding: 20px 0;
17 | font-weight: 500;
18 | color: #000240;
19 | }
20 |
21 | .center1 form {
22 | padding: 0 40px;
23 | box-sizing: border-box;
24 | }
25 |
26 | form .txt_field1 {
27 | position: relative;
28 | background-color: #E8F5FF;
29 | border-radius: 10px;
30 | height: 50px;
31 | margin: 25px 0;
32 | }
33 |
34 | .txt_field1 input {
35 | width: 100%;
36 | padding: 5px 5px;
37 | height: 40px;
38 | font-size: 16px;
39 | border: none;
40 | background: none;
41 | outline: none;
42 | }
43 | .txt_field1 textarea {
44 | width: 100%;
45 | padding: 5px 5px;
46 | height: 40px;
47 | font-size: 16px;
48 | border: none;
49 | background: none;
50 | outline: none;
51 | }
52 |
53 | .txt_field1 label {
54 | position: absolute;
55 | top: 50%;
56 | left: 5px;
57 | color: #b5b6cb;
58 | transform: translateY(-50%);
59 | font-size: 16px;
60 | pointer-events: none;
61 | transition: .5s;
62 | }
63 |
64 | .txt_field1 span::before {
65 | content: '';
66 | position: absolute;
67 | top: 40px;
68 | left: 0;
69 | width: 0%;
70 | height: 2px;
71 | background: #2691d9;
72 | transition: .5s;
73 | }
74 |
75 | .txt_field1 input:focus~label,
76 | .txt_field1 input:valid~label {
77 | top: -10px;
78 | color: rgb(30 58 138);
79 | }
80 | .txt_field1 textarea:focus~label,
81 | .txt_field1 textarea:valid~label {
82 | top: -10px;
83 | color: rgb(30 58 138);
84 | }
85 | .txt_field1 input:focus~span::before,
86 | .txt_field1 input:valid~span::before {
87 | width: 100%;
88 | }
89 | .txt_field1 textarea:focus~span::before,
90 | .txt_field1 textarea:valid~span::before {
91 | width: 100%;
92 | }
93 |
94 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "client",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@emotion/react": "^11.11.0",
7 | "@emotion/styled": "^11.11.0",
8 | "@fortawesome/free-regular-svg-icons": "^6.4.0",
9 | "@fortawesome/free-solid-svg-icons": "^6.4.0",
10 | "@fortawesome/react-fontawesome": "^0.2.0",
11 | "@heroicons/react": "^1.0.6",
12 | "@mui/material": "^5.13.2",
13 | "@mui/styled-engine-sc": "^5.12.0",
14 | "@react-google-maps/api": "^2.18.1",
15 | "@reduxjs/toolkit": "^1.9.5",
16 | "@testing-library/jest-dom": "^5.16.5",
17 | "@testing-library/react": "^13.4.0",
18 | "@testing-library/user-event": "^13.5.0",
19 | "apexcharts": "^3.41.0",
20 | "axios": "^1.3.5",
21 | "date-fns": "^2.30.0",
22 | "formik": "^2.2.9",
23 | "google-map-react": "^2.2.1",
24 | "leaflet": "^1.9.4",
25 | "moment": "^2.29.4",
26 | "react": "^18.2.0",
27 | "react-apexcharts": "^1.4.0",
28 | "react-autosuggest": "^10.1.0",
29 | "react-dom": "^18.2.0",
30 | "react-hot-toast": "^2.4.1",
31 | "react-icons": "^4.8.0",
32 | "react-leaflet": "^4.2.1",
33 | "react-loader-spinner": "^5.3.4",
34 | "react-places-autocomplete": "^7.3.0",
35 | "react-razorpay": "^1.2.0",
36 | "react-redux": "^8.0.5",
37 | "react-router-dom": "^6.10.0",
38 | "react-scripts": "5.0.1",
39 | "react-simple-star-rating": "^5.1.7",
40 | "react-slick": "^0.29.0",
41 | "react-spring": "^9.7.1",
42 | "react-spring-3d-carousel": "^1.3.4",
43 | "react-stars": "^2.2.5",
44 | "react-toastify": "^9.1.2",
45 | "redux": "^4.2.1",
46 | "redux-persist": "^6.0.0",
47 | "slick-carousel": "^1.8.1",
48 | "socket.io-client": "^4.6.2",
49 | "styled-components": "^5.3.10",
50 | "tailwind-scrollbar": "^3.0.4",
51 | "web-vitals": "^2.1.4"
52 | },
53 | "scripts": {
54 | "start": "react-scripts start",
55 | "build": "react-scripts build",
56 | "test": "react-scripts test",
57 | "eject": "react-scripts eject"
58 | },
59 | "eslintConfig": {
60 | "extends": [
61 | "react-app",
62 | "react-app/jest"
63 | ]
64 | },
65 | "browserslist": {
66 | "production": [
67 | ">0.2%",
68 | "not dead",
69 | "not op_mini all"
70 | ],
71 | "development": [
72 | "last 1 chrome version",
73 | "last 1 firefox version",
74 | "last 1 safari version"
75 | ]
76 | },
77 | "devDependencies": {
78 | "autoprefixer": "^9.8.6",
79 | "postcss-cli": "^10.1.0",
80 | "tailwindcss": "^3.3.2"
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/Routes/userRoute.jsx:
--------------------------------------------------------------------------------
1 | import { Routes, Route } from "react-router-dom";
2 | import Navbar from "../components/user/Navbar/Navbar";
3 | import Cart from "../components/user/cart";
4 | import UserLogin from "../components/user/login/login";
5 | import Signup from "../components/user/login/Register";
6 | import SingleService from "../components/user/singleservice/SingleService";
7 | import ServicesPage from "../components/user/servicesPage/ServicesPage";
8 | import Bookings from "../components/user/Bookings/Bookings";
9 | import BookingDetail from "../components/user/Bookings/BookingDetails";
10 | import UserAuth from "../Auth/userAuth";
11 | import Profile from "../components/user/Profile/profile";
12 | import Footer from "../components/user/Footer/Footer";
13 | import Chat from "../components/user/Chat/chat";
14 | import Home from "../components/user/home/home";
15 | import ChatButton from "../components/user/Chat/chatButton";
16 | import { useState } from "react";
17 | import Error from "../components/404/404";
18 |
19 | function UserRoute() {
20 |
21 | const [showchat, setShowChat] = useState(false)
22 |
23 | const handleChat = (() => {
24 | setShowChat(!showchat)
25 | })
26 | return (
27 | <>
28 |
29 |
30 | {showchat && }
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 | export default UserRoute;
58 |
59 |
60 |
--------------------------------------------------------------------------------
/src/components/admin/Login/login.js:
--------------------------------------------------------------------------------
1 | import { useNavigate } from 'react-router-dom';
2 | import axios from 'axios';
3 | import toast from 'react-hot-toast';
4 | import { validateEmail } from '../../../validateForm';
5 | import BASE_URL from '../../../config/config';
6 | import { useState } from 'react';
7 | import './login.css'
8 |
9 | function AdminLogin() {
10 | const [password, setPassword] = useState('');
11 | const [email, setEmail] = useState('');
12 | const navigate = useNavigate();
13 |
14 | const handleSubmit = async (e) => {
15 | e.preventDefault();
16 | if (!email || !password) {
17 | toast.error('Please fill all the blanks')
18 | return
19 | }
20 | if (!validateEmail(email)) {
21 | toast.error('Invalid Email , Please enter valid Email ID.')
22 | return;
23 | }
24 | try {
25 | const headers = { Authorization: `Bearer ${localStorage.getItem('token')}` }
26 | const response = await axios.post(`${BASE_URL}/admin/login`, { email, password }, { headers });
27 | if (response.data && response.data.email) {
28 | localStorage.setItem('token', response.data.token);
29 | navigate('/admin');
30 | } else {
31 | toast.error(response.data.message);
32 | }
33 | } catch (error) {
34 | console.log(error);
35 | }
36 | };
37 |
38 | return (
39 | <>
40 |
41 |
Admin Login
42 |
68 |
69 | >
70 |
71 | );
72 | }
73 |
74 | export default AdminLogin;
75 |
--------------------------------------------------------------------------------
/src/components/user/Ratings/Ratings.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react'
2 | import { StarIcon } from '@heroicons/react/solid';
3 | import { getReviews } from '../../../Api/userAPI';
4 | import moment from 'moment';
5 | import ReactStars from 'react-stars';
6 | import BASE_URL from '../../../config/config';
7 |
8 | function Ratings({ serviceId }) {
9 | const [review, setReview] = useState([])
10 | useEffect(() => {
11 | getReviews(serviceId).then((res) => {
12 | setReview(res.data);
13 | console.log();
14 | })
15 | }, [])
16 |
17 | return (
18 | <>
19 |
20 |
21 |
22 | {review.length > 0 &&
23 |
24 |
25 |
Customer Reviews
26 | {review.length > 0 && review.map
27 | ((item) => (
28 |
29 |
30 |
31 |
32 |
{item.user.username}
33 |
34 |
35 |
42 |
43 | {item.rating >= 4.5 ? 'Awesome Service' :
44 | item.rating >= 3.5 ? 'Good Service' :
45 | 'Average Service'}
46 |
47 |
48 |
Reviewed on {moment(item.date).format('MMMM Do, YYYY')}
49 |
{item.feedback}
50 |
))}
51 |
52 |
}
53 |
54 |
55 |
56 |
57 | >
58 | )
59 | }
60 |
61 | export default Ratings
--------------------------------------------------------------------------------
/src/components/user/login/login.jsx:
--------------------------------------------------------------------------------
1 | import { useNavigate, Link } from 'react-router-dom';
2 | import { useState } from 'react';
3 | import './login.css'
4 | import { validateEmail } from '../../../validateForm';
5 | import { useDispatch } from 'react-redux';
6 | import { userData } from '../../../redux/Slice/userSlice'
7 | import { userLogin } from '../../../Api/userAPI';
8 | import toast from 'react-hot-toast';
9 |
10 | function UserLogin() {
11 | const [password, setPassword] = useState('');
12 | const [email, setEmail] = useState('');
13 |
14 | const navigate = useNavigate();
15 | const dispatch = useDispatch()
16 | const handleSubmit = async (e) => {
17 | e.preventDefault()
18 | if (!email || !password) {
19 | toast.error('Please fill all the blanks')
20 | return
21 | }
22 | if (!validateEmail(email)) {
23 | toast.error('Invalid Email , Please enter valid Email ID.')
24 | return;
25 | }
26 |
27 | await userLogin(email, password).then((res) => {
28 | if (res.data.error) {
29 | toast.error(res.data.error)
30 | } else {
31 | localStorage.setItem("userToken", res.data.token)
32 | dispatch(userData({ field: 'data', value: res.data.userData }))
33 | navigate('/')
34 | }
35 | })
36 | }
37 |
38 | return (
39 | <>
40 |
41 |
Login
42 |
68 |
69 | Not a member? Register
70 |
71 |
72 | >
73 |
74 | );
75 | }
76 |
77 | export default UserLogin;
78 |
--------------------------------------------------------------------------------
/src/components/admin/Media/Banner.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { addBanner } from '../../../Api/AdminAPI';
3 | import { BiArrowBack } from 'react-icons/bi';
4 | import toast from 'react-hot-toast';
5 |
6 | function AddBanner({ close }) {
7 | const [image, setImage] = useState(null);
8 | const [previewImage, setPreviewImage] = useState(null);
9 |
10 | const handleBack = () => {
11 | close()
12 | }
13 | const handleImageUpload = (e) => {
14 | const image = e.target.files[0];
15 | setImage(image);
16 | setPreviewImage(URL.createObjectURL(image))
17 | };
18 |
19 | const handleSubmit = async () => {
20 | try {
21 | const formData = new FormData();
22 |
23 | if (image) {
24 | formData.append('image', image);
25 | }
26 |
27 | await addBanner(formData);
28 | toast.success('Upload successful');
29 | close()
30 | } catch (error) {
31 | console.error('Error uploading:', error);
32 | }
33 | };
34 |
35 | return (
36 |
37 |
38 |
39 |
40 |
41 |
42 |
Add Banner
43 |
44 |
45 |
46 |
68 |
69 |
70 | );
71 | }
72 |
73 | export default AddBanner;
74 |
--------------------------------------------------------------------------------
/src/components/comfirmations/StartJobModal.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import axios from 'axios';
3 | import { toast } from 'react-hot-toast';
4 | import { startJob } from '../../Api/providerAPI';
5 |
6 | function StartJob({ onClose, data, action }) {
7 | const [bookingId, setBookingId] = useState('');
8 |
9 | const headers = { Authorization: `Bearer ${localStorage.getItem('ProviderToken')}` };
10 | const handleFormSubmit = async (e) => {
11 | e.preventDefault();
12 | try {
13 | if (data.BookingID === bookingId) {
14 | const response = await startJob(data, headers)
15 | if (response.status === 200) {
16 | toast.success('Booking ID verified successfully!');
17 | action()
18 | onClose()
19 | }
20 | }
21 | else {
22 | toast.error('Invalid booking ID. Please try again.');
23 | }
24 | } catch (error) {
25 | console.error('Error:', error);
26 | toast.error('An error occurred. Please try again later.');
27 | }
28 | };
29 |
30 | return (
31 |
32 |
33 |
34 | Please Enter BookingId to Start JOB
35 |
36 |
62 |
63 |
64 | );
65 | }
66 |
67 | export default StartJob;
68 |
--------------------------------------------------------------------------------
/src/components/Provider/login.jsx:
--------------------------------------------------------------------------------
1 | import { useNavigate } from 'react-router-dom';
2 | import { useState } from 'react';
3 | import '../admin/Login/login.css'
4 | import { toast } from 'react-hot-toast';
5 | import { Login } from '../../Api/providerAPI';
6 |
7 | function ProviderLogin() {
8 | const [password, setPassword] = useState('');
9 | const [email, setEmail] = useState('');
10 | const navigate = useNavigate();
11 |
12 | const handleSubmit = async (e) => {
13 | e.preventDefault();
14 |
15 | try {
16 | const response = await Login(email, password)
17 | if (response && response.data.email) {
18 | localStorage.setItem('ProviderToken', response.data.token);
19 | toast.success(response.data.message);
20 |
21 | navigate('/provider/');
22 | } else {
23 | toast.error(response.data.message);
24 | }
25 | } catch (error) {
26 | console.log(error);
27 | }
28 | };
29 |
30 | return (
31 | <>
32 |
33 |
34 |
35 | Quick Serve
36 |
37 |
38 |
39 | Provider PANEL
40 |
41 |
42 |
43 |
Provider Login
44 |
72 |
73 | >
74 |
75 | );
76 | }
77 |
78 | export default ProviderLogin;
79 |
--------------------------------------------------------------------------------
/src/components/user/Profile/profile.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import { getProfile } from '../../../Api/userAPI';
3 | import {TfiEmail} from 'react-icons/tfi'
4 | import { BiPhoneCall } from 'react-icons/bi';
5 | import BASE_URL from '../../../config/config';
6 | const Profile = () => {
7 | const [profile, setProfile] = useState([])
8 | const headers = { Authorization: `Bearer ${localStorage.getItem('userToken')}` };
9 |
10 | useEffect(() => {
11 | getProfile(headers).then((res) => {
12 | setProfile(res.data)
13 | })
14 |
15 | }, [])
16 | return (
17 |
18 |
19 |
20 | My Profile
21 |
22 |
23 |
26 |
27 |
28 |
29 |
30 |
35 |
36 |
37 |
38 | {profile.username}
39 |
40 |
41 | {profile.email}
42 |
43 |
44 | {profile.mobile}
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | );
54 | }
55 |
56 | export default Profile;
57 |
--------------------------------------------------------------------------------
/src/components/admin/Media/Advertisement.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { addAdvertisement } from '../../../Api/AdminAPI';
3 | import { BiArrowBack } from 'react-icons/bi';
4 | import toast from 'react-hot-toast';
5 |
6 | function AddAdvertisement({ close }) {
7 | const [image, setImage] = useState(null);
8 | const [previewImage, setPreviewImage] = useState(null);
9 |
10 | const handleBack = () => {
11 | close()
12 | }
13 | const handleImageUpload = (e) => {
14 | const image = e.target.files[0];
15 | setImage(image);
16 | setPreviewImage(URL.createObjectURL(image))
17 | };
18 |
19 | const handleSubmit = async () => {
20 | try {
21 | const formData = new FormData();
22 |
23 | if (image) {
24 | formData.append('image', image);
25 | }
26 |
27 | await addAdvertisement(formData);
28 | toast.success('Upload successful');
29 | close()
30 | } catch (error) {
31 | console.error('Error uploading:', error);
32 | }
33 | };
34 |
35 | return (
36 |
37 |
38 |
39 |
40 |
41 |
42 |
Add Advertisement
43 |
44 |
45 |
46 |
68 |
69 |
70 | );
71 | }
72 |
73 | export default AddAdvertisement;
74 |
--------------------------------------------------------------------------------
/src/components/admin/Dashboard/StatCard.jsx:
--------------------------------------------------------------------------------
1 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
2 | import { faCalendar, faUser, faUsers, faRupeeSign } from '@fortawesome/free-solid-svg-icons';
3 | import { MdOutlineDoneAll, MdPendingActions } from 'react-icons/md';
4 | import { BsPatchQuestionFill } from 'react-icons/bs';
5 | import { FaRupeeSign } from 'react-icons/fa';
6 |
7 | function StatCard({ value }) {
8 | return (
9 |
10 | {value &&
11 | value.map((item,index) => (
12 |
13 |
14 |
15 |
16 |
17 | {item.name}
18 |
19 |
20 |
21 |
22 | {item.name === 'Earnings' && (
23 |
24 | )}
25 | {item.name === 'Bookings' && (
26 |
27 | )}
28 | {item.name === 'Users' && (
29 |
30 | )}
31 | {item.name === 'Providers' && (
32 |
33 | )}
34 | {item.name === 'Completed' && (
35 |
36 |
37 | )}
38 | {item.name === 'Upcomings' && (
39 |
40 |
41 | )}
42 | {item.name === 'Requests' && (
43 |
44 |
45 | )}
46 |
47 |
48 |
49 |
50 |
51 | {item.count}
52 |
53 |
54 |
55 |
56 | ))}
57 |
58 | );
59 | }
60 |
61 | export default StatCard
--------------------------------------------------------------------------------
/src/components/admin/Media/EditMedia/Advt.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import { BiArrowBack } from 'react-icons/bi';
3 | import toast from 'react-hot-toast';
4 | import { fetchAdvt, updateAdvt } from '../../../../Api/AdminAPI';
5 | import BASE_URL from '../../../../config/config';
6 |
7 | function EditAdvt({ close, Id }) {
8 | const [image, setImage] = useState(null);
9 | const [previewImage, setPreviewImage] = useState(null);
10 |
11 | useEffect(() => {
12 | const fetchData = async () => {
13 | try {
14 | const response = await fetchAdvt(Id);
15 | setPreviewImage(`${BASE_URL}/public/images/${response.image}`);
16 | } catch (error) {
17 | console.error('Error fetching advertisement data:', error);
18 | }
19 | };
20 | fetchData();
21 | }, [Id]);
22 |
23 | const handleBack = () => {
24 | close();
25 | };
26 |
27 | const handleImageUpload = (e) => {
28 | const image = e.target.files[0];
29 | setImage(image);
30 | setPreviewImage(URL.createObjectURL(image));
31 | };
32 |
33 | const handleSubmit = async (e) => {
34 | e.preventDefault()
35 | try {
36 | const formData = new FormData();
37 |
38 | if (image) {
39 | formData.append('image', image);
40 | }
41 |
42 | await updateAdvt(Id, formData);
43 |
44 | toast.success('Upload successful');
45 | close();
46 | } catch (error) {
47 | console.error('Error uploading:', error);
48 | }
49 | };
50 |
51 | return (
52 |
53 |
54 |
55 |
56 |
57 |
58 |
Edit Advertisement
59 |
60 |
61 |
62 |
84 |
85 |
86 | );
87 | }
88 |
89 | export default EditAdvt;
90 |
--------------------------------------------------------------------------------
/src/components/admin/City/addCity.jsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react';
2 | import { BiArrowBack } from 'react-icons/bi';
3 | import { addCity} from '../../../Api/AdminAPI';
4 | import toast from 'react-hot-toast'
5 |
6 | const AddCityModel = ({ onClose, City }) => {
7 | const [cityName, setCityName] = useState('');
8 | const handleGoBack = () => {
9 | onClose();
10 | };
11 | const onChange = (e) => {
12 | setCityName(e.target.value);
13 | };
14 | const handleSubmit = async (e) => {
15 | e.preventDefault();
16 | try {
17 | const headers = { Authorization: `Bearer ${localStorage.getItem('token')}` };
18 | const existingCity = City.find((city) => city.cityName.toLowerCase() === cityName.toLowerCase());
19 | if (existingCity) {
20 | toast.error('City already exists!');
21 | return;
22 | }
23 |
24 | const response = await addCity(cityName, headers);
25 | if (response) {
26 | toast.success('city added succesfully')
27 | onClose();
28 | } else {
29 | toast(response.message);
30 | }
31 | } catch (error) {
32 | console.log(error);
33 | alert(error.message);
34 | }
35 | };
36 |
37 |
38 | return (
39 |
40 |
41 |
42 |
43 |
44 |
45 |
Add City
46 |
47 |
48 |
49 |
68 |
69 |
70 | );
71 | };
72 |
73 | export default AddCityModel;
74 |
--------------------------------------------------------------------------------
/src/Api/userAPI.js:
--------------------------------------------------------------------------------
1 | import { Axiosuser } from "../axios";
2 |
3 |
4 | export const userLogin = async (email, password) => {
5 | const res = await Axiosuser.post("/login", { email, password })
6 | return res;
7 | }
8 | export const userSignup = async (formData) => {
9 | const res = await Axiosuser.post("/register", formData)
10 | return res;
11 | }
12 |
13 | export const addToCart = async (serviceId, headers) => {
14 | const res = await Axiosuser.post(`/cart/${serviceId}`, {}, { headers })
15 | return res
16 | }
17 |
18 | export const getServicesbycategory = async (categoryname) => {
19 | const res = await Axiosuser.get(`/services/:${categoryname}`)
20 | return res
21 | }
22 |
23 | export const RemoveCart = async (serviceId, headers) => {
24 | const res = await Axiosuser.delete(`/cart/${serviceId}`, { headers })
25 | return res
26 | }
27 |
28 | export const getCart = async (headers) => {
29 | const res = await Axiosuser.get('/cart', { headers })
30 | return res.data
31 | }
32 |
33 | export const addAddress = async (data, headers) => {
34 | const res = await Axiosuser.post('/address', data, { headers })
35 | return res
36 | }
37 |
38 | export const getAddress = async (headers) => {
39 | const res = await Axiosuser.get('/address', { headers })
40 | return res
41 | }
42 | export const deleteAddress = async (Id, headers) => {
43 | const res = await Axiosuser.delete(`/address/${Id}`, { headers })
44 | return res
45 | }
46 | export const AddBooking = async (data, headers) => {
47 | const res = await Axiosuser.post('/booking', data, { headers })
48 | return res
49 | }
50 |
51 | export const getProfile = async (headers) => {
52 | const res = await Axiosuser.get('/profile', { headers })
53 | return res
54 | }
55 |
56 | export const getBookings = async (headers) => {
57 | const res = await Axiosuser.get('/bookings', { headers })
58 | return res
59 | }
60 |
61 | //chat
62 |
63 | export const sendMessage = async (data, headers) => {
64 | const res = await Axiosuser.post('/chat', { data }, { headers })
65 | return res
66 | }
67 | export const startConversation = async (data, headers) => {
68 | const res = await Axiosuser.post('/conversation', { user: data }, { headers })
69 | return res
70 | }
71 |
72 | export const getChat = async (headers) => {
73 | const res = await Axiosuser.get('/chat', { headers })
74 | return res
75 | }
76 |
77 | export const getMedia = async () => {
78 | const res = await Axiosuser.get('/media')
79 | return res
80 | }
81 |
82 | export const AddReview = async (data, headers) => {
83 | const res = await Axiosuser.post('/review', { data }, { headers })
84 | return res
85 | }
86 |
87 | export const getServiceDetails = async (serviceId) => {
88 | const res = await Axiosuser.get(`/service/${serviceId}`)
89 | return res
90 | }
91 |
92 | export const getReviews = async (serviceId) => {
93 | const res = await Axiosuser.get(`/review/${serviceId}`)
94 | return res
95 | }
--------------------------------------------------------------------------------
/src/components/user/Bookings/Bookings.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react'
2 | import { BsChevronCompactRight } from 'react-icons/bs'
3 | import { getBookings } from '../../../Api/userAPI'
4 | import moment from 'moment'
5 | import BookingDetail from './BookingDetails'
6 | import Loader from '../../Loader'
7 | function Bookings() {
8 | const [bookings, setbookings] = useState([])
9 | const [showDetails, setShowDetails] = useState(false)
10 | const [bookingId, setBookingId] = useState()
11 | const [loading, setLoading] = useState(true);
12 |
13 | const headers = { Authorization: `Bearer ${localStorage.getItem('userToken')}` };
14 |
15 | useEffect(() => {
16 | getBookings(headers).then((res) => {
17 | setbookings(res.data)
18 | setLoading(false)
19 | })
20 | }, [])
21 |
22 | const handleModel = (BookingID) => {
23 | setShowDetails(showDetails => !showDetails);
24 | setBookingId(BookingID);
25 | };
26 |
27 | return (
28 | <>
29 | {loading ? :
30 |
31 |
32 |
33 |
Bookings
34 |
35 |
36 |
37 | {bookings.map((item) => (<>
38 | {/*
Category */}
39 |
handleModel(item.BookingID))} key={item.BookingID} className=" py-1 px-6 bg-white flex justify-between items-center rounded-lg shadow-lg mb-4">
40 |
41 |
42 | Booking {item.status}
43 |
44 |
45 | {item.serviceData.map((service) => (
{service.servicename} ))}
46 |
47 |
{item.startTime}
48 |
{moment(item.date).format('MMMM Do, YYYY')}
49 |
50 |
51 |
52 |
53 |
54 |
>))}
55 | {showDetails &&
56 |
57 |
58 |
59 |
60 | }
61 |
62 |
}
63 | >
64 | )
65 | }
66 |
67 | export default Bookings
--------------------------------------------------------------------------------
/src/components/Provider/Bookings/BookingCards.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import moment from 'moment';
3 | import StartJob from '../../comfirmations/StartJobModal';
4 |
5 | function BookingsCard({ value, accept, status, action }) {
6 | const [showModal, setShowModal] = useState(false);
7 | const [Data, setData] = useState()
8 |
9 | const handleStartJob = (services, bookingId, booking) => {
10 | setShowModal(!showModal);
11 | const data = {
12 | services: services,
13 | bookingId: bookingId,
14 | BookingID: booking
15 | }
16 | setData(data)
17 | };
18 |
19 | return (
20 | <>
21 |
22 |
23 |
24 |
25 |
26 | {status} Booking
27 |
28 |
29 |
30 | {value.map((bookingItem) => (
31 |
35 |
36 | {bookingItem.services.map((service) => (
37 |
38 |
39 | {service.serviceData.servicename}
40 |
41 |
42 | ))}
43 |
{bookingItem.startTime}
44 |
{moment(bookingItem.date).format("MMMM Do, YYYY")}
45 |
46 |
47 |
48 | {status === 'Requested' && (
49 |
51 | accept(
52 | bookingItem.services,
53 | bookingItem.bookingId,
54 |
55 | )}
56 | className="bg-green-600 text-white py-1 px-3 rounded-md"
57 | >
58 | Accept
59 |
60 | )}
61 |
62 | {status === 'Upcoming' && (
63 |
65 | handleStartJob(
66 | bookingItem.services,
67 | bookingItem.bookingId,
68 | bookingItem.booking
69 | )}
70 | className="bg-blue-600 text-white py-1 px-3 rounded-md"
71 | >
72 | Start
73 |
74 | )}
75 |
76 |
77 | ))}
78 |
79 |
80 |
81 | {showModal &&
}
82 | >
83 | );
84 | }
85 |
86 | export default BookingsCard;
87 |
--------------------------------------------------------------------------------
/src/components/admin/Media/EditMedia/banner.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import { BiArrowBack } from 'react-icons/bi';
3 | import toast from 'react-hot-toast';
4 | import { fetchBanner, updateBanner } from '../../../../Api/AdminAPI';
5 | import BASE_URL from '../../../../config/config';
6 |
7 | function EditBanner({ close,Id }) {
8 | const [image, setImage] = useState(null);
9 | const [previewImage, setPreviewImage] = useState(null);
10 | const handleBack = () => {
11 | close()
12 | }
13 |
14 | useEffect(() => {
15 | const fetchData = async () => {
16 | try {
17 | const response = await fetchBanner(Id);
18 | setPreviewImage(`${BASE_URL}/public/images/${response.image}`);
19 | } catch (error) {
20 | console.error('Error fetching advertisement data:', error);
21 | }
22 | };
23 | fetchData();
24 | }, [Id]);
25 | const handleImageUpload = (e) => {
26 | const image = e.target.files[0];
27 | setImage(image);
28 | setPreviewImage(URL.createObjectURL(image))
29 | };
30 |
31 | const handleSubmit = async (e) => {
32 | try {
33 | e.preventDefault()
34 | const formData = new FormData();
35 |
36 | if (image) {
37 | formData.append('image', image);
38 | }
39 | updateBanner(Id,formData).then(()=>{
40 | close()
41 | toast.success('Upload successful');
42 | })
43 | } catch (error) {
44 | console.error('Error uploading:', error);
45 | }
46 | };
47 |
48 | return (
49 |
50 |
51 |
52 |
53 |
54 |
55 |
Edit Banner
56 |
57 |
58 |
59 |
81 |
82 |
83 | );
84 | }
85 |
86 | export default EditBanner;
87 |
--------------------------------------------------------------------------------
/src/components/Provider/sidebar.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { NavLink } from 'react-router-dom';
3 | import { MdPerson, MdCategory, MdPendingActions,MdOutlineDoneAll, MdOutlineLogout,MdNotificationsActive } from 'react-icons/md';
4 | import { RiDashboardFill } from 'react-icons/ri';
5 | import { AiOutlineCalendar } from 'react-icons/ai';
6 | import { BsPatchQuestionFill } from 'react-icons/bs';
7 |
8 | function Sidebar() {
9 |
10 | const handleNavLinkFocus = (event) => {
11 | event.target.style.color = 'yellow';
12 |
13 | };
14 |
15 | const handleNavLinkBlur = (event) => {
16 | event.target.style.color = 'inherit';
17 |
18 | };
19 |
20 | return (
21 |
22 |
23 |
24 |
25 |
26 |
27 | Dashboard
28 |
29 |
30 | {/*
31 |
32 |
33 | Providers
34 |
35 | */}
36 |
37 |
38 |
39 | Profile
40 |
41 |
42 |
43 |
44 |
45 | Requests
46 |
47 |
48 |
49 |
50 |
51 | Pending
52 |
53 |
54 |
55 |
56 |
57 |
58 | Completed
59 |
60 |
61 |
62 |
63 |
64 | Notifications
65 |
66 |
67 |
68 |
69 |
70 | Logout
71 |
72 |
73 |
74 |
75 |
76 | );
77 | }
78 |
79 | export default Sidebar;
80 |
--------------------------------------------------------------------------------
/src/components/Provider/Profile/Profile.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import { getProfile } from '../../../Api/userAPI';
3 | import { TfiEmail } from 'react-icons/tfi'
4 | import { BiPhoneCall } from 'react-icons/bi';
5 | import { GrLocation } from 'react-icons/gr'
6 | import { getProviderprofile } from '../../../Api/providerAPI';
7 | import BASE_URL from '../../../config/config';
8 | import Loader from '../../Loader';
9 | const Profile = () => {
10 | const [profile, setProfile] = useState([])
11 | const [loading, setLoading] = useState(true);
12 |
13 | const headers = { Authorization: `Bearer ${localStorage.getItem('ProviderToken')}` };
14 |
15 | useEffect(() => {
16 | getProviderprofile(headers).then((res) => {
17 | setProfile(res.data)
18 | setLoading(false)
19 | })
20 |
21 | }, [])
22 |
23 | return (
24 | <>
25 | {loading ? :
26 |
27 |
28 | My Profile
29 |
30 |
31 |
34 |
35 |
36 |
41 |
42 |
43 |
44 | {profile?.providername}
45 |
46 |
{profile?.category}
47 |
48 |
49 |
50 | {profile?.email}
51 |
52 |
53 | {profile?.phone}
54 |
55 |
56 | {profile?.location}
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
}
68 | >
69 |
70 | );
71 | }
72 |
73 | export default Profile;
74 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Getting Started with Create React App
2 |
3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
4 |
5 | ## Available Scripts
6 |
7 | In the project directory, you can run:
8 |
9 | ### `npm start`
10 |
11 | Runs the app in the development mode.\
12 | Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
13 |
14 | The page will reload when you make changes.\
15 | You may also see any lint errors in the console.
16 |
17 | ### `npm test`
18 |
19 | Launches the test runner in the interactive watch mode.\
20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
21 |
22 | ### `npm run build`
23 |
24 | Builds the app for production to the `build` folder.\
25 | It correctly bundles React in production mode and optimizes the build for the best performance.
26 |
27 | The build is minified and the filenames include the hashes.\
28 | Your app is ready to be deployed!
29 |
30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
31 |
32 | ### `npm run eject`
33 |
34 | **Note: this is a one-way operation. Once you `eject`, you can't go back!**
35 |
36 | If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
37 |
38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
39 |
40 | You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
41 |
42 | ## Learn More
43 |
44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
45 |
46 | To learn React, check out the [React documentation](https://reactjs.org/).
47 |
48 | ### Code Splitting
49 |
50 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
51 |
52 | ### Analyzing the Bundle Size
53 |
54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
55 |
56 | ### Making a Progressive Web App
57 |
58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
59 |
60 | ### Advanced Configuration
61 |
62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
63 |
64 | ### Deployment
65 |
66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
67 |
68 | ### `npm run build` fails to minify
69 |
70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
71 |
--------------------------------------------------------------------------------
/src/components/admin/category/addCategory.jsx:
--------------------------------------------------------------------------------
1 | import { useState } from 'react';
2 | import { BiArrowBack } from 'react-icons/bi';
3 | import { addCategory } from '../../../Api/AdminAPI';
4 | import toast from 'react-hot-toast';
5 |
6 | const AddCategoryModel = ({ onClose, category }) => {
7 | const [selectedImage, setSelectedImage] = useState(null);
8 | const [previewImage, setPreviewImage] = useState(null);
9 | const [categoryName, setCategoryName] = useState('');
10 |
11 | const handleImageChange = (e) => {
12 | const image = e.target.files[0];
13 | setSelectedImage(image);
14 | setPreviewImage(URL.createObjectURL(image));
15 | };
16 |
17 | const handleGoBack = () => {
18 | onClose();
19 |
20 | };
21 |
22 | const onChange = (e) => {
23 | setCategoryName(e.target.value);
24 | };
25 |
26 | const handleSubmit = async (e) => {
27 | e.preventDefault();
28 |
29 | try {
30 | const existingCategory = category.find((category) => category.categoryName.toLowerCase() === categoryName.toLowerCase());
31 | if (existingCategory) {
32 | toast.error('category already exists!');
33 | return;
34 | }
35 | const formData = new FormData();
36 | formData.append('image', selectedImage);
37 | formData.append('categoryName', categoryName);
38 | const headers = { Authorization: `Bearer ${localStorage.getItem('token')}` };
39 | const response = await addCategory(formData, headers)
40 | if (response) {
41 | toast.success('category added successfully');
42 | onClose();
43 |
44 | } else {
45 | alert(response.message);
46 | }
47 | } catch (error) {
48 | console.log(error);
49 | alert(error.response.message);
50 | }
51 | };
52 |
53 | return (
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
Add Category
63 |
64 |
65 |
66 |
100 |
101 |
102 |
103 |
104 | );
105 | };
106 |
107 | export default AddCategoryModel;
108 |
--------------------------------------------------------------------------------
/src/components/user/singleservice/SingleService.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import Ratings from "../Ratings/Ratings";
3 | import { useParams } from "react-router-dom";
4 | import { addToCart, getServiceDetails } from "../../../Api/userAPI";
5 | import { toast } from "react-hot-toast";
6 | import BookNow from "../BookNow/BookNow";
7 | import { StarIcon } from "@heroicons/react/solid";
8 | import BASE_URL from "../../../config/config";
9 | import { useSelector } from "react-redux";
10 |
11 | const SingleService = () => {
12 | const [service, setService] = useState()
13 | const [showModal, setShowModal] = useState(false)
14 |
15 | const { serviceId } = useParams();
16 | const headers = { Authorization: `Bearer ${localStorage.getItem('userToken')}` };
17 |
18 | const handleAddToCart = (serviceId) => {
19 | if (headers.Authorization !== 'Bearer null') {
20 | addToCart(serviceId, headers).then((res) => {
21 | if (res.data) {
22 | toast.success(res.data.message)
23 | }
24 | })
25 | } else {
26 | toast.error('please Login')
27 | }
28 | };
29 |
30 | const handleModel = () => {
31 | if(headers.Authorization !== 'Bearer null'){
32 | setShowModal(!showModal)
33 | }else{
34 | toast.error('Please Login to Book a service')
35 | }
36 | }
37 |
38 | useEffect(() => {
39 | getServiceDetails(serviceId).then((res) => {
40 | setService(res.data);
41 | });
42 |
43 | }, []);
44 | return (
45 | <>
46 |
47 |
48 |
49 |
50 | {service &&
51 |
52 |
53 |
54 |
55 |
56 |
57 | {service.category}
58 |
59 |
60 | {service.servicename}
61 |
62 |
63 | {service.description}
64 |
65 |
66 | ₹ {service.price}
67 |
68 |
*Extra Charges Applicable for Spare Parts
69 |
70 |
71 |
72 | Book Now
73 |
74 | handleAddToCart(service._id)} className="px-4 border w-full h-12 bg-blue-900 rounded-md text-white items-center gap-2 hover:bg-blue-700">
75 | Add to Cart
76 |
77 |
78 |
79 |
80 |
}
81 |
82 |
83 | {service &&
}
84 | {showModal &&
}
85 |
86 |
87 | >
88 | );
89 | };
90 |
91 | export default SingleService;
92 |
--------------------------------------------------------------------------------
/src/components/user/BookNow/BookNow.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react'
2 | import { AddBooking } from '../../../Api/userAPI';
3 | import { useDispatch, useSelector } from 'react-redux';
4 | import Address from '../Checkouts/Address';
5 | import TimeShedule from '../Checkouts/TimeShedule';
6 | import Map from '../Checkouts/Map';
7 | import Payment from '../payment/Payment';
8 | import { clearCart } from '../../../redux/Slice/cartSlice';
9 |
10 | function BookNow({ action, serviceData }) {
11 |
12 | const user = useSelector((state) => state.user)
13 | const [showModal, setShowModal] = useState(true)
14 | const [showAddressModal, setShowAddressModal] = useState(false)
15 | const [showMap, setShowMap] = useState(false)
16 | const [selectedAddress, setSelectedAddress] = useState([]);
17 | const [selectedTime, setSelectedTime] = useState([]);
18 | const [showPayment, setShowPayment] = useState(false)
19 | const [TotalPrice, setTotalPrice] = useState(0)
20 |
21 | const headers = { Authorization: `Bearer ${localStorage.getItem('userToken')}` };
22 |
23 | const handlepayment = () => {
24 | if (serviceData) {
25 | setShowPayment(!showPayment)
26 | setTotalPrice(serviceData.price)
27 | }
28 | }
29 |
30 | const CurrentAddress = selectedAddress.map((address) => address.id).join('');
31 | const data = {
32 | userId: user.data._id,
33 | service: [{
34 | _id: serviceData._id,
35 | qty: 1
36 | }],
37 | dateTime: selectedTime,
38 | totalPrice: TotalPrice,
39 | address: CurrentAddress
40 | };
41 |
42 | const paymentSuccess = () => {
43 | if (serviceData) {
44 | AddBooking(data, headers)
45 | action()
46 |
47 | }
48 | }
49 | const handleAddressSelection = (address) => {
50 | setSelectedAddress(address);
51 | };
52 |
53 | const handleTimeSelection = (date, time) => {
54 | setSelectedTime([date, time]);
55 | };
56 |
57 | const toggleModal = () => {
58 | setShowModal(!showModal)
59 | }
60 |
61 | const addresshandle = () => {
62 | setShowAddressModal(!showAddressModal)
63 | }
64 | const maphandle = () => { setShowMap(!showMap) }
65 | console.log(selectedTime);
66 | console.log(CurrentAddress);
67 | console.log(TotalPrice);
68 |
69 | return (
70 | <>
71 |
72 | {showModal && (
73 |
74 |
82 |
83 | )}
84 | {showAddressModal && (
85 |
93 | )}
94 | {showMap && (
95 |
96 |
100 |
101 | )}
102 |
103 | {showPayment && (
104 |
110 | )}
111 | >
112 | )
113 | }
114 |
115 | export default BookNow
--------------------------------------------------------------------------------
/src/components/admin/Media/MediaCards.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import axios from 'axios';
3 | import { addMediaCards } from '../../../Api/AdminAPI';
4 | import toast from 'react-hot-toast';
5 | import { BiArrowBack } from 'react-icons/bi';
6 |
7 |
8 | function MediaCard({onClose}) {
9 | const [title, setTitle] = useState('');
10 | const [images, setImages] = useState(['', '', '', '']);
11 |
12 | const handleBack = () => { onClose() }
13 | const handleTitleChange = (e) => {
14 | setTitle(e.target.value);
15 | };
16 |
17 | const handleImageUpload = (e, index) => {
18 | const file = e.target.files[0];
19 | setImages((prevImages) => {
20 | const updatedImages = [...prevImages];
21 | updatedImages[index] = file;
22 | return updatedImages;
23 | });
24 | };
25 |
26 | const handleSubmit = async () => {
27 | try {
28 | const formData = new FormData();
29 | formData.append('title', title);
30 |
31 | images.forEach((image) => {
32 | if (image) {
33 | formData.append('images', image);
34 | }
35 | });
36 |
37 | await addMediaCards(formData);
38 | toast.success('Upload successful');
39 | onClose()
40 | } catch (error) {
41 | console.error('Error uploading:', error);
42 | }
43 | };
44 |
45 | return (
46 |
47 |
48 |
56 |
57 |
Enter Title Name
58 |
59 |
60 | {images.map((image, index) => (
61 |
62 |
63 | {image && (
64 |
69 | )}
70 |
71 |
72 |
73 | {image ? 'Change Image' : 'Select Image'}
74 |
75 |
handleImageUpload(e, index)} style={{ display: 'none' }} />
76 |
77 | ))}
78 |
79 |
80 |
81 | Submit
82 |
83 |
84 |
85 |
86 |
87 | );
88 | }
89 |
90 | export default MediaCard;
91 |
--------------------------------------------------------------------------------
/src/components/admin/Services/addservice.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Noto+Sans:wght@700&family=Poppins:wght@400;500;600&display=swap');
2 |
3 |
4 | body {
5 | margin: 0;
6 | padding: 0;
7 | }
8 |
9 | .center {
10 | position: absolute;
11 | top: 50%;
12 | left: 50%;
13 | transform: translate(-50%, -50%);
14 | background-color: #E8F5FF;
15 | border-radius: 10px;
16 | box-shadow: 10px 10px 15px rgba(0, 0, 0, 0.05);
17 | }
18 |
19 | .center h1 {
20 | text-align: center;
21 | padding: 20px 0;
22 | font-weight: 500;
23 | color: #000240;
24 | }
25 |
26 | .center form {
27 | padding: 0 40px;
28 | box-sizing: border-box;
29 | }
30 |
31 | form .txt_field {
32 | position: relative;
33 | background-color: #C2EDFF;
34 | /* border-bottom: 2px solid #adadad; */
35 | border-radius: 10px;
36 | height: 50px;
37 | margin: 25px 0;
38 | }
39 |
40 | .txt_field input {
41 | width: 300px;
42 | /* padding: 15px 5px 5px 5px; */
43 | padding-left: 10px;
44 | height: 50px;
45 | font-size: 16px;
46 | border: none;
47 | background: none;
48 | outline: none;
49 | }
50 |
51 | .select-field {
52 | width: 100%;
53 | padding: 5px 5px;
54 | height: 50px;
55 | font-size: 16px;
56 | border: none;
57 | background: none;
58 | outline: none;
59 | }
60 |
61 | .txt_field textarea {
62 | width: 100%;
63 | padding: 5px 5px;
64 | height: 50px;
65 | font-size: 16px;
66 | border: none;
67 | background: none;
68 | outline: none;
69 | }
70 |
71 | .txt_field label {
72 | position: absolute;
73 | top: 50%;
74 | left: 5px;
75 | color: #b5b6cb;
76 | transform: translateY(-50%);
77 | font-size: 16px;
78 | pointer-events: none;
79 | transition: .5s;
80 | }
81 |
82 | .txt_field span::before {
83 | content: '';
84 | position: absolute;
85 | top: 40px;
86 | left: 0;
87 | width: 0%;
88 | height: 2px;
89 | background: #2691d9;
90 | transition: .5s;
91 | }
92 |
93 | .txt_field input:focus~label,
94 | .txt_field input:valid~label {
95 | top: -10px;
96 | color: rgb(30 58 138);
97 | }
98 |
99 | .txt_field textarea:focus~label,
100 | .txt_field textarea:valid~label {
101 | top: -10px;
102 | color: rgb(30 58 138);
103 | }
104 |
105 | .select-field:focus~label {
106 | top: -10px;
107 | color: rgb(30 58 138);
108 | }
109 |
110 | .txt_field input:focus~span::before,
111 | .txt_field input:valid~span::before {
112 | width: 100%;
113 | }
114 |
115 | .txt_field textarea:focus~span::before,
116 | .txt_field textarea:valid~span::before {
117 | width: 100%;
118 | }
119 |
120 | .pass {
121 | margin: -5px 0 20px 5px;
122 | color: #a6a6a6;
123 | cursor: pointer;
124 | }
125 |
126 | .pass:hover {
127 | text-decoration: underline;
128 | }
129 |
130 | input[type="submit"] {
131 | width: 100%;
132 | height: 50px;
133 | border: 1px solid;
134 | background: #2691d9;
135 | border-radius: 25px;
136 | font-size: 18px;
137 | color: #e9f4fb;
138 | font-weight: 700;
139 | cursor: pointer;
140 | outline: none;
141 | }
142 |
143 | input[type="submit"]:hover {
144 | border-color: #2691d9;
145 | transition: .5s;
146 | }
147 |
148 | .signup_link {
149 | margin: 30px 0;
150 | text-align: center;
151 | font-size: 16px;
152 | color: #666666;
153 | }
154 |
155 | .signup_link a {
156 | color: #2691d9;
157 | text-decoration: none;
158 | }
159 |
160 | .signup_link a:hover {
161 | text-decoration: underline;
162 | }
163 |
164 | #UserTable_length {
165 | position: relative;
166 | top: 50px;
167 | }
168 |
169 | .dataTables_filter {
170 | position: relative;
171 | left: 800px;
172 | top: 10px;
173 | }
174 |
175 | #UserTable_paginate {
176 | position: relative;
177 | left: 900px;
178 | bottom: 20px;
179 |
180 |
181 | }
182 |
183 | .profile_img {
184 | border-color: #e2e8f0;
185 | object-fit: contain;
186 | cursor: pointer;
187 | }
188 |
189 | .profile {
190 | width: 300px;
191 | height: 150px;
192 | border-width: 4px;
193 | margin-top: 10px;
194 | margin-bottom: 10px;
195 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
196 | border-style: solid;
197 | }
--------------------------------------------------------------------------------
/src/components/Provider/Navbar.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { NavLink, useNavigate } from 'react-router-dom';
3 | import { AiOutlineMenu, AiOutlineClose } from 'react-icons/ai';
4 | import { MdPerson, MdCategory, MdPendingActions, MdOutlineDoneAll, MdOutlineLogout, MdNotificationsActive } from 'react-icons/md';
5 | import { BsPatchQuestionFill } from 'react-icons/bs';
6 | import { RiDashboardFill } from 'react-icons/ri';
7 |
8 | const ProviderNavbar = () => {
9 | const [nav, setNav] = useState(false);
10 | const Navigate = useNavigate();
11 |
12 | const closeSidebar = () => {
13 | setNav(false);
14 | };
15 |
16 | const Logout = () => {
17 | localStorage.removeItem('ProviderToken');
18 | Navigate('/provider/login');
19 | };
20 |
21 | return (
22 |
23 |
24 |
27 |
28 |
29 | Quick Serve
30 |
31 |
32 |
33 |
34 | {nav ?
: ''}
35 |
36 | Provider Panel
37 |
38 |
39 |
40 |
setNav(!nav)}
42 | size={30}
43 | className='block absolute left-4 top-4 lg:hidden cursor-pointer'
44 | />
45 |
46 | Quick Serve
47 |
48 |
49 |
50 |
51 |
57 |
58 | Dashboard
59 |
60 |
66 |
67 | Profile
68 |
69 |
75 |
76 | Requests
77 |
78 |
84 |
85 | Upcoming
86 |
87 |
93 |
94 | Completed
95 |
96 |
97 |
98 | Logout
99 |
100 |
101 |
102 |
103 |
104 | );
105 | };
106 |
107 | export default ProviderNavbar;
108 |
--------------------------------------------------------------------------------
/src/components/user/login/Register.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { useDispatch, useSelector } from 'react-redux';
3 | import { Link, useNavigate } from 'react-router-dom';
4 | import { userData } from '../../../redux/Slice/userSlice'
5 | import { userSignup } from '../../../Api/userAPI';
6 | import { toast } from 'react-hot-toast';
7 |
8 | const Signup = () => {
9 | const [selectedImage, setSelectedImage] = useState(null);
10 | const [previewImage, setPreviewImage] = useState(null);
11 |
12 | const signup = useSelector((state) => state.user);
13 | const dispatch = useDispatch();
14 | const navigate = useNavigate();
15 |
16 | const handleImageChange = (e) => {
17 | const image = e.target.files[0];
18 | setSelectedImage(image);
19 | setPreviewImage(URL.createObjectURL(image));
20 | };
21 |
22 | const onChange = (e) => {
23 | dispatch(userData({ field: e.target.name, value: e.target.value }));
24 | };
25 |
26 | const handleSubmit = async (e) => {
27 | e.preventDefault();
28 | try {
29 | const formData = new FormData();
30 | formData.append('image', selectedImage);
31 | formData.append('username', signup.username);
32 | formData.append('email', signup.email);
33 | formData.append('mobile', signup.mobile);
34 | formData.append('password', signup.password);
35 | const response = await userSignup(formData);
36 |
37 | if (response.data.email) {
38 | navigate('/Login');
39 | toast.success('Registered Successfully');
40 | } else {
41 | toast.error(response.data.message);
42 | }
43 | } catch (error) {
44 | console.log(error);
45 | }
46 | };
47 |
48 | return (
49 |
50 |
51 |
52 |
Signup
53 |
120 |
121 |
122 |
123 | );
124 | };
125 |
126 | export default Signup;
127 |
--------------------------------------------------------------------------------
/src/components/admin/category/editCategory.jsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react';
2 | import { BiArrowBack } from 'react-icons/bi';
3 | import { editCategory, updateCategory } from '../../../Api/AdminAPI';
4 | import BASE_URL from '../../../config/config';
5 | const EditCategoryModel = ({ open, Id }) => {
6 | const [selectedImage, setSelectedImage] = useState(null);
7 | const [previewImage, setPreviewImage] = useState(null);
8 | const [categoryname, setCategoryname] = useState('');
9 | const [categoryImage, setCategoryImage] = useState(null);
10 |
11 | const handleImageChange = (e) => {
12 | const image = e.target.files[0];
13 | setSelectedImage(image);
14 | setPreviewImage(URL.createObjectURL(image));
15 | };
16 |
17 | const handleGoBack = () => {
18 | open(false);
19 | };
20 | const headers = { Authorization: `Bearer ${localStorage.getItem('token')}` };
21 | useEffect(() => {
22 | editCategory(Id, headers).then((data) => {
23 | setCategoryname(data.categoryName);
24 | setCategoryImage(data.image)
25 | });
26 | }, []);
27 |
28 | const onChange = (e) => {
29 | setCategoryname(e.target.value);
30 | };
31 |
32 | const handleSubmit = async (e) => {
33 | e.preventDefault();
34 |
35 | try {
36 | const formData = new FormData();
37 | if (selectedImage) {
38 | formData.append('image', selectedImage);
39 | }
40 | formData.append('categoryName', categoryname);
41 | const headers = { Authorization: `Bearer ${localStorage.getItem('token')}` };
42 | const response = await updateCategory(Id, formData, headers)
43 | if (response) {
44 | open(false);
45 | } else {
46 | alert(response.message);
47 | }
48 | } catch (error) {
49 | console.log(error);
50 | alert(error.response.message);
51 | }
52 | };
53 |
54 |
55 | return (
56 |
57 |
58 |
59 |
60 |
61 |
62 |
Edit Category
63 |
64 |
65 |
66 |
102 |
103 |
104 | );
105 | };
106 |
107 | export default EditCategoryModel;
108 |
--------------------------------------------------------------------------------
/src/components/admin/City/city.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import AddCityModel from './addCity';
3 | import DeleteCategory from '../../comfirmations/DeleteCategory'
4 | import { MdDelete } from 'react-icons/md'
5 | import { getCity } from '../../../Api/AdminAPI';
6 | import DeleteCity from '../../comfirmations/DeleteCity';
7 |
8 | function City() {
9 | const [searchTerm, setSearchTerm] = useState('');
10 | const [showAddModal, setShowAddModal] = useState(false);
11 | const [showDeleteModal, setShowDeleteModal] = useState(false);
12 | const [CityId, setCityId] = useState('');
13 | const [city, setCity] = useState([])
14 |
15 | useEffect(() => {
16 | getCity().then((res) => {
17 | setCity(res.data)
18 | })
19 | }, [showAddModal,showDeleteModal])
20 |
21 | const toggleModal = () => {
22 | setShowAddModal(!showAddModal)
23 | }
24 |
25 | const handleDelete = ((cityId) => {
26 | setShowDeleteModal(true);
27 | setCityId(cityId);
28 | })
29 |
30 | const filteredData = city.filter((item) =>
31 | item.cityName.toLowerCase().includes(searchTerm.toLowerCase())
32 | );
33 |
34 | return (
35 | <>
36 |
37 |
38 |
39 |
setSearchTerm(e.target.value))}
44 | placeholder="Search..."
45 | />
46 |
55 |
56 |
60 | Add City
61 |
62 |
63 |
64 |
65 |
66 |
67 | Category Name
68 | Action
69 |
70 |
71 |
72 | {filteredData.map((item) => (
73 |
74 | {item.cityName}
75 | handleDelete(item._id)} />
76 |
77 |
78 |
79 | ))}
80 |
81 |
82 | {showAddModal && (
83 |
89 | )}
90 | {showDeleteModal && (
91 |
92 |
96 |
97 | )}
98 |
99 |
100 | >
101 | );
102 | }
103 |
104 | export default City;
105 |
--------------------------------------------------------------------------------
/src/components/admin/users/users.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react'
2 | import BlockUser from '../../comfirmations/BlockUser';
3 | import { getUsers } from '../../../Api/AdminAPI';
4 | import '../Services/Services.css'
5 | import Button from '@mui/material/Button';
6 | import BASE_URL from '../../../config/config';
7 |
8 | function UserList() {
9 | const [showBlockModal, setShowBlockModal] = useState(false);
10 | const [users, setUsers] = useState([])
11 | const [userId, setUserId] = useState('')
12 | const [block, setBlock] = useState(true);
13 |
14 | const headers = { Authorization: `Bearer ${localStorage.getItem('token')}` };
15 |
16 | useEffect(() => {
17 | getUsers(headers).then(data => {
18 | setUsers(data)
19 | })
20 | }, [showBlockModal])
21 |
22 | const handleBlock = (userId, isBlocked) => {
23 | setUserId(userId);
24 | setBlock(!isBlocked);
25 | setShowBlockModal(true);
26 | };
27 |
28 | return (
29 |
30 |
31 |
32 |
51 |
52 |
53 |
54 |
55 | Image
56 | Name
57 | Email
58 | Number
59 | Action
60 |
61 |
62 |
63 | {users.map(item => (
64 |
65 |
66 | {item.username}
67 | {item.email}
68 | {item.mobile}
69 |
70 |
71 | {item.isBlocked ? (
72 | handleBlock(item._id, true)} variant="contained" color="success"> Unblock )
73 | :
74 | ( handleBlock(item._id, false)} variant="contained" color="error"> Block
75 | )}
76 |
77 |
78 | ))}
79 |
80 |
81 | {showBlockModal && (
82 |
83 |
87 |
88 | )}
89 |
90 |
91 |
92 |
93 |
94 |
95 | )
96 | }
97 |
98 | export default UserList
--------------------------------------------------------------------------------
/src/components/user/ServiceCard/ServiceCard.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import { StarIcon, HeartIcon } from '@heroicons/react/solid';
3 | // import { getServicesbycategory } from '../../Api/AdminAPI';
4 | import { getServices } from '../../../Api/AdminAPI';
5 | import { addToCart } from '../../../Api/userAPI';
6 | import toast from 'react-hot-toast';
7 | import { Link } from 'react-router-dom';
8 | import { useParams } from 'react-router-dom';
9 | import BookNow from '../BookNow/BookNow';
10 | import BASE_URL from '../../../config/config';
11 | import { useSelector } from 'react-redux';
12 |
13 | const ServiceCard = () => {
14 |
15 | const headers = { Authorization: `Bearer ${localStorage.getItem('userToken')}` };
16 |
17 | const { categoryName } = useParams();
18 | const [service, setService] = useState([])
19 | const [serviceData, setServiceData] = useState([])
20 | const [showModal, setShowModal] = useState(false)
21 |
22 | const handleAddToCart = (serviceId) => {
23 |
24 | if (headers.Authorization !== 'Bearer null') {
25 | addToCart(serviceId, headers).then((res) => {
26 | if (res.data) {
27 | toast.success(res.data.message)
28 | }
29 | })
30 | } else {
31 | toast.error('please Login')
32 | }
33 | };
34 |
35 | const handleModel = (serviceId) => {
36 | if (headers.Authorization !== 'Bearer null') {
37 | setShowModal(!showModal)
38 | const filteredServices = service.filter((service) => service._id === serviceId)
39 | const [filteredService] = filteredServices;
40 | setServiceData(filteredService);
41 | }else{
42 | toast.error('Please login to book a service')
43 | }
44 | }
45 |
46 | useEffect(() => {
47 | getServices().then((data) => {
48 | if (categoryName) {
49 | const filteredServices = data.filter((service) => service.category === categoryName);
50 | setService(filteredServices);
51 | } else {
52 | setService(data)
53 | }
54 |
55 | });
56 | }, [categoryName]);
57 |
58 | return (
59 | <>
60 |
61 |
62 |
View All Services
63 |
64 |
65 |
66 |
67 |
68 | {(service.map((service) => (
69 |
70 |
71 |
72 | {/*
73 |
74 | 4
75 |
*/}
76 |
81 |
82 |
83 |
84 |
85 |
86 |
{service.servicename}
87 | {/* */}
88 |
89 |
90 |
{service.description}
91 |
92 | ₹{service.price}
93 | {/* /hour */}
94 |
95 |
96 | *Extra Charges Applicable for Spare Parts
97 |
98 |
99 |
100 | handleModel(service._id)} className="p-2 text-blue/900 border-2 rounded-lg border-blue-900 ">
101 | BOOK NOW
102 |
103 | handleAddToCart(service._id)} className="p-2 dark:text-white rounded-lg bg-gradient-to-r from-blue-900 to-blue-500">
104 | ADD TO CART
105 |
106 |
107 |
108 |
109 | )))}
110 |
111 |
112 | {showModal && }
113 |
114 | >
115 | );
116 | };
117 |
118 | export default ServiceCard;
119 |
--------------------------------------------------------------------------------
/src/components/admin/Bookings/bookings.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import moment from 'moment';
3 | import { getBookings } from '../../../Api/AdminAPI';
4 |
5 | function Bookings() {
6 | const [booking, setBooking] = useState([]);
7 | const [filter, setFilter] = useState('all');
8 | const [searchInput, setSearchInput] = useState('');
9 |
10 | const headers = { Authorization: `Bearer ${localStorage.getItem('token')}` };
11 |
12 | useEffect(() => {
13 | getBookings(headers)
14 | .then((res) => {
15 | setBooking(res.data);
16 | });
17 | }, []);
18 |
19 | const handleSearch = () => {
20 | const filteredBookings = booking.filter((bookingItem) =>
21 | bookingItem.BookingID.includes(searchInput)
22 | );
23 | setBooking(filteredBookings);
24 | };
25 |
26 | return (
27 | <>
28 |
29 |
30 |
31 |
32 |
Bookings
33 |
34 |
35 |
36 |
37 | setSearchInput(e.target.value)}
41 | value={searchInput}
42 | className="w-full px-3 h-10 rounded-l border-2 border-blue-900 focus:outline-none focus:border-blue-500"
43 | />
44 |
49 | Search
50 |
51 |
52 |
53 |
54 | setFilter('all')}
57 | >
58 | All
59 |
60 |
61 | setFilter('Completed')}
64 | >
65 | Completed
66 |
67 |
68 | setFilter('Pending')}
71 | >
72 | Pending
73 |
74 |
75 |
76 |
77 | {booking
78 | .filter((bookingItem) => {
79 | if (filter === 'all') {
80 | return true;
81 | } else {
82 | return bookingItem.status === filter;
83 | }
84 | })
85 | .filter((bookingItem) =>
86 | bookingItem.BookingID.includes(searchInput)
87 | )
88 | .map((bookingItem) => (
89 |
93 |
94 |
95 |
96 |
BookingId: {bookingItem.BookingID}
97 |
Status: {bookingItem.status}
98 |
99 |
100 |
101 | {bookingItem.serviceData.map((service) => (
102 |
103 |
{service.servicename} ({service.category})
104 |
105 | ))}
106 |
{bookingItem.startTime}
107 |
{moment(bookingItem.date).format('MMMM Do, YYYY')}
108 |
109 | {bookingItem.userData.map((user) => (
110 |
111 | Client: {user.username}
112 |
113 | ))}
114 |
115 |
116 |
117 |
118 | ))}
119 |
120 |
121 | >
122 | );
123 | }
124 |
125 | export default Bookings;
126 |
--------------------------------------------------------------------------------
/src/components/admin/Support/chat.jsx:
--------------------------------------------------------------------------------
1 |
2 | import React, { useEffect, useState } from 'react';
3 | import io from 'socket.io-client';
4 | import Sidebar from './chatSidebar';
5 | import { IoSendSharp } from 'react-icons/io5';
6 | import { getChat, getConversation, sendMessage } from '../../../Api/AdminAPI';
7 | import BASE_URL from '../../../config/config';
8 | import { FaUserCircle } from 'react-icons/fa';
9 |
10 | const socket = io(BASE_URL);
11 |
12 | const AdminChat = () => {
13 | const [users, setUsers] = useState([]);
14 | const [selectedUser, setSelectedUser] = useState(null);
15 | const [messages, setMessages] = useState([]);
16 | const [message, setMessage] = useState('');
17 | const [conversationId, setConversationId] = useState(null);
18 | const headers = { Authorization: `Bearer ${localStorage.getItem('token')}` };
19 |
20 | useEffect(() => {
21 | getChat(headers).then((res) => {
22 | const data = res.data;
23 | const users = data.map((message) => message.user);
24 | setUsers(users);
25 | });
26 |
27 | return () => {
28 | socket.disconnect();
29 | };
30 | }, []);
31 |
32 | useEffect(() => {
33 | if (socket) {
34 | socket.on('message received', (newMessageReceived) => {
35 | setMessages((prevMessages) => [...prevMessages, newMessageReceived]);
36 | });
37 | }
38 | }, []);
39 |
40 | const sendReply = (event) => {
41 | event.preventDefault();
42 | if (selectedUser && message.trim() !== '') {
43 | const data = {
44 | conversationId: conversationId,
45 | message: message,
46 | };
47 | socket.emit('new message', data);
48 | sendMessage(data, headers);
49 | setMessage('');
50 | }
51 | };
52 |
53 | const selectUser = (userId, username) => {
54 | setSelectedUser({ userId, username });
55 | getConversation(userId, headers).then((res) => {
56 | setMessages(res.data.messages);
57 | setConversationId(res.data._id);
58 | socket.emit('join chat', res.data._id);
59 | });
60 | };
61 |
62 | return (
63 |
64 |
65 |
66 |
67 | {selectedUser ? (
68 |
69 |
70 |
Chat with {selectedUser.username}
71 |
72 |
73 | {messages.map((msg) => (
74 |
79 | {msg.sender === selectedUser.userId ? (
80 |
81 | ) : (
82 |
87 | )}
88 |
89 |
93 | {msg.message}
94 |
95 |
96 | ))}
97 |
98 |
116 |
117 | ) : (
118 |
119 |
120 |
121 | Please select a user to start the chat
122 |
123 |
124 | )}
125 |
126 |
127 |
128 | );
129 | };
130 |
131 | export default AdminChat;
132 |
--------------------------------------------------------------------------------
/src/components/user/Footer/Footer.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import { getCategories, getCity } from '../../../Api/AdminAPI';
3 | import { FaFacebook, FaTwitter, FaInstagram, FaLinkedin, FaGithub } from 'react-icons/fa';
4 | import { IoLogoYoutube } from 'react-icons/io';
5 | import { HiOutlineMail } from 'react-icons/hi';
6 | import { TbLetterQ } from 'react-icons/tb';
7 | import { Link } from 'react-router-dom';
8 |
9 | const Footer = () => {
10 | const [categories, setCategories] = useState([]);
11 | const [cities, setCities] = useState([])
12 | useEffect(() => {
13 | getCategories().then((res) => {
14 | setCategories(res);
15 | });
16 | getCity().then((res) => {
17 | setCities(res.data);
18 | })
19 | }, []);
20 |
21 | return (
22 |
121 | );
122 | };
123 |
124 | export default Footer;
125 |
--------------------------------------------------------------------------------
/src/components/admin/Media/EditMedia/Cards.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import toast from 'react-hot-toast';
3 | import { BiArrowBack } from 'react-icons/bi';
4 | import { fetchCard, updateCard } from '../../../../Api/AdminAPI';
5 | import BASE_URL from '../../../../config/config';
6 |
7 | function EditMediaCard({ onClose, Id }) {
8 | const [title, setTitle] = useState('');
9 | const [images, setImages] = useState(['', '', '', '']);
10 |
11 | useEffect(() => {
12 | const fetchMediaCard = async () => {
13 | try {
14 | const cardData = await fetchCard(Id);
15 | setTitle(cardData.title);
16 | const cardImages = cardData.images.map((image) => image.image);
17 | setImages(cardImages);
18 | } catch (error) {
19 | console.error('Error fetching card:', error);
20 | }
21 | };
22 | fetchMediaCard();
23 | }, [Id]);
24 |
25 | const handleBack = () => {
26 | onClose();
27 | };
28 |
29 | const handleTitleChange = (e) => {
30 | setTitle(e.target.value);
31 | };
32 |
33 | const handleImageUpload = (e, index) => {
34 | const file = e.target.files[0];
35 | setImages((prevImages) => {
36 | const updatedImages = [...prevImages];
37 | updatedImages[index] = file;
38 | return updatedImages;
39 | });
40 | };
41 |
42 | const handleSubmit = async () => {
43 | try {
44 | const formData = new FormData();
45 | formData.append('title', title);
46 |
47 | images.forEach((image) => {
48 | if (image instanceof File) {
49 | formData.append('images', image);
50 | }
51 | });
52 | updateCard(Id, formData)
53 | toast.success('Upload successful');
54 | onClose();
55 | } catch (error) {
56 | console.error('Error uploading:', error);
57 | }
58 | };
59 |
60 | return (
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
Edit Media Card
69 |
70 |
71 |
72 |
Enter Title Name
73 |
74 |
75 | {images.map((image, index) => (
76 |
77 |
78 | {image && typeof image === 'string' ? (
79 |
84 | ) : (
85 | image && (
86 |
91 | )
92 | )}
93 |
94 |
95 |
96 | {image ? 'Change Image' : 'Select Image'}
97 |
98 |
handleImageUpload(e, index)} style={{ display: 'none' }} />
99 |
100 | ))}
101 |
102 |
103 |
104 | Update
105 |
106 |
107 |
108 |
109 |
110 | );
111 | }
112 |
113 | export default EditMediaCard;
114 |
--------------------------------------------------------------------------------
/src/components/admin/category/Category.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import AddCategoryModel from './addCategory';
3 | import EditCategoryModel from './editCategory';
4 | import DeleteCategory from '../.././comfirmations/DeleteCategory'
5 | import { MdDelete, MdEdit } from 'react-icons/md'
6 | import { getCategories } from '../../../Api/AdminAPI';
7 | import BASE_URL from '../../../config/config';
8 | function Category() {
9 | const [searchTerm, setSearchTerm] = useState('');
10 | const [showAddModal, setShowAddModal] = useState(false);
11 | const [showEditModal, setShowEditModal] = useState(false);
12 | const [showDeleteModal, setShowDeleteModal] = useState(false);
13 | const [CategoryId, setCategoryId] = useState('');
14 | const [category, setCategory] = useState([])
15 |
16 | useEffect(() => {
17 | getCategories().then((data) => {
18 | setCategory(data)
19 | })
20 |
21 | }, [showAddModal,showEditModal,showDeleteModal])
22 |
23 | const toggleModal = () => {
24 | setShowAddModal(!showAddModal)
25 | }
26 |
27 | const handleDelete = ((CategoryId) => {
28 | setShowDeleteModal(true);
29 | setCategoryId(CategoryId);
30 | })
31 | const handleEdit = ((CategoryId) => {
32 | setShowEditModal(true)
33 | setCategoryId(CategoryId);
34 | })
35 | const filteredData = category.filter((item) =>
36 | item.categoryName.toLowerCase().includes(searchTerm.toLowerCase())
37 | );
38 |
39 | return (
40 | <>
41 |
42 |
43 |
44 |
setSearchTerm(e.target.value))}
49 | placeholder="Search..."
50 | />
51 |
60 |
61 |
65 | Add Category
66 |
67 |
68 |
69 |
70 |
71 |
72 | Image
73 | Category Name
74 | Action
75 |
76 |
77 |
78 | {filteredData.map((item) => (
79 |
80 |
81 |
82 |
83 | {item.categoryName}
84 |
85 |
86 | handleDelete(item._id)} />
87 | handleEdit(item._id)} />
88 |
89 |
90 |
91 |
92 | ))}
93 |
94 |
95 | {showAddModal && (
96 |
102 | )}
103 | {showEditModal && (
104 |
105 |
109 |
110 | )}
111 | {showDeleteModal && (
112 |
113 |
117 |
118 | )}
119 |
120 |
121 | >
122 | );
123 | }
124 |
125 | export default Category;
126 |
--------------------------------------------------------------------------------
/src/components/user/Checkouts/Address.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import { BiArrowBack } from 'react-icons/bi';
3 | import toast from 'react-hot-toast';
4 | import { deleteAddress, getAddress } from '../../../Api/userAPI';
5 | import { MdDeleteOutline } from 'react-icons/md';
6 | import { useSelector } from 'react-redux';
7 | import { getCity } from '../../../Api/AdminAPI';
8 |
9 | const Address = ({ onClose, shedule, map, onSelectAddress }) => {
10 | const [address, setAddress] = useState([]);
11 | const [city, setCity] = useState([]);
12 |
13 | const [selectedAddress, setSelectedAddress] = useState([]);
14 | const [isUpdated, setIsUpdated] = useState(false)
15 |
16 | const headers = { Authorization: `Bearer ${localStorage.getItem('userToken')}` };
17 |
18 | const handleGoBack = () => {
19 | shedule();
20 | onClose();
21 | };
22 |
23 | const selectAddress = address.filter((address) => address.id === selectedAddress)
24 |
25 | const proceed = () => {
26 | const selected = address.find((addr) => addr.id === selectedAddress);
27 | if (selected) {
28 | const selectedCity = city.find((city) =>
29 | selected.address.includes(city.cityName)
30 | ); if (selectedCity) {
31 | onSelectAddress(selectAddress);
32 | shedule();
33 | onClose();
34 | } else {
35 | toast.error('Service not available at selected address.');
36 | }
37 | } else {
38 | toast.error('Please select an address.');
39 | }
40 | };
41 |
42 |
43 | const addAddress = () => {
44 | map();
45 | onClose();
46 | };
47 | const handleDelete = ((Id) => {
48 | deleteAddress(Id, headers).then((res) => {
49 | setIsUpdated(!isUpdated)
50 | })
51 | })
52 |
53 | useEffect(() => {
54 | try {
55 | getAddress(headers).then((res) => {
56 | setAddress(res.data);
57 | });
58 | getCity().then((res) => {
59 | setCity(res.data)
60 | })
61 | } catch (error) {
62 | console.log(error);
63 | }
64 | }, [isUpdated]);
65 |
66 | return (
67 | <>
68 |
69 |
70 |
71 |
72 |
73 |
74 |
Saved Address
75 |
76 |
77 |
78 |
79 |
80 |
+ Add Address
81 |
82 |
83 | {address.map((address) => (
84 |
85 |
86 |
setSelectedAddress(address.id)}
91 | />
92 |
93 |
{address.house}
94 | handleDelete(address.id)} size={20} color="red" className="ms-5" />
95 |
96 |
97 |
98 |
{address.address}
99 |
100 | ))}
101 |
102 |
103 |
104 |
105 |
106 |
107 |
112 | PROCEED
113 |
114 |
115 |
116 |
117 |
118 | >
119 | );
120 | };
121 |
122 | export default Address;
123 |
--------------------------------------------------------------------------------
/src/components/admin/Services/addServices.jsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react';
2 | import { useDispatch, useSelector } from 'react-redux';
3 | import { addService } from "../../../redux/Slice/serviceSlice";
4 | import { BiArrowBack } from 'react-icons/bi';
5 | import './addservice.css';
6 | import { AddService, getCategories } from '../../../Api/AdminAPI';
7 |
8 | const AddServiceModel = ({ onClose }) => {
9 | const [selectedImage, setSelectedImage] = useState(null);
10 | const [previewImage, setPreviewImage] = useState(null);
11 | const [categoryName, setCategoryName] = useState([])
12 | const dispatch = useDispatch();
13 | const service = useSelector((state) => state.service);
14 |
15 | const handleImageChange = (e) => {
16 | const image = e.target.files[0];
17 | setSelectedImage(image);
18 | setPreviewImage(URL.createObjectURL(image));
19 | };
20 | useEffect(() => {
21 | getCategories()
22 | .then((data) => {
23 | setCategoryName(data.map((item) => item.categoryName));
24 | })
25 | .catch((error) => {
26 | console.error("Error fetching categories:", error);
27 | });
28 | }, []);
29 |
30 | const handleGoBack = () => {
31 | onClose();
32 | };
33 |
34 | const onChange = (e) => {
35 | dispatch(addService({ field: e.target.name, value: e.target.value }));
36 | };
37 |
38 | const handleSubmit = async (e) => {
39 | e.preventDefault();
40 |
41 | const { servicename, category, description, serviceincludes, price } = service;
42 |
43 | try {
44 | const formData = new FormData();
45 | formData.append('image', selectedImage);
46 | formData.append('servicename', servicename);
47 | formData.append('category', category);
48 | formData.append('description', description);
49 | formData.append('serviceincludes', serviceincludes);
50 | formData.append('price', price);
51 | const headers = { Authorization: `Bearer ${localStorage.getItem('token')}` };
52 | AddService(formData, headers).then((data) => {
53 | if (data) {
54 | onClose();
55 | } else {
56 | alert(data.message);
57 | }
58 |
59 | })
60 | } catch (error) {
61 | console.log(error);
62 | alert(error.data.message);
63 | }
64 | };
65 |
66 | return (
67 |
68 |
69 |
70 |
71 |
72 |
73 |
Add Services
74 |
75 |
76 |
77 |
139 |
140 |
141 |
142 |
143 | );
144 | };
145 |
146 | export default AddServiceModel;
147 |
--------------------------------------------------------------------------------
/src/components/user/Bookings/BookingDetails.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import { BiArrowBack } from 'react-icons/bi';
3 | import { AddReview, getBookings } from '../../../Api/userAPI';
4 | import moment from 'moment';
5 | import ReactStars from 'react-stars';
6 | import toast from 'react-hot-toast'
7 | import { useSelector } from 'react-redux';
8 | import Loader from '../../Loader';
9 |
10 | function BookingDetail({ action, data }) {
11 | const [bookings, setBookings] = useState();
12 | const [rating, setRatingValue] = useState(0);
13 | const [feedback, setFeedback] = useState('')
14 | const [loading, setLoading] = useState(true);
15 |
16 | const headers = { Authorization: `Bearer ${localStorage.getItem('userToken')}` };
17 | const user = useSelector((state) => state.user.data)
18 | const handleRating = (rate) => {
19 | setRatingValue(rate);
20 | };
21 | const handleSubmit = (e) => {
22 | e.preventDefault();
23 | if (rating === 0) {
24 | toast.error('Please select a rating');
25 | } else if (!feedback) {
26 | toast.error('Please provide feedback');
27 | } else {
28 | const data = {
29 | userId: user._id,
30 | rating: rating,
31 | feedback: feedback,
32 | serviceIDs: bookings.serviceData,
33 | };
34 | AddReview(data, headers).then((res) => {
35 | if (res) {
36 | toast.success(res.data.message);
37 | action();
38 | }
39 | });
40 | }
41 | };
42 |
43 |
44 | useEffect(() => {
45 | getBookings(headers).then((res) => {
46 | if (data) {
47 | setLoading(false)
48 | const filteredBookings = res.data.filter((booking) => booking.BookingID === data);
49 | const [filteredBooking] = filteredBookings;
50 | setBookings(filteredBooking);
51 | }
52 | });
53 | }, []);
54 |
55 | const handleComplaintClick = (BookingID) => {
56 | const email = 'complaints.quickserve@gmail.com';
57 | const subject = `Complaint for Booking ID: ${BookingID}`;
58 | const mailtoLink = `mailto:${email}?subject=${encodeURIComponent(subject)}`;
59 |
60 | window.open(mailtoLink);
61 | };
62 |
63 | const today = moment().format('MMMM Do, YYYY');
64 | const isToday = bookings?.date === today;
65 |
66 | return (
67 | <>
68 | {loading ? :
69 |
70 |
71 |
72 |
action())}>
73 |
74 |
75 |
Booking Details
76 |
77 |
78 | {bookings && (
79 |
80 |
81 |
82 |
ID: {bookings.BookingID}
83 |
{moment(bookings.date).format('MMMM Do, YYYY')} At {bookings.startTime}
84 |
85 |
86 | {bookings.status !== 'Completed' && isToday && (
87 | Cancel
88 | )}
89 |
90 |
91 |
92 |
93 | {bookings.serviceData.map((item, index) => (
94 |
95 | {/*
{index + 1}.
*/}
96 |
{item.servicename}
97 |
98 | ))}
99 |
Paid: ₹ {bookings.totalPrice}
100 |
101 |
102 |
103 | )}
104 | {bookings && bookings.status === 'Completed' && (
105 |
106 |
107 |
Rate Now
108 |
115 |
116 |
117 | setFeedback(e.target.value))}
122 | placeholder="Enter your feedback..."
123 | >
124 |
125 |
126 |
Submit
127 |
handleComplaintClick(bookings.BookingID)}
130 | >
131 | Register a Complaint
132 |
133 |
134 | )}
135 |
136 |
137 |
}
138 |
139 | >
140 | );
141 | }
142 |
143 | export default BookingDetail;
--------------------------------------------------------------------------------
/src/components/user/Checkouts/TimeShedule.jsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react';
2 | import { BiArrowBack } from 'react-icons/bi';
3 | import { BsChevronRight } from 'react-icons/bs';
4 | import { isSameDay } from 'date-fns';
5 | import toast from 'react-hot-toast';
6 |
7 | const TimeShedule = ({ onClose, modal, payment, onTimeSelection, selectedAddress, action }) => {
8 | const [selectedDate, setSelectedDate] = useState(null);
9 | const [selectedTime, setSelectedTime] = useState(null);
10 | const [address, setAddress] = useState('');
11 |
12 | useEffect(() => {
13 | const Address = selectedAddress.map((address) => address.address);
14 | setAddress(Address);
15 | }, [selectedAddress]);
16 |
17 | const handleGoBack = () => {
18 | onClose();
19 | action()
20 | };
21 |
22 | const handleAddress = () => {
23 | modal();
24 | onClose();
25 | };
26 |
27 | const handleProceedToPayment = () => {
28 | if (selectedDate && selectedTime && address.length > 0 && address !=='') {
29 | payment();
30 | onTimeSelection(selectedDate, selectedTime);
31 | } else {
32 | if (!selectedDate) {
33 | toast.error('Please select a date.');
34 | } else if (!selectedTime) {
35 | toast.error('Please select a time.');
36 | }
37 | toast.error('Please select an address.');
38 |
39 | }
40 | };
41 |
42 |
43 | const handleDateSelection = (date) => {
44 | setSelectedDate(date);
45 | setSelectedTime(null);
46 | };
47 |
48 | const handleTimeSelection = (time) => {
49 | setSelectedTime(time);
50 | };
51 |
52 | const renderDates = () => {
53 | const today = new Date();
54 | const tomorrow = new Date(today);
55 | tomorrow.setDate(tomorrow.getDate() + 1);
56 | const dayAfterTomorrow = new Date(today);
57 | dayAfterTomorrow.setDate(dayAfterTomorrow.getDate() + 2);
58 |
59 | const getDayOfWeek = (date) => {
60 | const days = ['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'];
61 | return days[date.getDay()];
62 | };
63 |
64 | const dates = [
65 | { date: today, label: getDayOfWeek(today) },
66 | { date: tomorrow, label: getDayOfWeek(tomorrow) },
67 | { date: dayAfterTomorrow, label: getDayOfWeek(dayAfterTomorrow) }
68 | ];
69 |
70 | return dates.map((item) => (
71 | handleDateSelection(item.date)}
76 | >
77 |
{item.label}
78 | {item.date.getDate()}
79 |
80 | ));
81 | };
82 |
83 | const renderTimes = () => {
84 | const availableTimes = [
85 | '9:00 AM', '10:00 AM', '11:00 AM', '12:00 PM', '1:00 PM', '2:00 PM', '3:00 PM', '4:00 PM', '5:00 PM'
86 | ];
87 |
88 | const currentTime = new Date();
89 | const currentHour = currentTime.getHours();
90 | const currentMinute = currentTime.getMinutes();
91 |
92 | const isToday = selectedDate && isSameDay(selectedDate, new Date());
93 | const startIndex = isToday ? Math.max(0, currentHour - 8) : 0;
94 |
95 | return availableTimes.slice(startIndex).map((time) => (
96 | handleTimeSelection(time)}
100 | >
101 |
{time}
102 |
103 | ));
104 | };
105 |
106 | return (
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
Schedule Professionals
115 |
116 |
117 |
118 |
119 |
120 |
121 | {address && address.length > 0 ? address : 'No address selected'}
122 |
123 |
124 |
125 |
126 | {renderDates()}
127 |
128 |
129 |
Select start time
130 | Your service will take
131 |
132 |
133 |
134 | {renderTimes()}
135 |
136 |
137 |
142 | PROCEED TO PAYMENT
143 |
144 |
145 |
146 |
147 |
148 |
149 | );
150 | };
151 |
152 | export default TimeShedule;
153 |
--------------------------------------------------------------------------------
/src/components/admin/AdminNavbar/AdminNavbar.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { NavLink, Navigate, useNavigate } from 'react-router-dom';
3 | import { AiOutlineMenu, AiOutlineClose } from 'react-icons/ai';
4 | import { MdPerson, MdCategory, MdMiscellaneousServices, MdOutlineLogout } from 'react-icons/md';
5 | import { BsPersonGear } from 'react-icons/bs';
6 | import { RiDashboardFill } from 'react-icons/ri';
7 | import { GoFileMedia } from 'react-icons/go';
8 | import { AiOutlineCalendar } from 'react-icons/ai';
9 | import { GiModernCity } from 'react-icons/gi'
10 | import { BiChat } from 'react-icons/bi';
11 |
12 | const AdminNavbar = () => {
13 | const [nav, setNav] = useState(false);
14 | const Navigate = useNavigate()
15 |
16 | const closeSidebar = () => {
17 | setNav(false);
18 | };
19 |
20 | const handleNavLinkFocus = (event) => {
21 | event.target.style.color = 'yellow';
22 | };
23 |
24 | const handleNavLinkBlur = (event) => {
25 | event.target.style.color = 'inherit';
26 | };
27 |
28 | const Logout = () => {
29 | localStorage.removeItem('token');
30 | Navigate('/admin/login')
31 | }
32 |
33 | return (
34 |
35 |
36 |
39 |
40 |
41 |
42 | Quick Serve
43 |
44 |
45 |
46 |
47 |
48 | {nav ?
: ''}
49 |
50 | Admin Panel
51 |
52 |
53 |
54 |
setNav(!nav)}
56 | size={30}
57 | className='block absolute left-4 top-4 lg:hidden cursor-pointer'
58 | />
59 |
60 | Quick Serve
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | Dashboard
69 |
70 |
71 |
72 |
73 |
74 | Providers
75 |
76 |
77 |
78 |
79 |
80 | Users
81 |
82 |
83 |
84 |
85 |
86 | Categories
87 |
88 |
89 |
90 |
91 |
92 | Services
93 |
94 |
95 |
96 |
97 |
98 | Media
99 |
100 |
101 |
102 |
103 |
104 | Bookings
105 |
106 |
107 |
108 |
109 |
110 | City
111 |
112 |
113 |
114 |
115 |
116 | Support
117 |
118 |
119 |
120 |
121 | Logout
122 |
123 |
124 |
125 |
126 |
127 |
128 | );
129 | };
130 |
131 | export default AdminNavbar;
132 |
--------------------------------------------------------------------------------