fixd larg lines in HomePage , add cookies rather than localStorage,make canvas background Login page
This commit is contained in:
@ -1,321 +1,117 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { motion } from 'framer-motion';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Search, MapPin, Home, DollarSign, ShieldCheck } from 'lucide-react';
|
||||
|
||||
export default function HeroSearch({ onSearch, isAuthenticated }) {
|
||||
"use client";
|
||||
import { useState } from "react";
|
||||
import { motion } from "framer-motion";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Search, MapPin, Home, DollarSign } from "lucide-react";
|
||||
import { useFilterOptions } from "@/app/hooks/UseFilterOfHeroSearch";
|
||||
import ShowLoginDialog from "./showLoginDialog";
|
||||
import FilterSelect from "./FilterSelect";
|
||||
export default function HeroSearch({ onSearch }) {
|
||||
const { t } = useTranslation();
|
||||
const [activeTab, setActiveTab] = useState('buy');
|
||||
const { cities, identityTypes, ownerSources, priceRanges, propertyTypes, rentPeriods } = useFilterOptions();
|
||||
const [activeTab, setActiveTab] = useState("buy");
|
||||
const [filters, setFilters] = useState({
|
||||
city: 'all',
|
||||
propertyType: 'all',
|
||||
priceRange: 'all',
|
||||
identityType: 'syrian',
|
||||
ownerSource: 'all',
|
||||
rentPeriod: 'all',
|
||||
availableToday: false
|
||||
city: "all",
|
||||
propertyType: "all",
|
||||
priceRange: "all",
|
||||
identityType: "syrian",
|
||||
ownerSource: "all",
|
||||
rentPeriod: "all",
|
||||
availableToday: false,
|
||||
});
|
||||
const [showLoginDialog, setShowLoginDialog] = useState(false);
|
||||
|
||||
const cities = [
|
||||
{ id: 'all', label: t('allCities') },
|
||||
{ id: 'دمشق', label: t('damascus') },
|
||||
{ id: 'حلب', label: t('aleppo') },
|
||||
{ id: 'حمص', label: t('homs') },
|
||||
{ id: 'اللاذقية', label: t('latakia') },
|
||||
{ id: 'درعا', label: t('daraa') }
|
||||
];
|
||||
|
||||
const propertyTypes = [
|
||||
{ id: 'all', label: t('all') },
|
||||
{ id: 'apartment', label: t('residentialApartments') },
|
||||
{ id: 'studio', label: t('studio') },
|
||||
{ id: 'commercial', label: t('commercialProperty') },
|
||||
{ id: 'villa', label: t('villaFarm') }
|
||||
];
|
||||
|
||||
const priceRanges = [
|
||||
{ id: 'all', label: t('allPrices') },
|
||||
{ id: '0-500', label: t('priceRange1') },
|
||||
{ id: '500-1000', label: t('priceRange2') },
|
||||
{ id: '1000-2000', label: t('priceRange3') },
|
||||
{ id: '2000-3000', label: t('priceRange4') },
|
||||
{ id: '3000+', label: t('priceRange5') }
|
||||
];
|
||||
|
||||
const identityTypes = [
|
||||
{ id: 'syrian', label: t('syrianId') },
|
||||
{ id: 'passport', label: t('passport') }
|
||||
];
|
||||
|
||||
const ownerSources = [
|
||||
{ id: 'all', label: t('all') },
|
||||
{ id: 'owner', label: t('fromOwner') },
|
||||
{ id: 'agency', label: t('fromAgency') }
|
||||
];
|
||||
|
||||
const rentPeriods = [
|
||||
{ id: 'all', label: t('all') },
|
||||
{ id: 'daily', label: t('dailyRent') },
|
||||
{ id: 'monthly', label: t('monthlyRent') }
|
||||
];
|
||||
|
||||
const handleTabClick = (tab) => {
|
||||
setActiveTab(tab);
|
||||
if ((tab === 'rent' || tab === 'sell') && !isAuthenticated) {
|
||||
setShowLoginDialog(true);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSearch = () => {
|
||||
if ((activeTab === 'rent' || activeTab === 'sell') && !isAuthenticated) {
|
||||
setShowLoginDialog(true);
|
||||
return;
|
||||
}
|
||||
|
||||
onSearch({
|
||||
...filters,
|
||||
mode: activeTab,
|
||||
city: filters.city || 'all',
|
||||
propertyType: filters.propertyType || 'all',
|
||||
priceRange: filters.priceRange || 'all',
|
||||
ownerSource: filters.ownerSource || 'all',
|
||||
rentPeriod: filters.rentPeriod || 'all'
|
||||
city: filters.city || "all",
|
||||
propertyType: filters.propertyType || "all",
|
||||
priceRange: filters.priceRange || "all",
|
||||
ownerSource: filters.ownerSource || "all",
|
||||
rentPeriod: filters.rentPeriod || "all",
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<motion.div
|
||||
className="bg-white/10 backdrop-blur-lg rounded-2xl p-6 sm:p-8 border border-white/20 shadow-2xl"
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.8, delay: 0.5 }}
|
||||
>
|
||||
<div className="flex flex-wrap gap-2 mb-8">
|
||||
{['rent', 'buy', 'sell'].map((tab) => (
|
||||
<motion.button
|
||||
key={tab}
|
||||
onClick={() => handleTabClick(tab)}
|
||||
className={`px-4 py-2 rounded-lg font-medium text-sm transition-all ${
|
||||
activeTab === tab
|
||||
? 'bg-amber-500 text-white'
|
||||
: 'bg-white/20 text-white hover:bg-white/30'
|
||||
}`}
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
>
|
||||
{t(`${tab}Tab`)}
|
||||
</motion.button>
|
||||
))}
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-white mb-2">
|
||||
<div className="flex items-center gap-1">
|
||||
<MapPin className="w-4 h-4" />
|
||||
{t("cityStreetLabel")}
|
||||
</div>
|
||||
</label>
|
||||
<select
|
||||
value={filters.city}
|
||||
onChange={(e) => setFilters({...filters, city: e.target.value})}
|
||||
className="w-full px-4 py-3 bg-white/90 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500 text-sm appearance-none cursor-pointer"
|
||||
style={{
|
||||
backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%23666'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7'%3E%3C/path%3E%3C/svg%3E")`,
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundPosition: 'left 1rem center',
|
||||
backgroundSize: '1rem',
|
||||
paddingLeft: '2.5rem'
|
||||
}}
|
||||
>
|
||||
{cities.map(city => (
|
||||
<option key={city.id} value={city.id}>{city.label}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
{activeTab === 'rent' && (
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-white mb-2">
|
||||
<div className="flex items-center gap-1">
|
||||
<Home className="w-4 h-4" />
|
||||
{t("rentTypeLabel")}
|
||||
</div>
|
||||
</label>
|
||||
<select
|
||||
value={filters.propertyType}
|
||||
onChange={(e) => setFilters({...filters, propertyType: e.target.value})}
|
||||
className="w-full px-4 py-3 bg-white/90 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500 text-sm appearance-none cursor-pointer"
|
||||
style={{
|
||||
backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%23666'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7'%3E%3C/path%3E%3C/svg%3E")`,
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundPosition: 'left 1rem center',
|
||||
backgroundSize: '1rem',
|
||||
paddingLeft: '2.5rem'
|
||||
}}
|
||||
>
|
||||
{propertyTypes.map(type => (
|
||||
<option key={type.id} value={type.id}>{type.label}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-white mb-2">
|
||||
<div className="flex items-center gap-1">
|
||||
<DollarSign className="w-4 h-4" />
|
||||
{t("priceLabel")}
|
||||
</div>
|
||||
</label>
|
||||
<select
|
||||
value={filters.priceRange}
|
||||
onChange={(e) => setFilters({...filters, priceRange: e.target.value})}
|
||||
className="w-full px-4 py-3 bg-white/90 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500 text-sm appearance-none cursor-pointer"
|
||||
style={{
|
||||
backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%23666'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7'%3E%3C/path%3E%3C/svg%3E")`,
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundPosition: 'left 1rem center',
|
||||
backgroundSize: '1rem',
|
||||
paddingLeft: '2.5rem'
|
||||
}}
|
||||
>
|
||||
{priceRanges.map(range => (
|
||||
<option key={range.id} value={range.id}>{range.label}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-white mb-2">
|
||||
<div className="flex items-center gap-1">
|
||||
{t("identityTypeLabel")}
|
||||
</div>
|
||||
</label>
|
||||
<select
|
||||
value={filters.identityType}
|
||||
onChange={(e) => setFilters({...filters, identityType: e.target.value})}
|
||||
className="w-full px-4 py-3 bg-white/90 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500 text-sm appearance-none cursor-pointer"
|
||||
style={{
|
||||
backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%23666'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7'%3E%3C/path%3E%3C/svg%3E")`,
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundPosition: 'left 1rem center',
|
||||
backgroundSize: '1rem',
|
||||
paddingLeft: '2.5rem'
|
||||
}}
|
||||
>
|
||||
{identityTypes.map(type => (
|
||||
<option key={type.id} value={type.id}>{type.label}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-4 mt-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-white mb-2">{t("ownerSourceLabel")}</label>
|
||||
<select
|
||||
value={filters.ownerSource}
|
||||
onChange={(e) => setFilters({ ...filters, ownerSource: e.target.value })}
|
||||
className="w-full px-4 py-3 bg-white/90 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500 text-sm appearance-none cursor-pointer"
|
||||
style={{
|
||||
backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%23666'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7'%3E%3C/path%3E%3C/svg%3E")`,
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundPosition: 'left 1rem center',
|
||||
backgroundSize: '1rem',
|
||||
paddingLeft: '2.5rem'
|
||||
}}
|
||||
>
|
||||
{ownerSources.map((source) => (
|
||||
<option key={source.id} value={source.id}>
|
||||
{source.label}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<motion.div
|
||||
className="bg-white/10 backdrop-blur-lg rounded-2xl p-6 sm:p-8 border border-white/20 shadow-2xl"
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.8, delay: 0.5 }}
|
||||
>
|
||||
<div className="flex flex-wrap gap-2 mb-8">
|
||||
{["rent", "buy", "sell"].map((tab) => {
|
||||
const isActive = activeTab === tab;
|
||||
|
||||
{activeTab === 'rent' && (
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-white mb-2">{t("rentTypeLabel")}</label>
|
||||
<select
|
||||
value={filters.rentPeriod}
|
||||
onChange={(e) => setFilters({ ...filters, rentPeriod: e.target.value })}
|
||||
className="w-full px-4 py-3 bg-white/90 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500 text-sm appearance-none cursor-pointer"
|
||||
style={{
|
||||
backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%23666'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7'%3E%3C/path%3E%3C/svg%3E")`,
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundPosition: 'left 1rem center',
|
||||
backgroundSize: '1rem',
|
||||
paddingLeft: '2.5rem'
|
||||
}}
|
||||
>
|
||||
{rentPeriods.map((period) => (
|
||||
<option key={period.id} value={period.id}>
|
||||
{period.label}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className={`${activeTab === 'rent' ? 'md:col-span-2' : 'md:col-span-3'} flex flex-col justify-between p-4 rounded-2xl border border-dashed border-white/30 bg-white/5`}>
|
||||
<label className="mt-4 flex items-center gap-3 text-white text-sm">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={filters.availableToday}
|
||||
onChange={(e) => setFilters({ ...filters, availableToday: e.target.checked })}
|
||||
className="w-5 h-5 text-amber-500 rounded border-gray-300 bg-white"
|
||||
/>
|
||||
<span className="font-medium">{t("availableToday")}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-6">
|
||||
<motion.button
|
||||
onClick={handleSearch}
|
||||
className="w-full bg-amber-500 hover:bg-amber-600 text-white font-bold py-4 px-6 rounded-xl transition-all duration-300 flex items-center justify-center text-base gap-3 shadow-lg hover:shadow-xl"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
<Search className="w-5 h-5" />
|
||||
{t("searchButton")}
|
||||
</motion.button>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{showLoginDialog && !isAuthenticated && (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 px-4 py-8">
|
||||
<div className="w-full max-w-md rounded-3xl bg-white p-6 shadow-2xl border border-gray-200">
|
||||
<div className="flex items-center gap-3 mb-5">
|
||||
<ShieldCheck className="w-7 h-7 text-amber-500" />
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900">{t("loginRequired")}</h3>
|
||||
<p className="text-sm text-gray-600">{t("loginRequiredDesc")}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<div className="rounded-2xl bg-gray-50 p-4">
|
||||
<p className="text-sm text-gray-700">{t("loginPrompt")}</p>
|
||||
</div>
|
||||
<div className="flex flex-col gap-3 sm:flex-row sm:justify-end">
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowLoginDialog(false)}
|
||||
className="w-full sm:w-auto px-5 py-3 rounded-xl border border-gray-300 text-gray-700 hover:bg-gray-100 transition-colors"
|
||||
key={tab}
|
||||
onClick={() => handleTabClick(tab)}
|
||||
className={`relative px-5 py-2.5 rounded-lg font-medium text-sm transition-colors duration-200 outline-none select-none ${isActive ? "text-white" : "text-amber-50 hover:text-white"}`}
|
||||
>
|
||||
{t("close")}
|
||||
{isActive && <motion.div layoutId="activeTabBackground" className="absolute inset-0 bg-amber-500 rounded-lg shadow-md" transition={{ type: "spring", stiffness: 500, damping: 35 }} />}
|
||||
<span className="relative z-10">{t(`${tab}Tab`)}</span>
|
||||
</button>
|
||||
<Link
|
||||
href="/login"
|
||||
className="w-full sm:w-auto px-5 py-3 rounded-xl bg-amber-500 text-white font-semibold text-center hover:bg-amber-600 transition-colors"
|
||||
>
|
||||
{t("login")}
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{/* city */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||||
<FilterSelect icon={<MapPin className="w-4 h-4" />} value={filters.city} onChange={(e) => setFilters({ ...filters, city: e.target.value })} option={cities} label={t(t("cityStreetLabel"))} />
|
||||
{activeTab === "rent" && (
|
||||
<FilterSelect
|
||||
icon={<Home className="w-4 h-4" />}
|
||||
value={filters.propertyType}
|
||||
onChange={(e) => setFilters({ ...filters, city: e.target.value })}
|
||||
option={propertyTypes}
|
||||
label={t("rentTypeLabel")}
|
||||
/>
|
||||
)}
|
||||
{/* price */}
|
||||
<FilterSelect
|
||||
icon={<DollarSign className="w-4 h-4" />}
|
||||
value={filters.priceRange}
|
||||
onChange={(e) => setFilters({ ...filters, priceRange: e.target.value })}
|
||||
option={priceRanges}
|
||||
label={t("priceLabel")}
|
||||
/>
|
||||
{/* type */}
|
||||
<FilterSelect value={filters.identityType} onChange={(e) => setFilters({ ...filters, identityType: e.target.value })} option={identityTypes} label={t("identityTypeLabel")} />
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-4 mt-4">
|
||||
{/* owener */}
|
||||
<FilterSelect value={filters.ownerSource} onChange={(e) => setFilters({ ...filters, ownerSource: e.target.value })} option={ownerSources} label={t("ownerSourceLabel")} />
|
||||
{activeTab === "rent" && <FilterSelect value={filters.rentPeriod} onChange={(e) => setFilters({ ...filters, rentPeriod: e.target.value })} option={rentPeriods} label={t("rentTypeLabel")} />}
|
||||
<div className={`${activeTab === "rent" ? "md:col-span-2" : "md:col-span-3"} flex flex-col justify-between p-4 rounded-2xl border border-dashed border-white/30 bg-white/5`}>
|
||||
{/* checkbox */}
|
||||
<label className="mt-4 flex items-center gap-3 text-amber-50 text-sm">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={filters.availableToday}
|
||||
onChange={(e) => setFilters({ ...filters, availableToday: e.target.checked })}
|
||||
className="w-5 h-5 text-amber-500 rounded border-gray-300 bg-white"
|
||||
/>
|
||||
<span className="font-medium">{t("availableToday")}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="mt-6">
|
||||
<motion.button
|
||||
onClick={handleSearch}
|
||||
className="w-full bg-amber-500 hover:bg-amber-600 text-white font-bold py-4 px-6 rounded-xl transition-all duration-300 flex items-center justify-center text-base gap-3 shadow-lg hover:shadow-xl"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
<Search className="w-5 h-5" />
|
||||
{t("searchButton")}
|
||||
</motion.button>
|
||||
</div>
|
||||
</motion.div>
|
||||
{showLoginDialog && !isAuthenticated && <ShowLoginDialog setShowLoginDialog={setShowLoginDialog} />}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user