├── src ├── components │ ├── Comments │ │ ├── index.tsx │ │ ├── CommentCard.tsx │ │ ├── CommentsCards.tsx │ │ └── usersData.tsx │ ├── House │ │ ├── index.tsx │ │ ├── HousesData.tsx │ │ ├── House.tsx │ │ └── Houses.tsx │ ├── Articles │ │ ├── index.tsx │ │ ├── ArticleCard.tsx │ │ └── ArticlesCards.tsx │ ├── Navbar │ │ ├── index.tsx │ │ ├── HorizontalNavbar.tsx │ │ ├── Navbar.tsx │ │ └── VerticalNavbar.tsx │ ├── Search │ │ ├── index.tsx │ │ ├── DefaultSearchBar.tsx │ │ ├── SearchCityBar.tsx │ │ ├── SearchPriceBar.tsx │ │ ├── DropDownMenu.tsx │ │ └── SearchDropDownMenu.tsx │ ├── Vehicle │ │ ├── index.tsx │ │ ├── CarsData.tsx │ │ ├── MotorbikesData.tsx │ │ ├── Vehicle.tsx │ │ └── Vehicles.tsx │ ├── Header.tsx │ ├── Footer.tsx │ ├── HeroSection.tsx │ ├── Dialog.tsx │ └── Description.tsx ├── vite-env.d.ts ├── assets │ └── imgs │ │ ├── cars │ │ ├── c1.webp │ │ ├── c2.webp │ │ ├── c3.webp │ │ ├── c4.webp │ │ ├── c5.webp │ │ ├── c6.webp │ │ ├── c7.webp │ │ ├── c8.webp │ │ ├── c9.webp │ │ ├── c10.webp │ │ ├── c11.webp │ │ ├── c12.webp │ │ ├── c13.webp │ │ ├── c14.webp │ │ └── c15.webp │ │ ├── cards │ │ ├── car.jpg │ │ ├── bikeDark.png │ │ ├── houseDark.jpg │ │ └── houseLight.webp │ │ ├── houses │ │ ├── h1.webp │ │ ├── h2.webp │ │ ├── h3.webp │ │ ├── h4.webp │ │ ├── h5.webp │ │ ├── h6.webp │ │ ├── h7.webp │ │ ├── h8.webp │ │ ├── h9.webp │ │ ├── h10.webp │ │ ├── h11.webp │ │ ├── h12.webp │ │ ├── h13.webp │ │ ├── h14.webp │ │ └── h15.webp │ │ ├── house-interior.avif │ │ ├── motorbikes │ │ ├── m1.webp │ │ ├── m10.webp │ │ ├── m11.webp │ │ ├── m12.webp │ │ ├── m13.webp │ │ ├── m14.webp │ │ ├── m15.webp │ │ ├── m2.webp │ │ ├── m3.webp │ │ ├── m4.webp │ │ ├── m5.webp │ │ ├── m6.webp │ │ ├── m7.webp │ │ ├── m8.webp │ │ └── m9.webp │ │ └── description-section │ │ ├── house.jpg │ │ ├── moto.jpg │ │ └── lambo1.jpg ├── main.tsx ├── pages │ ├── CarsPage.tsx │ ├── MotorBikesPage.tsx │ ├── HomePage.tsx │ ├── NotFoundPage.tsx │ ├── HousesPage.tsx │ └── VehiclesPage.tsx ├── index.css ├── layouts │ └── MainLayout.tsx ├── App.tsx └── types.ts ├── .prettierrc ├── postcss.config.js ├── tsconfig.node.json ├── vite.config.ts ├── .gitignore ├── index.html ├── favicon.svg ├── tailwind.config.js ├── .eslintrc.cjs ├── SECURITY.md ├── tsconfig.json ├── package.json ├── public └── vite.svg └── README.md /src/components/Comments/index.tsx: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["prettier-plugin-tailwindcss"] 3 | } 4 | -------------------------------------------------------------------------------- /src/components/House/index.tsx: -------------------------------------------------------------------------------- 1 | import Houses from "./Houses"; 2 | export default Houses; 3 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /src/components/Articles/index.tsx: -------------------------------------------------------------------------------- 1 | import ArticleCards from "./ArticlesCards"; 2 | 3 | export default ArticleCards; 4 | -------------------------------------------------------------------------------- /src/assets/imgs/cars/c1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/cars/c1.webp -------------------------------------------------------------------------------- /src/assets/imgs/cars/c2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/cars/c2.webp -------------------------------------------------------------------------------- /src/assets/imgs/cars/c3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/cars/c3.webp -------------------------------------------------------------------------------- /src/assets/imgs/cars/c4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/cars/c4.webp -------------------------------------------------------------------------------- /src/assets/imgs/cars/c5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/cars/c5.webp -------------------------------------------------------------------------------- /src/assets/imgs/cars/c6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/cars/c6.webp -------------------------------------------------------------------------------- /src/assets/imgs/cars/c7.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/cars/c7.webp -------------------------------------------------------------------------------- /src/assets/imgs/cars/c8.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/cars/c8.webp -------------------------------------------------------------------------------- /src/assets/imgs/cars/c9.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/cars/c9.webp -------------------------------------------------------------------------------- /src/assets/imgs/cards/car.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/cards/car.jpg -------------------------------------------------------------------------------- /src/assets/imgs/cars/c10.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/cars/c10.webp -------------------------------------------------------------------------------- /src/assets/imgs/cars/c11.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/cars/c11.webp -------------------------------------------------------------------------------- /src/assets/imgs/cars/c12.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/cars/c12.webp -------------------------------------------------------------------------------- /src/assets/imgs/cars/c13.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/cars/c13.webp -------------------------------------------------------------------------------- /src/assets/imgs/cars/c14.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/cars/c14.webp -------------------------------------------------------------------------------- /src/assets/imgs/cars/c15.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/cars/c15.webp -------------------------------------------------------------------------------- /src/assets/imgs/houses/h1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/houses/h1.webp -------------------------------------------------------------------------------- /src/assets/imgs/houses/h2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/houses/h2.webp -------------------------------------------------------------------------------- /src/assets/imgs/houses/h3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/houses/h3.webp -------------------------------------------------------------------------------- /src/assets/imgs/houses/h4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/houses/h4.webp -------------------------------------------------------------------------------- /src/assets/imgs/houses/h5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/houses/h5.webp -------------------------------------------------------------------------------- /src/assets/imgs/houses/h6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/houses/h6.webp -------------------------------------------------------------------------------- /src/assets/imgs/houses/h7.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/houses/h7.webp -------------------------------------------------------------------------------- /src/assets/imgs/houses/h8.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/houses/h8.webp -------------------------------------------------------------------------------- /src/assets/imgs/houses/h9.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/houses/h9.webp -------------------------------------------------------------------------------- /src/assets/imgs/houses/h10.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/houses/h10.webp -------------------------------------------------------------------------------- /src/assets/imgs/houses/h11.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/houses/h11.webp -------------------------------------------------------------------------------- /src/assets/imgs/houses/h12.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/houses/h12.webp -------------------------------------------------------------------------------- /src/assets/imgs/houses/h13.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/houses/h13.webp -------------------------------------------------------------------------------- /src/assets/imgs/houses/h14.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/houses/h14.webp -------------------------------------------------------------------------------- /src/assets/imgs/houses/h15.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/houses/h15.webp -------------------------------------------------------------------------------- /src/components/Navbar/index.tsx: -------------------------------------------------------------------------------- 1 | import Navbar from "./Navbar"; 2 | import MenuBurger from "./VerticalNavbar"; 3 | export { Navbar, MenuBurger }; 4 | -------------------------------------------------------------------------------- /src/assets/imgs/cards/bikeDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/cards/bikeDark.png -------------------------------------------------------------------------------- /src/assets/imgs/cards/houseDark.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/cards/houseDark.jpg -------------------------------------------------------------------------------- /src/assets/imgs/house-interior.avif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/house-interior.avif -------------------------------------------------------------------------------- /src/assets/imgs/motorbikes/m1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/motorbikes/m1.webp -------------------------------------------------------------------------------- /src/assets/imgs/motorbikes/m10.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/motorbikes/m10.webp -------------------------------------------------------------------------------- /src/assets/imgs/motorbikes/m11.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/motorbikes/m11.webp -------------------------------------------------------------------------------- /src/assets/imgs/motorbikes/m12.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/motorbikes/m12.webp -------------------------------------------------------------------------------- /src/assets/imgs/motorbikes/m13.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/motorbikes/m13.webp -------------------------------------------------------------------------------- /src/assets/imgs/motorbikes/m14.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/motorbikes/m14.webp -------------------------------------------------------------------------------- /src/assets/imgs/motorbikes/m15.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/motorbikes/m15.webp -------------------------------------------------------------------------------- /src/assets/imgs/motorbikes/m2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/motorbikes/m2.webp -------------------------------------------------------------------------------- /src/assets/imgs/motorbikes/m3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/motorbikes/m3.webp -------------------------------------------------------------------------------- /src/assets/imgs/motorbikes/m4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/motorbikes/m4.webp -------------------------------------------------------------------------------- /src/assets/imgs/motorbikes/m5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/motorbikes/m5.webp -------------------------------------------------------------------------------- /src/assets/imgs/motorbikes/m6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/motorbikes/m6.webp -------------------------------------------------------------------------------- /src/assets/imgs/motorbikes/m7.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/motorbikes/m7.webp -------------------------------------------------------------------------------- /src/assets/imgs/motorbikes/m8.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/motorbikes/m8.webp -------------------------------------------------------------------------------- /src/assets/imgs/motorbikes/m9.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/motorbikes/m9.webp -------------------------------------------------------------------------------- /src/assets/imgs/cards/houseLight.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/cards/houseLight.webp -------------------------------------------------------------------------------- /src/assets/imgs/description-section/house.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/description-section/house.jpg -------------------------------------------------------------------------------- /src/assets/imgs/description-section/moto.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/description-section/moto.jpg -------------------------------------------------------------------------------- /src/assets/imgs/description-section/lambo1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Friedrich482/react-houses-cars-motorbikes-sell/HEAD/src/assets/imgs/description-section/lambo1.jpg -------------------------------------------------------------------------------- /src/components/Search/index.tsx: -------------------------------------------------------------------------------- 1 | import SearchPriceBar from "./SearchPriceBar"; 2 | import SearchDropDownMenu from "./SearchDropDownMenu"; 3 | export default SearchDropDownMenu; 4 | export { SearchPriceBar }; 5 | -------------------------------------------------------------------------------- /src/components/Vehicle/index.tsx: -------------------------------------------------------------------------------- 1 | import Vehicles from "./Vehicles"; 2 | import CarsData from "./CarsData"; 3 | import MotorBikesData from "./MotorbikesData"; 4 | export default Vehicles; 5 | export { CarsData, MotorBikesData }; 6 | -------------------------------------------------------------------------------- /src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.tsx"; 4 | import "./index.css"; 5 | 6 | ReactDOM.createRoot(document.getElementById("root")!).render( 7 | 8 | 9 | , 10 | ); 11 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true, 8 | "strict": true 9 | }, 10 | "include": ["vite.config.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | server: { 8 | port: 3000, 9 | }, 10 | preview: { 11 | port: 8000, 12 | }, 13 | }); 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Houses + Cars + Motorbikes 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /favicon.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /src/pages/CarsPage.tsx: -------------------------------------------------------------------------------- 1 | import { CarsData } from "../components/Vehicle"; 2 | import type { DarkModeProps } from "../types"; 3 | import VehiclesPage from "./VehiclesPage"; 4 | 5 | const CarsPage = ({ dark }: DarkModeProps) => { 6 | document.title = "Cars"; 7 | const vehicleSelected = "Car"; 8 | return ( 9 | 14 | ); 15 | }; 16 | export default CarsPage; 17 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | export default { 3 | content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"], 4 | theme: { 5 | extend: { 6 | colors: { 7 | "default-white": " rgb(241, 241, 241)", 8 | "default-black": "hsl(240 10% 3.9%);", 9 | }, 10 | screens: { 11 | "description-section": "960px", 12 | "very-small": "350px", 13 | "house-break": "470px", 14 | }, 15 | }, 16 | }, 17 | plugins: [], 18 | }; 19 | -------------------------------------------------------------------------------- /src/pages/MotorBikesPage.tsx: -------------------------------------------------------------------------------- 1 | import { MotorBikesData } from "../components/Vehicle"; 2 | import type { DarkModeProps } from "../types"; 3 | import VehiclesPage from "./VehiclesPage"; 4 | 5 | const CarsPage = ({ dark }: DarkModeProps) => { 6 | document.title = "Motorbikes"; 7 | const vehicleSelected = "Motorbike"; 8 | return ( 9 | 14 | ); 15 | }; 16 | export default CarsPage; 17 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { browser: true, es2020: true }, 4 | extends: [ 5 | "eslint:recommended", 6 | "plugin:@typescript-eslint/recommended", 7 | "plugin:react-hooks/recommended", 8 | ], 9 | ignorePatterns: ["dist", ".eslintrc.cjs"], 10 | parser: "@typescript-eslint/parser", 11 | plugins: ["react-refresh"], 12 | rules: { 13 | "react-refresh/only-export-components": [ 14 | "warn", 15 | { allowConstantExport: true }, 16 | ], 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /src/components/Header.tsx: -------------------------------------------------------------------------------- 1 | import { Navbar } from "./Navbar"; 2 | import type { DarkModeProps } from "../types"; 3 | import { twMerge as tm } from "tailwind-merge"; 4 | const Header = ({ dark, setDark }: DarkModeProps) => { 5 | return ( 6 |
12 | 13 |
14 | ); 15 | }; 16 | 17 | export default Header; 18 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | body { 6 | display: flex; 7 | align-items: center; 8 | justify-content: center; 9 | /* background-color: rgb(241, 241, 241); */ 10 | background-attachment: fixed; 11 | font-family: "__geistSansFont_deb525", arial; 12 | font-weight: 400; 13 | font-style: normal; 14 | } 15 | #root { 16 | width: 100%; 17 | } 18 | html { 19 | scroll-behavior: smooth; 20 | } 21 | 22 | input::-webkit-outer-spin-button, 23 | input::-webkit-inner-spin-button { 24 | -webkit-appearance: none; 25 | margin: 0; 26 | } 27 | 28 | input[type="number"] { 29 | -moz-appearance: textfield; 30 | } 31 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a 20 | reported vulnerability, what to expect if the vulnerability is accepted or 21 | declined, etc. 22 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | "jsx": "react-jsx", 16 | 17 | /* Linting */ 18 | "strict": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "noFallthroughCasesInSwitch": true 22 | }, 23 | "include": ["src"], 24 | "references": [{ "path": "./tsconfig.node.json" }] 25 | } 26 | -------------------------------------------------------------------------------- /src/pages/HomePage.tsx: -------------------------------------------------------------------------------- 1 | import type { DarkModeProps } from "../types"; 2 | import HeroSection from "../components/HeroSection"; 3 | import Description from "../components/Description"; 4 | import ArticleCards from "../components/Articles"; 5 | import CommentsCards from "../components/Comments/CommentsCards"; 6 | const HomePage = ({ dark, setDark }: DarkModeProps) => { 7 | document.title = "Home"; 8 | return ( 9 |
10 | 11 | 12 | 13 | 14 |
15 | ); 16 | }; 17 | export default HomePage; 18 | -------------------------------------------------------------------------------- /src/layouts/MainLayout.tsx: -------------------------------------------------------------------------------- 1 | import { Outlet } from "react-router"; 2 | import { ToastContainer } from "react-toastify"; 3 | import "react-toastify/ReactToastify.css"; 4 | import { twMerge as tm } from "tailwind-merge"; 5 | import Header from "../components/Header"; 6 | import Footer from "../components/Footer"; 7 | import type { DarkModeProps } from "../types"; 8 | 9 | const MainLayout = ({ dark, setDark }: DarkModeProps) => { 10 | return ( 11 |
17 |
18 | 19 |
20 | 21 |
22 | ); 23 | }; 24 | export default MainLayout; 25 | -------------------------------------------------------------------------------- /src/components/Search/DefaultSearchBar.tsx: -------------------------------------------------------------------------------- 1 | import { twMerge as tm } from "tailwind-merge"; 2 | import { MdKeyboardArrowDown, MdKeyboardArrowUp } from "react-icons/md"; 3 | import { DefaultSearchBarProps } from "../../types"; 4 | // import { useEffect } from "react"; 5 | 6 | const DefaultSearchBar = ({ dark, searchParameter }: DefaultSearchBarProps) => { 7 | return ( 8 | 21 | ); 22 | }; 23 | export default DefaultSearchBar; 24 | -------------------------------------------------------------------------------- /src/components/Footer.tsx: -------------------------------------------------------------------------------- 1 | import type { DarkModeProps } from "../types"; 2 | import { twMerge as tm } from "tailwind-merge"; 3 | const Footer = ({ dark }: DarkModeProps) => { 4 | return ( 5 | 29 | ); 30 | }; 31 | 32 | export default Footer; 33 | -------------------------------------------------------------------------------- /src/pages/NotFoundPage.tsx: -------------------------------------------------------------------------------- 1 | import type { DarkModeProps } from "../types"; 2 | import { Link } from "react-router-dom"; 3 | import { twMerge as tm } from "tailwind-merge"; 4 | const NotFoundPage = ({ dark }: DarkModeProps) => { 5 | document.title = "Not found"; 6 | return ( 7 |
8 |
14 | 404 15 |
16 |
17 | This page could not be found 18 |
19 | 26 | Go back to the main page 27 | 28 |
29 | ); 30 | }; 31 | export default NotFoundPage; 32 | -------------------------------------------------------------------------------- /src/components/Search/SearchCityBar.tsx: -------------------------------------------------------------------------------- 1 | import { CiSearch } from "react-icons/ci"; 2 | import type { SearchCity } from "../../types"; 3 | import { twMerge as tm } from "tailwind-merge"; 4 | const SearchCityBar = ({ citySearch, setCitySearch, dark }: SearchCity) => { 5 | const searchCityInputHandler = ( 6 | event: React.ChangeEvent, 7 | ) => { 8 | setCitySearch(event.target.value); 9 | }; 10 | return ( 11 | <> 12 | 18 | { 22 | searchCityInputHandler(event); 23 | }} 24 | className={tm( 25 | "h-full w-10/12 flex-shrink-0 rounded-lg bg-default-white indent-1 outline-none", 26 | dark && "bg-default-black text-white", 27 | )} 28 | placeholder="Enter city..." 29 | /> 30 | 31 | ); 32 | }; 33 | export default SearchCityBar; 34 | -------------------------------------------------------------------------------- /src/components/Search/SearchPriceBar.tsx: -------------------------------------------------------------------------------- 1 | import { CiSearch } from "react-icons/ci"; 2 | import { SearchPrice } from "../../types"; 3 | import { twMerge as tm } from "tailwind-merge"; 4 | const SearchPriceBar = ({ dark, priceSearch, setPriceSearch }: SearchPrice) => { 5 | const searchPriceInputHandler = ( 6 | event: React.ChangeEvent, 7 | ) => { 8 | setPriceSearch(Number(event.target.value)); 9 | }; 10 | return ( 11 | <> 12 | 18 | { 22 | searchPriceInputHandler(event); 23 | }} 24 | className={tm( 25 | "h-full w-10/12 flex-shrink-0 rounded-lg bg-default-white indent-1 outline-none", 26 | dark && "bg-default-black text-white", 27 | )} 28 | min={0} 29 | placeholder="Enter price..." 30 | /> 31 | 32 | ); 33 | }; 34 | export default SearchPriceBar; 35 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-mp-app", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview", 11 | "prettier-watch": "onchange \"**/*\" -- prettier --write --ignore-unknown {{changed}}" 12 | }, 13 | "dependencies": { 14 | "onchange": "^7.1.0", 15 | "react": "^18.2.0", 16 | "react-dom": "^18.2.0", 17 | "react-icons": "^5.0.1", 18 | "react-router": "^6.23.0", 19 | "react-router-dom": "^6.23.0", 20 | "react-toastify": "^10.0.5" 21 | }, 22 | "devDependencies": { 23 | "@types/react": "^18.2.66", 24 | "@types/react-dom": "^18.2.22", 25 | "@typescript-eslint/eslint-plugin": "^7.2.0", 26 | "@typescript-eslint/parser": "^7.2.0", 27 | "@vitejs/plugin-react": "^4.2.1", 28 | "autoprefixer": "^10.4.19", 29 | "eslint": "^8.57.0", 30 | "eslint-plugin-react-hooks": "^4.6.0", 31 | "eslint-plugin-react-refresh": "^0.4.6", 32 | "postcss": "^8.4.38", 33 | "prettier": "^3.2.5", 34 | "prettier-plugin-tailwindcss": "^0.5.13", 35 | "tailwind-merge": "^2.2.2", 36 | "tailwindcss": "^3.4.3", 37 | "typescript": "^5.2.2", 38 | "vite": "^5.2.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/components/HeroSection.tsx: -------------------------------------------------------------------------------- 1 | import type { DarkModeProps } from "../types"; 2 | import { twMerge as tm } from "tailwind-merge"; 3 | const HeroSection = ({ dark }: DarkModeProps) => { 4 | return ( 5 |
6 |

12 | Discover Your Next Journey: Homes, Cars, and Bikes Await! 13 |

14 |

20 | Awesome website to buy your cars, homes and bikes and best prices and 21 | with only few clicks! 22 |

23 | 24 | 32 | 33 |
34 | ); 35 | }; 36 | export default HeroSection; 37 | -------------------------------------------------------------------------------- /src/components/Articles/ArticleCard.tsx: -------------------------------------------------------------------------------- 1 | import type { ArticleCardProps } from "../../types"; 2 | import { twMerge as tm } from "tailwind-merge"; 3 | import { Link } from "react-router-dom"; 4 | const ArticleCard = ({ name, src, dark }: ArticleCardProps) => { 5 | return ( 6 | 13 | {`${name} 21 |

27 | See our {`${name}s`} 28 |

29 | 30 | ); 31 | }; 32 | export default ArticleCard; 33 | -------------------------------------------------------------------------------- /src/components/Comments/CommentCard.tsx: -------------------------------------------------------------------------------- 1 | import { twMerge as tm } from "tailwind-merge"; 2 | import type { User, DarkModeProps } from "../../types"; 3 | const CommentCard = ({ 4 | firstName, 5 | lastName, 6 | title, 7 | comment, 8 | image, 9 | dark, 10 | }: User & Omit) => { 11 | return ( 12 |
19 |
20 | {`image 25 |
26 |

{`${firstName} ${lastName}`}

29 |

{`${title}`}

30 |
31 |
32 |
{comment}
33 |
34 | ); 35 | }; 36 | export default CommentCard; 37 | -------------------------------------------------------------------------------- /public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/Comments/CommentsCards.tsx: -------------------------------------------------------------------------------- 1 | import usersData from "./usersData"; 2 | import type { User, DarkModeProps } from "../../types"; 3 | import CommentCard from "./CommentCard"; 4 | import { twMerge as tm } from "tailwind-merge"; 5 | 6 | const CommentsCards = ({ dark }: DarkModeProps) => { 7 | const mappedData = usersData.map((user: User) => ({ ...user, dark })); 8 | return ( 9 |
10 |

16 | Our Users Opinion 17 |

18 |
19 | {mappedData.map( 20 | ({ 21 | id, 22 | firstName, 23 | lastName, 24 | image, 25 | comment, 26 | title, 27 | dark, 28 | }: User & Omit) => ( 29 | 39 | ), 40 | )} 41 |
42 |
43 | ); 44 | }; 45 | export default CommentsCards; 46 | -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Route, 3 | createBrowserRouter, 4 | createRoutesFromElements, 5 | RouterProvider, 6 | } from "react-router-dom"; 7 | import "react-toastify/dist/ReactToastify.css"; 8 | import { useState } from "react"; 9 | import MainLayout from "./layouts/MainLayout"; 10 | import HomePage from "./pages/HomePage"; 11 | import HousesPage from "./pages/HousesPage"; 12 | import CarsPage from "./pages/CarsPage"; 13 | import MotorBikesPage from "./pages/MotorBikesPage"; 14 | import NotFoundPage from "./pages/NotFoundPage"; 15 | function App() { 16 | const [dark, setDark] = useState(false); 17 | const router = createBrowserRouter( 18 | createRoutesFromElements( 19 | }> 20 | } /> 21 | } 24 | /> 25 | } 28 | /> 29 | } 32 | /> 33 | } 36 | /> 37 | , 38 | ), 39 | ); 40 | return ; 41 | } 42 | 43 | export default App; 44 | -------------------------------------------------------------------------------- /src/components/Articles/ArticlesCards.tsx: -------------------------------------------------------------------------------- 1 | import HouseLight from "../../assets/imgs/cards/houseLight.webp"; 2 | import HouseDark from "../../assets/imgs/cards/houseDark.jpg"; 3 | import MotorBike from "../../assets/imgs/cards/bikeDark.png"; 4 | import Car from "../../assets/imgs/cards/car.jpg"; 5 | import ArticleCard from "./ArticleCard"; 6 | import type { DarkModeProps } from "../../types"; 7 | import type { ArticleCardProps } from "../../types"; 8 | import { twMerge as tm } from "tailwind-merge"; 9 | const ArticleCards = ({ dark }: DarkModeProps) => { 10 | const cardsElements = [ 11 | { 12 | name: "House", 13 | src: dark ? HouseDark : HouseLight, 14 | dark: dark, 15 | }, 16 | { 17 | name: "Car", 18 | src: Car, 19 | dark: dark, 20 | }, 21 | { 22 | name: "Motorbike", 23 | src: MotorBike, 24 | dark: dark, 25 | }, 26 | ]; 27 | return ( 28 |
29 |

35 | Articles 36 |

37 |
38 | {cardsElements.map(({ src, name, dark }: ArticleCardProps) => ( 39 | 40 | ))} 41 |
42 |
43 | ); 44 | }; 45 | export default ArticleCards; 46 | -------------------------------------------------------------------------------- /src/components/Navbar/HorizontalNavbar.tsx: -------------------------------------------------------------------------------- 1 | import { twMerge as tm } from "tailwind-merge"; 2 | import type { DarkModeProps } from "../../types"; 3 | import { MdSell } from "react-icons/md"; 4 | import { Link } from "react-router-dom"; 5 | const HorizontalNavbar = ({ dark }: DarkModeProps) => { 6 | return ( 7 |
8 | 12 | 13 |

14 | Friedrich Sell's 15 |

16 | 17 |
    23 |
  • 29 | Houses 30 |
  • 31 |
  • 37 | Cars 38 |
  • 39 |
  • 45 | Motorbikes 46 |
  • 47 |
48 |
49 | ); 50 | }; 51 | export default HorizontalNavbar; 52 | -------------------------------------------------------------------------------- /src/components/Vehicle/CarsData.tsx: -------------------------------------------------------------------------------- 1 | import Car1 from "../../assets/imgs/cars/c1.webp"; 2 | import Car2 from "../../assets/imgs/cars/c2.webp"; 3 | import Car3 from "../../assets/imgs/cars/c3.webp"; 4 | import Car4 from "../../assets/imgs/cars/c4.webp"; 5 | import Car5 from "../../assets/imgs/cars/c5.webp"; 6 | import Car6 from "../../assets/imgs/cars/c6.webp"; 7 | import Car7 from "../../assets/imgs/cars/c7.webp"; 8 | import Car8 from "../../assets/imgs/cars/c8.webp"; 9 | import Car9 from "../../assets/imgs/cars/c9.webp"; 10 | import Car10 from "../../assets/imgs/cars/c10.webp"; 11 | import Car11 from "../../assets/imgs/cars/c11.webp"; 12 | import Car12 from "../../assets/imgs/cars/c12.webp"; 13 | import Car13 from "../../assets/imgs/cars/c13.webp"; 14 | import Car14 from "../../assets/imgs/cars/c14.webp"; 15 | import Car15 from "../../assets/imgs/cars/c15.webp"; 16 | 17 | const CarsData = [ 18 | { id: 1, src: Car1, price: 300000, sold: false, name: "Aventador" }, 19 | { id: 2, src: Car2, price: 250000, sold: false, name: "Urus" }, 20 | { id: 3, src: Car3, price: 200000, sold: false, name: "Countach" }, 21 | { id: 4, src: Car4, price: 215000, sold: false, name: "Gallardo" }, 22 | { id: 5, src: Car5, price: 300000, sold: false, name: "Huracan" }, 23 | { id: 6, src: Car6, price: 215000, sold: false, name: "Diablo" }, 24 | { id: 7, src: Car7, price: 400000, sold: false, name: "Toyota" }, 25 | { id: 8, src: Car8, price: 250000, sold: false, name: "Honda" }, 26 | { id: 9, src: Car9, price: 240000, sold: false, name: "Hummer" }, 27 | { id: 10, src: Car10, price: 275000, sold: false, name: "Nissan" }, 28 | { id: 11, src: Car11, price: 400000, sold: false, name: "Bugatti" }, 29 | { id: 12, src: Car12, price: 215000, sold: false, name: "Renault" }, 30 | { id: 13, src: Car13, price: 250000, sold: false, name: "Ford" }, 31 | { id: 14, src: Car14, price: 200000, sold: false, name: "Lexus" }, 32 | { id: 15, src: Car15, price: 300000, sold: false, name: "Puma" }, 33 | ]; 34 | export default CarsData; 35 | -------------------------------------------------------------------------------- /src/pages/HousesPage.tsx: -------------------------------------------------------------------------------- 1 | import Houses from "../components/House"; 2 | import type { DarkModeProps } from "../types"; 3 | import { twMerge as tm } from "tailwind-merge"; 4 | import SearchDropDownMenu from "../components/Search/"; 5 | import { useState } from "react"; 6 | const HousesPage = ({ dark }: DarkModeProps) => { 7 | document.title = "Houses"; 8 | const [priceSearch, setPriceSearch] = useState(0); 9 | const [citySearch, setCitySearch] = useState(""); 10 | const [dropDownMenuVisibility, setDropDownMenuVisibility] = useState(false); 11 | const [searchParameter, setSearchParameter] = useState("none"); 12 | const isVehicle = false; 13 | return ( 14 |
15 |
16 |

22 | Houses 23 |

24 | 36 |
37 |
42 | 48 |
49 |
50 | ); 51 | }; 52 | export default HousesPage; 53 | -------------------------------------------------------------------------------- /src/pages/VehiclesPage.tsx: -------------------------------------------------------------------------------- 1 | import Vehicles from "../components/Vehicle"; 2 | import type { VehiclePageProps } from "../types"; 3 | import { twMerge as tm } from "tailwind-merge"; 4 | import SearchDropDownMenu from "../components/Search"; 5 | import { useState } from "react"; 6 | 7 | const VehiclesPage = ({ 8 | dark, 9 | vehicleSelected, 10 | vehicleData, 11 | }: VehiclePageProps) => { 12 | const [priceSearch, setPriceSearch] = useState(0); 13 | const [citySearch, setCitySearch] = useState(""); 14 | const [dropDownMenuVisibility, setDropDownMenuVisibility] = useState(false); 15 | const [searchParameter, setSearchParameter] = useState("none"); 16 | const isVehicle = true; 17 | return ( 18 |
19 |
20 |

26 | {`${vehicleSelected}s`} 27 |

28 | 40 |
41 |
46 | 55 |
56 |
57 | ); 58 | }; 59 | export default VehiclesPage; 60 | -------------------------------------------------------------------------------- /src/components/Vehicle/MotorbikesData.tsx: -------------------------------------------------------------------------------- 1 | import MotorBike1 from "../../assets/imgs/motorbikes/m1.webp"; 2 | import MotorBike2 from "../../assets/imgs/motorbikes/m2.webp"; 3 | import MotorBike3 from "../../assets/imgs/motorbikes/m3.webp"; 4 | import MotorBike4 from "../../assets/imgs/motorbikes/m4.webp"; 5 | import MotorBike5 from "../../assets/imgs/motorbikes/m5.webp"; 6 | import MotorBike6 from "../../assets/imgs/motorbikes/m6.webp"; 7 | import MotorBike7 from "../../assets/imgs/motorbikes/m7.webp"; 8 | import MotorBike8 from "../../assets/imgs/motorbikes/m8.webp"; 9 | import MotorBike9 from "../../assets/imgs/motorbikes/m9.webp"; 10 | import MotorBike10 from "../../assets/imgs/motorbikes/m10.webp"; 11 | import MotorBike11 from "../../assets/imgs/motorbikes/m11.webp"; 12 | import MotorBike12 from "../../assets/imgs/motorbikes/m12.webp"; 13 | import MotorBike13 from "../../assets/imgs/motorbikes/m13.webp"; 14 | import MotorBike14 from "../../assets/imgs/motorbikes/m14.webp"; 15 | import MotorBike15 from "../../assets/imgs/motorbikes/m15.webp"; 16 | 17 | const MotorBikesData = [ 18 | { id: 1, src: MotorBike1, price: 150000, sold: false, name: "Triumph" }, 19 | { 20 | id: 2, 21 | src: MotorBike2, 22 | price: 150000, 23 | sold: false, 24 | name: "AJP", 25 | }, 26 | { 27 | id: 3, 28 | src: MotorBike3, 29 | price: 250000, 30 | sold: false, 31 | name: "Harley", 32 | }, 33 | { id: 4, src: MotorBike4, price: 200000, sold: false, name: "Aprilia" }, 34 | { id: 5, src: MotorBike5, price: 175000, sold: false, name: "Kawasaki" }, 35 | { id: 6, src: MotorBike6, price: 350000, sold: false, name: "Ktm" }, 36 | { id: 7, src: MotorBike7, price: 225000, sold: false, name: "Yamaha" }, 37 | { 38 | id: 8, 39 | src: MotorBike8, 40 | price: 350000, 41 | sold: false, 42 | name: "Ajs", 43 | }, 44 | { id: 9, src: MotorBike9, price: 250000, sold: false, name: "Benelli" }, 45 | { id: 10, src: MotorBike10, price: 450000, sold: false, name: "Bmw r32" }, 46 | { id: 11, src: MotorBike11, price: 250000, sold: false, name: "Honda" }, 47 | { id: 12, src: MotorBike12, price: 300000, sold: false, name: "Suzuki" }, 48 | { id: 13, src: MotorBike13, price: 250000, sold: false, name: "Evoke" }, 49 | { id: 14, src: MotorBike14, price: 150000, sold: false, name: "Arch" }, 50 | { 51 | id: 15, 52 | src: MotorBike15, 53 | price: 350000, 54 | sold: false, 55 | name: "Indian", 56 | }, 57 | ]; 58 | 59 | export default MotorBikesData; 60 | -------------------------------------------------------------------------------- /src/components/Search/DropDownMenu.tsx: -------------------------------------------------------------------------------- 1 | import { twMerge as tm } from "tailwind-merge"; 2 | import { DropDownMenuFilter, DropDownMenuFilterVisibility } from "../../types"; 3 | import { useEffect, useRef } from "react"; 4 | 5 | const DropDownMenu = ({ 6 | searchParameter, 7 | setSearchParameter, 8 | dark, 9 | dropDownMenuVisibility, 10 | setDropDownMenuVisibility, 11 | isVehicle, 12 | }: DropDownMenuFilter & 13 | DropDownMenuFilterVisibility & { isVehicle: boolean }) => { 14 | const handlePerPriceSearchOptionClick = () => { 15 | setSearchParameter("price"); 16 | setDropDownMenuVisibility(false); 17 | }; 18 | 19 | const handlePerCitySearchOptionClick = () => { 20 | setSearchParameter("city"); 21 | setDropDownMenuVisibility(false); 22 | }; 23 | 24 | const ref = useRef(null); 25 | 26 | useEffect(() => { 27 | const handleOutSideClick = (event: MouseEvent) => { 28 | if ( 29 | !ref.current?.contains(event.target as Node) && 30 | dropDownMenuVisibility && 31 | searchParameter === "none" 32 | ) { 33 | setDropDownMenuVisibility(false); 34 | } 35 | }; 36 | 37 | window.addEventListener("mousedown", handleOutSideClick); 38 | 39 | return () => { 40 | window.removeEventListener("mousedown", handleOutSideClick); 41 | }; 42 | }, [dropDownMenuVisibility, setDropDownMenuVisibility, searchParameter]); 43 | 44 | return ( 45 | 49 |
    55 |
  • { 61 | handlePerPriceSearchOptionClick(); 62 | }} 63 | > 64 | Per Price 65 |
  • 66 | 67 | {!isVehicle && ( 68 |
  • { 74 | handlePerCitySearchOptionClick(); 75 | }} 76 | > 77 | Per City 78 |
  • 79 | )} 80 |
81 |
82 | ); 83 | }; 84 | 85 | export default DropDownMenu; 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Houses, Cars & Motorcycles Sell App 2 | 3 | Welcome in my house, cars and motorcycles Sale App 🏠 ! 4 | 5 | ## Overview 6 | 7 | This is a simple project to get familiar with React (state Management, Side Effects & DOM Manipulation) and some of its libraries like : 8 | 9 | - **React Icons** 10 | - **React Router** 11 | - ... 12 | 13 | And others like **Tailwind Merge** to apply specific CSS classes depending of some conditions, **TypeScript** in a React project. 14 | 15 | Nota Bene : The project has dark mode and is fully responsive 16 | 17 | ### Some screenshots form the project 18 | 19 | Image of HousePage : lightmode 20 | 21 | Image of HousePage : darkmode 22 | 23 | Image of the HousesPage : lightmode 24 | 25 | Image of the HousesPage : darkmode 26 | 27 | Image of the CarsPage : lightmode 28 | 29 | Image of the CarsPage : darkmode 30 | 31 | Image of the MotorBikes : lightmode 32 | 33 | Image of the MotorBikes : darkmode 34 | 35 | ## Run the application 36 | 37 | You can have a look on the project by visiting the following link (on Vercel) : 38 | 39 | Or to run locally use : 40 | 41 | ```code 42 | git clone https://github.com/Friedrich482/react-houses-cars-motorbikes-sell.git 43 | ``` 44 | 45 | After that, go in the root of the project and install all dependencies by using : 46 | 47 | ```code 48 | npm install 49 | ``` 50 | 51 | And finally to serve the project locally, use the command : 52 | 53 | ```code 54 | npm run dev 55 | ``` 56 | 57 | After that open `localhost:3000` to see the result. 58 | -------------------------------------------------------------------------------- /src/components/House/HousesData.tsx: -------------------------------------------------------------------------------- 1 | import House2 from "../../assets/imgs/houses/h2.webp"; 2 | import House1 from "../../assets/imgs/houses/h1.webp"; 3 | import House3 from "../../assets/imgs/houses/h3.webp"; 4 | import House4 from "../../assets/imgs/houses/h4.webp"; 5 | import House5 from "../../assets/imgs/houses/h5.webp"; 6 | import House6 from "../../assets/imgs/houses/h6.webp"; 7 | import House7 from "../../assets/imgs/houses/h7.webp"; 8 | import House8 from "../../assets/imgs/houses/h8.webp"; 9 | import House9 from "../../assets/imgs/houses/h9.webp"; 10 | import House10 from "../../assets/imgs/houses/h10.webp"; 11 | import House11 from "../../assets/imgs/houses/h11.webp"; 12 | import House12 from "../../assets/imgs/houses/h12.webp"; 13 | import House13 from "../../assets/imgs/houses/h13.webp"; 14 | import House14 from "../../assets/imgs/houses/h14.webp"; 15 | import House15 from "../../assets/imgs/houses/h15.webp"; 16 | 17 | const HousesData = [ 18 | { 19 | id: 1, 20 | src: House1, 21 | location: "Nashville", 22 | price: 120000, 23 | sold: false, 24 | }, 25 | { 26 | id: 2, 27 | src: House2, 28 | location: "Philadelphia", 29 | price: 200000, 30 | sold: false, 31 | }, 32 | { 33 | id: 3, 34 | src: House3, 35 | location: "Seattle", 36 | price: 115000, 37 | sold: false, 38 | }, 39 | { 40 | id: 4, 41 | src: House4, 42 | location: "Detroit", 43 | price: 150000, 44 | sold: false, 45 | }, 46 | { 47 | id: 5, 48 | src: House5, 49 | location: "Houston", 50 | price: 99000, 51 | sold: false, 52 | }, 53 | { 54 | id: 6, 55 | src: House6, 56 | location: "Dallas", 57 | price: 99000, 58 | sold: false, 59 | }, 60 | { 61 | id: 7, 62 | src: House7, 63 | location: "Kansas City", 64 | price: 120000, 65 | sold: false, 66 | }, 67 | { 68 | id: 8, 69 | src: House8, 70 | location: "Charlotte", 71 | price: 200000, 72 | sold: false, 73 | }, 74 | { 75 | id: 9, 76 | src: House9, 77 | location: "Nashville", 78 | price: 115000, 79 | sold: false, 80 | }, 81 | { 82 | id: 10, 83 | src: House10, 84 | location: "Philadelphia", 85 | price: 150000, 86 | sold: false, 87 | }, 88 | { 89 | id: 11, 90 | src: House11, 91 | location: "Dallas", 92 | price: 99000, 93 | sold: false, 94 | }, 95 | { 96 | id: 12, 97 | src: House12, 98 | location: "San Diego", 99 | price: 99000, 100 | sold: false, 101 | }, 102 | { 103 | id: 13, 104 | src: House13, 105 | location: "Los Angeles", 106 | price: 120000, 107 | sold: false, 108 | }, 109 | { 110 | id: 14, 111 | src: House14, 112 | location: "Austin", 113 | price: 200000, 114 | sold: false, 115 | }, 116 | { 117 | id: 15, 118 | src: House15, 119 | location: "Seattle", 120 | price: 115000, 121 | sold: false, 122 | }, 123 | ]; 124 | 125 | export default HousesData; 126 | -------------------------------------------------------------------------------- /src/components/Dialog.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | import { twMerge as tm } from "tailwind-merge"; 3 | import type { ModalProps } from "../types"; 4 | const Dialog = ({ 5 | openModal, 6 | toggleModal, 7 | dialogRef, 8 | tempPrice, 9 | dark, 10 | setOpenModal, 11 | setYesButtonDialog, 12 | vehicleSelected, 13 | isVehicle, 14 | }: ModalProps) => { 15 | useEffect(() => { 16 | openModal 17 | ? (document.body.style.overflow = "hidden") 18 | : (document.body.style.overflow = "unset"); 19 | }, [openModal]); 20 | 21 | useEffect(() => { 22 | const handleOutSideClick = (event: Event) => { 23 | if (event.target === dialogRef.current && openModal) { 24 | setOpenModal(false); 25 | dialogRef.current?.close(); 26 | } 27 | }; 28 | 29 | window.addEventListener("mousedown", handleOutSideClick); 30 | 31 | return () => { 32 | window.removeEventListener("mousedown", handleOutSideClick); 33 | }; 34 | }, [dialogRef, openModal, setOpenModal]); 35 | const yesButtonFunction = () => { 36 | setYesButtonDialog(true); 37 | toggleModal(tempPrice); 38 | }; 39 | return ( 40 | 48 |
55 |

56 | Are you sure to buy this{" "} 57 | {isVehicle ? vehicleSelected?.toLocaleLowerCase() : "house"} ? 58 |

59 |

60 | You will be charged {tempPrice} $ for this sale 61 |

62 |
63 | 76 | 88 |
89 |
90 |
91 | ); 92 | }; 93 | 94 | export default Dialog; 95 | -------------------------------------------------------------------------------- /src/components/House/House.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState, useRef } from "react"; 2 | import { FaMapMarkerAlt } from "react-icons/fa"; 3 | import { SlBadge } from "react-icons/sl"; 4 | import type { House } from "../../types"; 5 | import { twMerge as tm } from "tailwind-merge"; 6 | const House = ({ 7 | src, 8 | id, 9 | price, 10 | location, 11 | sold, 12 | dark, 13 | toggleModal, 14 | yesButtonDialog, 15 | setYesButtonDialog, 16 | }: House) => { 17 | const [houseSold, setHouseSold] = useState(sold); 18 | const houseIdRef = useRef(null); 19 | 20 | const handleSoldButtonClick = () => { 21 | updateHouseId(id); 22 | toggleModal(price); 23 | }; 24 | 25 | const updateHouseId = (newId: number) => { 26 | houseIdRef.current = newId; 27 | }; 28 | 29 | useEffect(() => { 30 | if (yesButtonDialog && houseIdRef.current === id) { 31 | setHouseSold(true); 32 | setYesButtonDialog(false); 33 | } 34 | }, [ 35 | yesButtonDialog, 36 | setYesButtonDialog, 37 | setHouseSold, 38 | houseSold, 39 | houseIdRef, 40 | id, 41 | ]); 42 | return ( 43 | <> 44 |
51 | {`House 56 |
57 | 63 |

69 | {location} 70 |

71 |
72 |

77 | 78 | {price} $ 79 |

80 | 93 |
94 | 95 | ); 96 | }; 97 | 98 | export default House; 99 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | export type HouseProps = { 2 | src: string; 3 | id: number; 4 | price: number; 5 | location: string; 6 | sold: boolean; 7 | }; 8 | 9 | export type DarkModeProps = { 10 | dark: boolean; 11 | setDark: React.Dispatch>; 12 | }; 13 | 14 | export type UseCloseMenuProps = { 15 | dropDownList: boolean; 16 | }; 17 | 18 | type dark = Omit; 19 | 20 | export type ModalProps = { 21 | openModal: boolean; 22 | setOpenModal: React.Dispatch>; 23 | toggleModal: (price: number) => void; 24 | dialogRef: React.RefObject; 25 | tempPrice: number; 26 | yesButtonDialog: boolean; 27 | setYesButtonDialog: React.Dispatch>; 28 | } & dark & { vehicleSelected?: string; isVehicle?: boolean }; 29 | 30 | export type House = HouseProps & 31 | dark & 32 | Omit; 33 | 34 | export type HousesListProps = dark & 35 | Omit & 36 | Omit & 37 | Omit; 38 | 39 | export type ArticleCardProps = { 40 | name: string; 41 | src: string; 42 | } & dark; 43 | 44 | export type User = { 45 | id: number; 46 | firstName: string; 47 | lastName: string; 48 | title: string; 49 | image: string; 50 | comment: string; 51 | }; 52 | 53 | export type UserDark = User & dark; 54 | 55 | export type SearchPrice = { 56 | priceSearch: number; 57 | setPriceSearch: React.Dispatch>; 58 | } & dark; 59 | 60 | export type SearchCity = { 61 | citySearch: string; 62 | setCitySearch: React.Dispatch>; 63 | } & dark; 64 | 65 | export type SearchDropDownMenuProps = SearchPrice & 66 | SearchCity & 67 | DropDownMenuFilterVisibility & 68 | DropDownMenuFilter & { isVehicle: boolean }; 69 | 70 | export type DefaultSearchBarProps = dark & 71 | Omit; 72 | 73 | export type DropDownMenuFilter = { 74 | searchParameter: string; 75 | setSearchParameter: React.Dispatch>; 76 | } & dark; 77 | 78 | export type DropDownMenuFilterVisibility = { 79 | dropDownMenuVisibility: boolean; 80 | setDropDownMenuVisibility: React.Dispatch>; 81 | }; 82 | type unitVehicle = { 83 | id: number; 84 | src: string; 85 | price: number; 86 | sold: boolean; 87 | name: string; 88 | }; 89 | export type Vehicle = unitVehicle & 90 | dark & 91 | Omit< 92 | ModalProps, 93 | | "dialogRef" 94 | | "setOpenModal" 95 | | "tempPrice" 96 | | "openModal" 97 | | "vehicleSelected" 98 | | "isVehicle" 99 | > & { vehicleSelected: string }; 100 | 101 | export type VehicleData = unitVehicle[]; 102 | 103 | export type VehiclesProps = { vehicleData: VehicleData } & dark & 104 | Omit & 105 | Omit & 106 | Omit & { 107 | vehicleSelected: string; 108 | isVehicle: boolean; 109 | }; 110 | 111 | export type VehiclePageProps = dark & { vehicleSelected: string } & { 112 | vehicleData: VehicleData; 113 | }; 114 | -------------------------------------------------------------------------------- /src/components/Search/SearchDropDownMenu.tsx: -------------------------------------------------------------------------------- 1 | import SearchPriceBar from "./SearchPriceBar"; 2 | import SearchCityBar from "./SearchCityBar"; 3 | import DefaultSearchBar from "./DefaultSearchBar"; 4 | import DropDownMenu from "./DropDownMenu"; 5 | import { twMerge as tm } from "tailwind-merge"; 6 | import { IoIosCloseCircleOutline } from "react-icons/io"; 7 | import type { SearchDropDownMenuProps } from "../../types"; 8 | import { useEffect } from "react"; 9 | const SearchDropDownMenu = ({ 10 | dark, 11 | priceSearch, 12 | setPriceSearch, 13 | dropDownMenuVisibility, 14 | setDropDownMenuVisibility, 15 | citySearch, 16 | setCitySearch, 17 | searchParameter, 18 | setSearchParameter, 19 | isVehicle, 20 | }: SearchDropDownMenuProps) => { 21 | const handleSearchDropDownMenuClick = () => { 22 | setDropDownMenuVisibility(true); 23 | }; 24 | const handleCloseButtonClick = () => { 25 | setSearchParameter("none"); 26 | }; 27 | 28 | useEffect(() => { 29 | dropDownMenuVisibility 30 | ? (document.body.style.overflow = "hidden") 31 | : (document.body.style.overflow = "unset"); 32 | }, [dropDownMenuVisibility, searchParameter]); 33 | 34 | return ( 35 | <> 36 |
43 |
{ 49 | searchParameter === "none" && handleSearchDropDownMenuClick(); 50 | }} 51 | > 52 | {searchParameter === "none" ? ( 53 | 54 | ) : searchParameter === "price" ? ( 55 | <> 56 | 61 | 62 | ) : ( 63 | !isVehicle && ( 64 | <> 65 | 70 | 71 | ) 72 | )} 73 |
74 | {dropDownMenuVisibility && searchParameter === "none" ? ( 75 | 83 | ) : null} 84 | { 91 | handleCloseButtonClick(); 92 | }} 93 | title="Close" 94 | /> 95 |
96 | 97 | ); 98 | }; 99 | export default SearchDropDownMenu; 100 | -------------------------------------------------------------------------------- /src/components/Vehicle/Vehicle.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState, useRef } from "react"; 2 | import { SlBadge } from "react-icons/sl"; 3 | import { IoCarSport } from "react-icons/io5"; 4 | import { FaMotorcycle } from "react-icons/fa"; 5 | import { twMerge as tm } from "tailwind-merge"; 6 | import type { Vehicle } from "../../types"; 7 | const Vehicle = ({ 8 | id, 9 | price, 10 | sold, 11 | src, 12 | dark, 13 | name, 14 | toggleModal, 15 | yesButtonDialog, 16 | setYesButtonDialog, 17 | vehicleSelected, 18 | }: Vehicle) => { 19 | const [vehicleSold, setVehicleSold] = useState(sold); 20 | const houseIdRef = useRef(null); 21 | 22 | const handleSoldButtonClick = () => { 23 | updateHouseId(id); 24 | toggleModal(price); 25 | }; 26 | 27 | const updateHouseId = (newId: number) => { 28 | houseIdRef.current = newId; 29 | }; 30 | useEffect(() => { 31 | if (yesButtonDialog && houseIdRef.current === id) { 32 | setVehicleSold(true); 33 | setYesButtonDialog(false); 34 | } 35 | }, [ 36 | yesButtonDialog, 37 | setYesButtonDialog, 38 | setVehicleSold, 39 | vehicleSold, 40 | houseIdRef, 41 | id, 42 | ]); 43 | 44 | return ( 45 | <> 46 |
53 | {`House 58 |
59 | {vehicleSelected === "Car" ? ( 60 | 66 | ) : ( 67 | 73 | )} 74 |

80 | {name} 81 |

82 |
83 | 84 |

89 | 90 | {price} $ 91 |

92 | 105 |
106 | 107 | ); 108 | }; 109 | export default Vehicle; 110 | -------------------------------------------------------------------------------- /src/components/Description.tsx: -------------------------------------------------------------------------------- 1 | import HouseImg from "../assets/imgs/description-section/house.jpg"; 2 | import LamboImg from "../assets/imgs/description-section/lambo1.jpg"; 3 | import MotoImg from "../assets/imgs/description-section/moto.jpg"; 4 | import type { DarkModeProps } from "../types"; 5 | import { twMerge as tm } from "tailwind-merge"; 6 | const Description = ({ dark }: DarkModeProps) => { 7 | return ( 8 |
12 |
13 |
14 |

20 | Who are Us ? 21 |

22 |

28 | "The solution to buy Houses, Cars & Motorcycles" 29 |

30 |
31 |

37 | Houses, Cars and Motorbikes are our speciality. Embark on an exciting 38 | journey with us as you explore our expansive marketplace, designed to 39 | cater to all your needs when it comes to acquiring new assets. Whether 40 | you're in search of your dream home, a reliable car for your daily 41 | commute, or an exhilarating motorbike for your adventures, we've got 42 | you covered. Our platform boasts a diverse selection of properties, 43 | vehicles, and bikes, ensuring there's something for everyone. With our 44 | intuitive interface and dedicated customer service, we strive to make 45 | your buying experience both convenient and enjoyable. Trust us to be 46 | your trusted partner in this exciting chapter of your life, as you 47 | find the perfect asset to complement your lifestyle! 48 |

49 |
50 |
51 | House Image for the description 59 |
60 | Lamborghini Image for the description 68 | Moto Image for the description 76 |
77 |
78 |
79 | ); 80 | }; 81 | export default Description; 82 | -------------------------------------------------------------------------------- /src/components/Vehicle/Vehicles.tsx: -------------------------------------------------------------------------------- 1 | import { useRef, useState } from "react"; 2 | import { VehiclesProps } from "../../types"; 3 | import Dialog from "../Dialog"; 4 | import { toast } from "react-toastify"; 5 | import { twMerge as tm } from "tailwind-merge"; 6 | import Vehicle from "./Vehicle"; 7 | const Vehicles = ({ 8 | dark, 9 | priceSearch, 10 | searchParameter, 11 | vehicleData, 12 | vehicleSelected, 13 | isVehicle, 14 | }: VehiclesProps) => { 15 | const [tempPrice, setTempPrice] = useState(0); 16 | const [openModal, setOpenModal] = useState(false); 17 | const [yesButtonDialog, setYesButtonDialog] = useState(false); 18 | 19 | const dialogRef = useRef(null); 20 | 21 | const toggleModal = (price: number) => { 22 | if (openModal) { 23 | setOpenModal(false); 24 | dialogRef.current?.close(); 25 | 26 | toast.success( 27 |
28 |

29 | {vehicleSelected} successfully sold !
{price} $ have been 30 | taken from your account. 31 |

32 |
, 33 | ); 34 | } else { 35 | setTempPrice(price); 36 | setOpenModal(true); 37 | dialogRef.current?.showModal(); 38 | } 39 | }; 40 | const vehicles = vehicleData.map(({ src, id, price, sold, name }) => ( 41 | 54 | )); 55 | const filteredPerPriceVehicles = vehicleData 56 | .filter(({ price }) => priceSearch === price) 57 | .map(({ src, id, price, sold, name }) => ( 58 | 71 | )); 72 | 73 | return ( 74 | <> 75 | {searchParameter === "none" ? ( 76 | vehicles 77 | ) : priceSearch === 0 ? ( 78 | vehicles 79 | ) : filteredPerPriceVehicles.length === 0 ? ( 80 |

86 | {`No ${vehicleSelected.toLowerCase()}s found at ${priceSearch} $`} 87 |

88 | ) : ( 89 | <> 90 |

91 | 92 | {filteredPerPriceVehicles.length} 93 | {" "} 94 | {filteredPerPriceVehicles.length === 1 95 | ? `${vehicleSelected.toLocaleLowerCase()} found at ${priceSearch}$` 96 | : `${vehicleSelected.toLocaleLowerCase()}s found at ${priceSearch}$`} 97 |

98 |
99 | {filteredPerPriceVehicles} 100 |
101 | 102 | )} 103 | 115 | 116 | ); 117 | }; 118 | export default Vehicles; 119 | -------------------------------------------------------------------------------- /src/components/Navbar/Navbar.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState, useRef } from "react"; 2 | import { MdDarkMode } from "react-icons/md"; 3 | import { CiLight } from "react-icons/ci"; 4 | import { FaGithub } from "react-icons/fa"; 5 | import type { DarkModeProps } from "../../types"; 6 | import { twMerge as tm } from "tailwind-merge"; 7 | import HorizontalNavbar from "./HorizontalNavbar"; 8 | import VerticalNavbar from "./VerticalNavbar"; 9 | const Navbar = ({ dark, setDark }: DarkModeProps) => { 10 | const [dropDownList, setDropDownList] = useState(false); 11 | const darkModeButtonHandler = (previousState: boolean) => { 12 | setDropDownList(!previousState); 13 | }; 14 | const darkHandler = (previousState: boolean) => { 15 | !previousState ? setDark(!previousState) : true; 16 | }; 17 | const lightHandler = (previousState: boolean) => { 18 | previousState ? setDark(!previousState) : true; 19 | }; 20 | // This part checks if the users click outside the dark mode dropdown menu to close it. 21 | const ref = useRef(null); 22 | useEffect(() => { 23 | const handleOutSideClick = (event: Event) => { 24 | if (!ref.current?.contains(event.target as Node) && dropDownList) { 25 | darkModeButtonHandler(dropDownList); 26 | } 27 | }; 28 | 29 | window.addEventListener("mousedown", handleOutSideClick); 30 | 31 | return () => { 32 | window.removeEventListener("mousedown", handleOutSideClick); 33 | }; 34 | }, [ref, dropDownList]); 35 | useEffect(() => { 36 | dropDownList 37 | ? (document.body.style.overflow = "hidden") 38 | : (document.body.style.overflow = "unset"); 39 | }, [dropDownList]); 40 | return ( 41 | <> 42 | 78 | 79 | 80 |
    87 |
  • { 93 | lightHandler(dark); 94 | }} 95 | > 96 | 97 | Light 98 |
  • 99 |
  • { 105 | darkHandler(dark); 106 | }} 107 | > 108 | 109 | Dark 110 |
  • 111 |
112 |
113 | 114 | ); 115 | }; 116 | export default Navbar; 117 | -------------------------------------------------------------------------------- /src/components/Navbar/VerticalNavbar.tsx: -------------------------------------------------------------------------------- 1 | import type { DarkModeProps } from "../../types"; 2 | import { twMerge as tm } from "tailwind-merge"; 3 | import { IoIosClose } from "react-icons/io"; 4 | import { MdSell } from "react-icons/md"; 5 | import { RxHamburgerMenu } from "react-icons/rx"; 6 | import { useState, useRef, useEffect } from "react"; 7 | import { Link } from "react-router-dom"; 8 | const VerticalNavbar = ({ dark }: DarkModeProps) => { 9 | const [openVerticalNavbar, setOpenVerticalNavbar] = useState(false); 10 | const handleCloseButtonClick = (previousState: boolean) => { 11 | setOpenVerticalNavbar(!previousState); 12 | }; 13 | const menuBurgerButtonHandler = (previousState: boolean) => { 14 | setOpenVerticalNavbar(!previousState); 15 | }; 16 | useEffect(() => { 17 | openVerticalNavbar 18 | ? (document.body.style.overflow = "hidden") 19 | : (document.body.style.overflow = "unset"); 20 | }, [openVerticalNavbar]); 21 | const ref = useRef(null); 22 | useEffect(() => { 23 | const handleOutSideClick = (event: Event) => { 24 | if (!ref.current?.contains(event.target as Node) && openVerticalNavbar) { 25 | setOpenVerticalNavbar(!openVerticalNavbar); 26 | } 27 | }; 28 | 29 | window.addEventListener("mousedown", handleOutSideClick); 30 | 31 | return () => { 32 | window.removeEventListener("mousedown", handleOutSideClick); 33 | }; 34 | }, [ref, openVerticalNavbar]); 35 | 36 | return ( 37 | <> 38 |
39 |
{ 45 | menuBurgerButtonHandler(openVerticalNavbar); 46 | }} 47 | > 48 | 54 |
55 |
56 | 63 |
69 |
70 | 71 |
72 | 75 |

81 | Friedrich Sell's 82 |

83 |
84 | 85 | { 92 | handleCloseButtonClick(openVerticalNavbar); 93 | }} 94 | /> 95 |
96 | 97 |
    98 |
  • 104 | Houses 105 |
  • 106 |
  • 112 | Cars 113 |
  • 114 |
  • 120 | Motorbikes 121 |
  • 122 |
123 |
124 |
125 | 126 | ); 127 | }; 128 | export default VerticalNavbar; 129 | -------------------------------------------------------------------------------- /src/components/House/Houses.tsx: -------------------------------------------------------------------------------- 1 | import { useState, useRef } from "react"; 2 | import House from "./House"; 3 | import HousesData from "./HousesData"; 4 | import Dialog from "../Dialog"; 5 | import { toast } from "react-toastify"; 6 | import type { HousesListProps } from "../../types"; 7 | import { twMerge as tm } from "tailwind-merge"; 8 | const Houses = ({ 9 | dark, 10 | priceSearch, 11 | citySearch, 12 | searchParameter, 13 | }: HousesListProps) => { 14 | const [tempPrice, setTempPrice] = useState(0); 15 | const [openModal, setOpenModal] = useState(false); 16 | const [yesButtonDialog, setYesButtonDialog] = useState(false); 17 | 18 | const dialogRef = useRef(null); 19 | 20 | const toggleModal = (price: number) => { 21 | if (openModal) { 22 | setOpenModal(false); 23 | dialogRef.current?.close(); 24 | 25 | toast.success( 26 |
27 |

28 | House successfully sold !
{price} $ have been taken from your 29 | account. 30 |

31 |
, 32 | ); 33 | } else { 34 | setTempPrice(price); 35 | setOpenModal(true); 36 | dialogRef.current?.showModal(); 37 | } 38 | }; 39 | const houses = HousesData.map(({ src, id, price, location, sold }) => ( 40 | 52 | )); 53 | const filteredPerPriceHouses = HousesData.filter( 54 | ({ price }) => priceSearch === price, 55 | ).map(({ src, id, price, location, sold }) => ( 56 | 68 | )); 69 | const filteredPerCityHouses = HousesData.filter( 70 | ({ location }) => citySearch === location, 71 | ).map(({ src, id, price, location, sold }) => ( 72 | 84 | )); 85 | return ( 86 | <> 87 | {searchParameter === "none" ? ( 88 | houses 89 | ) : searchParameter === "price" ? ( 90 | priceSearch === 0 ? ( 91 | houses 92 | ) : filteredPerPriceHouses.length === 0 ? ( 93 |

99 | No houses found at {priceSearch} $ 100 |

101 | ) : ( 102 | <> 103 |

104 | 105 | {filteredPerPriceHouses.length} 106 | {" "} 107 | {filteredPerPriceHouses.length === 1 108 | ? `house found at ${priceSearch}$` 109 | : `houses found at ${priceSearch}$`} 110 |

111 |
112 | {filteredPerPriceHouses} 113 |
114 | 115 | ) 116 | ) : citySearch === "" ? ( 117 | houses 118 | ) : filteredPerCityHouses.length === 0 ? ( 119 |

125 | No houses found at {citySearch} 126 |

127 | ) : ( 128 | <> 129 |

130 | 131 | {filteredPerCityHouses.length} 132 | {" "} 133 | {filteredPerCityHouses.length === 1 134 | ? `house found at ${citySearch}` 135 | : `houses found at ${citySearch}`} 136 |

137 |
138 | {filteredPerCityHouses} 139 |
140 | 141 | )} 142 | 152 | 153 | ); 154 | }; 155 | 156 | export default Houses; 157 | -------------------------------------------------------------------------------- /src/components/Comments/usersData.tsx: -------------------------------------------------------------------------------- 1 | const usersData = [ 2 | { 3 | id: 1, 4 | firstName: "Terry", 5 | lastName: "Medhurst", 6 | image: "https://randomuser.me/api/portraits/men/64.jpg", 7 | title: "Help Desk Operator", 8 | comment: 9 | "I stumbled upon this app while looking for my dream home, and I couldn't be happier with the experience. The range of houses available is astounding, and the user-friendly interface made the whole process a breeze.", 10 | }, 11 | 12 | { 13 | id: 2, 14 | firstName: "Sheldon", 15 | lastName: "Quigley", 16 | image: "https://randomuser.me/api/portraits/women/91.jpg", 17 | title: "Senior Cost Accountant", 18 | comment: 19 | "As a car enthusiast, I've used countless apps to browse through vehicle listings, but none have impressed me as much as this one. The attention to detail in the descriptions and the stunning photos really set it apart.", 20 | }, 21 | 22 | { 23 | id: 3, 24 | firstName: "Terrill", 25 | lastName: "Hills", 26 | image: "https://randomuser.me/api/portraits/men/53.jpg", 27 | title: "Mechanical Systems Engineer", 28 | comment: 29 | "Finding the perfect motorcycle can be a daunting task, but thanks to this app, it was a seamless experience. The selection is extensive, and the filtering options helped me narrow down my choices quickly.", 30 | }, 31 | 32 | { 33 | id: 4, 34 | 35 | firstName: "Miles", 36 | 37 | lastName: "Cummerata", 38 | 39 | image: "https://randomuser.me/api/portraits/men/37.jpg", 40 | 41 | title: "Paralegal", 42 | comment: 43 | "I've been on the hunt for a new home for months, and I finally found 'the one' on this app. The detailed listings and virtual tours gave me a real sense of what each property had to offer.", 44 | }, 45 | 46 | { 47 | id: 5, 48 | 49 | firstName: "Mavis", 50 | 51 | lastName: "Schultz", 52 | 53 | image: "https://randomuser.me/api/portraits/men/65.jpg", 54 | 55 | title: "Web Developer I", 56 | comment: 57 | "This app has made my car shopping journey incredibly smooth. The interface is intuitive, and the search filters allowed me to find exactly what I was looking for in no time.", 58 | }, 59 | 60 | { 61 | id: 6, 62 | 63 | firstName: "Alison", 64 | 65 | lastName: "Reichert", 66 | 67 | image: "https://randomuser.me/api/portraits/women/47.jpg", 68 | 69 | title: "Civil Engineer", 70 | comment: 71 | "I can't get enough of the motorcycle section on this app! The range of bikes available caters to every style and preference, and the detailed specs provided helped me make an informed decision.", 72 | }, 73 | 74 | { 75 | id: 7, 76 | 77 | firstName: "Oleta", 78 | 79 | lastName: "Abbott", 80 | 81 | image: "https://randomuser.me/api/portraits/women/65.jpg", 82 | 83 | title: "Sales Associate", 84 | comment: 85 | "From cozy cottages to luxurious estates, this app has it all. I was blown away by the variety of houses available, and the ease of navigating through the listings made the whole process enjoyable.", 86 | }, 87 | 88 | { 89 | id: 8, 90 | 91 | firstName: "Ewell", 92 | 93 | lastName: "Mueller", 94 | 95 | image: "https://randomuser.me/api/portraits/men/8.jpg", 96 | 97 | title: "Clinical Specialist", 98 | comment: 99 | "The transparency and honesty displayed in the car listings on this app are commendable. I felt confident in my decision-making knowing that I was getting accurate information about each vehicle.", 100 | }, 101 | 102 | { 103 | id: 9, 104 | 105 | firstName: "Demetrius", 106 | 107 | lastName: "Corkery", 108 | 109 | image: "https://randomuser.me/api/portraits/men/67.jpg", 110 | 111 | title: "Community Outreach Specialist", 112 | comment: 113 | "My experience with this app has been nothing short of fantastic. The customer support team was responsive and helpful, and the seamless integration of features made browsing for motorcycles a pleasure", 114 | }, 115 | 116 | { 117 | id: 10, 118 | 119 | firstName: "Eleanora", 120 | 121 | lastName: "Price", 122 | 123 | image: "https://randomuser.me/api/portraits/women/92.jpg", 124 | 125 | title: "Senior Sales Associate", 126 | comment: 127 | "I've recommended this app to all my friends and family who are in the market for a new home, car, or motorcycle. It truly is a one-stop-shop for all your asset-buying needs.", 128 | }, 129 | 130 | { 131 | id: 11, 132 | 133 | firstName: "Marcel", 134 | 135 | lastName: "Jones", 136 | 137 | image: "https://randomuser.me/api/portraits/men/21.jpg", 138 | 139 | title: "Account Executive", 140 | comment: 141 | "I never thought finding my dream car could be so enjoyable until I started using this app. The interface is sleek, the listings are comprehensive, and the whole process feels effortless.", 142 | }, 143 | 144 | { 145 | id: 12, 146 | 147 | firstName: "Assunta", 148 | 149 | lastName: "Rath", 150 | 151 | image: "https://randomuser.me/api/portraits/women/74.jpg", 152 | 153 | title: "Developer II", 154 | comment: 155 | "As a first-time homeBuyer, I was overwhelmed by the thought of navigating the real estate market. But this app made it simple and stress-free, thanks to its informative guides and easy-to-use search tools.", 156 | }, 157 | 158 | { 159 | id: 13, 160 | 161 | firstName: "Trace", 162 | 163 | lastName: "Douglas", 164 | 165 | image: "https://randomuser.me/api/portraits/women/8.jpg", 166 | 167 | title: "Sales Associate", 168 | comment: 169 | "I've been a motorcycle enthusiast for years, and this app is a game-changer. Whether you're a seasoned rider or a beginner, you'll find everything you need to fuel your passion for two-wheeled adventures.", 170 | }, 171 | 172 | { 173 | id: 14, 174 | 175 | firstName: "Enoch", 176 | 177 | lastName: "Lynch", 178 | 179 | image: "https://randomuser.me/api/portraits/men/58.jpg", 180 | 181 | title: "Professor", 182 | comment: 183 | "I'm impressed by the attention to detail in every listing on this app. From the high-quality photos to the in-depth descriptions, it's clear that the team behind this app is dedicated to providing the best possible experience for users.", 184 | }, 185 | 186 | { 187 | id: 15, 188 | 189 | firstName: "Jeanne", 190 | 191 | lastName: "Halvorson", 192 | 193 | image: "https://randomuser.me/api/portraits/women/89.jpg", 194 | 195 | title: "Software Test Engineer IV", 196 | comment: 197 | "I love how this app caters to every budget and lifestyle. Whether you're looking for a budget-friendly starter home or a luxury vehicle, you'll find options that suit your needs and preferences.", 198 | }, 199 | 200 | { 201 | id: 16, 202 | 203 | firstName: "Trycia", 204 | 205 | lastName: "Fadel", 206 | 207 | image: "https://randomuser.me/api/portraits/women/48.jpg", 208 | 209 | title: "Geological Engineer", 210 | comment: 211 | "The best part about this app is the community it fosters. From sharing tips and advice to connecting with fellow enthusiasts, it's more than just a marketplace—it's a hub for like-minded individuals to come together and share their passion for cars, motorcycles, and homes.", 212 | }, 213 | ]; 214 | export default usersData; 215 | --------------------------------------------------------------------------------