From 085eaf5fa2df78e2cc520c572cea68afa17adaa7 Mon Sep 17 00:00:00 2001 From: yotakii Date: Wed, 14 Jan 2026 14:57:45 +0300 Subject: [PATCH] edit1 --- client/src/App.js | 5 +- client/src/components/admin/AdminLayout.js | 51 ++----- client/src/components/layout/Footer.js | 164 ++++++++++++--------- client/src/components/layout/Header.js | 20 +-- client/src/context/SettingsContext.js | 42 ++++++ client/src/pages/Booking.js | 102 ++++++++++--- client/src/pages/BookingConfirmation.js | 120 +++++++++++++-- client/src/pages/admin/DashboardMain.js | 71 ++------- 8 files changed, 356 insertions(+), 219 deletions(-) create mode 100644 client/src/context/SettingsContext.js diff --git a/client/src/App.js b/client/src/App.js index 188f649..cd1edef 100644 --- a/client/src/App.js +++ b/client/src/App.js @@ -33,7 +33,6 @@ import ContentManagement from './pages/admin/ContentManagement'; import RoomManagement from './pages/admin/RoomManagement'; import BookingManagement from './pages/admin/BookingManagement'; import MediaManagement from './pages/admin/MediaManagement'; -import BlogManagement from './pages/admin/BlogManagement'; import SettingsManagement from './pages/admin/SettingsManagement'; // Loading Component @@ -93,18 +92,16 @@ function App() { } > - {/* NEW: redirect /admin -> /admin/dashboard */} } /> } /> } /> } /> } /> - } /> } /> } /> - {/* Optional fallback: keep if you want unknown admin routes to land on dashboard */} + {/* أي مسار غير معروف داخل /admin يروح للداشبورد */} } /> diff --git a/client/src/components/admin/AdminLayout.js b/client/src/components/admin/AdminLayout.js index 79aa9c8..4e77115 100644 --- a/client/src/components/admin/AdminLayout.js +++ b/client/src/components/admin/AdminLayout.js @@ -22,37 +22,28 @@ import { import { Menu as MenuIcon, Dashboard as DashboardIcon, - Article as ArticleIcon, Hotel as HotelIcon, CalendarMonth as CalendarIcon, Settings as SettingsIcon, Image as ImageIcon, ContentPaste as ContentIcon, - People as PeopleIcon, Logout as LogoutIcon, - AccountCircle as AccountIcon, - Assessment as AssessmentIcon + AccountCircle as AccountIcon } from '@mui/icons-material'; import { useAuth } from '../../context/AuthContext'; const drawerWidth = 260; +// ✅ Removed: Blog, Guests, Analytics (UI only) const menuItems = [ { title: 'Dashboard', path: '/admin/dashboard', icon: }, { title: 'Content', path: '/admin/content', icon: }, { title: 'Rooms', path: '/admin/rooms', icon: }, { title: 'Bookings', path: '/admin/bookings', icon: }, - { title: 'Blog', path: '/admin/blog', icon: }, { title: 'Media', path: '/admin/media', icon: }, - { title: 'Guests', path: '/admin/guests', icon: }, - { title: 'Analytics', path: '/admin/analytics', icon: }, { title: 'Settings', path: '/admin/settings', icon: }, ]; -// ✅ hide from sidebar only (keep code/routes for future) -const hiddenMenuTitles = new Set(['Guests', 'Blog']); -const adminMenuItems = menuItems.filter(item => !hiddenMenuTitles.has(item.title)); - const AdminLayout = () => { const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down('md')); @@ -82,9 +73,7 @@ const AdminLayout = () => { const handleNavigate = (path) => { navigate(path); - if (isMobile) { - setMobileOpen(false); - } + if (isMobile) setMobileOpen(false); }; const drawer = ( @@ -106,7 +95,7 @@ const AdminLayout = () => { - {adminMenuItems.map((item) => ( + {menuItems.map((item) => ( { > + The Old Vine Hotel @@ -175,14 +165,8 @@ const AdminLayout = () => { anchorEl={anchorEl} open={Boolean(anchorEl)} onClose={handleProfileMenuClose} - anchorOrigin={{ - vertical: 'bottom', - horizontal: 'right', - }} - transformOrigin={{ - vertical: 'top', - horizontal: 'right', - }} + anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }} + transformOrigin={{ vertical: 'top', horizontal: 'right' }} > @@ -206,38 +190,25 @@ const AdminLayout = () => { - - {/* Mobile drawer */} + {drawer} - {/* Desktop drawer */} diff --git a/client/src/components/layout/Footer.js b/client/src/components/layout/Footer.js index 7b8c684..c830704 100644 --- a/client/src/components/layout/Footer.js +++ b/client/src/components/layout/Footer.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect, useMemo, useState } from 'react'; import { Box, Container, @@ -24,11 +24,74 @@ import { import { Link as RouterLink } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { motion } from 'framer-motion'; +import api from '../../utils/api'; + +// ✅ Convert any weird value (like {coordinates}) into a safe string +const toText = (val, fallback = '') => { + if (val == null) return fallback; + if (typeof val === 'string') return val; + if (typeof val === 'number' || typeof val === 'boolean') return String(val); + if (Array.isArray(val)) return val.map(v => toText(v, '')).filter(Boolean).join(', '); + + if (typeof val === 'object') { + // common cases + if (typeof val.text === 'string') return val.text; + if (typeof val.label === 'string') return val.label; + if (typeof val.name === 'string') return val.name; + if (typeof val.address === 'string') return val.address; + + // GeoJSON-ish: { coordinates: [lng, lat] } or { coordinates: {lat,lng} } + if (val.coordinates) { + if (Array.isArray(val.coordinates) && val.coordinates.length >= 2) { + const [lng, lat] = val.coordinates; + if (lat != null && lng != null) return `${lat}, ${lng}`; + } + if (typeof val.coordinates === 'object') { + const lat = val.coordinates.lat ?? val.coordinates.latitude; + const lng = val.coordinates.lng ?? val.coordinates.lon ?? val.coordinates.longitude; + if (lat != null && lng != null) return `${lat}, ${lng}`; + } + } + + return fallback; + } + + return fallback; +}; const Footer = () => { const { t } = useTranslation(); const theme = useTheme(); + const [settings, setSettings] = useState(null); + + useEffect(() => { + let mounted = true; + (async () => { + try { + const res = await api.get('/api/settings/public'); + if (mounted) setSettings(res?.data?.data?.settings || null); + } catch (e) { + console.error('Footer settings load error:', e); + } + })(); + return () => { mounted = false; }; + }, []); + + const hotelName = toText(settings?.hotel?.name, 'The Old Vine Hotel'); + const address = toText(settings?.hotel?.address, 'Old Damascus City'); + const phone = toText(settings?.hotel?.phone, '0112241609'); + const email = toText(settings?.hotel?.email, 'reservations@oldvinehotel.com'); + const whatsapp = toText(settings?.hotel?.whatsapp, '+963986105010'); + + const social = settings?.hotel?.socialMedia || {}; + const socialLinks = useMemo(() => ([ + { icon: , url: toText(social.facebook, ''), label: 'Facebook' }, + { icon: , url: toText(social.instagram, ''), label: 'Instagram' }, + { icon: , url: toText(social.twitter, ''), label: 'Twitter' }, + { icon: , url: toText(social.linkedin, ''), label: 'LinkedIn' }, + ].filter(s => s.url)), [social]); + const quickLinks = [ { label: t('nav.home'), path: '/' }, { label: t('nav.about'), path: '/about' }, @@ -38,13 +101,6 @@ const Footer = () => { { label: t('nav.contact'), path: '/contact' }, ]; - const socialLinks = [ - { icon: , url: 'https://facebook.com/oldvinehotel', label: 'Facebook' }, - { icon: , url: 'https://instagram.com/oldvinehotel', label: 'Instagram' }, - { icon: , url: 'https://twitter.com/oldvinehotel', label: 'Twitter' }, - { icon: , url: 'https://linkedin.com/company/oldvinehotel', label: 'LinkedIn' }, - ]; - return ( { > - {/* Hotel Information */} { color: theme.palette.secondary.main, }} > - The Old Vine Hotel + {hotelName} + {t('footer.description')} - - {/* Social Media Links */} + - {socialLinks.map((social) => ( + {socialLinks.map((s) => ( { transition: 'all 0.3s ease', }} > - {social.icon} + {s.icon} ))} - {/* Quick Links */} { > {t('footer.quickLinks')} + - {quickLinks.map((link) => ( + {quickLinks.map((l) => ( - {link.label} + {l.label} ))} - {/* Contact Information */} { > {t('footer.contactInfo')} - + - - Old Damascus City - + {address} - + - - 0112241609 - + {phone} - + - - reservations@oldvinehotel.com - + {email} - + - - +963986105010 - + {whatsapp} - {/* Newsletter Signup */} { {t('footer.newsletterText')} - + { '& .MuiOutlinedInput-root': { backgroundColor: 'rgba(255, 255, 255, 0.1)', color: 'white', - '& fieldset': { - borderColor: 'rgba(255, 255, 255, 0.3)', - }, - '&:hover fieldset': { - borderColor: 'rgba(255, 255, 255, 0.5)', - }, - '&.Mui-focused fieldset': { - borderColor: theme.palette.secondary.main, - }, + '& fieldset': { borderColor: 'rgba(255, 255, 255, 0.3)' }, + '&:hover fieldset': { borderColor: 'rgba(255, 255, 255, 0.5)' }, + '&.Mui-focused fieldset': { borderColor: theme.palette.secondary.main }, }, '& .MuiInputBase-input::placeholder': { color: 'rgba(255, 255, 255, 0.7)', @@ -236,13 +273,7 @@ const Footer = () => { }, }} /> - @@ -252,7 +283,6 @@ const Footer = () => { - {/* Bottom Section */} { }} > - © {new Date().getFullYear()} The Old Vine Hotel. {t('footer.rights')} + © {new Date().getFullYear()} {hotelName}. {t('footer.rights')} - + { color: 'rgba(255, 255, 255, 0.8)', textDecoration: 'none', fontSize: '0.875rem', - '&:hover': { - color: theme.palette.secondary.main, - }, + '&:hover': { color: theme.palette.secondary.main }, }} > {t('footer.privacy')} @@ -286,9 +314,7 @@ const Footer = () => { color: 'rgba(255, 255, 255, 0.8)', textDecoration: 'none', fontSize: '0.875rem', - '&:hover': { - color: theme.palette.secondary.main, - }, + '&:hover': { color: theme.palette.secondary.main }, }} > {t('footer.terms')} @@ -300,4 +326,4 @@ const Footer = () => { ); }; -export default Footer; \ No newline at end of file +export default Footer; diff --git a/client/src/components/layout/Header.js b/client/src/components/layout/Header.js index 3ea408b..badb317 100644 --- a/client/src/components/layout/Header.js +++ b/client/src/components/layout/Header.js @@ -36,12 +36,6 @@ const Header = () => { const lightHeaderText = '#1a1a1a'; - const WA_NUMBER = '963986105010'; - const WA_TEXT = encodeURIComponent( - 'For all booking inquiries and reservation confirmations, kindly contact us via WhatsApp' - ); - const WA_LINK = `https://wa.me/${WA_NUMBER}?text=${WA_TEXT}`; - const navigationItems = [ { label: t('nav.home'), path: '/' }, { label: t('nav.about'), path: '/about' }, @@ -125,12 +119,11 @@ const Header = () => { ))} + {/* ✅ بدل واتساب: يروح على صفحة /booking */} { + {/* ✅ بدل واتساب: يروح على صفحة /booking */} + + + + + + + {!request && ( + + (No request details were passed to this page.) + + )} + ); }; -export default BookingConfirmation; \ No newline at end of file +export default BookingConfirmation; diff --git a/client/src/pages/admin/DashboardMain.js b/client/src/pages/admin/DashboardMain.js index 5278c3f..a4a9705 100644 --- a/client/src/pages/admin/DashboardMain.js +++ b/client/src/pages/admin/DashboardMain.js @@ -13,8 +13,8 @@ import { Hotel as HotelIcon, CalendarMonth as CalendarIcon, People as PeopleIcon, - Article as ArticleIcon, - TrendingUp as TrendingUpIcon + TrendingUp as TrendingUpIcon, + ContentPaste as ContentIcon } from '@mui/icons-material'; import api from '../../utils/api'; import { useAuth } from '../../context/AuthContext'; @@ -73,9 +73,7 @@ const DashboardMain = () => { const fetchStats = async () => { try { setLoading(true); - console.log('📊 Dashboard: Fetching stats...'); const response = await api.get('/api/admin/stats'); - console.log('📊 Dashboard: Stats received:', response.data); setStats(response.data.data.stats); } catch (err) { console.error('📊 Dashboard: Error fetching stats:', err); @@ -93,9 +91,7 @@ const DashboardMain = () => { ); } - if (error) { - return {error}; - } + if (error) return {error}; return ( @@ -109,7 +105,6 @@ const DashboardMain = () => { - {/* Stats Cards */} { color="#7CBF9E" /> - - - } - color="#3A635F" - /> - - + {/* { color="#0F2A26" /> + */} {/* Quick Actions */} @@ -166,14 +152,12 @@ const DashboardMain = () => { Quick Actions + - + window.location.href = '/admin/rooms'} + sx={{ cursor: 'pointer', '&:hover': { bgcolor: 'action.hover' } }} + onClick={() => (window.location.href = '/admin/rooms')} > @@ -182,13 +166,10 @@ const DashboardMain = () => { - + window.location.href = '/admin/bookings'} + sx={{ cursor: 'pointer', '&:hover': { bgcolor: 'action.hover' } }} + onClick={() => (window.location.href = '/admin/bookings')} > @@ -197,31 +178,13 @@ const DashboardMain = () => { - + window.location.href = '/admin/blog'} + sx={{ cursor: 'pointer', '&:hover': { bgcolor: 'action.hover' } }} + onClick={() => (window.location.href = '/admin/content')} > - - Write Blog Post - - - - - - window.location.href = '/admin/content'} - > - - + Edit Content @@ -230,7 +193,6 @@ const DashboardMain = () => { - {/* Recent Activity - Placeholder */} @@ -249,4 +211,3 @@ const DashboardMain = () => { }; export default DashboardMain; -