Merge pull request 'feat: added mock search results' (#3) from feature/mock-search-results into main
All checks were successful
Frontend CI / Lint and Build Frontend (push) Successful in 20s
All checks were successful
Frontend CI / Lint and Build Frontend (push) Successful in 20s
Reviewed-on: http://git.naali.duckdns.org/jarno/vibing/pulls/3
This commit was merged in pull request #3.
This commit is contained in:
@@ -17,10 +17,10 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: '18'
|
node-version: '18'
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
@@ -39,7 +39,7 @@ jobs:
|
|||||||
run: npm run build
|
run: npm run build
|
||||||
|
|
||||||
- name: Upload build artifacts
|
- name: Upload build artifacts
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: frontend-build
|
name: frontend-build
|
||||||
path: frontend/dist
|
path: frontend/dist
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import './Footer.css';
|
import './Footer.css';
|
||||||
import { useLanguage } from '../contexts/LanguageContext';
|
import { useLanguage } from '../hooks/useLanguage';
|
||||||
|
|
||||||
const Footer = () => {
|
const Footer = () => {
|
||||||
const { t } = useLanguage();
|
const { t } = useLanguage();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { useLanguage } from '../contexts/LanguageContext';
|
import { useLanguage } from '../hooks/useLanguage';
|
||||||
import LanguageSwitcher from './LanguageSwitcher';
|
import LanguageSwitcher from './LanguageSwitcher';
|
||||||
import './Header.css';
|
import './Header.css';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useLanguage } from '../contexts/LanguageContext';
|
import { useLanguage } from '../hooks/useLanguage';
|
||||||
import './LanguageSwitcher.css';
|
import './LanguageSwitcher.css';
|
||||||
|
|
||||||
const LanguageSwitcher = () => {
|
const LanguageSwitcher = () => {
|
||||||
|
|||||||
@@ -1,86 +1,5 @@
|
|||||||
import React, { createContext, useContext, useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
import { LanguageContext, translations } from './languageContextData';
|
||||||
const LanguageContext = createContext();
|
|
||||||
|
|
||||||
export const useLanguage = () => {
|
|
||||||
const context = useContext(LanguageContext);
|
|
||||||
if (!context) {
|
|
||||||
throw new Error('useLanguage must be used within a LanguageProvider');
|
|
||||||
}
|
|
||||||
return context;
|
|
||||||
};
|
|
||||||
|
|
||||||
const translations = {
|
|
||||||
en: {
|
|
||||||
// Header
|
|
||||||
home: 'Home',
|
|
||||||
about: 'About',
|
|
||||||
contact: 'Contact',
|
|
||||||
|
|
||||||
// CTA Section
|
|
||||||
readyToStart: 'Ready to get started?',
|
|
||||||
ctaSubtitle: 'Join thousands of developers building amazing applications with our modern stack.',
|
|
||||||
startBuilding: 'Start Building',
|
|
||||||
|
|
||||||
// Language Switcher
|
|
||||||
language: 'Language',
|
|
||||||
english: 'English',
|
|
||||||
finnish: 'Finnish',
|
|
||||||
|
|
||||||
// Search Page
|
|
||||||
searchPlaceholder: 'Enter your search query...',
|
|
||||||
searchButton: 'Search',
|
|
||||||
searchResults: 'Search Results',
|
|
||||||
searchResultsSubtitle: 'Here are the results for your search query.',
|
|
||||||
searchResultsPlaceholder: 'Search results will appear here. Try entering a search term above to get started.',
|
|
||||||
|
|
||||||
// Search Filters
|
|
||||||
dogFriendly: 'Dog Friendly',
|
|
||||||
accessible: 'Accessible',
|
|
||||||
familyFriendly: 'Family Friendly',
|
|
||||||
peopleCount: 'People',
|
|
||||||
priceRange: 'Price',
|
|
||||||
any: 'Any',
|
|
||||||
|
|
||||||
// Footer
|
|
||||||
footerDescription: 'Find fun things to do!',
|
|
||||||
},
|
|
||||||
fi: {
|
|
||||||
// Header
|
|
||||||
home: 'Koti',
|
|
||||||
about: 'Tietoja',
|
|
||||||
contact: 'Yhteystiedot',
|
|
||||||
|
|
||||||
|
|
||||||
// CTA Section
|
|
||||||
readyToStart: 'Valmiina aloittamaan?',
|
|
||||||
ctaSubtitle: 'Liity tuhansien kehittäjien joukkoon, jotka rakentavat upeita sovelluksia modernilla teknologiapinoamme.',
|
|
||||||
startBuilding: 'Aloita rakentaminen',
|
|
||||||
|
|
||||||
// Language Switcher
|
|
||||||
language: 'Kieli',
|
|
||||||
english: 'Englanti',
|
|
||||||
finnish: 'Suomi',
|
|
||||||
|
|
||||||
// Search Page
|
|
||||||
searchPlaceholder: 'Syötä hakukyselysi...',
|
|
||||||
searchButton: 'Hae',
|
|
||||||
searchResults: 'Hakutulokset',
|
|
||||||
searchResultsSubtitle: 'Tässä ovat hakutulokset kyselysi perusteella.',
|
|
||||||
searchResultsPlaceholder: 'Hakutulokset näkyvät täällä. Kokeile syöttää hakusana yllä aloittaaksesi.',
|
|
||||||
|
|
||||||
// Search Filters
|
|
||||||
dogFriendly: 'Koiraystävällinen',
|
|
||||||
accessible: 'Esteetön',
|
|
||||||
familyFriendly: 'Lapsiystävällinen',
|
|
||||||
peopleCount: 'Henkilöt',
|
|
||||||
priceRange: 'Hinta',
|
|
||||||
any: 'Mikä tahansa',
|
|
||||||
|
|
||||||
// Footer
|
|
||||||
footerDescription: 'Löydä hauskaa tekemistä!',
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const LanguageProvider = ({ children }) => {
|
export const LanguageProvider = ({ children }) => {
|
||||||
const [language, setLanguage] = useState('en');
|
const [language, setLanguage] = useState('en');
|
||||||
|
|||||||
75
frontend/src/contexts/languageContextData.js
Normal file
75
frontend/src/contexts/languageContextData.js
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
import { createContext } from 'react';
|
||||||
|
|
||||||
|
export const LanguageContext = createContext();
|
||||||
|
|
||||||
|
export const translations = {
|
||||||
|
en: {
|
||||||
|
// Header
|
||||||
|
home: 'Home',
|
||||||
|
about: 'About',
|
||||||
|
contact: 'Contact',
|
||||||
|
|
||||||
|
// CTA Section
|
||||||
|
readyToStart: 'Ready to get started?',
|
||||||
|
ctaSubtitle: 'Join thousands of developers building amazing applications with our modern stack.',
|
||||||
|
startBuilding: 'Start Building',
|
||||||
|
|
||||||
|
// Language Switcher
|
||||||
|
language: 'Language',
|
||||||
|
english: 'English',
|
||||||
|
finnish: 'Finnish',
|
||||||
|
|
||||||
|
// Search Page
|
||||||
|
searchPlaceholder: 'Enter your search query...',
|
||||||
|
searchButton: 'Search',
|
||||||
|
searchResults: 'Search Results',
|
||||||
|
searchResultsSubtitle: 'Here are the results for your search query.',
|
||||||
|
searchResultsPlaceholder: 'Search results will appear here. Try entering a search term above to get started.',
|
||||||
|
|
||||||
|
// Search Filters
|
||||||
|
dogFriendly: 'Dog Friendly',
|
||||||
|
accessible: 'Accessible',
|
||||||
|
familyFriendly: 'Family Friendly',
|
||||||
|
peopleCount: 'People',
|
||||||
|
priceRange: 'Price',
|
||||||
|
any: 'Any',
|
||||||
|
|
||||||
|
// Footer
|
||||||
|
footerDescription: 'Find fun things to do!',
|
||||||
|
},
|
||||||
|
fi: {
|
||||||
|
// Header
|
||||||
|
home: 'Koti',
|
||||||
|
about: 'Tietoja',
|
||||||
|
contact: 'Yhteystiedot',
|
||||||
|
|
||||||
|
|
||||||
|
// CTA Section
|
||||||
|
readyToStart: 'Valmiina aloittamaan?',
|
||||||
|
ctaSubtitle: 'Liity tuhansien kehittäjien joukkoon, jotka rakentavat upeita sovelluksia modernilla teknologiapinoamme.',
|
||||||
|
startBuilding: 'Aloita rakentaminen',
|
||||||
|
|
||||||
|
// Language Switcher
|
||||||
|
language: 'Kieli',
|
||||||
|
english: 'Englanti',
|
||||||
|
finnish: 'Suomi',
|
||||||
|
|
||||||
|
// Search Page
|
||||||
|
searchPlaceholder: 'Syötä hakukyselysi...',
|
||||||
|
searchButton: 'Hae',
|
||||||
|
searchResults: 'Hakutulokset',
|
||||||
|
searchResultsSubtitle: 'Tässä ovat hakutulokset kyselysi perusteella.',
|
||||||
|
searchResultsPlaceholder: 'Hakutulokset näkyvät täällä. Kokeile syöttää hakusana yllä aloittaaksesi.',
|
||||||
|
|
||||||
|
// Search Filters
|
||||||
|
dogFriendly: 'Koiraystävällinen',
|
||||||
|
accessible: 'Esteetön',
|
||||||
|
familyFriendly: 'Lapsiystävällinen',
|
||||||
|
peopleCount: 'Henkilöt',
|
||||||
|
priceRange: 'Hinta',
|
||||||
|
any: 'Mikä tahansa',
|
||||||
|
|
||||||
|
// Footer
|
||||||
|
footerDescription: 'Löydä hauskaa tekemistä!',
|
||||||
|
}
|
||||||
|
};
|
||||||
10
frontend/src/hooks/useLanguage.js
Normal file
10
frontend/src/hooks/useLanguage.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { useContext } from 'react';
|
||||||
|
import { LanguageContext } from '../contexts/languageContextData';
|
||||||
|
|
||||||
|
export const useLanguage = () => {
|
||||||
|
const context = useContext(LanguageContext);
|
||||||
|
if (!context) {
|
||||||
|
throw new Error('useLanguage must be used within a LanguageProvider');
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
};
|
||||||
@@ -205,6 +205,107 @@
|
|||||||
gap: 2rem;
|
gap: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Search Results Section */
|
||||||
|
.search-results {
|
||||||
|
padding: 4rem 0;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.results-title {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: 700;
|
||||||
|
margin: 0 0 3rem 0;
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.results-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
|
||||||
|
gap: 2rem;
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-card {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-card .card-content {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-card .card-body {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-card .card-body p {
|
||||||
|
margin: 0;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.amenities {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.amenity-tag {
|
||||||
|
background: linear-gradient(135deg, var(--color-primary) 0%, var(--color-primary-dark) 100%);
|
||||||
|
color: var(--color-dark);
|
||||||
|
padding: 0.25rem 0.75rem;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-weight: 600;
|
||||||
|
box-shadow: 0 2px 8px var(--color-shadow-primary);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.amenity-tag:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 4px 12px var(--color-shadow-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No Results Section */
|
||||||
|
.no-results {
|
||||||
|
padding: 4rem 0;
|
||||||
|
background: white;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-results-content h2 {
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: 700;
|
||||||
|
margin: 0 0 1rem 0;
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-results-content p {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loading State */
|
||||||
|
.search-button.searching {
|
||||||
|
background: linear-gradient(135deg, var(--color-secondary-dark) 0%, var(--color-dark) 100%);
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-button.searching:hover {
|
||||||
|
transform: none;
|
||||||
|
box-shadow: 0 4px 12px var(--color-shadow-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
/* Responsive Design */
|
/* Responsive Design */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.hero {
|
.hero {
|
||||||
@@ -261,6 +362,27 @@
|
|||||||
.features-grid {
|
.features-grid {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search-results {
|
||||||
|
padding: 3rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.results-title {
|
||||||
|
font-size: 1.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.results-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-results {
|
||||||
|
padding: 3rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-results-content h2 {
|
||||||
|
font-size: 1.75rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 480px) {
|
@media (max-width: 480px) {
|
||||||
@@ -284,6 +406,14 @@
|
|||||||
min-width: 180px;
|
min-width: 180px;
|
||||||
padding: 0.75rem;
|
padding: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.results-title {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-results-content h2 {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dark Mode Support */
|
/* Dark Mode Support */
|
||||||
@@ -334,4 +464,24 @@
|
|||||||
.features {
|
.features {
|
||||||
background: var(--color-bg-dark);
|
background: var(--color-bg-dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search-results {
|
||||||
|
background: var(--color-bg-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-results {
|
||||||
|
background: var(--color-bg-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.results-title {
|
||||||
|
color: var(--color-text-primary-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-results-content h2 {
|
||||||
|
color: var(--color-text-primary-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-results-content p {
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Header, Footer, Button, Card } from '../components';
|
import { Header, Footer, Button, Card } from '../components';
|
||||||
import { useLanguage } from '../contexts/LanguageContext';
|
import { useLanguage } from '../hooks/useLanguage';
|
||||||
import './Home.css';
|
import './Home.css';
|
||||||
|
|
||||||
const Home = () => {
|
const Home = () => {
|
||||||
@@ -13,14 +13,62 @@ const Home = () => {
|
|||||||
peopleCount: '',
|
peopleCount: '',
|
||||||
priceRange: ''
|
priceRange: ''
|
||||||
});
|
});
|
||||||
|
const [searchResults, setSearchResults] = useState([]);
|
||||||
|
const [isSearching, setIsSearching] = useState(false);
|
||||||
|
|
||||||
|
// Mockup data for search results
|
||||||
|
const mockResults = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
title: "Cozy Mountain Cabin",
|
||||||
|
subtitle: "€€ • 4 guests • Dog friendly",
|
||||||
|
image: "https://images.unsplash.com/photo-1449824913935-59a10b8d2000?q=80&w=1920&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
|
||||||
|
description: "Beautiful mountain cabin with stunning views, perfect for a peaceful getaway. Features a hot tub and fireplace.",
|
||||||
|
amenities: ["Dog friendly", "Fireplace", "Hot tub", "Mountain view"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
title: "Modern City Apartment",
|
||||||
|
subtitle: "€€€ • 2 guests • Accessible",
|
||||||
|
image: "https://images.unsplash.com/photo-1502672260266-1c1ef2d93688?q=80&w=1920&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
|
||||||
|
description: "Stylish apartment in the heart of the city with modern amenities and easy access to public transportation.",
|
||||||
|
amenities: ["Accessible", "City view", "Gym access", "Parking"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
title: "Family Beach House",
|
||||||
|
subtitle: "€€€€ • 6 guests • Family friendly",
|
||||||
|
image: "https://images.unsplash.com/photo-1520250497591-112f2f40a3f4?q=80&w=1920&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
|
||||||
|
description: "Spacious beachfront property perfect for family vacations. Includes a pool, playground, and direct beach access.",
|
||||||
|
amenities: ["Family friendly", "Beach access", "Pool", "Playground"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
title: "Rustic Farmhouse",
|
||||||
|
subtitle: "€€ • 8 guests • Dog friendly",
|
||||||
|
image: "https://images.unsplash.com/photo-1571896349842-33c89424de2d?q=80&w=1920&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
|
||||||
|
description: "Charming farmhouse surrounded by nature. Perfect for large groups looking for a rural escape.",
|
||||||
|
amenities: ["Dog friendly", "Large groups", "Nature", "Fireplace"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
title: "Luxury Villa",
|
||||||
|
subtitle: "€€€€ • 4 guests • Accessible",
|
||||||
|
image: "https://images.unsplash.com/photo-1613490493576-7fde63acd811?q=80&w=1920&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
|
||||||
|
description: "Exclusive villa with premium amenities including a private pool, chef's kitchen, and stunning ocean views.",
|
||||||
|
amenities: ["Accessible", "Private pool", "Ocean view", "Chef's kitchen"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
title: "Cozy Studio",
|
||||||
|
subtitle: "€ • 2 guests • Family friendly",
|
||||||
|
image: "https://images.unsplash.com/photo-1560448204-e02f11c3d0e2?q=80&w=1920&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
|
||||||
|
description: "Affordable studio apartment perfect for couples or small families. Located in a quiet neighborhood.",
|
||||||
|
amenities: ["Family friendly", "Affordable", "Quiet", "Central location"]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
const handleGetStarted = () => {
|
|
||||||
alert('Get Started button clicked!');
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleLearnMore = () => {
|
|
||||||
alert('Learn More button clicked!');
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleFilterChange = (filterName, value) => {
|
const handleFilterChange = (filterName, value) => {
|
||||||
setFilters(prev => ({
|
setFilters(prev => ({
|
||||||
@@ -30,9 +78,30 @@ const Home = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
// Handle search logic here
|
if (!searchQuery.trim()) {
|
||||||
console.log('Search query:', searchQuery);
|
alert('Please enter a search query');
|
||||||
console.log('Filters:', filters);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsSearching(true);
|
||||||
|
|
||||||
|
// Simulate API call delay
|
||||||
|
setTimeout(() => {
|
||||||
|
// Filter results based on search query and filters
|
||||||
|
let filteredResults = mockResults.filter(result => {
|
||||||
|
const matchesQuery = result.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||||
|
result.description.toLowerCase().includes(searchQuery.toLowerCase());
|
||||||
|
|
||||||
|
const matchesDogFriendly = !filters.dogFriendly || result.amenities.includes('Dog friendly');
|
||||||
|
const matchesAccessible = !filters.accessible || result.amenities.includes('Accessible');
|
||||||
|
const matchesFamilyFriendly = !filters.familyFriendly || result.amenities.includes('Family friendly');
|
||||||
|
|
||||||
|
return matchesQuery && matchesDogFriendly && matchesAccessible && matchesFamilyFriendly;
|
||||||
|
});
|
||||||
|
|
||||||
|
setSearchResults(filteredResults);
|
||||||
|
setIsSearching(false);
|
||||||
|
}, 1000);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -57,8 +126,12 @@ const Home = () => {
|
|||||||
onChange={(e) => setSearchQuery(e.target.value)}
|
onChange={(e) => setSearchQuery(e.target.value)}
|
||||||
onKeyPress={(e) => e.key === 'Enter' && handleSearch()}
|
onKeyPress={(e) => e.key === 'Enter' && handleSearch()}
|
||||||
/>
|
/>
|
||||||
<button className="search-button" onClick={handleSearch}>
|
<button
|
||||||
{t('searchButton')}
|
className={`search-button ${isSearching ? 'searching' : ''}`}
|
||||||
|
onClick={handleSearch}
|
||||||
|
disabled={isSearching}
|
||||||
|
>
|
||||||
|
{isSearching ? 'Searching...' : t('searchButton')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -140,6 +213,50 @@ const Home = () => {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
{/* Search Results Section */}
|
||||||
|
{searchResults.length > 0 && (
|
||||||
|
<section className="search-results">
|
||||||
|
<div className="container">
|
||||||
|
<h2 className="results-title">
|
||||||
|
Found {searchResults.length} result{searchResults.length !== 1 ? 's' : ''} for "{searchQuery}"
|
||||||
|
</h2>
|
||||||
|
<div className="results-grid">
|
||||||
|
{searchResults.map(result => (
|
||||||
|
<Card
|
||||||
|
key={result.id}
|
||||||
|
title={result.title}
|
||||||
|
subtitle={result.subtitle}
|
||||||
|
image={result.image}
|
||||||
|
imageAlt={result.title}
|
||||||
|
className="result-card"
|
||||||
|
>
|
||||||
|
<p>{result.description}</p>
|
||||||
|
<div className="amenities">
|
||||||
|
{result.amenities.map((amenity, index) => (
|
||||||
|
<span key={index} className="amenity-tag">
|
||||||
|
{amenity}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* No Results Message */}
|
||||||
|
{searchResults.length === 0 && !isSearching && searchQuery && (
|
||||||
|
<section className="no-results">
|
||||||
|
<div className="container">
|
||||||
|
<div className="no-results-content">
|
||||||
|
<h2>No results found for "{searchQuery}"</h2>
|
||||||
|
<p>Try adjusting your search terms or filters to find more options.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)}
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<Footer />
|
<Footer />
|
||||||
|
|||||||
Reference in New Issue
Block a user