├── .firebase └── hosting.YnVpbGQ.cache ├── .firebaserc ├── .gitignore ├── README.md ├── firebase.json ├── package-lock.json ├── package.json ├── public ├── fakeDB.JSON ├── favicon.ico ├── index.html ├── manifest.json └── robots.txt └── src ├── App.css ├── App.js ├── App.test.js ├── Components ├── Banner │ ├── Banner.css │ └── Banner.js ├── Contact │ ├── Contact.css │ └── Contact.js ├── OfferServices │ ├── OfferServices.css │ └── OfferServices.js ├── OurPartners │ ├── OurPartners.css │ └── OurPartners.js └── Shared │ ├── BackToTop │ ├── BackToTop.css │ └── BackToTop.js │ ├── Footer │ ├── Footer.css │ └── Footer.js │ ├── Header │ ├── Header.css │ └── Header.js │ ├── Loading │ └── Loading.js │ └── PageTitle │ └── PageTitle.js ├── Optional ├── AboutUs.js ├── Faq.js └── PrivacyPolicy.js ├── Pages ├── AllReviews │ ├── Review │ │ ├── Review.css │ │ └── Review.js │ └── Reviews │ │ ├── Reviews.css │ │ └── Reviews.js ├── BloodsPage │ ├── AvailableDonor │ │ └── AvailableDonor.js │ ├── BloodDonate │ │ ├── BloodDonate.css │ │ └── BloodDonate.js │ ├── BloodHome │ │ └── BloodHome.js │ ├── BloodPatient │ │ └── BloodPatient.js │ └── Guidelines │ │ └── Guidelines.js ├── CheckOut │ └── CheckOut │ │ ├── CheckOut.css │ │ └── CheckOut.js ├── CoursesPage │ ├── AllCourses │ │ ├── AllCourses.css │ │ └── AllCourses.js │ ├── CourseDetails │ │ ├── CourseDetails.css │ │ └── CourseDetails.js │ └── SingleCourse │ │ ├── SingleCourse.css │ │ └── SingleCourse.js ├── Dashboard │ ├── AddBlog │ │ └── AddBlog.js │ ├── AddCourse │ │ ├── AddCourse.css │ │ └── AddCourse.js │ ├── AddPlace │ │ └── AddPlace.js │ ├── AddReview │ │ ├── AddReview.css │ │ └── AddReview.js │ ├── AllTransaction │ │ └── AllTransaction.js │ ├── CheckoutForm │ │ └── CheckoutForm.js │ ├── Dashboard │ │ ├── Dashboard.css │ │ └── Dashboard.js │ ├── DashboardHome │ │ └── DashboardHome.js │ ├── ManageCourses │ │ ├── ManageCourses.js │ │ └── UpdateCourse.js │ ├── ManageOrders │ │ └── ManageOrders.js │ ├── ManagePlaces │ │ └── ManagePlaces.js │ ├── Orders │ │ └── Orders.js │ ├── Payment │ │ └── Payment.js │ ├── Users │ │ ├── UserRow.js │ │ └── Users.js │ └── __payment_steps.js ├── EducationBlogsPage │ ├── AllBlogs │ │ └── AllBlogs.js │ ├── BlogDetails │ │ └── BlogDetails.js │ └── SingleBlog │ │ └── SingleBlog.js ├── Home │ ├── Home.css │ └── Home.js ├── Login │ ├── Login │ │ ├── Login.css │ │ └── Login.js │ ├── Register │ │ └── Register.js │ ├── RequireAdmin │ │ └── RequireAdmin.js │ └── RequireAuth │ │ └── RequireAuth.js ├── NotFound │ └── NotFound.js ├── PlaceBooking │ └── PlaceBooking.js └── TravelPage │ ├── AllPlaces │ └── AllPlaces.js │ ├── PlaceDetails │ └── PlaceDetails.js │ └── SinglePlace │ └── SinglePlace.js ├── firebase.init.js ├── hooks ├── useAdmin │ └── useAdmin.js ├── useBlogDetails │ └── useBlogDetails.js ├── useCourseDetails │ └── useCourseDetails.js ├── usePlaceDetails │ └── usePlaceDetails.js └── useToken │ └── useToken.js ├── images ├── best-cook.png ├── blood-concept.jpg ├── delivery-concept.jpg ├── fast-delivery.png ├── logo.png └── review.jpg ├── index.css ├── index.js ├── logo.svg ├── reportWebVitals.js └── setupTests.js /.firebase/hosting.YnVpbGQ.cache: -------------------------------------------------------------------------------- 1 | fakeDB.JSON,1674368028478,8f0974d8ed36739fe0ae4c676b14cc059bc80e83621b9f29c76bdb141b8740e8 2 | favicon.ico,1655560771700,5e12c71418e52a573911a3e5128e1b55e316b5912f8e749f649084d26d4f483b 3 | manifest.json,1655353656276,aff3449bdc238776f5d6d967f19ec491b36aed5fb7f23ccff6500736fd58494a 4 | robots.txt,1655353657779,bfe106a3fb878dc83461c86818bf74fc1bdc7f28538ba613cd3e775516ce8b49 5 | asset-manifest.json,1677191618050,a3639ed21a96467a59ef840556097811861ff6175baaf993f410ca83400974f2 6 | index.html,1677191618050,42469948036246f3bd8687bcba3e3b6aa96e577c2bff4df300629ef44615850e 7 | static/js/787.beb77ff5.chunk.js,1677191618065,864efbac16a80e6f42adeaa335e089695d7873578a88cd006045ebb9cfa16cbe 8 | static/js/787.beb77ff5.chunk.js.map,1677191618081,a49faf1fb700667092e4f4cad92519fb3364e7fccfe2c911b0346534a2a9dcbd 9 | static/js/main.42abb3ac.js.LICENSE.txt,1677191618065,a4bf333c58f9e94274c19b9aee77a652337affee13e747a3e15415ca14c01597 10 | static/media/review.8693276546367883219d.jpg,1677191618065,6e79fc230beb384db59ceec9ebcdf2eb74b2270d4c032860146711b7f4e501bb 11 | static/media/logo.e89c1383872aa95a5c3c.png,1677191618065,0562a877f82e12c660fc14436a6da61e9a7033cda1b7e95fd9d4e0d9e0a06d57 12 | static/css/main.1b79b855.css,1677191618065,84a0931ca3bbd63689f2816ad4b169c4875261b0e9bb961845281eed56985f95 13 | static/css/main.1b79b855.css.map,1677191618065,70d5640db8e98f7e32e4908e761fd3e68797e658c6b7f6bb548d9a853ff89822 14 | static/js/main.42abb3ac.js,1677191618065,d27ed7a5c61cf200210eada1945c8601adf5eeb985821fbed89c6a49b539895a 15 | static/js/main.42abb3ac.js.map,1677191618081,f0f793491a0a04c99915cf052127e7af5378e4dc023690d1406e5762c38b81bd 16 | -------------------------------------------------------------------------------- /.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "agency-97aa4" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 📌Tech Specter An Organization Management Web Application with Daily Needs📌 2 | 3 | It's a web-based application that will help those users who want to make their life easier and secure. User can be getting amazing resources, great source of information for travelers, reading vlogs and most important is blood management in our project, there are lot of services provide which we need in our mechanical life. 4 | 5 | 6 | ## 🚀 Important Links 7 | 8 | - [Live Website- Tech Specter](https://agency-97aa4.web.app/) 9 | - [Project Presentation](https://docs.google.com/presentation/d/1O11rhGDIw7LHqvoPr_UsC3YpMGp1UbJh/edit?usp=share_link&ouid=109756157162586402730&rtpof=true&sd=true) 10 | - [Project Documentation](https://drive.google.com/file/d/1tOQI7dNMEWEoLmJH5NdPcDhLLxtFvLZU/view?usp=share_link) 11 | - [Server Side](https://github.com/shahidmonowarr/tech-specter-server). 12 | 13 | ## 💎 Features : 14 | 15 | 01. Tech Specter is a Fully Responsive website. 16 | 02. Users can purchase different types of courses, can booked travel, can read different types of blogs, and also can checkout availabel donors for blood. 17 | 03. Authentication system is available for both user and admin. 18 | 04. User can add their review and also can see others. 19 | 05. Dashboard is available for both user and admin. 20 | 06. Payment method is included. 21 | 07. Users can view and delete their purchases or bookings also can add reviews. 22 | 08. Admin can make an admin, delete or update services, and approve orders. 23 | 24 | ## 🛠 Front-end Thechnology : 25 | * React.js 26 | * Context-API 27 | * Bootstrap5 28 | * helmet 29 | * Firebase 30 | 31 | ## 🛠 Back-end Thechnology : 32 | * Node.js 33 | * Express.js 34 | * JWT 35 | 36 | ## 🛠 Database : 37 | * MongoDB 38 | 39 | ## 🗃️ Problem Scenario: 40 | Without problem nothing is impossible. All system has some problems. we also face some problems in real life and we will try to solve this. 41 | We can recapitulate a problem here: 42 | * People do not have complete trust in online systems; hence they do not reap the full benefits of these systems. 43 | * There is a manual mechanism for order, but it is all done online. 44 | * Using a variety of platforms may not be sufficient for all user. 45 | The system can be accessed at any time and from any location. This system is highly straightforward and user-friendly; a few examples are: 46 | * There is huge collection of donor. 47 | * Anyone can get blood on time. 48 | * Smart way of appointment. 49 | * Can upload prescription for future 50 | * Reduce cost 51 | * Best courses 52 | * Can know acceptability by rating and many more. 53 | 54 | ## 💡 Challenges: 55 | Reliability and satisfaction is the main factor of a perfect website. Our main challenges are to ensure the reliability and satisfaction to the user. However, choosing a suitable platform and relying on hardware is an important issue. These Projects have been created for the Bangladeshi Patient and Doctors help assistance. 56 | Every job has its own set of difficulties. As a result, we must also face a modest number of challenges. 57 | * Because it's a Web-based system, folks that ought to build appointments and 58 | bookings on-line victimization any web-connected device (computer, laptop, 59 | sensible phone, tablet, etc.) would be unable to try and do so. 60 | * If a user fails to review the notification for confirmation of a booking, the 61 | system's main goal will be failed. 62 | 63 | For this we perfectly maintain those requirements: 64 | 65 | * UI and UX design 66 | * Security 67 | * Performance 68 | * Authorization 69 | * Scalability 70 | 71 | 72 | ## 🔥 Motivation 73 | Suppose I am 52 years old now. Now I like to travel SINGAPORE. I am not familiar with online searching. But now I use this website which can provide best offer gathered by admin. From this scenario, we realize how can it help me. As a student I need to develop my skills and sometimes I need to go to travel for refreshment. That’s all I can get by using this application. Reading blogs is best practice now. It also in our application. The system also has a blood donor module, which allows users to register for blood donations and locate blood groups for future use. One can request for blood, donate blood. Blood for humanity. 74 | 75 | ## ⏳ Conclusion 76 | We successfully constructed our web based application. We tested many times with our browsers and the result is, it works properly. Hope so the user enjoys our service also .The user can handle it so nicely. We connect some users to find the limitations but they enjoy it with good experience. We tried our best and the result is outstanding. 77 | -------------------------------------------------------------------------------- /firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "build", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ], 9 | "rewrites": [ 10 | { 11 | "source": "**", 12 | "destination": "/index.html" 13 | } 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "a-helping-hand-client", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@fortawesome/free-brands-svg-icons": "^6.1.1", 7 | "@fortawesome/react-fontawesome": "^0.1.18", 8 | "@react-google-maps/api": "^2.13.1", 9 | "@stripe/react-stripe-js": "^1.10.0", 10 | "@stripe/stripe-js": "^1.36.0", 11 | "@testing-library/jest-dom": "^5.16.4", 12 | "@testing-library/react": "^13.3.0", 13 | "@testing-library/user-event": "^13.5.0", 14 | "@trendyol-js/react-carousel": "^3.0.0", 15 | "aos": "^3.0.0-beta.6", 16 | "axios": "^0.27.2", 17 | "bootstrap": "^5.1.3", 18 | "emailjs-com": "^3.2.0", 19 | "firebase": "^9.9.3", 20 | "mdb-react-ui-kit": "^4.1.0", 21 | "react": "^18.2.0", 22 | "react-bootstrap": "^2.4.0", 23 | "react-dom": "^18.2.0", 24 | "react-firebase-hooks": "^5.0.3", 25 | "react-helmet-async": "^1.3.0", 26 | "react-hook-form": "^7.34.2", 27 | "react-phone-number-input": "^3.2.13", 28 | "react-query": "^3.39.2", 29 | "react-rating": "^2.0.5", 30 | "react-router-dom": "^6.3.0", 31 | "react-router-hash-link": "^2.4.3", 32 | "react-scripts": "5.0.1", 33 | "react-toastify": "^9.0.8", 34 | "web-vitals": "^2.1.4" 35 | }, 36 | "scripts": { 37 | "start": "react-scripts start", 38 | "build": "react-scripts build", 39 | "test": "react-scripts test", 40 | "eject": "react-scripts eject" 41 | }, 42 | "eslintConfig": { 43 | "extends": [ 44 | "react-app", 45 | "react-app/jest" 46 | ] 47 | }, 48 | "browserslist": { 49 | "production": [ 50 | ">0.2%", 51 | "not dead", 52 | "not op_mini all" 53 | ], 54 | "development": [ 55 | "last 1 chrome version", 56 | "last 1 firefox version", 57 | "last 1 safari version" 58 | ] 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /public/fakeDB.JSON: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "header1": "Develop your career with amazing resources", 4 | "header2": "[Grab your best courses]", 5 | "image": "https://i.ibb.co/jGwSgbH/12145615-Wavy-Edu-05-Single-08-1.jpg", 6 | "name": "Courses", 7 | "subtitle": "For Programmers", 8 | "category1": "Development", 9 | "category2": "Design", 10 | "category3": "Marketing", 11 | "cateImg1": "https://i.ibb.co/0cvg9w4/development.png", 12 | "cateImg2": "https://i.ibb.co/T810YGP/design.png", 13 | "cateImg3": "https://i.ibb.co/FbhLZdp/marketing.png", 14 | "btnText": "View All Courses", 15 | "link": "/allCourses", 16 | "description": "An online learning platform is a web space or portal for educational content and resources that offers a student everything they need in one place: lectures, resources, opportunities to meet and chat with other students, and more." 17 | }, 18 | { 19 | "header1": "Best travel agency websites are a great source of information for travelers.", 20 | "header2": "[We are here for you.]", 21 | "image": "https://i.ibb.co/NSt3xsb/12291290-Wavy-Trv-01-Single-06-1.jpg", 22 | "name": "Travels ", 23 | "subtitle": "For Refreshment", 24 | "category1": "Date Analysis", 25 | "category2": "Pickup Transportation", 26 | "category3": "Tent Benefit", 27 | "cateImg1": "https://i.ibb.co/HhNz1P8/calendar.png", 28 | "cateImg2": "https://i.ibb.co/127QMyq/pickup.png", 29 | "cateImg3": "https://i.ibb.co/YXy5v90/tool.png", 30 | "btnText": "View All Places", 31 | "link": "/allPlaces", 32 | "description": "If a man stays at one place for a long time, he becomes monotonous and his life becomes boring and callous. Traveling removes our monotony and gives pleasure. Similarly, it also broadens our outlook and refreshes our mind. A good traveler can easily educate others." 33 | }, 34 | { 35 | "header1": "Reading blogs will not only keep you updated with information but can help you", 36 | "header2": "[Becoming a great person as well]", 37 | "image": "https://i.ibb.co/ZHDZZtd/12083320-Wavy-Bus-15-Single-06-min.jpg", 38 | "name": "Blogs", 39 | "subtitle": "For Students", 40 | "category1": "Development", 41 | "category2": "Marketing", 42 | "category3": "Health", 43 | "cateImg1": "https://i.ibb.co/0cvg9w4/development.png", 44 | "cateImg2": "https://i.ibb.co/FbhLZdp/marketing.png", 45 | "cateImg3": "https://i.ibb.co/XkK2zF3/health.png", 46 | "btnText": "View All Blogs", 47 | "link": "/allBlogs", 48 | "description": "However, following a positive attitude as well as spreading that rationalist to other people will make your skills more rewarding. This blog will help you in becoming that positivist social butterfly with its everyday tips on how to be a better person as well as how to build stronger skills. Believe me, you will be surprised after reading a few posts." 49 | }, 50 | { 51 | "header1": "Blood donation is a safe process. Patient need blood for their treatment.", 52 | "header2": "[Donate your blood or collect if needed]", 53 | "image": "https://i.ibb.co/BnCpxq5/12146072-Wavy-Lst-04-Single-01-min-1.jpg", 54 | "name": "Bloods", 55 | "subtitle": "For Needy", 56 | "category1": "Blood Donation", 57 | "category2": "Platelet Donation", 58 | "category3": "Plasma Donation", 59 | "cateImg1": "https://i.ibb.co/CQJSGnJ/blood-analysis.png", 60 | "cateImg2": "https://i.ibb.co/S769bW3/blood-bag.png", 61 | "cateImg3": "https://i.ibb.co/qMQxZV0/blood-transfusion.png", 62 | "btnText": "View All Bloods", 63 | "link": "/blood", 64 | "description": "However, following a positive attitude as well as spreading that rationalist to other people will make your skills more rewarding. This blog will help you in becoming that positivist social butterfly with its everyday tips on how to be a better person as well as how to build stronger skills. Believe me, you will be surprised after reading a few posts." 65 | } 66 | ] -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahidmonowarr/tech-specter-client/87077e7335351323a2066924bca851ce0f711bca/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | 15 | 17 | 18 | 19 | 23 | 24 | 33 | TECH SPECTER 34 | 35 | 36 | 37 |
38 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Alfa+Slab+One&family=Bebas+Neue&family=Montserrat&display=swap'); 2 | 3 | .App { 4 | text-align: center; 5 | } 6 | 7 | .App-logo { 8 | height: 40vmin; 9 | pointer-events: none; 10 | } 11 | 12 | @media (prefers-reduced-motion: no-preference) { 13 | .App-logo { 14 | animation: App-logo-spin infinite 20s linear; 15 | } 16 | } 17 | 18 | .App-header { 19 | background-color: #282c34; 20 | min-height: 100vh; 21 | display: flex; 22 | flex-direction: column; 23 | align-items: center; 24 | justify-content: center; 25 | font-size: calc(10px + 2vmin); 26 | color: white; 27 | } 28 | 29 | .App-link { 30 | color: #61dafb; 31 | } 32 | 33 | @keyframes App-logo-spin { 34 | from { 35 | transform: rotate(0deg); 36 | } 37 | to { 38 | transform: rotate(360deg); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /src/Components/Banner/Banner.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&display=swap"); 2 | 3 | body { 4 | font-family: "Poppins", sans-serif !important; 5 | } -------------------------------------------------------------------------------- /src/Components/Banner/Banner.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Link } from "react-router-dom"; 3 | import PageTitle from "../Shared/PageTitle/PageTitle"; 4 | import "./Banner.css"; 5 | const imageUrl = "https://images.unsplash.com/photo-1551434678-e076c223a692?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2850&q=80"; 6 | const Banner = () => { 7 | return ( 8 |
9 |
10 |
11 |
12 | Hello There... 13 |

Find Your

14 |

Solutions Here

15 |

We are providing best solutions here

16 |
17 | Get Started 18 |
19 |
20 |
21 |
22 |
23 | ); 24 | }; 25 | 26 | export default Banner; 27 | -------------------------------------------------------------------------------- /src/Components/Contact/Contact.css: -------------------------------------------------------------------------------- 1 | .contact-img{ 2 | height: 490px; 3 | padding: 10px; 4 | 5 | } 6 | 7 | 8 | .contact-title h2 { 9 | text-transform: uppercase; 10 | font-size: 3rem; 11 | font-weight: 600; 12 | color: #444; 13 | padding-bottom: 20px; 14 | position: relative; 15 | } 16 | 17 | .contact { 18 | 19 | background: #fff; 20 | box-shadow: 0 5px 7px 7px #c9dff0; 21 | min-height: 240px; 22 | padding: 0 10px 10px; 23 | border-radius: 20px; 24 | border: 0; 25 | margin-bottom: 30px; 26 | } -------------------------------------------------------------------------------- /src/Components/Contact/Contact.js: -------------------------------------------------------------------------------- 1 | import emailjs from 'emailjs-com'; 2 | import React from "react"; 3 | import { Button, Col, Form, Row } from "react-bootstrap"; 4 | import "./Contact.css"; 5 | 6 | const Contact = () => { 7 | const sendEmail = (e) => { 8 | e.preventDefault(); 9 | 10 | emailjs.sendForm('service_j5ax74i', 'template_r30vlp2', e.target, 'user_D6NRRRQqBmKlFFSRdDwrA') 11 | .then((result) => { 12 | console.log(result.text); 13 | }, (error) => { 14 | console.log(error.text); 15 | }); 16 | e.target.reset(); 17 | }; 18 | return ( 19 |
20 |
21 |
22 |
23 |

24 | Contact Us 25 |

Feel free to Contact!

26 |

27 |
28 | 29 |
30 |
31 |
32 | 39 |
40 |
41 |
42 |

43 | Drop 44 | 45 | {" "} 46 | us a Message{" "} 47 | 48 |

49 |

We'd Love To Hear From You

50 | 51 |
52 |
53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | We'll never share your email with anyone else. 63 | 64 | 65 | 66 | 70 | 76 | 77 | 80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 | ); 88 | }; 89 | 90 | export default Contact; 91 | -------------------------------------------------------------------------------- /src/Components/OfferServices/OfferServices.css: -------------------------------------------------------------------------------- 1 | .offer-button{ 2 | background-color: #D11F1F; 3 | font-weight: 500; 4 | border: none; 5 | } 6 | .offer-button:hover{ 7 | background-color: #850101; 8 | } 9 | .offer-button a{ 10 | text-decoration: none; 11 | color: #fff; 12 | } 13 | 14 | .spec{ 15 | display:flex; 16 | gap: 3; 17 | align-items: center; 18 | } 19 | .spec img{ 20 | width: 45px; 21 | } 22 | 23 | .offer-wrapper::before{ 24 | content: ''; 25 | left: 0; 26 | top: 0; 27 | z-index: -1; 28 | position: absolute; 29 | width: 210px; 30 | height: 180px; 31 | background-color: #d72323; 32 | } 33 | .offer-wrapper{ 34 | padding: 20px 60px 60px 20px; 35 | position: relative; 36 | z-index: 1; 37 | } 38 | .offer-wrapper::after{ 39 | content: ''; 40 | right: 0; 41 | bottom: 0; 42 | z-index: -1; 43 | position: absolute; 44 | width: 40%; 45 | height: 60%; 46 | } 47 | 48 | .offer-info::after{ 49 | position: absolute; 50 | right: 0; 51 | top: -30px; 52 | content: ''; 53 | z-index: 0; 54 | width: 0; 55 | height: 0; 56 | border-bottom: 30px solid #801414; 57 | border-right: 20px solid transparent; 58 | box-sizing: border-box; 59 | } 60 | .offer-info{ 61 | position: absolute; 62 | text-align: right; 63 | bottom: 20px; 64 | right: 20px; 65 | background-color: #d72323; 66 | padding: 10px; 67 | } 68 | .offer-info span{ 69 | font-size: 50px; 70 | font-weight: 700; 71 | color: #fff; 72 | line-height: 60px; 73 | display: block; 74 | } 75 | .offer-info strong{ 76 | font-size: 20px; 77 | line-height: 30px; 78 | text-transform: capitalize; 79 | font-weight: 700; 80 | display: block; 81 | color: #fff; 82 | letter-spacing: 0; 83 | } 84 | 85 | .dash{ 86 | height: 4px; 87 | width: 30px; 88 | background: #d72323; 89 | } 90 | 91 | .vert-move { 92 | -webkit-animation: mover 1.5s infinite alternate; 93 | animation: mover 1.5s infinite alternate; 94 | } 95 | .vert-move { 96 | -webkit-animation: mover 1.5s infinite alternate; 97 | animation: mover 1.5s infinite alternate; 98 | } 99 | @-webkit-keyframes mover { 100 | 0% { transform: translateY(20px); } 101 | 100% { transform: translateY(-10px); } 102 | } 103 | @keyframes mover { 104 | 0% { transform: translateY(20px); } 105 | 100% { transform: translateY(-10px); } 106 | } -------------------------------------------------------------------------------- /src/Components/OfferServices/OfferServices.js: -------------------------------------------------------------------------------- 1 | import Aos from "aos"; 2 | import "aos/dist/aos.css"; 3 | import React, { useEffect, useState } from "react"; 4 | import { Button, Col, Container, Row } from "react-bootstrap"; 5 | import { Link } from "react-router-dom"; 6 | import "./OfferServices.css"; 7 | 8 | const OfferServices = () => { 9 | const [services, setServices] = useState([]); 10 | 11 | useEffect(() => { 12 | Aos.init({ duration: 500 }); 13 | }, []); 14 | 15 | useEffect(() => { 16 | fetch("fakeDB.JSON") 17 | .then((res) => res.json()) 18 | .then((data) => { 19 | setServices(data); 20 | // console.log(data); 21 | }); 22 | }, []); 23 | return ( 24 |
25 |
26 |

27 | Services 28 |

What we provide to you!

29 |

30 |
31 | 32 | 33 | {services.map((service) => ( 34 | 35 | 36 | 37 | 38 |
39 |
40 | 45 |
46 |
47 | {service.name} 48 | {service.subtitle} 49 |
50 |
51 | 52 | 53 | 54 |
55 |
56 |
57 |
About
58 |
59 |

60 | {service.header1} 61 |
{service.header2} 62 |

63 |

{service.description}

64 |
65 | 66 |
{service.category1}
67 |
68 |
69 | 70 |
{service.category2}
71 |
72 |
73 | 74 |
{service.category3}
75 |
76 |
77 | 78 | 81 | 82 |
83 |
84 | 85 |
86 |
87 | ))} 88 |
89 |
90 | ); 91 | }; 92 | 93 | export default OfferServices; 94 | -------------------------------------------------------------------------------- /src/Components/OurPartners/OurPartners.css: -------------------------------------------------------------------------------- 1 | .brands{ 2 | display: flex; 3 | align-items: center; 4 | justify-content: space-evenly; 5 | } 6 | .brand img{ 7 | width: 100%; 8 | cursor: pointer; 9 | } -------------------------------------------------------------------------------- /src/Components/OurPartners/OurPartners.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Container } from 'react-bootstrap'; 3 | import './OurPartners.css'; 4 | 5 | const OurPartners = () => { 6 | return ( 7 |
8 | 9 |
10 |

11 | Our Partners 12 |

We are with!

13 |

14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | 24 |
25 | ); 26 | }; 27 | 28 | export default OurPartners; -------------------------------------------------------------------------------- /src/Components/Shared/BackToTop/BackToTop.css: -------------------------------------------------------------------------------- 1 | .scroll-top{ 2 | position: fixed; 3 | bottom: 30px; 4 | right: 12px; 5 | height: 30px; 6 | width: 30px; 7 | color: rgb(53, 14, 14); 8 | background-color: rgb(185, 185, 154); 9 | z-index: 10; 10 | border-radius: 50%; 11 | border: none; 12 | padding-top: 5px; 13 | font-size: larger; 14 | font-weight: 900; 15 | } 16 | 17 | .scroll-top:hover{ 18 | background-color: black; 19 | color: white; 20 | transition: all 0.5s; 21 | } 22 | 23 | .scroll-top { 24 | -webkit-animation: mover 1.5s infinite alternate; 25 | animation: mover 1.5s infinite alternate; 26 | } 27 | .scroll-top { 28 | -webkit-animation: mover 1.5s infinite alternate; 29 | animation: mover 1.5s infinite alternate; 30 | } 31 | @-webkit-keyframes mover { 32 | 0% { transform: translateY(5px); } 33 | 100% { transform: translateY(-5px); } 34 | } 35 | @keyframes mover { 36 | 0% { transform: translateY(5px); } 37 | 100% { transform: translateY(-5px); } 38 | } -------------------------------------------------------------------------------- /src/Components/Shared/BackToTop/BackToTop.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react'; 2 | import "./BackToTop.css"; 3 | 4 | const BackToTop = () => { 5 | const [backToTopBtn, setBackToTopBtn] = useState(false); 6 | 7 | useEffect(() => { 8 | window.addEventListener("scroll", () => { 9 | if(window.scrollY > 100){ 10 | setBackToTopBtn(true); 11 | } 12 | else{ 13 | setBackToTopBtn(false); 14 | } 15 | }) 16 | }, []); 17 | 18 | const scrollUp = () => { 19 | window.scrollTo({ 20 | top:0, 21 | behavior: "smooth" 22 | }) 23 | } 24 | return ( 25 |
26 | {backToTopBtn && ( 27 | 31 | )} 32 |
33 | ); 34 | }; 35 | 36 | export default BackToTop; -------------------------------------------------------------------------------- /src/Components/Shared/Footer/Footer.css: -------------------------------------------------------------------------------- 1 | .footer-logo img{ 2 | width: 80%; 3 | height: auto; 4 | } 5 | -------------------------------------------------------------------------------- /src/Components/Shared/Footer/Footer.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Link } from "react-router-dom"; 3 | import logo from "../../../images/logo.png"; 4 | import "./Footer.css"; 5 | 6 | const Footer = () => { 7 | return ( 8 |
9 |
10 |
14 |
18 |
19 | Get connected with us on social networks: 20 |
21 | 22 | 45 |
46 | 47 |
48 |
49 |
50 |
51 |
Company name
52 |
60 |
61 | footer 62 |
63 |
64 |
65 |
Services
66 |
74 | 75 |

Courses

76 | 77 | 78 |

Travels

79 | 80 | 81 |

Blogs

82 | 83 | 84 |

Bloods

85 | 86 |
87 | 88 |
89 |
Useful links
90 |
98 | 99 |

Dashboard

100 | 101 | 102 |

About Us

103 | 104 | 105 |

Privacy Policy

106 | 107 | 108 |

FAQ

109 | 110 |
111 | 112 |
113 |
Contact
114 |
122 |

123 | Dhaka, PT 2323, BD 124 |

125 |

126 | shahid@gmail.com 127 |

128 |

129 | + 01 737 149 954 130 |

131 |

132 | + 01 704 894 643 133 |

134 |
135 |
136 |
137 |
138 | {/* Section: Links */} 139 | 140 | {/* Copyright */} 141 |
145 | © 2023 Copyright Tech Specter 146 |
147 |
148 |
149 |
150 | ); 151 | }; 152 | 153 | export default Footer; 154 | -------------------------------------------------------------------------------- /src/Components/Shared/Header/Header.css: -------------------------------------------------------------------------------- 1 | 2 | .logo img{ 3 | width: 135px; 4 | height: auto; 5 | } 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/Components/Shared/Header/Header.js: -------------------------------------------------------------------------------- 1 | import { signOut } from "firebase/auth"; 2 | import React from "react"; 3 | import { Button, Container, Nav, Navbar, NavDropdown } from "react-bootstrap"; 4 | import { useAuthState } from "react-firebase-hooks/auth"; 5 | import { HashLink } from "react-router-hash-link"; 6 | import auth from "../../../firebase.init"; 7 | import logo from "../../../images/logo.png"; 8 | import "./Header.css"; 9 | 10 | const Header = () => { 11 | const [user] = useAuthState(auth); 12 | 13 | const logOut = () => { 14 | signOut(auth); 15 | localStorage.removeItem("accessToken"); 16 | }; 17 | 18 | return ( 19 | 25 | 26 | 27 |
28 | logo 29 |
30 |
31 | 42 | 64 |
65 |
66 | ); 67 | }; 68 | 69 | export default Header; 70 | -------------------------------------------------------------------------------- /src/Components/Shared/Loading/Loading.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Spinner } from 'react-bootstrap'; 3 | 4 | const Loading = () => { 5 | return ( 6 |
7 | ; 8 |
9 | ); 10 | }; 11 | 12 | export default Loading; -------------------------------------------------------------------------------- /src/Components/Shared/PageTitle/PageTitle.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Helmet } from 'react-helmet-async'; 3 | 4 | const PageTitle = ({title}) => { 5 | return ( 6 | 7 | {title} - Tech Specter 8 | 9 | ); 10 | }; 11 | 12 | export default PageTitle; -------------------------------------------------------------------------------- /src/Optional/AboutUs.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Accordion, Container } from 'react-bootstrap'; 3 | import PageTitle from '../Components/Shared/PageTitle/PageTitle'; 4 | 5 | const AboutUs = () => { 6 | return ( 7 | 8 | 9 |
10 |

11 | About Us 12 |

About Tech specter!

13 |

14 |
15 | 16 | 17 | Overview 18 | 19 | Our website address is: https://techspecter.com. This privacy policy is for this website and served by Tech specter and governs the privacy of its users who choose to use it. The policy sets out the different areas where user privacy is concerned and outlines the obligations & requirements of the users, the website and website owners. Furthermore the way this website processes, stores and protects user data and information will also be detailed within this policy. 20 | 21 | 22 | 23 | Refunds 24 | 25 | Our refund and returns policy lasts 30 days. If 30 days have passed since your purchase, we can't offer you a full refund or exchange. To be eligible for a return, your item must be unused and in the same condition that you received it. It must also be in the original packaging. To complete your return, we require a receipt or proof of purchase. Please do not send your purchase back to the manufacturer. There are certain situations where only partial refunds are granted (if applicable). 26 | 27 | 28 | 29 | Privacy policy amendment 30 | 31 | We may amend or update this policy from time to time and will notify you of any material changes to this policy. Previous versions of this privacy policy are available upon request. We encourage you to periodically review this page for the latest information on our privacy practices. Your continued use of the Site after any changes or revisions to this Privacy Policy shall indicate your agreement with the terms of such revised Privacy Policy. 32 | 33 | 34 | 35 |
36 | ); 37 | }; 38 | 39 | export default AboutUs; -------------------------------------------------------------------------------- /src/Optional/Faq.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Accordion, Container } from 'react-bootstrap'; 3 | import PageTitle from '../Components/Shared/PageTitle/PageTitle'; 4 | 5 | const Faq = () => { 6 | return ( 7 | 8 | 9 |
10 |

11 | FAQ 12 |

Frequently Asked Questions!

13 |

14 |
15 | 16 | 17 | How do I get started on Tech specter? 18 | 19 | After entering to the website you can visit the home page and see the services we provide to the customers. You can also see the reviews of the customers. If you want to buy a product you can go to the service page and select the product you want to buy. After selecting the product you can add it to the cart and then you can proceed to checkout. After checkout you can pay the amount and then you can get the product. 20 | 21 | 22 | 23 | Are there any extra fees? 24 | 25 | We just charge the amount of the product you buy. There are no extra fees. We also provide free shipping to our customers. 26 | 27 | 28 | 29 | Do you offer any other services? 30 | 31 | Yes, we offer other services like web development, web design, software development, software design, mobile app development, mobile app design, digital marketing etc. You can visit our service page to see the services we offer. Also you can visit our blog page to see the blogs we write. You can also visit our contact page to contact us. You can also visit our about page to know more about us. You can also visit our FAQ page to see the frequently asked questions. You can also visit our privacy policy page to see our privacy policy. 32 | 33 | 34 | 35 | Can I make changes to an order I already placed? 36 | 37 | Yes, you can make changes to an order you already placed if you not yet paid. So You can contact us within 24 hours of placing the order. If you contact us after 24 hours, we will not be able to make any changes to your order. 38 | 39 | 40 | 41 | Where Is my Order? 42 | 43 | Please visit the My Orders page to the dashboard for a list of your confirmed orders. You can also check the status of your order by clicking on the order number. If you have any questions about your order, please contact us. 44 | 45 | 46 | 47 | Where are You Located? 48 | 49 | Mirpur DOHS, Dhaka North, Mirpur Thana of Dhaka City. The Neighborhood is located close to Mirpur Cantonment. The Postal Code of Mirpur DOHS is 1216. 50 | 51 | 52 | 53 |
54 | ); 55 | }; 56 | 57 | export default Faq; -------------------------------------------------------------------------------- /src/Optional/PrivacyPolicy.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Accordion, Container } from 'react-bootstrap'; 3 | import PageTitle from '../Components/Shared/PageTitle/PageTitle'; 4 | 5 | const PrivacyPolicy = () => { 6 | return ( 7 | 8 | 9 |
10 |

11 | Privacy Policy 12 |

Terms and conditions of Tech specter!

13 |

14 |
15 | 16 | 17 | Overview 18 | 19 | Our website address is: https://techspecter.com. This privacy policy is for this website and served by Tech specter and governs the privacy of its users who choose to use it. The policy sets out the different areas where user privacy is concerned and outlines the obligations & requirements of the users, the website and website owners. Furthermore the way this website processes, stores and protects user data and information will also be detailed within this policy. 20 | 21 | 22 | 23 | Consent 24 | 25 | By using our website, you hereby consent to our Privacy Policy and agree to its terms. This Privacy Policy applies only to our online activities and is valid for visitors to our website with regards to the information that they shared and/or collect in Tech specter. This policy is not applicable to any information collected offline or via channels other than this website. 26 | 27 | 28 | 29 | Information We Collect 30 | 31 | The personal information that you are asked to provide, and the reasons why you are asked to provide it, will be made clear to you at the point we ask you to provide your personal information. 32 | 33 | If you contact us directly, we may receive additional information about you such as your name, email address, phone number, the contents of the message and/or attachments you may send us, and any other information you may choose to provide. 34 | 35 | When you register for an Account, we may ask for your contact information, including items such as name, address, email address, and telephone number. 36 | 37 | 38 | 39 | How We use your Information 40 | 41 |
    42 |
  • Provide, operate, and maintain our website
  • 43 |
  • Improve, personalize, and expand our website
  • 44 |
  • Understand and analyze how you use our website
  • 45 |
  • Develop new products, services, features, and functionality
  • 46 |
  • Send you emails
  • 47 |
  • Find and prevent fraud
  • 48 |
49 |
50 |
51 | 52 | Refunds 53 | 54 | Our refund and returns policy lasts 30 days. If 30 days have passed since your purchase, we can't offer you a full refund or exchange. To be eligible for a return, your item must be unused and in the same condition that you received it. It must also be in the original packaging. To complete your return, we require a receipt or proof of purchase. Please do not send your purchase back to the manufacturer. There are certain situations where only partial refunds are granted (if applicable). 55 | 56 | 57 | 58 | Cookies and Web Beacons 59 | 60 | Like any other website, One Tech specter uses 'cookies'. These cookies are used to store information including visitors preferences, and the pages on the website that the visitor accessed or visited. The information is used to optimize the users experience by customizing our web page content based on visitors browser type and/or other information. 61 | 62 | 63 |
64 |
65 | ); 66 | }; 67 | 68 | export default PrivacyPolicy; -------------------------------------------------------------------------------- /src/Pages/AllReviews/Review/Review.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahidmonowarr/tech-specter-client/87077e7335351323a2066924bca851ce0f711bca/src/Pages/AllReviews/Review/Review.css -------------------------------------------------------------------------------- /src/Pages/AllReviews/Review/Review.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Card, Col } from 'react-bootstrap'; 3 | import Rating from 'react-rating'; 4 | import img1 from '../../../images/review.jpg'; 5 | import './Review.css'; 6 | 7 | const Review = ({review}) => { 8 | const { name, description, rating } = review; 9 | return ( 10 | 11 | 12 | 13 | 14 |
15 | {name} 16 |
17 |
18 | Rating: 19 | {" "} 26 | {rating} 27 |
28 | {description?.slice(0, 140)} 29 |
30 |
31 | 32 | ); 33 | }; 34 | 35 | export default Review; -------------------------------------------------------------------------------- /src/Pages/AllReviews/Reviews/Reviews.css: -------------------------------------------------------------------------------- 1 | .reviews { 2 | /* background: aliceblue; */ 3 | height: auto; 4 | } 5 | 6 | .reviews > div { 7 | position: relative; 8 | margin-top: 30px; 9 | } 10 | 11 | 12 | .review-title h2 { 13 | font-size: 2rem; 14 | font-weight: 600; 15 | color: #444; 16 | padding-bottom: 20px; 17 | position: relative; 18 | } 19 | 20 | .review-title { 21 | text-align: center; 22 | } 23 | 24 | .reviews .card { 25 | background: #fff; 26 | box-shadow: 0 8px 30px 7px #c9dff0; 27 | min-height: 340px; 28 | padding: 0 10px 10px; 29 | border-radius: 20px; 30 | border: 0; 31 | } 32 | 33 | .reviews .card h5 { 34 | color: #ed5217; 35 | font-weight: 800; 36 | font-size: 24px; 37 | line-height: 1.3; 38 | } 39 | 40 | .reviews .card h5 span { 41 | font-size: 18px; 42 | color: #666666; 43 | } 44 | 45 | .reviews .card p { 46 | font-size: 18px; 47 | color: #777; 48 | padding-bottom: 15px; 49 | } 50 | 51 | .reviews .card .img-top { 52 | max-width: 100px; 53 | border-radius: 50%; 54 | margin: 15px auto 0; 55 | box-shadow: 0 8px 20px -4px #95abbb; 56 | width: 100px; 57 | height: 100px; 58 | } -------------------------------------------------------------------------------- /src/Pages/AllReviews/Reviews/Reviews.js: -------------------------------------------------------------------------------- 1 | import { Toast } from 'bootstrap'; 2 | import React, { useEffect, useState } from 'react'; 3 | import { Card, Row, Spinner } from "react-bootstrap"; 4 | import Review from '../Review/Review'; 5 | import './Reviews.css'; 6 | 7 | 8 | const Reviews = () => { 9 | const [loading, setLoading] = useState(true); 10 | const [reviews, setReviews]=useState(); 11 | useEffect(() => { 12 | fetch("https://tech-specter.onrender.com/reviews") 13 | .then((res) => res.json()) 14 | .then((data) => { 15 | setReviews(data); 16 | setLoading(false); 17 | }) 18 | .catch((error) => Toast.error(error.message)); 19 | }, []); 20 | 21 | const filteredReviews = reviews?.filter( 22 | (review) => review.category === "website" 23 | ); 24 | 25 | return ( 26 |
31 | 32 |
33 |
34 |

35 | Review 36 |

What our client say!

37 |

38 |
39 | {loading ? ( 40 |
41 | 42 |
43 | ) : ( 44 | 45 | 46 | {filteredReviews?.map((review) => ( 47 | 48 | ))} 49 | 50 | 51 | )} 52 |
53 |
54 | ); 55 | }; 56 | 57 | export default Reviews; -------------------------------------------------------------------------------- /src/Pages/BloodsPage/AvailableDonor/AvailableDonor.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import { Pagination, Table, Toast } from "react-bootstrap"; 3 | 4 | const AvailableDonor = () => { 5 | const pageSize = 5; 6 | const [currentPage, setCurrentPage] = useState(1); 7 | const [donors, setDonors] = useState([]); 8 | 9 | useEffect(() => { 10 | fetch("https://tech-specter.onrender.com/blood") 11 | .then((res) => res.json()) 12 | .then((data) => { 13 | // console.log(data); 14 | setDonors(data); 15 | }) 16 | .catch((error) => Toast.error(error.message)); 17 | }, []); 18 | 19 | const totalPages = Math.ceil(donors.length / pageSize); 20 | const startIndex = (currentPage - 1) * pageSize; 21 | const endIndex = startIndex + pageSize; 22 | const currentDonors = donors.slice(startIndex, endIndex); 23 | 24 | const handlePageChange = (pageNumber) => { 25 | setCurrentPage(pageNumber); 26 | }; 27 | 28 | return ( 29 |
30 |
31 |
32 |
33 | Available Donor List [Total {currentDonors.length}] 34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | {currentDonors.map((donor, index) => ( 49 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | ))} 63 | 64 |
IndexDonor NameDonor EmailPhone No.Blood GroupLast Donate DateAddress
{startIndex + index + 1}{donor.name}{donor.email}{donor.phone}{donor.bloodGroup}{donor.lastBloodDonateDate}{donor.address}
65 |
66 | 67 | handlePageChange(1)} disabled={currentPage === 1} /> 68 | handlePageChange(currentPage - 1)} disabled={currentPage === 1} /> 69 | {Array.from({ length: totalPages }, (_, i) => ( 70 | handlePageChange(i + 1)}> 71 | {i + 1} 72 | 73 | ))} 74 | handlePageChange(currentPage + 1)} disabled={currentPage === totalPages} /> 75 | handlePageChange(totalPages)} disabled={currentPage === totalPages} /> 76 | 77 |
78 |
79 |
80 |
81 | ); 82 | }; 83 | 84 | export default AvailableDonor; 85 | -------------------------------------------------------------------------------- /src/Pages/BloodsPage/BloodDonate/BloodDonate.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahidmonowarr/tech-specter-client/87077e7335351323a2066924bca851ce0f711bca/src/Pages/BloodsPage/BloodDonate/BloodDonate.css -------------------------------------------------------------------------------- /src/Pages/BloodsPage/BloodDonate/BloodDonate.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import React from "react"; 3 | import { useAuthState } from "react-firebase-hooks/auth"; 4 | import { useForm } from "react-hook-form"; 5 | import "react-phone-number-input/style.css"; 6 | import { toast } from "react-toastify"; 7 | import auth from "../../../firebase.init"; 8 | import "./BloodDonate.css"; 9 | 10 | const BloodDonate = () => { 11 | const { 12 | register, 13 | handleSubmit, 14 | reset, 15 | formState: { errors }, 16 | } = useForm(); 17 | const [user] = useAuthState(auth); 18 | const onSubmit = (data) => { 19 | // console.log(data); 20 | axios.post("https://tech-specter.onrender.com/blood", data).then((res) => { 21 | if (res.data.insertedId) { 22 | toast("Details Added Successfully, We will contact you soon"); 23 | reset(); 24 | } 25 | // console.log(res); 26 | }); 27 | }; 28 | return ( 29 |
30 |
31 | {/* Material form register */} 32 |
33 |
34 | Blood Donor Registration 35 |
36 | 37 | {/* */} 38 |
39 | {/* */} 40 |
41 |
42 |
43 |
44 | 50 | 51 |
52 |
53 |
54 |
55 | 61 | 62 |
63 |
64 |
65 | 66 |
67 |
68 |
69 | 86 | 98 | 99 |
100 |
101 |
102 |
103 | 109 | 110 |
111 |
112 |
113 | 114 |
115 |
116 |
117 | 124 | 127 |
128 |
129 |
130 |
131 | 147 | 148 |
149 |
150 |
151 | 152 |
153 | 160 | 161 |
162 | 168 |
169 | {/* */} 170 |
171 |
172 |
173 |
174 | ); 175 | }; 176 | 177 | export default BloodDonate; 178 | -------------------------------------------------------------------------------- /src/Pages/BloodsPage/BloodHome/BloodHome.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Button, ButtonGroup, Container } from "react-bootstrap"; 3 | import { Link, Outlet } from "react-router-dom"; 4 | import PageTitle from "../../../Components/Shared/PageTitle/PageTitle"; 5 | 6 | const BloodHome = () => { 7 | return ( 8 | <> 9 | 10 | 11 |

12 | Available Blood Donor 13 |

14 |

15 | Donate Your Blood to Us, Save More Life Together 16 |

17 | 18 | 19 | 23 | 26 | 27 | 31 | 34 | 35 | 39 | 42 | 43 | 47 | 50 | 51 | 52 | 53 | 54 |
55 | 56 | ); 57 | }; 58 | 59 | export default BloodHome; 60 | -------------------------------------------------------------------------------- /src/Pages/BloodsPage/BloodPatient/BloodPatient.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import React from "react"; 3 | import { useAuthState } from "react-firebase-hooks/auth"; 4 | import { useForm } from "react-hook-form"; 5 | import { toast } from "react-toastify"; 6 | import auth from "../../../firebase.init"; 7 | 8 | const BloodPatient = () => { 9 | const [user] = useAuthState(auth); 10 | const { register, handleSubmit, reset, formState: { errors } } = useForm(); 11 | 12 | const onSubmit = (data) => { 13 | // console.log(data); 14 | axios.post("https://tech-specter.onrender.com/patient", data).then((res) => { 15 | if (res.data.insertedId) { 16 | toast("Request Added Successfully, We will contact you soon"); 17 | reset(); 18 | } 19 | // console.log(res); 20 | }); 21 | }; 22 | 23 | return ( 24 |
25 |
26 | {/* Material form register */} 27 |
28 |
29 | Patient Request Registration 30 |
31 | 32 | {/* */} 33 |
34 | {/* */} 35 |
36 |
37 |
38 |
39 | 45 | 46 |
47 |
48 |
49 |
50 | 56 | 57 |
58 |
59 |
60 | 61 |
62 |
63 |
64 | 80 | 92 | 93 |
94 |
95 |
96 |
97 | 103 | 104 |
105 |
106 |
107 | 108 |
109 |
110 |
111 | 118 | 121 |
122 |
123 |
124 |
125 | 141 | 142 |
143 |
144 |
145 | 146 |
147 | 154 | 155 |
156 | 162 |
163 | {/* */} 164 |
165 |
166 |
167 |
168 | ); 169 | }; 170 | 171 | export default BloodPatient; 172 | -------------------------------------------------------------------------------- /src/Pages/BloodsPage/Guidelines/Guidelines.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Card, Container } from "react-bootstrap"; 3 | 4 | const Guidelines = () => { 5 | return ( 6 | 7 | 8 | 9 | 13 | Read This Blog About Blood Donation 14 | 15 | 16 | Blood donation is a selfless act that can save the lives of 17 | countless people in need. It is a simple and quick process that has 18 | the potential to make a huge difference in the lives of others. 19 | 20 | 21 |
Why people donate Blood:
22 |
23 | There are several reasons why people donate blood. Some do it to 24 | give back to their community, while others do it to help a loved one 25 | in need. No matter the reason, the act of donating blood is a noble 26 | and selfless one that can have a profound impact on the lives of 27 | others. 28 |
29 | 30 |
Process of Blood donating:
31 |
32 | The process of donating blood is relatively simple. First, you will 33 | need to find a blood donation center or blood drive in your area. 34 | Many hospitals, community centers, and other organizations host 35 | blood drives on a regular basis. Once you have found a location, you 36 | will need to make an appointment to donate. 37 |
38 | 39 |
Medical Checkup:
40 |
41 | Before donating blood, you will need to fill out a medical 42 | questionnaire to ensure that you are eligible to donate. There are 43 | certain medical conditions and medications that can disqualify you 44 | from donating blood. It is important to be honest and upfront about 45 | your medical history to ensure the safety of both the donor and the 46 | recipient. 47 |
48 | 49 |
On the day of your appointment:
50 |
51 | On the day of your appointment, you will need to arrive at the blood 52 | donation center a few minutes early to check in. You will be asked 53 | to provide identification and to complete a few more forms. Next, 54 | you will undergo a mini-physical, which will include checking your 55 | pulse, blood pressure, and hemoglobin levels. This is to ensure that 56 | you are healthy enough to donate blood. 57 |
58 | 59 |
What you have to do:
60 |
61 | Once you have been cleared to donate, you will be taken to a private 62 | room where the actual blood donation will take place. A trained 63 | phlebotomist will insert a sterile needle into a vein in your arm 64 | and collect the blood. The entire process takes about 10-15 minutes 65 | and is relatively painless. 66 |
67 | 68 |
What you have to do:
69 |
70 | Once you have been cleared to donate, you will be taken to a private 71 | room where the actual blood donation will take place. A trained 72 | phlebotomist will insert a sterile needle into a vein in your arm 73 | and collect the blood. The entire process takes about 10-15 minutes 74 | and is relatively painless. After the blood has been collected, you 75 | will be given a snack and encouraged to relax for a few minutes 76 | before leaving. It is important to drink plenty of fluids and avoid 77 | strenuous activity for the rest of the day. Most people are able to 78 | return to their normal activities the next day. 79 |
80 | 81 |
Benefits to donating Blood:
82 |
83 | There are many benefits to donating blood. In addition to helping 84 | others, it can also have a positive impact on your own health. 85 | Donating blood can help lower your risk of heart disease and can 86 | also stimulate the production of new red blood cells, which can help 87 | improve your overall health and well-being. 88 |
89 | 90 | It is important to note that there is a constant need for blood 91 | donations. Blood is a perishable product and must be constantly 92 | replenished. By donating blood, you can help ensure that there is a 93 | sufficient supply of blood available for those in need. 94 | 95 | 96 | In conclusion, donating blood is a simple and selfless act that can 97 | save the lives of countless people. If you are eligible to donate, 98 | consider making an appointment to give blood today. You never know 99 | when you or someone you love may need a blood transfusion, and by 100 | donating blood, you can help ensure that there is a sufficient 101 | supply available for those in need. 102 | 103 |
104 |
105 |
106 | ); 107 | }; 108 | 109 | export default Guidelines; 110 | -------------------------------------------------------------------------------- /src/Pages/CheckOut/CheckOut/CheckOut.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;700;900&display=swap'); 2 | 3 | 4 | .form-holder { 5 | display: flex; 6 | flex-direction: column; 7 | justify-content: center; 8 | align-items: center; 9 | text-align: center; 10 | min-height: 60vh; 11 | 12 | } 13 | 14 | .form-holder .form-content { 15 | position: relative; 16 | text-align: center; 17 | display: -webkit-box; 18 | display: -moz-box; 19 | display: -ms-flexbox; 20 | display: -webkit-flex; 21 | display: flex; 22 | -webkit-justify-content: center; 23 | justify-content: center; 24 | -webkit-align-items: center; 25 | align-items: center; 26 | padding: 5px; 27 | } 28 | 29 | .form-content .form-items { 30 | background-color: #495056; 31 | border: 3px solid #fff; 32 | padding: 40px; 33 | display: inline-block; 34 | width: 100%; 35 | min-width: 360px; 36 | -webkit-border-radius: 10px; 37 | -moz-border-radius: 10px; 38 | border-radius: 10px; 39 | text-align: left; 40 | -webkit-transition: all 0.4s ease; 41 | transition: all 0.4s ease; 42 | } 43 | 44 | .form-content h3 { 45 | color: #fff; 46 | text-align: left; 47 | font-size: 28px; 48 | font-weight: 600; 49 | margin-bottom: 5px; 50 | } 51 | 52 | .form-content p { 53 | color: #fff; 54 | text-align: left; 55 | font-size: 17px; 56 | font-weight: 300; 57 | line-height: 20px; 58 | margin-bottom: 30px; 59 | } 60 | 61 | .form-content input{ 62 | width: 100%; 63 | padding: 9px 20px; 64 | text-align: left; 65 | border: 0; 66 | outline: 0; 67 | border-radius: 6px; 68 | background-color: #fff; 69 | font-size: 15px; 70 | font-weight: 300; 71 | color: #8D8D8D; 72 | -webkit-transition: all 0.3s ease; 73 | transition: all 0.3s ease; 74 | margin-top: 16px; 75 | } 76 | 77 | 78 | .submit{ 79 | background-color: #6C757D; 80 | outline: none; 81 | border: 0px; 82 | box-shadow: none; 83 | } 84 | 85 | .submit:hover, .submit:focus, .submit:active{ 86 | background-color: #495056; 87 | outline: none !important; 88 | border: none !important; 89 | box-shadow: none; 90 | } 91 | 92 | .form-content textarea { 93 | position: static !important; 94 | width: 100%; 95 | padding: 8px 20px; 96 | border-radius: 6px; 97 | text-align: left; 98 | background-color: #fff; 99 | border: 0; 100 | font-size: 15px; 101 | font-weight: 300; 102 | color: #8D8D8D; 103 | outline: none; 104 | resize: none; 105 | height: 120px; 106 | -webkit-transition: none; 107 | transition: none; 108 | margin-bottom: 14px; 109 | } 110 | 111 | .form-content textarea:hover, .form-content textarea:focus { 112 | border: 0; 113 | background-color: #ebeff8; 114 | color: #8D8D8D; 115 | } 116 | -------------------------------------------------------------------------------- /src/Pages/CheckOut/CheckOut/CheckOut.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import React from "react"; 3 | import { Container } from "react-bootstrap"; 4 | import { useAuthState } from "react-firebase-hooks/auth"; 5 | import { useNavigate, useParams } from "react-router-dom"; 6 | import { toast } from 'react-toastify'; 7 | import PageTitle from "../../../Components/Shared/PageTitle/PageTitle"; 8 | import auth from "../../../firebase.init"; 9 | import useCourseDetails from "../../../hooks/useCourseDetails/useCourseDetails"; 10 | import "./CheckOut.css"; 11 | 12 | const CheckOut = () => { 13 | const { serviceId } = useParams(); 14 | const [course] = useCourseDetails(serviceId); 15 | const [user] = useAuthState(auth); 16 | 17 | const navigate = useNavigate(); 18 | 19 | if(user){ 20 | // console.log(user); 21 | } 22 | 23 | const handlePlaceOrder = event =>{ 24 | event.preventDefault(); 25 | const order = { 26 | email: user.email, 27 | service: course.name, 28 | serviceId: serviceId, 29 | image: course.image, 30 | price: course.price, 31 | description: course.description, 32 | phone: event.target.phone.value, 33 | status: "Pending" 34 | 35 | } 36 | axios.post('https://tech-specter.onrender.com/order', order) 37 | .then(res => { 38 | const {data}= res; 39 | if (data.insertedId) { 40 | toast('Your Order is Booked'); 41 | event.target.reset(); 42 | navigate('/dashboard/myOrders'); 43 | } 44 | // console.log(res); 45 | }) 46 | } 47 | 48 | return ( 49 | 50 | 51 |
52 |
53 |
54 |
55 |

Place Your Order

56 |

Fill in the data below.

57 |
58 | 65 | 66 | 74 | 81 | 89 | 90 |
91 |
92 |
93 |
94 |
95 |
96 | ); 97 | }; 98 | 99 | export default CheckOut; 100 | -------------------------------------------------------------------------------- /src/Pages/CoursesPage/AllCourses/AllCourses.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahidmonowarr/tech-specter-client/87077e7335351323a2066924bca851ce0f711bca/src/Pages/CoursesPage/AllCourses/AllCourses.css -------------------------------------------------------------------------------- /src/Pages/CoursesPage/AllCourses/AllCourses.js: -------------------------------------------------------------------------------- 1 | import { Toast } from "bootstrap"; 2 | import React, { useEffect, useState } from "react"; 3 | import { 4 | Button, 5 | ButtonGroup, 6 | Container, 7 | Pagination, 8 | Row, 9 | Spinner 10 | } from "react-bootstrap"; 11 | import PageTitle from "../../../Components/Shared/PageTitle/PageTitle"; 12 | import SingleCourse from "../SingleCourse/SingleCourse"; 13 | import "./AllCourses.css"; 14 | 15 | const AllCourses = () => { 16 | const [courses, setCourses] = useState([]); 17 | const count = courses.length; 18 | useEffect(() => { 19 | fetch("https://tech-specter.onrender.com/course") 20 | .then((res) => res.json()) 21 | .then((data) => { 22 | setCourses(data); 23 | }) 24 | .catch((error) => Toast.error(error.message)); 25 | }, []); 26 | 27 | const [tempCourses, setTempCourses] = useState(courses); 28 | const [currentPage, setCurrentPage] = useState(1); 29 | const [coursesPerPage, setCoursesPerPage] = useState(6); 30 | 31 | const filterCourses = (courseCate) => { 32 | const cateServices = courses.filter((currentCourses) => { 33 | return currentCourses.category === courseCate; 34 | }); 35 | if (courseCate === "All") { 36 | setTempCourses(courses); 37 | } else { 38 | setTempCourses(cateServices); 39 | } 40 | setCurrentPage(1); 41 | }; 42 | 43 | const totalPages = Math.ceil(tempCourses.length / coursesPerPage); 44 | 45 | const handlePageChange = (pageNumber) => { 46 | setCurrentPage(pageNumber); 47 | }; 48 | 49 | const indexOfLastCourse = currentPage * coursesPerPage; 50 | const indexOfFirstCourse = indexOfLastCourse - coursesPerPage; 51 | const currentCourses = tempCourses.slice( 52 | indexOfFirstCourse, 53 | indexOfLastCourse 54 | ); 55 | 56 | return ( 57 | <> 58 | {!count ? ( 59 |
60 | 61 | Loading... 62 | 63 |
Loading...
64 |
65 | ) : ( 66 | 67 | 68 |

69 | LATEST courses 70 |

71 |

72 | What We provide to Our Customer! 73 |

74 | 75 | 76 | 83 | 90 | 97 | 104 | 105 | 106 | 107 | {currentCourses.length === 0 108 | ? courses?.map((singleCourse) => ( 109 | 113 | )) 114 | : currentCourses.map((singleCourse) => ( 115 | 119 | ))} 120 | 121 |
122 | 123 | {[...Array(totalPages)].map((_, index) => ( 124 | handlePageChange(index + 1)} 128 | > 129 | {index + 1} 130 | 131 | ))} 132 | 133 |
134 |
135 | )} 136 | 137 | ); 138 | }; 139 | 140 | export default AllCourses; 141 | -------------------------------------------------------------------------------- /src/Pages/CoursesPage/CourseDetails/CourseDetails.css: -------------------------------------------------------------------------------- 1 | .rating{ 2 | margin-left: 35px; 3 | color: #EFB101; 4 | } -------------------------------------------------------------------------------- /src/Pages/CoursesPage/CourseDetails/CourseDetails.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import { Col, Container, Row, Toast } from "react-bootstrap"; 3 | import Button from "react-bootstrap/Button"; 4 | import Card from "react-bootstrap/Card"; 5 | import Rating from "react-rating"; 6 | import { Link, useParams } from "react-router-dom"; 7 | import PageTitle from "../../../Components/Shared/PageTitle/PageTitle"; 8 | import useCourseDetails from "../../../hooks/useCourseDetails/useCourseDetails"; 9 | import "./CourseDetails.css"; 10 | 11 | const CourseDetails = () => { 12 | const { serviceId } = useParams(); 13 | const [course] = useCourseDetails(serviceId); 14 | 15 | const [loading, setLoading] = useState(true); 16 | const [reviews, setReviews] = useState(); 17 | 18 | useEffect(() => { 19 | fetch("https://tech-specter.onrender.com/reviews") 20 | .then((res) => res.json()) 21 | .then((data) => { 22 | setReviews(data); 23 | setLoading(false); 24 | }) 25 | .catch((error) => Toast.error(error.message)); 26 | }, []); 27 | 28 | const filteredReviews = reviews?.filter( 29 | (review) => review.category === "course" 30 | ); 31 | // console.log(filteredReviews); 32 | 33 | return ( 34 | 35 | 36 |

43 | {course.category} 44 |

45 | 46 | 47 | 53 | 54 | 55 | Instructor Details: 56 | 57 | 58 | 59 | 63 | 64 | 65 | 66 | Junior Ahmed 67 | 68 | A technology entrepreneur. He himself is a full stack web 69 | developer and software architect and has been involved in 70 | the web development and software profession for over 14 71 | years. 72 | 73 |
74 | 75 | juniorahmed.cse@gmail.com{" "} 76 | Phone: +880 1711 000 000{" "} 77 | 78 | Reviews:{" "} 79 | 86 | 87 | 88 |
89 | 90 |
91 |
92 | 93 |
Reviews
94 | 95 | {filteredReviews?.map((review) => ( 96 | 104 | 108 | 109 |
{review.name}
110 |

111 | {" "} 118 | {review.rating} 119 |

120 | {review.description} 121 |
122 |
123 | 124 | ))} 125 |
126 |
127 | 128 | 129 | 130 | 134 | {course.name} 135 | 136 |
137 | {" "} 144 |
145 | based on 129 reviews 146 |
147 | 148 |
149 | 150 | 151 | Price: 152 | {course.price} BDT 153 | 154 | {course.description} 155 | What we provide? 156 |
    157 |
  • 24 hours customer support
  • 158 |
  • Team of 4 peoples will work on your project
  • 159 |
  • Immediate solution to your problem
  • 160 |
  • Commitment to deliver your project on time
  • 161 |
162 | 163 | 166 | 167 | 168 | 171 | 172 |
173 |
174 | 175 |
176 |
177 | ); 178 | }; 179 | 180 | export default CourseDetails; 181 | -------------------------------------------------------------------------------- /src/Pages/CoursesPage/SingleCourse/SingleCourse.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahidmonowarr/tech-specter-client/87077e7335351323a2066924bca851ce0f711bca/src/Pages/CoursesPage/SingleCourse/SingleCourse.css -------------------------------------------------------------------------------- /src/Pages/CoursesPage/SingleCourse/SingleCourse.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Card, Col } from 'react-bootstrap'; 3 | import { useNavigate } from 'react-router-dom'; 4 | import './SingleCourse.css'; 5 | 6 | const SingleCourse = ({singleCourse}) => { 7 | const { _id, name, description, price, image } = singleCourse; 8 | const navigate = useNavigate(); 9 | 10 | const navigateToCourseDetails = id=>{ 11 | navigate(`/courseDetails/${id}`); 12 | // console.log(navigate); 13 | } 14 | 15 | return ( 16 | 17 | 18 |
19 | 24 |
25 | 26 | 27 | {name} 28 | 29 | Price: {price}.00 BDT 30 | {description.slice(0,60)}... 31 | 32 | 33 | 34 |
35 | 36 | ); 37 | }; 38 | 39 | export default SingleCourse; -------------------------------------------------------------------------------- /src/Pages/Dashboard/AddBlog/AddBlog.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import React from "react"; 3 | import { Col, Row } from "react-bootstrap"; 4 | import { useForm } from "react-hook-form"; 5 | import { toast } from "react-toastify"; 6 | 7 | const AddBlog = () => { 8 | const { register, handleSubmit, reset } = useForm(); 9 | 10 | const onSubmit = (data) => { 11 | console.log(data); 12 | 13 | axios.post("https://tech-specter.onrender.com/blogs", data).then((res) => { 14 | if (res.data.insertedId) { 15 | toast("Blog Added Successfully"); 16 | reset(); 17 | } 18 | console.log(res); 19 | }); 20 | }; 21 | return ( 22 |
23 | 24 | 25 | 31 | 32 | 33 |
34 |

35 | Add a Blog 36 |

37 | 38 |
39 | 44 | 50 | 63 | 69 | 75 | 81 | 87 | 93 | 99 | 105 | 111 | 117 | 123 | 129 | 133 |
134 |
135 | 136 |
137 |
138 | ); 139 | }; 140 | 141 | export default AddBlog; 142 | -------------------------------------------------------------------------------- /src/Pages/Dashboard/AddCourse/AddCourse.css: -------------------------------------------------------------------------------- 1 | .add-product form{ 2 | 3 | display: flex; 4 | flex-direction: column; 5 | align-items: center; 6 | justify-content: center; 7 | } 8 | 9 | .submit-btn:hover{ 10 | background-color: goldenrod; 11 | color: white; 12 | font-weight: 700; 13 | transition: 0.5s; 14 | } 15 | 16 | .add-product{ 17 | padding-top: 50px; 18 | background-image: url(''); 19 | background-position: center; 20 | background-repeat: no-repeat; 21 | background-size: cover; 22 | height: 90vh; 23 | } -------------------------------------------------------------------------------- /src/Pages/Dashboard/AddCourse/AddCourse.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import React from "react"; 3 | import { Col, Row } from "react-bootstrap"; 4 | import { useForm } from "react-hook-form"; 5 | import { toast } from "react-toastify"; 6 | import "./AddCourse.css"; 7 | 8 | const AddCourse = () => { 9 | const { register, handleSubmit, reset } = useForm(); 10 | const onSubmit = (data) => { 11 | // console.log(data); 12 | 13 | axios.post("https://tech-specter.onrender.com/course", data).then((res) => { 14 | if (res.data.insertedId) { 15 | toast("Added Successfully"); 16 | reset(); 17 | } 18 | // console.log(res); 19 | }); 20 | }; 21 | 22 | return ( 23 |
24 | 25 | 26 | 32 | 33 | 34 |
35 |

36 | Add a Course 37 |

38 |
39 | {" "} 44 |
45 | {" "} 51 |
52 | {" "} 58 |
59 | 70 |
71 | {" "} 77 |
78 | 79 |
80 |
81 | 82 |
83 |
84 | ); 85 | }; 86 | 87 | export default AddCourse; 88 | -------------------------------------------------------------------------------- /src/Pages/Dashboard/AddPlace/AddPlace.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import React from "react"; 3 | import { Col, Row } from "react-bootstrap"; 4 | import { useForm } from "react-hook-form"; 5 | import { toast } from "react-toastify"; 6 | 7 | const AddPlace = () => { 8 | const { register, handleSubmit, reset } = useForm(); 9 | const onSubmit = (data) => { 10 | // console.log(data); 11 | 12 | axios.post("https://tech-specter.onrender.com/travel", data).then((res) => { 13 | if (res.data.insertedId) { 14 | toast("Place Added Successfully"); 15 | reset(); 16 | } 17 | // console.log(res); 18 | }); 19 | }; 20 | 21 | return ( 22 |
23 | 24 | 25 | 31 | 32 | 33 |
34 |

35 | Add a Place 36 |

37 |
38 | 43 | 49 | 55 | 61 | 67 | 78 | 84 | 90 | 96 | 102 | 103 |
104 |
105 | 106 |
107 |
108 | ); 109 | }; 110 | 111 | export default AddPlace; 112 | -------------------------------------------------------------------------------- /src/Pages/Dashboard/AddReview/AddReview.css: -------------------------------------------------------------------------------- 1 | 2 | @media only screen and (max-width: 600px) { 3 | .add-product { 4 | height: 140vh; 5 | } 6 | } 7 | 8 | .add-product form{ 9 | 10 | display: flex; 11 | flex-direction: column; 12 | align-items: center; 13 | justify-content: center; 14 | } 15 | 16 | .add-product form input{ 17 | width: 65%; 18 | padding: 5px; 19 | border-radius: 10px; 20 | font-weight: 600; 21 | } 22 | 23 | .submit-btn:hover{ 24 | background-color: rgb(250, 53, 53); 25 | color: white; 26 | font-weight: 900; 27 | transition: 0.5s; 28 | 29 | } -------------------------------------------------------------------------------- /src/Pages/Dashboard/AddReview/AddReview.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import React, { useState } from "react"; 3 | import { Col, Row } from "react-bootstrap"; 4 | import { useAuthState } from "react-firebase-hooks/auth"; 5 | import { useForm } from "react-hook-form"; 6 | import Rating from "react-rating"; 7 | import { toast } from "react-toastify"; 8 | import auth from "../../../firebase.init"; 9 | import './AddReview.css'; 10 | 11 | const AddReview = () => { 12 | const { register, handleSubmit, reset } = useForm(); 13 | const [rating, setRating] = useState(5); 14 | const [user] = useAuthState(auth); 15 | const onSubmit = (data) => { 16 | // console.log(data); 17 | data.rating = rating; 18 | 19 | axios.post("https://tech-specter.onrender.com/reviews", data).then((res) => { 20 | if (res.data.insertedId) { 21 | toast("Review Added Successfully"); 22 | reset(); 23 | } 24 | // console.log(res); 25 | }); 26 | }; 27 | 28 | return ( 29 |
30 | 31 | 32 | 38 | 39 | 40 |

41 | Please Add A Review 42 |

43 |
44 | {" "} 45 | 57 |
58 |
59 |
Rating
60 |
61 |
62 | setRating(rate)} 67 | initialRating={rating} 68 | fractions={2} 69 | /> 70 |

{rating}

71 |
72 |
73 | {" "} 78 | 79 |
80 | 81 |
82 |
83 | ); 84 | }; 85 | 86 | export default AddReview; 87 | -------------------------------------------------------------------------------- /src/Pages/Dashboard/AllTransaction/AllTransaction.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { Pagination, Table } from "react-bootstrap"; 3 | import { useQuery } from "react-query"; 4 | import Loading from "../../../Components/Shared/Loading/Loading"; 5 | 6 | const AllTransaction = () => { 7 | const pageSize = 10; // Number of items to display per page 8 | const [currentPage, setCurrentPage] = useState(1); // Current page number 9 | 10 | const { 11 | data: allOrder, 12 | setAllOrder, 13 | isLoading, 14 | } = useQuery("allOrder", () => 15 | fetch("https://tech-specter.onrender.com/order", { 16 | method: "GET", 17 | headers: { 18 | authorization: `Bearer ${localStorage.getItem("accessToken")}`, 19 | }, 20 | }).then((res) => res.json()) 21 | ); 22 | 23 | if (isLoading) { 24 | return ; 25 | } 26 | 27 | const orderWithTransaction = allOrder.filter( (order) => order.transactionId); 28 | 29 | const totalPages = Math.ceil(allOrder.length / pageSize); // Total number of pages 30 | const startIndex = (currentPage - 1) * pageSize; // Index of first item on current page 31 | const endIndex = startIndex + pageSize; // Index of last item on current page 32 | const currentOrders = orderWithTransaction.slice(startIndex, endIndex); // Items to display on current page 33 | 34 | const handlePageChange = (pageNumber) => { 35 | setCurrentPage(pageNumber); 36 | }; 37 | return ( 38 |
39 |
40 |
41 |

42 | All Transaction Details [Total {orderWithTransaction.length}] 43 |

44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | {currentOrders.map((order, index) => ( 56 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | ))} 69 | 70 |
IndexEmailOrder NameOrder PriceTransaction Id
{startIndex + index + 1}{order.email}{order.service}{order.price}{order.transactionId}
71 |
72 | 73 | handlePageChange(1)} 75 | disabled={currentPage === 1} 76 | /> 77 | handlePageChange(currentPage - 1)} 79 | disabled={currentPage === 1} 80 | /> 81 | {Array.from({ length: totalPages }, (_, i) => ( 82 | handlePageChange(i + 1)} 86 | > 87 | {i + 1} 88 | 89 | ))} 90 | handlePageChange(currentPage + 1)} 92 | disabled={currentPage === totalPages} 93 | /> 94 | handlePageChange(totalPages)} 96 | disabled={currentPage === totalPages} 97 | /> 98 | 99 |
100 |
101 |
102 |
103 | ); 104 | }; 105 | 106 | export default AllTransaction; 107 | -------------------------------------------------------------------------------- /src/Pages/Dashboard/CheckoutForm/CheckoutForm.js: -------------------------------------------------------------------------------- 1 | import { CardElement, useElements, useStripe } from "@stripe/react-stripe-js"; 2 | import React, { useEffect, useState } from "react"; 3 | import { useAuthState } from "react-firebase-hooks/auth"; 4 | import auth from "../../../firebase.init"; 5 | 6 | const CheckoutForm = ({ singleOrder }) => { 7 | const stripe = useStripe(); 8 | const elements = useElements(); 9 | const [cardError, setCardError] = useState(""); 10 | const [success, setSuccess] = useState(""); 11 | const [processing, setProcessing] = useState(false); 12 | const [transactionId, setTransactionId] = useState(""); 13 | const [clientSecret, setClientSecret] = useState(""); 14 | const [user, loading, error] = useAuthState(auth); 15 | 16 | const { _id, price, email } = singleOrder; 17 | 18 | useEffect(() => { 19 | fetch("https://tech-specter.onrender.com/create-payment-intent", { 20 | method: "POST", 21 | headers: { 22 | "content-type": "application/json", 23 | authorization: `Bearer ${localStorage.getItem("accessToken")}`, 24 | }, 25 | body: JSON.stringify({ price }), 26 | }) 27 | .then((res) => res.json()) 28 | .then((data) => { 29 | if (data?.clientSecret) { 30 | setClientSecret(data.clientSecret); 31 | } 32 | }); 33 | }, [price]); 34 | 35 | const handleSubmit = async (event) => { 36 | event.preventDefault(); 37 | if (!stripe || !elements) { 38 | return; 39 | } 40 | 41 | const card = elements.getElement(CardElement); 42 | 43 | if (card == null) { 44 | return; 45 | } 46 | 47 | const { error, paymentMethod } = await stripe.createPaymentMethod({ 48 | type: "card", 49 | card, 50 | }); 51 | 52 | setCardError(error?.message || ""); 53 | setSuccess(""); 54 | setProcessing(true); 55 | 56 | //confirm card payment 57 | const { paymentIntent, error: intentError } = 58 | await stripe.confirmCardPayment(clientSecret, { 59 | payment_method: { 60 | card: card, 61 | billing_details: { 62 | name: user.displayName, 63 | email: email, 64 | }, 65 | }, 66 | }); 67 | if (intentError) { 68 | setCardError(intentError.message); 69 | setProcessing(false); 70 | } else { 71 | setCardError(""); 72 | setTransactionId(paymentIntent.id); 73 | // console.log(paymentIntent); 74 | setSuccess("Congrats! Your Payment is Completed"); 75 | 76 | //store payment on database 77 | const payment = { 78 | singleOrder: _id, 79 | transactionId: paymentIntent.id 80 | } 81 | fetch( `https://tech-specter.onrender.com/order/${_id}`,{ 82 | method: "PATCH", 83 | headers: { 84 | "content-type": "application/json", 85 | authorization: `Bearer ${localStorage.getItem("accessToken")}`, 86 | }, 87 | body: JSON.stringify(payment), 88 | }) 89 | .then((res) => res.json()) 90 | .then((data) => { 91 | setProcessing(false); 92 | // console.log(data); 93 | }); 94 | } 95 | }; 96 | return ( 97 | <> 98 |
99 | 115 | 122 | 123 | {cardError &&

{cardError}

} 124 | {success && ( 125 |
126 |

{success}

127 |

128 | Your Transaction Id:{" "} 129 | {transactionId} 130 |

131 |
132 | )} 133 | 134 | ); 135 | }; 136 | 137 | export default CheckoutForm; 138 | -------------------------------------------------------------------------------- /src/Pages/Dashboard/Dashboard/Dashboard.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahidmonowarr/tech-specter-client/87077e7335351323a2066924bca851ce0f711bca/src/Pages/Dashboard/Dashboard/Dashboard.css -------------------------------------------------------------------------------- /src/Pages/Dashboard/Dashboard/Dashboard.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useAuthState } from "react-firebase-hooks/auth"; 3 | import { Link, Outlet } from "react-router-dom"; 4 | import PageTitle from "../../../Components/Shared/PageTitle/PageTitle"; 5 | import auth from "../../../firebase.init"; 6 | import useAdmin from "../../../hooks/useAdmin/useAdmin"; 7 | import "./Dashboard.css"; 8 | 9 | const Dashboard = () => { 10 | const [user] = useAuthState(auth); 11 | const [admin] = useAdmin(user); 12 | 13 | return ( 14 |
15 | 16 |
17 |
18 | {admin ? ( 19 |
    20 |
  • 21 | 22 | Home 23 | 24 |
  • 25 |
  • 26 | 30 | All Users 31 | 32 |
  • 33 |
  • 34 | 38 | Add Course 39 | 40 |
  • 41 |
  • 42 | 46 | Add Place 47 | 48 |
  • 49 |
  • 50 | 54 | Add Blog 55 | 56 |
  • 57 |
  • 58 | 62 | Manage Courses 63 | 64 |
  • 65 |
  • 66 | 70 | Manage Places 71 | 72 |
  • 73 |
  • 74 | 78 | Manage Orders 79 | 80 |
  • 81 |
  • 82 | 86 | All Transaction 87 | 88 |
  • 89 |
90 | ) : ( 91 |
    92 |
  • 93 | 94 | Home 95 | 96 |
  • 97 |
  • 98 | 102 | Add Review 103 | 104 |
  • 105 |
  • 106 | 110 | My Orders 111 | 112 |
  • 113 |
114 | )} 115 |
116 |
117 |

Dashboard

118 | 119 |
120 |
121 |
122 | ); 123 | }; 124 | 125 | export default Dashboard; 126 | -------------------------------------------------------------------------------- /src/Pages/Dashboard/DashboardHome/DashboardHome.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import { reload, signOut } from "firebase/auth"; 3 | import React, { useEffect, useState } from "react"; 4 | import { Card, Col, Row } from "react-bootstrap"; 5 | import { useAuthState } from "react-firebase-hooks/auth"; 6 | import { useNavigate } from "react-router-dom"; 7 | import { toast } from "react-toastify"; 8 | import auth from "../../../firebase.init"; 9 | 10 | const DashboardHome = () => { 11 | const [userProfile, setUserProfile] = useState([]); 12 | const [user] = useAuthState(auth); 13 | const navigate = useNavigate(); 14 | 15 | useEffect(() => { 16 | if (user) { 17 | fetch(`https://tech-specter.onrender.com/userProfile?email=${user.email}`, { 18 | method: "GET", 19 | headers: { 20 | authorization: `Bearer ${localStorage.getItem("accessToken")}`, 21 | }, 22 | }) 23 | .then((res) => { 24 | // console.log("res", res); 25 | if (res.status === 401 || res.status === 403) { 26 | signOut(auth); 27 | localStorage.removeItem("accessToken"); 28 | navigate("/"); 29 | } 30 | return res.json(); 31 | }) 32 | .then((data) => { 33 | console.log("data", data); 34 | const myProfile = data.filter( 35 | (singleData) => singleData.email === user.email 36 | ); 37 | setUserProfile(myProfile); 38 | }); 39 | } 40 | }, [user]); 41 | 42 | const handleProfileUpdate = (event) => { 43 | event.preventDefault(); 44 | const profile = { 45 | name: user.displayName, 46 | email: user.email, 47 | image: event.target.image.value, 48 | bloodGroup: event.target.bloodGroup.value, 49 | status: event.target.status.value, 50 | phone: event.target.phone.value, 51 | address: event.target.address.value, 52 | about: event.target.about.value, 53 | }; 54 | axios.post("https://tech-specter.onrender.com/userProfile", profile).then((res) => { 55 | const { data } = res; 56 | if (data.insertedId) { 57 | toast("Your Profile is Updated"); 58 | event.target.reset(); 59 | reload(); 60 | navigate("/dashboard"); 61 | } 62 | // console.log(res); 63 | }); 64 | }; 65 | return ( 66 |
67 |

68 | Welcome to Dashboard,{" "} 69 | {user?.displayName}. 70 |

71 | 72 | 73 | {userProfile.map((profile) => ( 74 | 80 |
81 | 86 |
87 | 88 | 92 | Name: {profile.name} 93 | 94 | Email: {profile.email} 95 | 96 | Blood Group:{" "} 97 | {profile.bloodGroup} 98 | 99 | Phone NO: {profile.phone} 100 | Present Status: {profile.status} 101 | Address: {profile.address} 102 | About Me: {profile.about} 103 | 104 |
105 | ))} 106 | 107 | 108 |
109 |

110 | Update Your Profile 111 |

112 |
113 | 119 | 125 | 131 | 137 | 143 | 150 | 156 | 162 | 166 |
167 |
168 | 169 |
170 |
171 | ); 172 | }; 173 | 174 | export default DashboardHome; 175 | -------------------------------------------------------------------------------- /src/Pages/Dashboard/ManageCourses/ManageCourses.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Button, Table } from 'react-bootstrap'; 3 | import { useQuery } from 'react-query'; 4 | import { Link } from 'react-router-dom'; 5 | import { toast } from 'react-toastify'; 6 | import Loading from '../../../Components/Shared/Loading/Loading'; 7 | 8 | const ManageCourses = () => { 9 | const { 10 | data: allCourses, 11 | setAllCourses, 12 | isLoading, 13 | refetch, 14 | } = useQuery("allCourses", () => 15 | fetch("https://tech-specter.onrender.com/course", { 16 | method: "GET", 17 | headers: { 18 | authorization: `Bearer ${localStorage.getItem("accessToken")}`, 19 | }, 20 | }).then((res) => res.json()) 21 | ); 22 | 23 | //for delete 24 | const handleDeleteCourse = (id) => { 25 | const proceed = window.confirm("Are Sure To Cancel This Order?"); 26 | if (proceed) { 27 | const url = `https://tech-specter.onrender.com/course/${id}`; 28 | fetch(url, { 29 | method: "DELETE", 30 | headers: { 31 | authorization: `Bearer ${localStorage.getItem("accessToken")}`, 32 | }, 33 | }) 34 | .then((res) => res.json()) 35 | .then((data) => { 36 | if (data.deletedCount > 0) { 37 | toast("Order Deleted SuccessFully"); 38 | const remaining = allCourses.filter((course) => course._id !== id); 39 | setAllCourses(remaining); 40 | } 41 | }); 42 | } 43 | }; 44 | 45 | if (isLoading) { 46 | return ; 47 | } 48 | return ( 49 |
50 |
51 |
52 |

Remove Courses

53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | {allCourses.map((course, index) => ( 65 | 66 | 67 | 68 | 69 | 74 | 82 | 83 | ))} 84 | 85 |
Indexcourse Namecourse CategoryUpdateDelete
{index + 1}{course.name}{course.category} 70 | 71 | 72 | 73 | 75 | 81 |
86 |
87 |
88 |
89 | ); 90 | }; 91 | 92 | export default ManageCourses; -------------------------------------------------------------------------------- /src/Pages/Dashboard/ManageCourses/UpdateCourse.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import React, { useEffect, useState } from 'react'; 3 | import { Col, Row } from 'react-bootstrap'; 4 | import { useForm } from 'react-hook-form'; 5 | import { useParams } from 'react-router-dom'; 6 | import { toast } from 'react-toastify'; 7 | 8 | const UpdateCourse = () => { 9 | const { courseId } = useParams(); 10 | console.log(courseId); 11 | const { register, handleSubmit, reset } = useForm(); 12 | const [course, setCourse] = useState({}); 13 | 14 | useEffect(() => { 15 | axios.get(`https://tech-specter.onrender.com/course/${courseId}`).then((res) => { 16 | setCourse(res.data); 17 | }); 18 | }, [courseId]); 19 | 20 | const onSubmit = (data) => { 21 | axios.put(`https://tech-specter.onrender.com/course/${courseId}`, data).then((res) => { 22 | if (res.data.modifiedCount) { 23 | toast("Updated Successfully"); 24 | reset(); 25 | } 26 | }); 27 | }; 28 | 29 | return ( 30 |
31 | 32 | 33 | 39 | 40 | 41 |
42 |

43 | Update Course 44 |

45 |
46 | {" "} 52 |
53 | {" "} 60 |
61 | {" "} 68 |
69 | 79 |
80 | {" "} 87 |
88 | 89 |
90 |
91 | 92 |
93 |
94 | ); 95 | }; 96 | 97 | export default UpdateCourse; -------------------------------------------------------------------------------- /src/Pages/Dashboard/ManageOrders/ManageOrders.js: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import { Button, Pagination, Table } from "react-bootstrap"; 3 | import { useQuery } from "react-query"; 4 | import { toast } from "react-toastify"; 5 | import Loading from "../../../Components/Shared/Loading/Loading"; 6 | 7 | const ManageOrders = () => { 8 | const pageSize = 10; 9 | const [currentPage, setCurrentPage] = useState(1); 10 | 11 | const { 12 | data: allOrder, 13 | setAllOrder, 14 | isLoading, 15 | refetch, 16 | } = useQuery("allOrder", () => 17 | fetch("https://tech-specter.onrender.com/order", { 18 | method: "GET", 19 | headers: { 20 | authorization: `Bearer ${localStorage.getItem("accessToken")}`, 21 | }, 22 | }).then((res) => res.json()) 23 | ); 24 | 25 | if (isLoading) { 26 | return ; 27 | } 28 | 29 | const totalPages = Math.ceil(allOrder.length / pageSize); 30 | const startIndex = (currentPage - 1) * pageSize; 31 | const endIndex = startIndex + pageSize; 32 | const currentOrders = allOrder.slice(startIndex, endIndex); 33 | 34 | const handlePageChange = (pageNumber) => { 35 | setCurrentPage(pageNumber); 36 | }; 37 | 38 | //for confirm 39 | const handleConfirmOrder = (id) => { 40 | const matchedOrder = allOrder.filter((order) => order._id === id); 41 | matchedOrder[0].status = "Confirmed"; 42 | 43 | fetch(`https://tech-specter.onrender.com/order/${id}`, { 44 | method: "PUT", 45 | headers: { 46 | "content-type": "application/json", 47 | }, 48 | body: JSON.stringify(matchedOrder), 49 | }) 50 | .then((res) => res.json()) 51 | .then((data) => { 52 | console.log(data); 53 | toast("order confirmed"); 54 | refetch(); 55 | }); 56 | 57 | // fetch() 58 | }; 59 | 60 | //for delete 61 | const handleDeleteOrder = (id) => { 62 | const proceed = window.confirm("Are Sure To Cancel This Order?"); 63 | if (proceed) { 64 | const url = `https://tech-specter.onrender.com/order/${id}`; 65 | fetch(url, { 66 | method: "DELETE", 67 | headers: { 68 | authorization: `Bearer ${localStorage.getItem("accessToken")}`, 69 | }, 70 | }) 71 | .then((res) => res.json()) 72 | .then((data) => { 73 | if (data.deletedCount > 0) { 74 | toast("Order Deleted SuccessFully"); 75 | const remaining = allOrder.filter((order) => order._id !== id); 76 | setAllOrder(remaining); 77 | } 78 | }); 79 | } 80 | }; 81 | 82 | return ( 83 |
84 |
85 |
86 |

87 | Remove and Approve Orders [Total: {allOrder.length}] 88 |

89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | {currentOrders.map((order, index) => ( 102 | 108 | 109 | 110 | 111 | 112 | {order.paid ? ( 113 | 121 | ):( 122 | 125 | )} 126 | {/* */} 127 | 135 | 136 | ))} 137 | 138 |
IndexEmailOrder NameOrder StatusApproveRemove
{startIndex + index + 1}{order.email}{order.service}{order.status} 114 | 120 | 123 | Not Paid 124 | 128 | 134 |
139 |
140 | 141 | handlePageChange(1)} disabled={currentPage === 1} /> 142 | handlePageChange(currentPage - 1)} disabled={currentPage === 1} /> 143 | {Array.from({ length: totalPages }, (_, i) => ( 144 | handlePageChange(i + 1)}> 145 | {i + 1} 146 | 147 | ))} 148 | handlePageChange(currentPage + 1)} disabled={currentPage === totalPages} /> 149 | handlePageChange(totalPages)} disabled={currentPage === totalPages} /> 150 | 151 |
152 |
153 |
154 |
155 | ); 156 | }; 157 | 158 | export default ManageOrders; 159 | -------------------------------------------------------------------------------- /src/Pages/Dashboard/ManagePlaces/ManagePlaces.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Button, Table } from 'react-bootstrap'; 3 | import { useQuery } from 'react-query'; 4 | import { toast } from 'react-toastify'; 5 | import Loading from '../../../Components/Shared/Loading/Loading'; 6 | 7 | const ManagePlaces = () => { 8 | const { 9 | data: allPlaces, 10 | setAllPlaces, 11 | isLoading 12 | } = useQuery("allPlaces", () => 13 | fetch("https://tech-specter.onrender.com/travel", { 14 | method: "GET", 15 | headers: { 16 | authorization: `Bearer ${localStorage.getItem("accessToken")}`, 17 | }, 18 | }).then((res) => res.json()) 19 | ); 20 | 21 | //for delete 22 | const handleDeletePlace = (id) => { 23 | const proceed = window.confirm("Are Sure To Cancel This Order?"); 24 | if (proceed) { 25 | const url = `https://tech-specter.onrender.com/travel/${id}`; 26 | fetch(url, { 27 | method: "DELETE", 28 | headers: { 29 | authorization: `Bearer ${localStorage.getItem("accessToken")}`, 30 | }, 31 | }) 32 | .then((res) => res.json()) 33 | .then((data) => { 34 | if (data.deletedCount > 0) { 35 | toast("Order Deleted SuccessFully"); 36 | const remaining = allPlaces.filter((place) => place._id !== id); 37 | setAllPlaces(remaining); 38 | } 39 | }); 40 | } 41 | }; 42 | 43 | if (isLoading) { 44 | return ; 45 | } 46 | return ( 47 |
48 |
49 |
50 |

51 | Remove Places 52 |

53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | {allPlaces.map((place, index) => ( 64 | 65 | 66 | 67 | 68 | 76 | 77 | ))} 78 | 79 |
Indexplace Nameplace CategoryDelete
{index + 1}{place.name}{place.category} 69 | 75 |
80 |
81 |
82 |
83 | ); 84 | }; 85 | 86 | export default ManagePlaces; -------------------------------------------------------------------------------- /src/Pages/Dashboard/Orders/Orders.js: -------------------------------------------------------------------------------- 1 | import { signOut } from "firebase/auth"; 2 | import React, { useEffect, useState } from "react"; 3 | import { Card, Col, Row } from "react-bootstrap"; 4 | import { useAuthState } from "react-firebase-hooks/auth"; 5 | import { Link, useNavigate } from "react-router-dom"; 6 | import { toast } from "react-toastify"; 7 | import auth from "../../../firebase.init"; 8 | 9 | const Orders = () => { 10 | const [orders, setOrders] = useState([]); 11 | const [user] = useAuthState(auth); 12 | const navigate = useNavigate(); 13 | 14 | useEffect(() => { 15 | if (user) { 16 | fetch(`https://tech-specter.onrender.com/order?email=${user.email}`, { 17 | method: "GET", 18 | headers: { 19 | authorization: `Bearer ${localStorage.getItem("accessToken")}`, 20 | }, 21 | }) 22 | .then((res) => { 23 | // console.log("res", res); 24 | if (res.status === 401 || res.status === 403) { 25 | signOut(auth); 26 | localStorage.removeItem("accessToken"); 27 | navigate("/"); 28 | } 29 | return res.json(); 30 | }) 31 | .then((data) => { 32 | // console.log("data", data); 33 | const myOrders = data.filter(singleData => singleData.email === user.email); 34 | setOrders(myOrders); 35 | }); 36 | } 37 | }, [user]); 38 | 39 | const handleDeleteOrder = (id) => { 40 | const proceed = window.confirm("Are Sure To Cancel This Order?"); 41 | if (proceed) { 42 | const url = `https://tech-specter.onrender.com/order/${id}`; 43 | fetch(url, { 44 | method: "DELETE", 45 | headers: { 46 | authorization: `Bearer ${localStorage.getItem("accessToken")}`, 47 | }, 48 | }) 49 | .then((res) => res.json()) 50 | .then((data) => { 51 | if (data.deletedCount > 0) { 52 | toast("Order Deleted SuccessFully"); 53 | const remaining = orders.filter((order) => order._id !== id); 54 | setOrders(remaining); 55 | } 56 | }); 57 | } 58 | }; 59 | 60 | return ( 61 |
62 |

My Orders [Total {orders.length}]

63 | 64 | {orders?.map((order) => ( 65 | 73 | 74 |
75 | 80 |
81 | 82 | 86 | {order.service} 87 | 88 |
{order.status}
89 | Price: {order.price}.00 BDT 90 | {(order.date)&&Date: {order.date}} 91 | { 92 | (!order.paid) && 93 | } 94 | { 95 | (order.price && !order.paid) && 96 | } 97 | { 98 | (order.price && order.paid) && Paid 99 | } 100 |
101 |
102 | 103 | ))} 104 |
105 |
106 | ); 107 | }; 108 | 109 | export default Orders; 110 | -------------------------------------------------------------------------------- /src/Pages/Dashboard/Payment/Payment.js: -------------------------------------------------------------------------------- 1 | import { Elements } from '@stripe/react-stripe-js'; 2 | import { loadStripe } from '@stripe/stripe-js'; 3 | import React from 'react'; 4 | import Card from 'react-bootstrap/Card'; 5 | import { useAuthState } from 'react-firebase-hooks/auth'; 6 | import { useQuery } from 'react-query'; 7 | import { useParams } from 'react-router-dom'; 8 | import Loading from '../../../Components/Shared/Loading/Loading'; 9 | import auth from '../../../firebase.init'; 10 | import CheckoutForm from '../CheckoutForm/CheckoutForm'; 11 | 12 | const stripePromise = loadStripe('pk_test_51LjQDsIuMYzXtkmkPWiH8MIT8tMlHG55vpMv5QaXhcfHkIY4eizKa4r6CYgaKe3SY2g0vMfFREqLqhOutCTY1WvZ00R5WjrT5n'); 13 | 14 | const Payment = () => { 15 | const [user, loading, error] = useAuthState(auth); 16 | 17 | const {id} = useParams(); 18 | const url = `https://tech-specter.onrender.com/order/${id}`; 19 | 20 | const {data: singleOrder, isLoading} = useQuery(['order', id], () => fetch(url, { 21 | method: 'GET', 22 | headers:{ 23 | authorization: `Bearer ${localStorage.getItem('accessToken')}` 24 | } 25 | }).then(res=>res.json())); 26 | 27 | if(isLoading){ 28 | return 29 | } 30 | 31 | return ( 32 |
33 | 34 | 35 | Hello, {user.displayName} 36 | Pay for {singleOrder.service} 37 | 38 | Please pay: {singleOrder.price} BDT 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 |
51 | ); 52 | }; 53 | 54 | export default Payment; -------------------------------------------------------------------------------- /src/Pages/Dashboard/Users/UserRow.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Button } from 'react-bootstrap'; 3 | import { toast } from 'react-toastify'; 4 | 5 | const UserRow = ({user, index, refetch}) => { 6 | const {email, role} = user; 7 | 8 | const makeAdmin = () =>{ 9 | fetch(`https://tech-specter.onrender.com/user/admin/${email}`,{ 10 | method: 'PUT', 11 | headers: { 12 | authorization: `Bearer ${localStorage.getItem('accessToken')}` 13 | } 14 | }) 15 | .then(res => { 16 | if(res.status === 403){ 17 | toast.error('Failed to Make an admin'); 18 | } 19 | return res.json()}) 20 | .then(data =>{ 21 | if (data.modifiedCount > 0) { 22 | refetch(); 23 | toast.success(`Successfully made an admin`); 24 | } 25 | }) 26 | } 27 | return ( 28 | 29 | {index + 1} 30 | {user?.email} 31 | {role !== 'admin' &&} 32 | 33 | ); 34 | }; 35 | 36 | export default UserRow; -------------------------------------------------------------------------------- /src/Pages/Dashboard/Users/Users.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { Pagination, Table } from "react-bootstrap"; 3 | import { useQuery } from "react-query"; 4 | import Loading from "../../../Components/Shared/Loading/Loading"; 5 | import UserRow from "./UserRow"; 6 | 7 | const Users = () => { 8 | const pageSize = 10; // Number of items to display per page 9 | const [currentPage, setCurrentPage] = useState(1); // Current page number 10 | 11 | const { 12 | data: users, 13 | isLoading, 14 | refetch, 15 | } = useQuery("users", () => 16 | fetch("https://tech-specter.onrender.com/user", { 17 | method: "GET", 18 | headers: { 19 | authorization: `Bearer ${localStorage.getItem("accessToken")}`, 20 | }, 21 | }).then((res) => res.json()) 22 | ); 23 | 24 | if (isLoading) { 25 | return ; 26 | } 27 | 28 | const totalPages = Math.ceil(users.length / pageSize); // Total number of pages 29 | const startIndex = (currentPage - 1) * pageSize; // Index of first item on current page 30 | const endIndex = startIndex + pageSize; // Index of last item on current page 31 | const currentUsers = users.slice(startIndex, endIndex); // Items to display on current page 32 | 33 | const handlePageChange = (pageNumber) => { 34 | setCurrentPage(pageNumber); 35 | }; 36 | 37 | return ( 38 |
39 |

All Users [Total {users.length}]

40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | {currentUsers.map((user, index) => ( 50 | 56 | ))} 57 | 58 |
IndexUser EmailMake Admin
59 |
60 | 61 | handlePageChange(1)} disabled={currentPage === 1} /> 62 | handlePageChange(currentPage - 1)} disabled={currentPage === 1} /> 63 | {Array.from({ length: totalPages }, (_, i) => ( 64 | handlePageChange(i + 1)}> 65 | {i + 1} 66 | 67 | ))} 68 | handlePageChange(currentPage + 1)} disabled={currentPage === totalPages} /> 69 | handlePageChange(totalPages)} disabled={currentPage === totalPages} /> 70 | 71 |
72 |
73 | ); 74 | }; 75 | 76 | export default Users; 77 | -------------------------------------------------------------------------------- /src/Pages/Dashboard/__payment_steps.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 1. install stripe react stripe js 3 | * 2. open stripe account on stripe website 4 | * 3. get publishable key pk___ 5 | * 4. Create Elements wrapper using publishable key 6 | * 5. Create Checkout Form using Card element, useStripe, useElements 7 | * 6. get card elements info(credit card info) 8 | * 7. get credit card info/error + display card error (if any) 9 | * ---------------- 10 | * 9. get client secret from backend via payment intent post api 11 | * 10. store client secret on the client side 12 | * 11. Create card payment confirmation 13 | * 12. once payment is confirmed save payment information to the server 14 | * 13. display transaction id 15 | */ -------------------------------------------------------------------------------- /src/Pages/EducationBlogsPage/AllBlogs/AllBlogs.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import { 3 | Button, 4 | ButtonGroup, 5 | Container, 6 | Pagination, 7 | Row, 8 | Spinner, 9 | Toast 10 | } from "react-bootstrap"; 11 | import PageTitle from "../../../Components/Shared/PageTitle/PageTitle"; 12 | import SingleBlog from "../SingleBlog/SingleBlog"; 13 | 14 | const AllBlogs = () => { 15 | const [blogs, setBlogs] = useState([]); 16 | const count = blogs.length; 17 | 18 | useEffect(() => { 19 | fetch("https://tech-specter.onrender.com/blogs") 20 | .then((res) => res.json()) 21 | .then((data) => { 22 | console.log(data); 23 | setBlogs(data); 24 | }) 25 | .catch((error) => Toast.error(error.message)); 26 | }, []); 27 | 28 | const [tempBlogs, setTempBlogs] = useState(blogs); 29 | const [currentPage, setCurrentPage] = useState(1); 30 | const [blogsPerPage, setBlogsPerPage] = useState(6); 31 | 32 | const filterBlogs = (blogCate) => { 33 | const cateServices = blogs.filter((currentCourses) => { 34 | return currentCourses.category === blogCate; 35 | }); 36 | if (blogCate === "All") { 37 | setTempBlogs(blogs); 38 | } else { 39 | setTempBlogs(cateServices); 40 | } 41 | setCurrentPage(1); 42 | }; 43 | 44 | const totalPages = Math.ceil(tempBlogs.length / blogsPerPage); 45 | 46 | const handlePageChange = (pageNumber) => { 47 | setCurrentPage(pageNumber); 48 | }; 49 | 50 | const indexOfLastBlog = currentPage * blogsPerPage; 51 | const indexOfFirstBlog = indexOfLastBlog - blogsPerPage; 52 | const currentBlogs = tempBlogs.slice(indexOfFirstBlog, indexOfLastBlog); 53 | 54 | return ( 55 | <> 56 | {!count ? ( 57 |
58 | 59 | Loading... 60 | 61 |
Loading...
62 |
63 | ) : ( 64 | 65 | 66 |

67 | LATEST Blogs 68 |

69 |

70 | Learn a new thing to build career! 71 |

72 | 73 | 74 | 81 | 88 | 95 | 102 | 109 | 110 | 111 | 112 | {currentBlogs.length === 0 113 | ? blogs?.map((singleBlog) => ( 114 | 115 | )) 116 | : currentBlogs.map((singleBlog) => ( 117 | 121 | ))} 122 | 123 |
124 | 125 | {[...Array(totalPages)].map((_, index) => ( 126 | handlePageChange(index + 1)} 130 | > 131 | {index + 1} 132 | 133 | ))} 134 | 135 |
136 |
137 | )} 138 | 139 | ); 140 | }; 141 | 142 | export default AllBlogs; 143 | -------------------------------------------------------------------------------- /src/Pages/EducationBlogsPage/BlogDetails/BlogDetails.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Button, Card, Container } from 'react-bootstrap'; 3 | import { useParams } from 'react-router-dom'; 4 | import useBlogDetails from '../../../hooks/useBlogDetails/useBlogDetails'; 5 | 6 | const BlogDetails = () => { 7 | const { blogId } = useParams(); 8 | const [blog] = useBlogDetails(blogId); 9 | return ( 10 | 11 | 12 | 13 | 14 | {blog.name} 15 | 16 | {blog.description} 17 | 18 | 19 |
{blog.desTitle1} :

{blog.description1} 20 |
21 | 22 |
{blog.desTitle2} :

{blog.description2} 23 |
24 | 25 |
{blog.desTitle3} :

{blog.description3} 26 |
27 | 28 |
{blog.desTitle4} :

{blog.description4} 29 |
30 | 31 |
{blog.desTitle5} :

{blog.description5} 32 |
33 | 34 |
35 |
36 |
37 | ); 38 | }; 39 | 40 | export default BlogDetails; -------------------------------------------------------------------------------- /src/Pages/EducationBlogsPage/SingleBlog/SingleBlog.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Card, Col } from 'react-bootstrap'; 3 | import { useNavigate } from 'react-router-dom'; 4 | 5 | const SingleBlog = ({singleBlog}) => { 6 | const { _id, name, description, price, image } = singleBlog; 7 | const navigate = useNavigate(); 8 | 9 | const navigateToBlogDetails = id=>{ 10 | navigate(`/blogDetails/${id}`); 11 | // console.log(navigate); 12 | } 13 | return ( 14 | 15 | 16 |
17 | 22 |
23 | 24 | {name} 25 | 26 | 27 | {description.slice(0,97)}... 28 | 29 | 30 | 31 |
32 | 33 | ); 34 | }; 35 | 36 | export default SingleBlog; -------------------------------------------------------------------------------- /src/Pages/Home/Home.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahidmonowarr/tech-specter-client/87077e7335351323a2066924bca851ce0f711bca/src/Pages/Home/Home.css -------------------------------------------------------------------------------- /src/Pages/Home/Home.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Banner from '../../Components/Banner/Banner'; 3 | import Contact from '../../Components/Contact/Contact'; 4 | import OfferServices from '../../Components/OfferServices/OfferServices'; 5 | import OurPartners from '../../Components/OurPartners/OurPartners'; 6 | import PageTitle from '../../Components/Shared/PageTitle/PageTitle'; 7 | import Reviews from '../AllReviews/Reviews/Reviews'; 8 | import './Home.css'; 9 | 10 | const Home = () => { 11 | return ( 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | ); 21 | }; 22 | 23 | export default Home; -------------------------------------------------------------------------------- /src/Pages/Login/Login/Login.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #9A616D; 3 | } 4 | 5 | .btn{ 6 | background-color: black; 7 | } 8 | 9 | .vert-move { 10 | -webkit-animation: mover 1.5s infinite alternate; 11 | animation: mover 1.5s infinite alternate; 12 | } 13 | .vert-move { 14 | -webkit-animation: mover 1.5s infinite alternate; 15 | animation: mover 1.5s infinite alternate; 16 | } 17 | @-webkit-keyframes mover { 18 | 0% { transform: translateY(20px); } 19 | 100% { transform: translateY(-10px); } 20 | } 21 | @keyframes mover { 22 | 0% { transform: translateY(20px); } 23 | 100% { transform: translateY(-10px); } 24 | } -------------------------------------------------------------------------------- /src/Pages/Login/Login/Login.js: -------------------------------------------------------------------------------- 1 | import { MDBBtn, MDBCard, MDBCardBody, MDBCardImage, MDBCol, MDBContainer, MDBIcon, MDBInput, MDBRow } from 'mdb-react-ui-kit'; 2 | import React, { useEffect } from 'react'; 3 | import { Link, useLocation, useNavigate } from 'react-router-dom'; 4 | import './Login.css'; 5 | import { useSignInWithEmailAndPassword, useSignInWithGoogle } from 'react-firebase-hooks/auth'; 6 | import auth from '../../../firebase.init'; 7 | import { useForm } from 'react-hook-form'; 8 | import { Spinner } from 'react-bootstrap'; 9 | import Loading from '../../../Components/Shared/Loading/Loading'; 10 | import { toast } from 'react-toastify'; 11 | import useToken from '../../../hooks/useToken/useToken'; 12 | import PageTitle from '../../../Components/Shared/PageTitle/PageTitle'; 13 | 14 | 15 | const Login = () => { 16 | const [signInWithGoogle, gUser, gLoading, gError] = useSignInWithGoogle(auth); 17 | const { register, handleSubmit, formState: { errors } } = useForm(); 18 | 19 | const [ 20 | signInWithEmailAndPassword, 21 | user, 22 | loading, 23 | error, 24 | ] = useSignInWithEmailAndPassword(auth); 25 | 26 | const [token] = useToken(user || gUser) 27 | 28 | let signInError; 29 | const navigate = useNavigate(); 30 | const location = useLocation(); 31 | 32 | let from = location.state?.from?.pathname || "/"; 33 | 34 | useEffect( () =>{ 35 | if (token) { 36 | navigate(from, { replace: true }); 37 | toast('Logged In Successful'); 38 | } 39 | }, [token, from, navigate]) 40 | 41 | if(loading || gLoading){ 42 | return 43 | } 44 | 45 | if(error || gError){ 46 | signInError=

{error?.message || gError?.message}

47 | } 48 | 49 | const onSubmit = data => { 50 | signInWithEmailAndPassword(data.email, data.password); 51 | } 52 | 53 | return ( 54 |
55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 |
69 | 70 | TECH-SPECTER 71 |
72 | 73 |
SignIn to your account
74 |
75 | 76 | 77 | {/* for email */} 78 |
79 |

80 | 96 | 100 |
101 | 102 | {/* for password */} 103 |
104 |
105 | 120 | 124 |
125 | 126 | {signInError} 127 | 128 |
129 | 130 | Forgot password? 131 |

Don't have an account? Register here

132 | 133 |

Or SignIn with:

134 | signInWithGoogle()} className="mb-2 mx-auto w-30" size="lg" style={{backgroundColor: '#dd4b39'}} > 135 | 136 | google 137 | 138 | 139 | 140 |
141 |
142 | 143 |
144 |
145 | 146 |
147 |
148 | ); 149 | }; 150 | 151 | export default Login; -------------------------------------------------------------------------------- /src/Pages/Login/Register/Register.js: -------------------------------------------------------------------------------- 1 | import { MDBBtn, MDBCard, MDBCardBody, MDBCardImage, MDBCol, MDBContainer, MDBIcon, MDBRow } from 'mdb-react-ui-kit'; 2 | import React from 'react'; 3 | import { useCreateUserWithEmailAndPassword, useSignInWithGoogle, useUpdateProfile } from 'react-firebase-hooks/auth'; 4 | import { Link, useNavigate } from 'react-router-dom'; 5 | import auth from '../../../firebase.init'; 6 | import { useForm } from 'react-hook-form'; 7 | import Loading from '../../../Components/Shared/Loading/Loading'; 8 | import { reload } from 'firebase/auth'; 9 | import useToken from '../../../hooks/useToken/useToken'; 10 | import '../Login/Login.css'; 11 | import PageTitle from '../../../Components/Shared/PageTitle/PageTitle'; 12 | 13 | const Register = () => { 14 | const [signInWithGoogle, gUser, gLoading, gError] = useSignInWithGoogle(auth); 15 | const { register, handleSubmit, formState: { errors } } = useForm(); 16 | 17 | const [ 18 | createUserWithEmailAndPassword, 19 | user, 20 | loading, 21 | error, 22 | ] = useCreateUserWithEmailAndPassword(auth); 23 | 24 | const [updateProfile, updating, updateError] = useUpdateProfile(auth); 25 | 26 | const [token] = useToken(user || gUser); 27 | 28 | const navigate = useNavigate(); 29 | 30 | let signInError; 31 | 32 | if(loading || gLoading || updating){ 33 | return 34 | } 35 | 36 | if(error || gError || updateError){ 37 | signInError=

{error?.message || gError?.message || updateError?.message}

38 | } 39 | 40 | if(token){ 41 | navigate('/home'); 42 | } 43 | 44 | const onSubmit = async data => { 45 | await createUserWithEmailAndPassword(data.email, data.password); 46 | await updateProfile({displayName: data.name}); 47 | alert('Profile Updated'); 48 | reload(); 49 | navigate('/home'); 50 | 51 | 52 | } 53 | 54 | return ( 55 |
56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 |
70 | 71 | TECH-SPECTER 72 |
73 | 74 |
SignUp to your account
75 | 76 |
77 | 78 | {/* for name */} 79 |
80 |

81 | 92 | 95 |
96 | 97 | {/* for email */} 98 |
99 |

100 | 116 | 120 |
121 | 122 | {/* for password */} 123 |
124 |
125 | 140 | 144 |
145 | 146 | {signInError} 147 | 148 |
149 | 150 |

Already have an account? Login here

151 |

Or SignUp with:

152 | 153 | signInWithGoogle()} className="mb-2 mx-auto w-30" size="lg" style={{backgroundColor: '#dd4b39'}}> 154 | 155 | google 156 | 157 | 158 | 159 |
160 |
161 | 162 |
163 |
164 | 165 |
166 |
167 | ); 168 | }; 169 | 170 | export default Register; -------------------------------------------------------------------------------- /src/Pages/Login/RequireAdmin/RequireAdmin.js: -------------------------------------------------------------------------------- 1 | import { signOut } from 'firebase/auth'; 2 | import React from 'react'; 3 | import { useAuthState } from 'react-firebase-hooks/auth'; 4 | import { Navigate, useLocation } from 'react-router-dom'; 5 | import Loading from '../../../Components/Shared/Loading/Loading'; 6 | import auth from '../../../firebase.init'; 7 | import useAdmin from '../../../hooks/useAdmin/useAdmin'; 8 | 9 | const RequireAdmin = ({children}) => { 10 | const [user, loading] = useAuthState(auth); 11 | const [admin, adminLoading] = useAdmin(user); 12 | const location = useLocation(); 13 | 14 | if(loading || adminLoading){ 15 | return 16 | } 17 | 18 | if(!user || !admin){ 19 | signOut(auth); 20 | return 21 | } 22 | return children; 23 | }; 24 | 25 | export default RequireAdmin; -------------------------------------------------------------------------------- /src/Pages/Login/RequireAuth/RequireAuth.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useAuthState } from 'react-firebase-hooks/auth'; 3 | import { Navigate, useLocation } from 'react-router-dom'; 4 | import Loading from '../../../Components/Shared/Loading/Loading'; 5 | import auth from '../../../firebase.init'; 6 | 7 | const RequireAuth = ({children}) => { 8 | const [user, loading] = useAuthState(auth); 9 | const location = useLocation(); 10 | 11 | if(loading){ 12 | return 13 | } 14 | 15 | if(!user){ 16 | return 17 | } 18 | 19 | 20 | return children; 21 | }; 22 | 23 | export default RequireAuth; -------------------------------------------------------------------------------- /src/Pages/NotFound/NotFound.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Container } from 'react-bootstrap'; 3 | 4 | const NotFound = () => { 5 | return ( 6 | 7 |
8 | 14 |
15 |
16 | ); 17 | }; 18 | 19 | export default NotFound; -------------------------------------------------------------------------------- /src/Pages/PlaceBooking/PlaceBooking.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import React from 'react'; 3 | import { useAuthState } from 'react-firebase-hooks/auth'; 4 | import { useNavigate, useParams } from 'react-router-dom'; 5 | import { toast } from 'react-toastify'; 6 | import PageTitle from '../../Components/Shared/PageTitle/PageTitle'; 7 | import auth from '../../firebase.init'; 8 | import usePlaceDetails from '../../hooks/usePlaceDetails/usePlaceDetails'; 9 | 10 | const PlaceBooking = () => { 11 | const { serviceId } = useParams(); 12 | const [place] = usePlaceDetails(serviceId); 13 | const [user] = useAuthState(auth); 14 | 15 | const navigate = useNavigate(); 16 | 17 | if(user){ 18 | // console.log(user); 19 | } 20 | 21 | const handlePlaceOrder = event =>{ 22 | event.preventDefault(); 23 | const order = { 24 | email: user.email, 25 | service: place.name, 26 | serviceId: serviceId, 27 | image: place.image, 28 | price: place.price, 29 | date: place.date, 30 | description: place.description, 31 | phone: event.target.phone.value, 32 | status: "Pending" 33 | 34 | } 35 | axios.post('https://tech-specter.onrender.com/order', order) 36 | .then(res => { 37 | const {data}= res; 38 | if (data.insertedId) { 39 | toast('Your Order is Booked'); 40 | event.target.reset(); 41 | navigate('/dashboard/myOrders'); 42 | } 43 | // console.log(res); 44 | }) 45 | } 46 | 47 | return ( 48 |
49 | 50 |
51 |
52 |
53 |
54 |

Place Your Booking

55 |

Fill in the data below.

56 |
57 | 64 | 65 | 73 | 80 | 86 | 94 | 95 |
96 |
97 |
98 |
99 |
100 |
101 | ); 102 | }; 103 | 104 | export default PlaceBooking; -------------------------------------------------------------------------------- /src/Pages/TravelPage/AllPlaces/AllPlaces.js: -------------------------------------------------------------------------------- 1 | import { Toast } from "bootstrap"; 2 | import React, { useEffect, useState } from 'react'; 3 | import { Button, ButtonGroup, Container, Row, Spinner } from 'react-bootstrap'; 4 | import PageTitle from '../../../Components/Shared/PageTitle/PageTitle'; 5 | import SinglePlace from '../SinglePlace/SinglePlace'; 6 | 7 | const AllPlaces = () => { 8 | const [places, setPlaces] = useState([]); 9 | const count = places.length; 10 | 11 | useEffect(() => { 12 | fetch("https://tech-specter.onrender.com/travel") 13 | .then((res) => res.json()) 14 | .then((data) => { 15 | setPlaces(data); 16 | }) 17 | .catch((error) => Toast.error(error.message)); 18 | }, []); 19 | 20 | const [tempPlaces, setTempPlaces] = useState(places); 21 | 22 | const filterPlaces = (placeCate) => { 23 | const cateServices = places.filter((currentCourses) => { 24 | return currentCourses.category === placeCate; 25 | }); 26 | if (placeCate === "All") { 27 | setTempPlaces(places); 28 | } else { 29 | setTempPlaces(cateServices); 30 | } 31 | }; 32 | return ( 33 | <> 34 | {!count ? ( 35 |
36 | 37 | Loading... 38 | 39 |
Loading...
40 |
41 | ) : ( 42 | 43 | 44 |

45 | LATEST Places 46 |

47 |

48 | What We provide to Our Customer! 49 |

50 | 51 | 52 | 55 | 61 | 67 | 73 | 74 | 75 | 76 | {tempPlaces.length === 0 77 | ? places?.map((singlePlace) => ( 78 | 82 | )) 83 | : tempPlaces.map((singlePlace) => ( 84 | 88 | ))} 89 | 90 |
91 | )} 92 | 93 | ); 94 | }; 95 | 96 | export default AllPlaces; -------------------------------------------------------------------------------- /src/Pages/TravelPage/PlaceDetails/PlaceDetails.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | import { Carousel, Col, Container, Row, Toast } from "react-bootstrap"; 3 | import Button from "react-bootstrap/Button"; 4 | import Card from "react-bootstrap/Card"; 5 | import Rating from "react-rating"; 6 | import { Link, useParams } from "react-router-dom"; 7 | import PageTitle from "../../../Components/Shared/PageTitle/PageTitle"; 8 | import usePlaceDetails from "../../../hooks/usePlaceDetails/usePlaceDetails"; 9 | 10 | 11 | const PlaceDetails = () => { 12 | const { serviceId } = useParams(); 13 | const [place] = usePlaceDetails(serviceId); 14 | 15 | const [loading, setLoading] = useState(true); 16 | const [reviews, setReviews] = useState(); 17 | 18 | useEffect(() => { 19 | fetch("https://tech-specter.onrender.com/reviews") 20 | .then((res) => res.json()) 21 | .then((data) => { 22 | setReviews(data); 23 | setLoading(false); 24 | }) 25 | .catch((error) => Toast.error(error.message)); 26 | }, []); 27 | 28 | const filteredReviews = reviews?.filter( 29 | (review) => review.category === "travel" 30 | ); 31 | // console.log(filteredReviews); 32 | 33 | return ( 34 | 35 | 36 |

{place.category}

37 | 38 | 39 | 40 | 41 | First slide 47 | 48 | 49 | Second slide 55 | 56 | 57 | Third slide 64 | 65 | 66 | 67 |
Reviews
68 | 69 | {filteredReviews?.map((review) => ( 70 | 78 | 79 |
{review.name}
80 |
81 | {" "} 88 | {review.rating} 89 |
90 | {review.description} 91 |
92 | 93 | ))} 94 |
95 |
96 | 97 | 98 | 99 | {place.name} 100 |

based on 120 reviews
104 | 105 |
106 | 107 | Price: 108 | {place.price}.00 USD 109 | 110 | 111 | {place.description} 112 | 113 | 114 | {place.description1} 115 | 116 | 117 | {place.description2} 118 | 119 | 120 | {place.description3} 121 | 122 | 123 | What we provide? 124 | 125 |
    126 |
  • 24 hours customer support.
  • 127 |
  • Team of 4 peoples will always ready to help.
  • 128 |
  • Immediate solution to your problem.
  • 129 |
  • Commitment to make your travel safe.
  • 130 |
131 | 132 | 133 | 134 | 135 | 136 | 137 |
138 |
139 | 140 |
141 |
142 | ); 143 | }; 144 | 145 | export default PlaceDetails; -------------------------------------------------------------------------------- /src/Pages/TravelPage/SinglePlace/SinglePlace.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Card, Col } from 'react-bootstrap'; 3 | import { useNavigate } from 'react-router-dom'; 4 | 5 | const SinglePlace = ({singlePlace}) => { 6 | const { _id, name, description, price, image } = singlePlace; 7 | const navigate = useNavigate(); 8 | 9 | const navigateToTravelDetails = id=>{ 10 | navigate(`/placeDetails/${id}`); 11 | // console.log(navigate); 12 | } 13 | return ( 14 | 15 | 16 |
17 | 22 |
23 | 24 | 25 | {name} 26 | 27 | Price: {price}.00 USD 28 | {description.slice(0,85)}... 29 | 30 | 31 | 32 |
33 | 34 | ); 35 | }; 36 | 37 | export default SinglePlace; -------------------------------------------------------------------------------- /src/firebase.init.js: -------------------------------------------------------------------------------- 1 | // Import the functions you need from the SDKs you need 2 | import { initializeApp } from "firebase/app"; 3 | import { getAuth } from "firebase/auth"; 4 | // TODO: Add SDKs for Firebase products that you want to use 5 | // https://firebase.google.com/docs/web/setup#available-libraries 6 | 7 | // Your web app's Firebase configuration 8 | const firebaseConfig = { 9 | apiKey: process.env.REACT_APP_API_KEY, 10 | authDomain: process.env.REACT_APP_AUTH_DOMAIN, 11 | projectId: process.env.REACT_APP_PROJECT_ID, 12 | storageBucket: process.env.REACT_APP_STORAGE_BUCKET, 13 | messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID, 14 | appId: process.env.REACT_APP_APP_ID, 15 | }; 16 | 17 | // Initialize Firebase 18 | const app = initializeApp(firebaseConfig); 19 | 20 | const auth = getAuth(app); 21 | 22 | export default auth; -------------------------------------------------------------------------------- /src/hooks/useAdmin/useAdmin.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | 3 | const useAdmin = user =>{ 4 | const [admin, setAdmin] = useState(false); 5 | const [adminLoading, setAdminLoading] = useState(true); 6 | useEffect( () =>{ 7 | const email = user?.email; 8 | if(email){ 9 | fetch(`https://tech-specter.onrender.com/admin/${email}`, { 10 | method:'GET', 11 | headers: { 12 | 'content-type': 'application/json', 13 | authorization: `Bearer ${localStorage.getItem('accessToken')}` 14 | } 15 | }) 16 | .then(res=>res.json()) 17 | .then(data => { 18 | setAdmin(data.admin); 19 | setAdminLoading(false); 20 | }) 21 | } 22 | }, [user]) 23 | 24 | return [admin, adminLoading] 25 | } 26 | 27 | export default useAdmin; -------------------------------------------------------------------------------- /src/hooks/useBlogDetails/useBlogDetails.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | 3 | const useBlogDetails = blogId => { 4 | const [blog, setBlog] = useState({}); 5 | 6 | useEffect(() => { 7 | const url = `https://tech-specter.onrender.com/blogs/${blogId}`; 8 | 9 | fetch(url) 10 | .then((res) => res.json()) 11 | .then((data) => setBlog(data)); 12 | }, [blogId]); 13 | return [blog] 14 | }; 15 | 16 | export default useBlogDetails; -------------------------------------------------------------------------------- /src/hooks/useCourseDetails/useCourseDetails.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | 3 | const useCourseDetails = serviceId => { 4 | const [course, setCourse] = useState({}); 5 | 6 | useEffect(() => { 7 | const url = `https://tech-specter.onrender.com/course/${serviceId}`; 8 | 9 | fetch(url) 10 | .then((res) => res.json()) 11 | .then((data) => setCourse(data)); 12 | }, [serviceId]); 13 | return [course] 14 | }; 15 | 16 | export default useCourseDetails; 17 | -------------------------------------------------------------------------------- /src/hooks/usePlaceDetails/usePlaceDetails.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | 3 | const usePlaceDetails = serviceId => { 4 | const [place, setPlace] = useState({}); 5 | 6 | useEffect(() => { 7 | const url = `https://tech-specter.onrender.com/travel/${serviceId}`; 8 | 9 | fetch(url) 10 | .then((res) => res.json()) 11 | .then((data) => setPlace(data)); 12 | }, [serviceId]); 13 | return [place] 14 | }; 15 | 16 | export default usePlaceDetails; -------------------------------------------------------------------------------- /src/hooks/useToken/useToken.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | 3 | const useToken = user =>{ 4 | const [token, setToken] = useState(''); 5 | 6 | useEffect(()=>{ 7 | // console.log('user inside useToken',user); 8 | const email = user?.user?.email; 9 | const currentUser = {email: email}; 10 | if(email){ 11 | fetch(`https://tech-specter.onrender.com/user/${email}`, { 12 | method:'PUT', 13 | headers: { 14 | 'content-type': 'application/json' 15 | }, 16 | body:JSON.stringify(currentUser) 17 | }) 18 | .then(res => res.json()) 19 | .then(data => { 20 | // console.log('data inside useToken', data); 21 | const accessToken = data.token; 22 | localStorage.setItem('accessToken', accessToken); 23 | setToken(accessToken); 24 | }) 25 | } 26 | },[user]); 27 | return [token]; 28 | } 29 | 30 | export default useToken; -------------------------------------------------------------------------------- /src/images/best-cook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahidmonowarr/tech-specter-client/87077e7335351323a2066924bca851ce0f711bca/src/images/best-cook.png -------------------------------------------------------------------------------- /src/images/blood-concept.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahidmonowarr/tech-specter-client/87077e7335351323a2066924bca851ce0f711bca/src/images/blood-concept.jpg -------------------------------------------------------------------------------- /src/images/delivery-concept.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahidmonowarr/tech-specter-client/87077e7335351323a2066924bca851ce0f711bca/src/images/delivery-concept.jpg -------------------------------------------------------------------------------- /src/images/fast-delivery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahidmonowarr/tech-specter-client/87077e7335351323a2066924bca851ce0f711bca/src/images/fast-delivery.png -------------------------------------------------------------------------------- /src/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahidmonowarr/tech-specter-client/87077e7335351323a2066924bca851ce0f711bca/src/images/logo.png -------------------------------------------------------------------------------- /src/images/review.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahidmonowarr/tech-specter-client/87077e7335351323a2066924bca851ce0f711bca/src/images/review.jpg -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import "./index.css"; 4 | import App from "./App"; 5 | import reportWebVitals from "./reportWebVitals"; 6 | import "mdb-react-ui-kit/dist/css/mdb.min.css"; 7 | import { QueryClient, QueryClientProvider } from "react-query"; 8 | import { ReactQueryDevtools } from "react-query/devtools"; 9 | import { HelmetProvider } from "react-helmet-async"; 10 | 11 | const queryClient = new QueryClient(); 12 | 13 | const root = ReactDOM.createRoot(document.getElementById("root")); 14 | root.render( 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | ); 24 | 25 | // If you want to start measuring performance in your app, pass a function 26 | // to log results (for example: reportWebVitals(console.log)) 27 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 28 | reportWebVitals(); 29 | -------------------------------------------------------------------------------- /src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | --------------------------------------------------------------------------------