diff --git a/app/ClientLayout.js b/app/ClientLayout.js index ef59356..79f6131 100644 --- a/app/ClientLayout.js +++ b/app/ClientLayout.js @@ -1,17 +1,17 @@ -'use client'; +"use client"; -import { usePathname } from 'next/navigation'; -import { useTranslation } from 'react-i18next'; +import { usePathname } from "next/navigation"; +import { useTranslation } from "react-i18next"; import Link from "next/link"; import Image from "next/image"; import { NavLink, MobileNavLink } from "./components/NavLinks"; -import { - Globe, - LogIn, - UserPlus, - UserCircle, - LogOut, - Calendar, +import { + Globe, + LogIn, + UserPlus, + UserCircle, + LogOut, + Calendar, Building, PlusCircle, Heart, @@ -32,16 +32,16 @@ import { CalendarDays, Clock, Users, - DollarSign -} from 'lucide-react'; -import { useState, useEffect, useRef } from 'react'; -import { motion, AnimatePresence } from 'framer-motion'; -import './i18n/config'; + DollarSign, +} from "lucide-react"; +import { useState, useEffect, useRef } from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import "./i18n/config"; export default function ClientLayout({ children }) { const { t, i18n } = useTranslation(); const pathname = usePathname(); - const [currentLanguage, setCurrentLanguage] = useState('en'); + const [currentLanguage, setCurrentLanguage] = useState("en"); const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); const [showUserMenu, setShowUserMenu] = useState(false); const [user, setUser] = useState(null); @@ -51,23 +51,23 @@ export default function ClientLayout({ children }) { useEffect(() => { setIsMounted(true); - const savedLanguage = localStorage.getItem('language') || 'en'; + const savedLanguage = localStorage.getItem("language") || "en"; setCurrentLanguage(savedLanguage); i18n.changeLanguage(savedLanguage); - - const storedUser = localStorage.getItem('user'); + + const storedUser = localStorage.getItem("user"); if (storedUser) { const userData = JSON.parse(storedUser); - console.log('User data loaded:', userData); + console.log("User data loaded:", userData); setUser(userData); } - - if (savedLanguage === 'ar') { - document.documentElement.dir = 'rtl'; - document.documentElement.lang = 'ar'; + + if (savedLanguage === "ar") { + document.documentElement.dir = "rtl"; + document.documentElement.lang = "ar"; } else { - document.documentElement.dir = 'ltr'; - document.documentElement.lang = 'en'; + document.documentElement.dir = "ltr"; + document.documentElement.lang = "en"; } }, [i18n]); @@ -77,21 +77,21 @@ export default function ClientLayout({ children }) { setShowUserMenu(false); } }; - document.addEventListener('mousedown', handleClickOutside); - return () => document.removeEventListener('mousedown', handleClickOutside); + document.addEventListener("mousedown", handleClickOutside); + return () => document.removeEventListener("mousedown", handleClickOutside); }, []); const changeLanguage = (lng) => { i18n.changeLanguage(lng); setCurrentLanguage(lng); - localStorage.setItem('language', lng); - - if (lng === 'ar') { - document.documentElement.dir = 'rtl'; - document.documentElement.lang = 'ar'; + localStorage.setItem("language", lng); + + if (lng === "ar") { + document.documentElement.dir = "rtl"; + document.documentElement.lang = "ar"; } else { - document.documentElement.dir = 'ltr'; - document.documentElement.lang = 'en'; + document.documentElement.dir = "ltr"; + document.documentElement.lang = "en"; } }; @@ -104,21 +104,26 @@ export default function ClientLayout({ children }) { }; const logout = () => { - localStorage.removeItem('user'); + localStorage.removeItem("user"); setUser(null); setShowUserMenu(false); - window.location.href = '/'; + window.location.href = "/"; }; - const isAuthPage = ['/login', '/register', '/forgot-password', '/auth/choose-role'].includes(pathname); - - const isProfilePage = pathname === '/profile'; + const isAuthPage = [ + "/login", + "/register", + "/forgot-password", + "/auth/choose-role", + ].includes(pathname); - const isOwner = user?.role === 'owner'; - const isAdmin = user?.role === 'admin'; + const isProfilePage = pathname === "/profile"; - console.log('User role:', user?.role); - console.log('Is Admin:', isAdmin); + const isOwner = user?.role === "owner"; + const isAdmin = user?.role === "admin"; + + console.log("User role:", user?.role); + console.log("Is Admin:", isAdmin); const getUserInitial = () => { if (user?.name) { @@ -143,35 +148,36 @@ export default function ClientLayout({ children }) { {!isAuthPage && ( )} -
+
{children}
{!isAuthPage && !isProfilePage && ( )} ); -} \ No newline at end of file +} diff --git a/app/contexts/PropertyContext.js b/app/contexts/PropertyContext.js index 879fc94..d25f7b9 100644 --- a/app/contexts/PropertyContext.js +++ b/app/contexts/PropertyContext.js @@ -1,13 +1,13 @@ -'use client'; +"use client"; -import { createContext, useContext, useState, useCallback } from 'react'; +import { createContext, useContext, useState, useCallback } from "react"; const PropertyContext = createContext(); export const useProperties = () => { const context = useContext(PropertyContext); if (!context) { - throw new Error('useProperties must be used within PropertyProvider'); + throw new Error("useProperties must be used within PropertyProvider"); } return context; }; @@ -20,18 +20,18 @@ export const PropertyProvider = ({ children }) => { const addProperty = useCallback(async (propertyData) => { setLoading(true); try { - await new Promise(resolve => setTimeout(resolve, 500)); - + await new Promise((resolve) => setTimeout(resolve, 500)); + const newProperty = { id: Date.now().toString(), ...propertyData, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), bookings: [], - status: propertyData.status || 'available' + status: propertyData.status || "available", }; - - setProperties(prev => [...prev, newProperty]); + + setProperties((prev) => [...prev, newProperty]); return newProperty; } catch (err) { setError(err.message); @@ -44,13 +44,14 @@ export const PropertyProvider = ({ children }) => { const updateProperty = useCallback(async (id, updates) => { setLoading(true); try { - await new Promise(resolve => setTimeout(resolve, 500)); - - setProperties(prev => - prev.map(p => p.id === id - ? { ...p, ...updates, updatedAt: new Date().toISOString() } - : p - ) + await new Promise((resolve) => setTimeout(resolve, 500)); + + setProperties((prev) => + prev.map((p) => + p.id === id + ? { ...p, ...updates, updatedAt: new Date().toISOString() } + : p, + ), ); } catch (err) { setError(err.message); @@ -63,8 +64,8 @@ export const PropertyProvider = ({ children }) => { const deleteProperty = useCallback(async (id) => { setLoading(true); try { - await new Promise(resolve => setTimeout(resolve, 500)); - setProperties(prev => prev.filter(p => p.id !== id)); + await new Promise((resolve) => setTimeout(resolve, 500)); + setProperties((prev) => prev.filter((p) => p.id !== id)); } catch (err) { setError(err.message); throw err; @@ -73,69 +74,86 @@ export const PropertyProvider = ({ children }) => { } }, []); - const getProperty = useCallback((id) => { - return properties.find(p => p.id === id); - }, [properties]); + const getProperty = useCallback( + (id) => { + return properties.find((p) => p.id === id); + }, + [properties], + ); - const checkAvailability = useCallback((propertyId, startDate, endDate) => { - const property = properties.find(p => p.id === propertyId); - if (!property) return false; - - const checkStart = new Date(startDate); - const checkEnd = new Date(endDate); - - return !property.bookings?.some(booking => { - if (booking.status === 'cancelled' || booking.status === 'rejected') { - return false; - } - - const bookingStart = new Date(booking.startDate); - const bookingEnd = new Date(booking.endDate); - - return ( - (checkStart >= bookingStart && checkStart <= bookingEnd) || - (checkEnd >= bookingStart && checkEnd <= bookingEnd) || - (checkStart <= bookingStart && checkEnd >= bookingEnd) - ); - }); - }, [properties]); + const checkAvailability = useCallback( + (propertyId, startDate, endDate) => { + const property = properties.find((p) => p.id === propertyId); + if (!property) return false; - const getPropertiesByOwner = useCallback((ownerId) => { - return properties.filter(p => p.ownerId === ownerId); - }, [properties]); + const checkStart = new Date(startDate); + const checkEnd = new Date(endDate); + + return !property.bookings?.some((booking) => { + if (booking.status === "cancelled" || booking.status === "rejected") { + return false; + } + + const bookingStart = new Date(booking.startDate); + const bookingEnd = new Date(booking.endDate); + + return ( + (checkStart >= bookingStart && checkStart <= bookingEnd) || + (checkEnd >= bookingStart && checkEnd <= bookingEnd) || + (checkStart <= bookingStart && checkEnd >= bookingEnd) + ); + }); + }, + [properties], + ); + + const getPropertiesByOwner = useCallback( + (ownerId) => { + return properties.filter((p) => p.ownerId === ownerId); + }, + [properties], + ); const getAvailableProperties = useCallback(() => { - return properties.filter(p => p.status === 'available'); + return properties.filter((p) => p.status === "available"); }, [properties]); - const updatePropertyStatus = useCallback(async (id, status) => { - return updateProperty(id, { status }); - }, [updateProperty]); + const updatePropertyStatus = useCallback( + async (id, status) => { + return updateProperty(id, { status }); + }, + [updateProperty], + ); - const addBookingToProperty = useCallback(async (propertyId, bookingData) => { - const property = getProperty(propertyId); - if (!property) throw new Error('Property not found'); + const addBookingToProperty = useCallback( + async (propertyId, bookingData) => { + const property = getProperty(propertyId); + if (!property) throw new Error("Property not found"); - const updatedBookings = [...(property.bookings || []), bookingData]; - return updateProperty(propertyId, { bookings: updatedBookings }); - }, [getProperty, updateProperty]); + const updatedBookings = [...(property.bookings || []), bookingData]; + return updateProperty(propertyId, { bookings: updatedBookings }); + }, + [getProperty, updateProperty], + ); return ( - + {children} ); -}; \ No newline at end of file +}; diff --git a/public/apartment1.jpg b/public/apartment1.jpg new file mode 100644 index 0000000..bbbb2bd Binary files /dev/null and b/public/apartment1.jpg differ diff --git a/public/apartment2.jpg b/public/apartment2.jpg new file mode 100644 index 0000000..1ac158f Binary files /dev/null and b/public/apartment2.jpg differ diff --git a/public/house1.jpg b/public/house1.jpg new file mode 100644 index 0000000..7f18d25 Binary files /dev/null and b/public/house1.jpg differ diff --git a/public/logo.png b/public/logo.png index 88960db..0f8b944 100644 Binary files a/public/logo.png and b/public/logo.png differ diff --git a/public/logo1.png b/public/logo1.png new file mode 100644 index 0000000..88960db Binary files /dev/null and b/public/logo1.png differ diff --git a/public/seaside1.jpg b/public/seaside1.jpg new file mode 100644 index 0000000..47324fb Binary files /dev/null and b/public/seaside1.jpg differ diff --git a/public/villa1.jpg b/public/villa1.jpg new file mode 100644 index 0000000..7438d69 Binary files /dev/null and b/public/villa1.jpg differ diff --git a/public/villa2.jpg b/public/villa2.jpg new file mode 100644 index 0000000..7ac6355 Binary files /dev/null and b/public/villa2.jpg differ diff --git a/public/villa3.jpg b/public/villa3.jpg new file mode 100644 index 0000000..1e2b376 Binary files /dev/null and b/public/villa3.jpg differ diff --git a/public/villa4.jpg b/public/villa4.jpg new file mode 100644 index 0000000..47ca602 Binary files /dev/null and b/public/villa4.jpg differ diff --git a/public/villa5.jpg b/public/villa5.jpg new file mode 100644 index 0000000..6d7f095 Binary files /dev/null and b/public/villa5.jpg differ diff --git a/public/villa6.jpg b/public/villa6.jpg new file mode 100644 index 0000000..d82e097 Binary files /dev/null and b/public/villa6.jpg differ