diff --git a/app/ClientLayout.js b/app/ClientLayout.js index 28e92f0..1e85f1a 100644 --- a/app/ClientLayout.js +++ b/app/ClientLayout.js @@ -36,7 +36,7 @@ import { } from "lucide-react"; import { useState, useEffect, useRef } from "react"; import { motion, AnimatePresence } from "framer-motion"; -import AuthService from "../services/AuthService"; +import AuthService from "./services/AuthService"; import { UserRole, UserRoleLabels } from "./enums/UserRole"; import "./i18n/config"; @@ -64,7 +64,9 @@ export default function ClientLayout({ children }) { name: authUser.name || authUser.email, email: authUser.email, phone: authUser.phone, - role: AuthService.isOwner() ? UserRole.OWNER : UserRole.CUSTOMER, + role: AuthService.isAdmin() ? UserRole.ADMIN + : AuthService.isOwner() ? UserRole.OWNER + : UserRole.CUSTOMER, }); } else { setUser(null); diff --git a/app/admin/page.js b/app/admin/page.js index ece9978..50c0cb3 100644 --- a/app/admin/page.js +++ b/app/admin/page.js @@ -1,7 +1,8 @@ 'use client'; import { motion } from 'framer-motion'; -import { useState } from 'react'; +import { useState, useEffect } from 'react'; +import { useRouter } from 'next/navigation'; import { useTranslation } from 'react-i18next'; import { Home, @@ -18,14 +19,22 @@ import UsersList from '../components/admin/UsersList'; import LedgerBook from '../components/admin/LedgerBook'; import AddPropertyForm from '../components/admin/AddPropertyForm'; import { PropertyProvider } from '../contexts/PropertyContext'; +import AuthService from '../services/AuthService'; import '../i18n/config'; export default function AdminPage() { const { t, i18n } = useTranslation(); + const router = useRouter(); const [activeTab, setActiveTab] = useState('dashboard'); const [showAddProperty, setShowAddProperty] = useState(false); const [notifications, setNotifications] = useState(3); + useEffect(() => { + if (!AuthService.isAuthenticated() || !AuthService.isAdmin()) { + router.push('/'); + } + }, [router]); + const tabs = [ { id: 'dashboard', label: 'لوحة التحكم', icon: Home }, { id: 'properties', label: 'العقارات', icon: Home }, diff --git a/app/login/page.js b/app/login/page.js index 62ca3ba..3733ea2 100644 --- a/app/login/page.js +++ b/app/login/page.js @@ -95,8 +95,8 @@ export default function LoginPage() { // Decode token to get user info via AuthService const authUser = AuthService.getUser(); - const userRole = authUser?.roles?.includes('Owner') ? 'owner' - : authUser?.roles?.includes('Admin') ? 'admin' + const userRole = AuthService.isAdmin() ? 'admin' + : AuthService.isOwner() ? 'owner' : 'customer'; console.log('[Login] User role:', userRole); diff --git a/app/owner/bookings/page.js b/app/owner/bookings/page.js index d367ab6..84154cd 100644 --- a/app/owner/bookings/page.js +++ b/app/owner/bookings/page.js @@ -33,7 +33,7 @@ import { Building } from 'lucide-react'; import toast, { Toaster } from 'react-hot-toast'; -import AuthService from '../../../services/AuthService'; +import AuthService from '../../services/AuthService'; import Image from 'next/image'; const OwnerBookingCalendar = ({ property, onDateSelect, selectedDates }) => { @@ -424,21 +424,21 @@ export default function OwnerBookingsPage() { const [dateRange, setDateRange] = useState({ start: '', end: '' }); const [showCalendar, setShowCalendar] = useState(false); - useEffect(() => { - const storedUser = localStorage.getItem('user'); - // User loaded via AuthService - // Handled above - if (userData.role !== 'owner') { - router.push('/'); - } else { - setUser(userData); - loadBookings(); - } + useEffect(() => { + const authUser = AuthService.getUser(); + if (authUser && AuthService.isOwner()) { + setUser({ + name: authUser.name || authUser.email, + email: authUser.email, + role: 'owner', + }); + loadBookings(); } else { router.push('/auth/choose-role'); } }, [router]); + const loadBookings = () => { const storedBookings = localStorage.getItem('ownerBookings'); if (storedBookings) { @@ -511,30 +511,7 @@ export default function OwnerBookingsPage() { setIsLoading(false); }; - useEffect(() => { - let filtered = [...bookings]; - if (filterStatus !== 'all') { - filtered = filtered.filter(b => b.status === filterStatus); - } - - if (searchTerm) { - filtered = filtered.filter(b => - b.propertyTitle.includes(searchTerm) || - b.tenantName.includes(searchTerm) || - b.id.includes(searchTerm) - ); - } - - if (dateRange.start) { - filtered = filtered.filter(b => b.startDate >= dateRange.start); - } - if (dateRange.end) { - filtered = filtered.filter(b => b.endDate <= dateRange.end); - } - - setFilteredBookings(filtered); - }, [filterStatus, searchTerm, dateRange, bookings]); const handleViewDetails = (booking) => { setSelectedBooking(booking); diff --git a/app/owner/calendar/page.js b/app/owner/calendar/page.js index 7e4624b..926b165 100644 --- a/app/owner/calendar/page.js +++ b/app/owner/calendar/page.js @@ -36,7 +36,7 @@ import { Calendar as CalendarIcon } from 'lucide-react'; import toast, { Toaster } from 'react-hot-toast'; -import AuthService from '../../../services/AuthService'; +import AuthService from '../../services/AuthService'; const MonthlyCalendar = ({ properties, selectedPropertyId, onDateClick, onPropertySelect }) => { const [currentMonth, setCurrentMonth] = useState(new Date()); @@ -483,21 +483,22 @@ export default function OwnerCalendarPage() { const [selectedProperty, setSelectedProperty] = useState(null); const [showFilters, setShowFilters] = useState(false); - useEffect(() => { - const storedUser = localStorage.getItem('user'); - // User loaded via AuthService - // Handled above - if (userData.role !== 'owner') { - router.push('/'); - } else { - setUser(userData); - loadProperties(); - } + useEffect(() => { + const authUser = AuthService.getUser(); + if (authUser && AuthService.isOwner()) { + setUser({ + name: authUser.name || authUser.email, + email: authUser.email, + role: 'owner', + }); + loadCalendar(); } else { router.push('/auth/choose-role'); } }, [router]); + + const loadProperties = () => { const storedProperties = localStorage.getItem('ownerProperties'); if (storedProperties) { diff --git a/app/owner/profits/page.js b/app/owner/profits/page.js index bcc4ac9..22e0815 100644 --- a/app/owner/profits/page.js +++ b/app/owner/profits/page.js @@ -28,7 +28,7 @@ import { XCircle } from 'lucide-react'; import toast, { Toaster } from 'react-hot-toast'; -import AuthService from '../../../services/AuthService'; +import AuthService from '../../services/AuthService'; const StatCard = ({ title, value, change, icon: Icon, color, trend }) => { return ( @@ -234,22 +234,23 @@ export default function OwnerProfitsPage() { const [isLoading, setIsLoading] = useState(true); const [selectedProperty, setSelectedProperty] = useState(null); const [dateRange, setDateRange] = useState({ start: '', end: '' }); - const [selectedPeriod, setSelectedPeriod] = useState('month'); // month, year, all + const [selectedPeriod, setSelectedPeriod] = useState('month'); - useEffect(() => { - const storedUser = localStorage.getItem('user'); - // User loaded via AuthService - // Handled above - if (userData.role !== 'owner') { - router.push('/'); - } else { - setUser(userData); - loadProfitsData(); - } + useEffect(() => { + const authUser = AuthService.getUser(); + if (authUser && AuthService.isOwner()) { + setUser({ + name: authUser.name || authUser.email, + email: authUser.email, + role: 'owner', + }); + loadData(); } else { router.push('/auth/choose-role'); } - }, [router]); + }, [router]); // month, year, all + + const loadProfitsData = () => { const storedProfits = localStorage.getItem('ownerProfits'); diff --git a/app/owner/properties/page.js b/app/owner/properties/page.js index 7c16e5d..f885fdc 100644 --- a/app/owner/properties/page.js +++ b/app/owner/properties/page.js @@ -45,7 +45,7 @@ import { X } from 'lucide-react'; import toast, { Toaster } from 'react-hot-toast'; -import AuthService from '../../../services/AuthService'; +import AuthService from '../../services/AuthService'; const DeleteConfirmationModal = ({ isOpen, onClose, onConfirm, propertyTitle }) => { if (!isOpen) return null; @@ -693,20 +693,21 @@ export default function OwnerPropertiesPage() { const [editModal, setEditModal] = useState({ isOpen: false, property: null }); useEffect(() => { - const storedUser = localStorage.getItem('user'); - // User loaded via AuthService - // Handled above - if (userData.role !== 'owner') { - router.push('/'); - } else { - setUser(userData); - loadProperties(); - } + const authUser = AuthService.getUser(); + if (authUser && AuthService.isOwner()) { + setUser({ + name: authUser.name || authUser.email, + email: authUser.email, + role: 'owner', + }); + loadProperties(); } else { router.push('/auth/choose-role'); } }, [router]); + + const loadProperties = () => { const storedProperties = localStorage.getItem('ownerProperties'); if (storedProperties) { diff --git a/app/services/AuthService.js b/app/services/AuthService.js index 0f7fd58..25577c6 100644 --- a/app/services/AuthService.js +++ b/app/services/AuthService.js @@ -86,16 +86,23 @@ const AuthService = Object.freeze({ * @returns {boolean} */ isOwner() { - const roles = this.getRoles(); - return roles.includes('Owner'); + return this.getRoles().includes('Owner'); }, /** - * Authenticated user without Owner role (i.e. customer) + * User has Admin role + * @returns {boolean} + */ + isAdmin() { + return this.getRoles().includes('Admin'); + }, + + /** + * Authenticated user without Owner or Admin role (i.e. customer) * @returns {boolean} */ isCustomer() { - return this.isAuthenticated() && !this.isOwner(); + return this.isAuthenticated() && !this.isOwner() && !this.isAdmin(); }, /**