├── 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 |
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 |
15 | Search ...
16 |
17 |
18 |
19 |
20 |
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 |
30 | Discover us
31 |
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 |
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 |
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 |
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 |
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 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
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 | {
70 | setOpenModal(false);
71 | dialogRef.current?.close();
72 | }}
73 | >
74 | No
75 |
76 | {
83 | yesButtonFunction();
84 | }}
85 | >
86 | Yes
87 |
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 |
56 |
57 |
63 |
69 | {location}
70 |
71 |
72 |
77 |
78 | {price} $
79 |
80 |
(!houseSold ? handleSoldButtonClick() : true)}
90 | >
91 | {houseSold ? "Already sold !" : "Buy now !"}
92 |
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 |
58 |
59 | {vehicleSelected === "Car" ? (
60 |
66 | ) : (
67 |
73 | )}
74 |
80 | {name}
81 |
82 |
83 |
84 |
89 |
90 | {price} $
91 |
92 |
(!vehicleSold ? handleSoldButtonClick() : true)}
102 | >
103 | {vehicleSold ? "Already sold !" : "Buy now !"}
104 |
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 |
59 |
60 |
68 |
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 |
48 |
49 |
50 |
51 |
{
53 | darkModeButtonHandler(dropDownList);
54 | }}
55 | className={tm(
56 | "flex cursor-pointer items-center justify-center p-3 hover:rounded-lg hover:bg-neutral-300",
57 | dark && "hover:bg-neutral-800",
58 | )}
59 | >
60 | {dark ? (
61 |
62 | ) : (
63 |
64 | )}
65 |
66 |
67 |
73 |
74 |
75 |
76 |
77 |
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 |
--------------------------------------------------------------------------------