final updates
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 19 KiB |
42
client/package-lock.json
generated
42
client/package-lock.json
generated
@@ -30,6 +30,9 @@
|
|||||||
"react-router-dom": "^6.19.0",
|
"react-router-dom": "^6.19.0",
|
||||||
"react-scripts": "^5.0.1",
|
"react-scripts": "^5.0.1",
|
||||||
"swiper": "^11.0.5"
|
"swiper": "^11.0.5"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"cross-env": "^10.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@alloc/quick-lru": {
|
"node_modules/@alloc/quick-lru": {
|
||||||
@@ -2526,6 +2529,13 @@
|
|||||||
"integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==",
|
"integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@epic-web/invariant": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@epic-web/invariant/-/invariant-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@eslint-community/eslint-utils": {
|
"node_modules/@eslint-community/eslint-utils": {
|
||||||
"version": "4.9.0",
|
"version": "4.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz",
|
||||||
@@ -6565,6 +6575,24 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cross-env": {
|
||||||
|
"version": "10.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-10.1.0.tgz",
|
||||||
|
"integrity": "sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@epic-web/invariant": "^1.0.0",
|
||||||
|
"cross-spawn": "^7.0.6"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"cross-env": "dist/bin/cross-env.js",
|
||||||
|
"cross-env-shell": "dist/bin/cross-env-shell.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/cross-spawn": {
|
"node_modules/cross-spawn": {
|
||||||
"version": "7.0.6",
|
"version": "7.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||||
@@ -16978,20 +17006,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tailwindcss/node_modules/yaml": {
|
|
||||||
"version": "2.8.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz",
|
|
||||||
"integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==",
|
|
||||||
"license": "ISC",
|
|
||||||
"optional": true,
|
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
|
||||||
"yaml": "bin.mjs"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 14.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/tapable": {
|
"node_modules/tapable": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
"swiper": "^11.0.5"
|
"swiper": "^11.0.5"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "PORT=3060 react-scripts start",
|
"start": "cross-env PORT=3060 react-scripts start",
|
||||||
"build": "react-scripts build",
|
"build": "react-scripts build",
|
||||||
"test": "react-scripts test",
|
"test": "react-scripts test",
|
||||||
"eject": "react-scripts eject"
|
"eject": "react-scripts eject"
|
||||||
@@ -50,5 +50,8 @@
|
|||||||
"last 1 safari version"
|
"last 1 safari version"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"proxy": "http://localhost:5080"
|
"proxy": "http://localhost:5080",
|
||||||
|
"devDependencies": {
|
||||||
|
"cross-env": "^10.1.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 19 KiB |
@@ -2,7 +2,6 @@ import React, { useState, useEffect } from 'react';
|
|||||||
import {
|
import {
|
||||||
AppBar,
|
AppBar,
|
||||||
Toolbar,
|
Toolbar,
|
||||||
Typography,
|
|
||||||
Button,
|
Button,
|
||||||
Box,
|
Box,
|
||||||
IconButton,
|
IconButton,
|
||||||
@@ -15,8 +14,6 @@ import {
|
|||||||
ListItemText,
|
ListItemText,
|
||||||
useMediaQuery,
|
useMediaQuery,
|
||||||
useTheme,
|
useTheme,
|
||||||
Select,
|
|
||||||
FormControl,
|
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import {
|
import {
|
||||||
Menu as MenuIcon,
|
Menu as MenuIcon,
|
||||||
@@ -37,6 +34,16 @@ const Header = () => {
|
|||||||
const [languageAnchor, setLanguageAnchor] = useState(null);
|
const [languageAnchor, setLanguageAnchor] = useState(null);
|
||||||
const [scrolled, setScrolled] = useState(false);
|
const [scrolled, setScrolled] = useState(false);
|
||||||
|
|
||||||
|
// ✅ لون غامق ثابت للهيدر الفاتح (حتى لو الثيم Dark)
|
||||||
|
const lightHeaderText = '#1a1a1a';
|
||||||
|
|
||||||
|
// ✅ Pending 17: Book Now -> WhatsApp with preset message
|
||||||
|
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 = [
|
const navigationItems = [
|
||||||
{ label: t('nav.home'), path: '/' },
|
{ label: t('nav.home'), path: '/' },
|
||||||
{ label: t('nav.about'), path: '/about' },
|
{ label: t('nav.about'), path: '/about' },
|
||||||
@@ -53,25 +60,24 @@ const Header = () => {
|
|||||||
];
|
];
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleScroll = () => {
|
const handleScroll = () => setScrolled(window.scrollY > 50);
|
||||||
setScrolled(window.scrollY > 50);
|
|
||||||
};
|
|
||||||
window.addEventListener('scroll', handleScroll);
|
window.addEventListener('scroll', handleScroll);
|
||||||
|
handleScroll();
|
||||||
return () => window.removeEventListener('scroll', handleScroll);
|
return () => window.removeEventListener('scroll', handleScroll);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleDrawerToggle = () => {
|
// ✅ صفحات الخلفية عندها فاتحة (زيدي هون أي route تاني)
|
||||||
setMobileOpen(!mobileOpen);
|
const lightHeaderRoutes = ['/facilities', '/contact'];
|
||||||
};
|
const forceLightHeader = lightHeaderRoutes.some(
|
||||||
|
(r) => location.pathname === r || location.pathname.startsWith(r + '/')
|
||||||
|
);
|
||||||
|
|
||||||
const handleLanguageClick = (event) => {
|
const isLightHeader = scrolled || forceLightHeader;
|
||||||
setLanguageAnchor(event.currentTarget);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleLanguageClose = () => {
|
const handleDrawerToggle = () => setMobileOpen((prev) => !prev);
|
||||||
setLanguageAnchor(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
const handleLanguageClick = (event) => setLanguageAnchor(event.currentTarget);
|
||||||
|
const handleLanguageClose = () => setLanguageAnchor(null);
|
||||||
const handleLanguageChange = (languageCode) => {
|
const handleLanguageChange = (languageCode) => {
|
||||||
i18n.changeLanguage(languageCode);
|
i18n.changeLanguage(languageCode);
|
||||||
handleLanguageClose();
|
handleLanguageClose();
|
||||||
@@ -110,7 +116,7 @@ const Header = () => {
|
|||||||
sx={{
|
sx={{
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
backgroundColor: isActiveRoute(item.path) ? 'primary.main' : 'transparent',
|
backgroundColor: isActiveRoute(item.path) ? 'primary.main' : 'transparent',
|
||||||
color: isActiveRoute(item.path) ? 'white' : 'text.primary',
|
color: isActiveRoute(item.path) ? 'white' : lightHeaderText,
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
backgroundColor: 'primary.light',
|
backgroundColor: 'primary.light',
|
||||||
color: 'white',
|
color: 'white',
|
||||||
@@ -122,19 +128,20 @@ const Header = () => {
|
|||||||
</ListItem>
|
</ListItem>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
|
{/* ✅ Pending 17: Drawer Book Now -> WhatsApp */}
|
||||||
<ListItem disablePadding>
|
<ListItem disablePadding>
|
||||||
<ListItemButton
|
<ListItemButton
|
||||||
component={Link}
|
component="a"
|
||||||
to="/booking"
|
href={WA_LINK}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
sx={{
|
sx={{
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
backgroundColor: 'secondary.main',
|
backgroundColor: 'secondary.main',
|
||||||
color: 'secondary.contrastText',
|
color: 'secondary.contrastText',
|
||||||
m: 2,
|
m: 2,
|
||||||
borderRadius: 2,
|
borderRadius: 2,
|
||||||
'&:hover': {
|
'&:hover': { backgroundColor: 'secondary.dark' },
|
||||||
backgroundColor: 'secondary.dark',
|
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ListItemText primary={t('nav.booking')} />
|
<ListItemText primary={t('nav.booking')} />
|
||||||
@@ -149,15 +156,22 @@ const Header = () => {
|
|||||||
<AppBar
|
<AppBar
|
||||||
position="fixed"
|
position="fixed"
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: scrolled ? 'rgba(255, 255, 255, 0.95)' : 'transparent',
|
backgroundColor: isLightHeader ? 'rgba(255, 255, 255, 0.95)' : 'transparent',
|
||||||
color: scrolled ? 'text.primary' : 'white',
|
color: isLightHeader ? lightHeaderText : 'white',
|
||||||
transition: 'all 0.3s ease-in-out',
|
transition: 'all 0.3s ease-in-out',
|
||||||
backdropFilter: scrolled ? 'blur(10px)' : 'none',
|
backdropFilter: isLightHeader ? 'blur(10px)' : 'none',
|
||||||
boxShadow: scrolled ? 3 : 0,
|
boxShadow: isLightHeader ? 3 : 0,
|
||||||
zIndex: 1300, // Ensure header is always on top
|
zIndex: 1300,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Toolbar
|
||||||
|
sx={{
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
maxWidth: 1200,
|
||||||
|
width: '100%',
|
||||||
|
mx: 'auto',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Toolbar sx={{ justifyContent: 'space-between', maxWidth: 1200, width: '100%', mx: 'auto' }}>
|
|
||||||
{/* Logo */}
|
{/* Logo */}
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0, x: -20 }}
|
initial={{ opacity: 0, x: -20 }}
|
||||||
@@ -171,16 +185,14 @@ const Header = () => {
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
textDecoration: 'none',
|
textDecoration: 'none',
|
||||||
'&:hover': {
|
'&:hover': { opacity: 0.8 },
|
||||||
opacity: 0.8,
|
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
src="/images/logo.png"
|
src="/images/logo.png"
|
||||||
alt="Old Vine Hotel"
|
alt="Old Vine Hotel"
|
||||||
style={{
|
style={{
|
||||||
height: scrolled ? '50px' : '60px',
|
height: isLightHeader ? '50px' : '60px',
|
||||||
width: 'auto',
|
width: 'auto',
|
||||||
transition: 'all 0.3s ease-in-out',
|
transition: 'all 0.3s ease-in-out',
|
||||||
}}
|
}}
|
||||||
@@ -202,17 +214,17 @@ const Header = () => {
|
|||||||
component={Link}
|
component={Link}
|
||||||
to={item.path}
|
to={item.path}
|
||||||
sx={{
|
sx={{
|
||||||
color: scrolled
|
color: isLightHeader
|
||||||
? (isActiveRoute(item.path) ? 'secondary.main' : 'text.primary')
|
? (isActiveRoute(item.path) ? 'secondary.main' : lightHeaderText)
|
||||||
: (isActiveRoute(item.path) ? 'white' : 'white'),
|
: 'white',
|
||||||
fontWeight: isActiveRoute(item.path) ? 600 : 400,
|
fontWeight: isActiveRoute(item.path) ? 600 : 400,
|
||||||
borderBottom: isActiveRoute(item.path) ? 2 : 0,
|
borderBottom: isActiveRoute(item.path) ? 2 : 0,
|
||||||
borderColor: 'secondary.main',
|
borderColor: 'secondary.main',
|
||||||
borderRadius: 0,
|
borderRadius: 0,
|
||||||
opacity: isActiveRoute(item.path) ? 1 : 0.8,
|
opacity: isActiveRoute(item.path) ? 1 : 0.85,
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
backgroundColor: 'transparent',
|
backgroundColor: 'transparent',
|
||||||
color: scrolled ? 'secondary.main' : 'white',
|
color: isLightHeader ? 'secondary.main' : 'white',
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
@@ -227,21 +239,20 @@ const Header = () => {
|
|||||||
<LanguageIcon />
|
<LanguageIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
|
||||||
{/* Book Now Button */}
|
{/* ✅ Pending 17: Book Now -> WhatsApp */}
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0, scale: 0.9 }}
|
initial={{ opacity: 0, scale: 0.9 }}
|
||||||
animate={{ opacity: 1, scale: 1 }}
|
animate={{ opacity: 1, scale: 1 }}
|
||||||
transition={{ duration: 0.5, delay: 0.3 }}
|
transition={{ duration: 0.5, delay: 0.3 }}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
component={Link}
|
component="a"
|
||||||
to="/booking"
|
href={WA_LINK}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="secondary"
|
color="secondary"
|
||||||
sx={{
|
sx={{ fontWeight: 600, px: 3 }}
|
||||||
fontWeight: 600,
|
|
||||||
px: 3,
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{t('nav.booking')}
|
{t('nav.booking')}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -249,17 +260,13 @@ const Header = () => {
|
|||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Mobile Menu Button */}
|
{/* Mobile */}
|
||||||
{isMobile && (
|
{isMobile && (
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||||
<IconButton onClick={handleLanguageClick} sx={{ color: 'inherit' }}>
|
<IconButton onClick={handleLanguageClick} sx={{ color: 'inherit' }}>
|
||||||
<LanguageIcon />
|
<LanguageIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton
|
<IconButton color="inherit" onClick={handleDrawerToggle} sx={{ ml: 1 }}>
|
||||||
color="inherit"
|
|
||||||
onClick={handleDrawerToggle}
|
|
||||||
sx={{ ml: 1 }}
|
|
||||||
>
|
|
||||||
<MenuIcon />
|
<MenuIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -273,9 +280,7 @@ const Header = () => {
|
|||||||
anchor="right"
|
anchor="right"
|
||||||
open={mobileOpen}
|
open={mobileOpen}
|
||||||
onClose={handleDrawerToggle}
|
onClose={handleDrawerToggle}
|
||||||
ModalProps={{
|
ModalProps={{ keepMounted: true }}
|
||||||
keepMounted: true,
|
|
||||||
}}
|
|
||||||
sx={{
|
sx={{
|
||||||
'& .MuiDrawer-paper': {
|
'& .MuiDrawer-paper': {
|
||||||
boxSizing: 'border-box',
|
boxSizing: 'border-box',
|
||||||
@@ -307,7 +312,6 @@ const Header = () => {
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
</Menu>
|
</Menu>
|
||||||
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ html {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
font-family: "Montserrat", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
|
||||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
||||||
sans-serif;
|
sans-serif;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
@@ -18,6 +18,7 @@ body {
|
|||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
code {
|
code {
|
||||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||||
monospace;
|
monospace;
|
||||||
|
|||||||
@@ -17,10 +17,12 @@
|
|||||||
"exploreRooms": "استكشف الغرف"
|
"exploreRooms": "استكشف الغرف"
|
||||||
},
|
},
|
||||||
"home": {
|
"home": {
|
||||||
"welcomeTitle": "مرحباً بكم في فندق العريشة القديمة",
|
"welcomeTitle": "مرحباً بكم في فندق الدالية القديمة",
|
||||||
"welcomeSubtitle": "حيث تلتقي الرفاهية بالتقاليد",
|
"welcomeSubtitle": "حيث تلتقي الرفاهية بالتقاليد",
|
||||||
"welcomeDescription": "اكتشف تجربة ضيافة استثنائية في فندق العريشة القديمة، حيث كل تفصيل مصمم ليمنحك لحظات لا تُنسى من الراحة والأناقة.",
|
"welcomeDescription": "اكتشف تجربة ضيافة استثنائية في فندق العريشة القديمة، حيث كل تفصيل مصمم ليمنحك لحظات لا تُنسى من الراحة والأناقة.",
|
||||||
"featuresTitle": "لماذا تختارنا",
|
"featuresTitle": "لماذا تختارنا",
|
||||||
|
"feature6Title": "قاعة اجتماعات",
|
||||||
|
"feature6Description": "يوفّر بيئة فريدة لرجال الأعمال لعقد اجتماعاتهم ومؤتمراتهم.",
|
||||||
"feature1Title": "إقامة فاخرة",
|
"feature1Title": "إقامة فاخرة",
|
||||||
"feature1Description": "غرف وأجنحة أنيقة مع وسائل راحة متميزة",
|
"feature1Description": "غرف وأجنحة أنيقة مع وسائل راحة متميزة",
|
||||||
"feature2Title": "مطاعم راقية",
|
"feature2Title": "مطاعم راقية",
|
||||||
@@ -97,6 +99,8 @@
|
|||||||
"message": "الرسالة",
|
"message": "الرسالة",
|
||||||
"sendMessage": "إرسال رسالة",
|
"sendMessage": "إرسال رسالة",
|
||||||
"messageSent": "تم إرسال الرسالة بنجاح!",
|
"messageSent": "تم إرسال الرسالة بنجاح!",
|
||||||
|
"whatsappOpened": "تم فتح واتساب. اضغط إرسال داخل واتساب لإرسال الرسالة.",
|
||||||
|
"requiredFields": "رجاءً املأ الحقول المطلوبة (الاسم، البريد، الرسالة).",
|
||||||
"directions": "احصل على الاتجاهات",
|
"directions": "احصل على الاتجاهات",
|
||||||
"whatsapp": "واتساب"
|
"whatsapp": "واتساب"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -32,6 +32,8 @@
|
|||||||
"roomsTitle": "Our Rooms & Suites",
|
"roomsTitle": "Our Rooms & Suites",
|
||||||
"roomsSubtitle": "Comfort and elegance in every detail",
|
"roomsSubtitle": "Comfort and elegance in every detail",
|
||||||
"viewAllRooms": "View All Rooms",
|
"viewAllRooms": "View All Rooms",
|
||||||
|
"feature6Title": "Meeting Room",
|
||||||
|
"feature6Description": "A unique setting for business meetings and conferences.",
|
||||||
"offersTitle": "Special Offers",
|
"offersTitle": "Special Offers",
|
||||||
"offersSubtitle": "Exclusive deals for your perfect stay"
|
"offersSubtitle": "Exclusive deals for your perfect stay"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -27,6 +27,8 @@
|
|||||||
"feature2Description": "Cuisine exquise et expériences culinaires de classe mondiale",
|
"feature2Description": "Cuisine exquise et expériences culinaires de classe mondiale",
|
||||||
"feature4Title": "Emplacement privilégié",
|
"feature4Title": "Emplacement privilégié",
|
||||||
"feature5Title": "Belles terrasses",
|
"feature5Title": "Belles terrasses",
|
||||||
|
"feature6Title": "Salle de réunion",
|
||||||
|
"feature6Description": "Un cadre unique pour les réunions d’affaires et les conférences.",
|
||||||
"feature5Description": "Détendez-vous sur nos magnifiques terrasses avec des vues imprenables sur la vieille Damas",
|
"feature5Description": "Détendez-vous sur nos magnifiques terrasses avec des vues imprenables sur la vieille Damas",
|
||||||
"feature4Description": "Parfaitement situé pour les affaires et les loisirs",
|
"feature4Description": "Parfaitement situé pour les affaires et les loisirs",
|
||||||
"roomsTitle": "Nos chambres et suites",
|
"roomsTitle": "Nos chambres et suites",
|
||||||
@@ -95,8 +97,11 @@
|
|||||||
"hours": "Heures",
|
"hours": "Heures",
|
||||||
"name": "Nom complet",
|
"name": "Nom complet",
|
||||||
"message": "Message",
|
"message": "Message",
|
||||||
|
"subject": "Sujet",
|
||||||
"sendMessage": "Envoyer le message",
|
"sendMessage": "Envoyer le message",
|
||||||
"messageSent": "Message envoyé avec succès !",
|
"messageSent": "Message envoyé avec succès !",
|
||||||
|
"whatsappOpened": "WhatsApp est ouvert. Appuyez sur Envoyer dans WhatsApp pour envoyer votre message.",
|
||||||
|
"requiredFields": "Veuillez remplir les champs obligatoires (nom, e-mail, message).",
|
||||||
"directions": "Obtenir l'itinéraire",
|
"directions": "Obtenir l'itinéraire",
|
||||||
"whatsapp": "WhatsApp"
|
"whatsapp": "WhatsApp"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -332,8 +332,7 @@ const About = () => {
|
|||||||
</motion.div>
|
</motion.div>
|
||||||
</Container>
|
</Container>
|
||||||
</Box>
|
</Box>
|
||||||
|
{false && (
|
||||||
{/* Timeline Section */}
|
|
||||||
<Container maxWidth="lg" sx={{ py: 8 }}>
|
<Container maxWidth="lg" sx={{ py: 8 }}>
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0, y: 30 }}
|
initial={{ opacity: 0, y: 30 }}
|
||||||
@@ -345,10 +344,7 @@ const About = () => {
|
|||||||
variant="h3"
|
variant="h3"
|
||||||
component="h2"
|
component="h2"
|
||||||
textAlign="center"
|
textAlign="center"
|
||||||
sx={{
|
sx={{ mb: 6, color: 'primary.main' }}
|
||||||
mb: 6,
|
|
||||||
color: 'primary.main',
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
Our Journey
|
Our Journey
|
||||||
</Typography>
|
</Typography>
|
||||||
@@ -364,7 +360,7 @@ const About = () => {
|
|||||||
width: 2,
|
width: 2,
|
||||||
backgroundColor: 'primary.main',
|
backgroundColor: 'primary.main',
|
||||||
transform: 'translateX(-50%)',
|
transform: 'translateX(-50%)',
|
||||||
display: { xs: 'none', md: 'block' }
|
display: { xs: 'none', md: 'block' },
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -381,20 +377,25 @@ const About = () => {
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
mb: 6,
|
mb: 6,
|
||||||
flexDirection: { xs: 'column', md: index % 2 === 0 ? 'row' : 'row-reverse' },
|
flexDirection: {
|
||||||
textAlign: { xs: 'center', md: 'left' }
|
xs: 'column',
|
||||||
|
md: index % 2 === 0 ? 'row' : 'row-reverse',
|
||||||
|
},
|
||||||
|
textAlign: { xs: 'center', md: 'left' },
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box sx={{ flex: 1, px: { xs: 0, md: 4 } }}>
|
<Box sx={{ flex: 1, px: { xs: 0, md: 4 } }}>
|
||||||
<Card sx={{ p: 3, maxWidth: 400, mx: { xs: 'auto', md: index % 2 === 0 ? 0 : 'auto' } }}>
|
<Card
|
||||||
|
sx={{
|
||||||
|
p: 3,
|
||||||
|
maxWidth: 400,
|
||||||
|
mx: { xs: 'auto', md: index % 2 === 0 ? 0 : 'auto' },
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Typography
|
<Typography
|
||||||
variant="h4"
|
variant="h4"
|
||||||
component="h3"
|
component="h3"
|
||||||
sx={{
|
sx={{ color: 'secondary.main', fontWeight: 700, mb: 1 }}
|
||||||
color: 'secondary.main',
|
|
||||||
fontWeight: 700,
|
|
||||||
mb: 1
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{milestone.year}
|
{milestone.year}
|
||||||
</Typography>
|
</Typography>
|
||||||
@@ -417,7 +418,7 @@ const About = () => {
|
|||||||
border: `4px solid ${theme.palette.background.paper}`,
|
border: `4px solid ${theme.palette.background.paper}`,
|
||||||
boxShadow: 2,
|
boxShadow: 2,
|
||||||
display: { xs: 'none', md: 'block' },
|
display: { xs: 'none', md: 'block' },
|
||||||
zIndex: 1
|
zIndex: 1,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -428,6 +429,7 @@ const About = () => {
|
|||||||
</Box>
|
</Box>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</Container>
|
</Container>
|
||||||
|
)}
|
||||||
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,18 +5,15 @@ import {
|
|||||||
Typography,
|
Typography,
|
||||||
Grid,
|
Grid,
|
||||||
Card,
|
Card,
|
||||||
CardContent,
|
|
||||||
TextField,
|
TextField,
|
||||||
Button,
|
Button,
|
||||||
IconButton,
|
IconButton,
|
||||||
Alert,
|
Alert,
|
||||||
useTheme,
|
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import {
|
import {
|
||||||
Phone,
|
Phone,
|
||||||
Email,
|
Email,
|
||||||
LocationOn,
|
LocationOn,
|
||||||
AccessTime,
|
|
||||||
WhatsApp,
|
WhatsApp,
|
||||||
Facebook,
|
Facebook,
|
||||||
Instagram,
|
Instagram,
|
||||||
@@ -26,132 +23,153 @@ import {
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import { Helmet } from 'react-helmet-async';
|
import { Helmet } from 'react-helmet-async';
|
||||||
import { useQuery, useMutation } from 'react-query';
|
import { useQuery } from 'react-query';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
|
const HOTEL_WHATSAPP = '963986105010';
|
||||||
|
|
||||||
const Contact = () => {
|
const Contact = () => {
|
||||||
const { t } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
const theme = useTheme();
|
|
||||||
|
const lang = (i18n.resolvedLanguage || i18n.language || 'en').toLowerCase();
|
||||||
|
const isAr = lang.startsWith('ar');
|
||||||
|
const isFr = lang.startsWith('fr');
|
||||||
|
|
||||||
|
const tf = (key, en, ar, fr) => t(key, isAr ? ar : isFr ? fr : en);
|
||||||
|
|
||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
name: '',
|
name: '',
|
||||||
email: '',
|
email: '',
|
||||||
phone: '',
|
phone: '',
|
||||||
subject: '',
|
subject: '',
|
||||||
message: ''
|
message: '',
|
||||||
});
|
});
|
||||||
const [submitStatus, setSubmitStatus] = useState(null);
|
const [submitStatus, setSubmitStatus] = useState(null);
|
||||||
|
|
||||||
// Fetch contact information
|
|
||||||
const { data: contactInfo } = useQuery(
|
const { data: contactInfo } = useQuery(
|
||||||
'contactInfo',
|
'contactInfo',
|
||||||
() => axios.get('/api/contact/info').then(res => res.data.data),
|
() => axios.get('/api/contact/info').then((res) => res.data.data),
|
||||||
{
|
{
|
||||||
staleTime: 5 * 60 * 1000, // 5 minutes
|
staleTime: 5 * 60 * 1000,
|
||||||
}
|
retry: 0,
|
||||||
);
|
|
||||||
|
|
||||||
// Submit contact form
|
|
||||||
const submitContactForm = useMutation(
|
|
||||||
(formData) => axios.post('/api/contact', formData),
|
|
||||||
{
|
|
||||||
onSuccess: () => {
|
|
||||||
setSubmitStatus({ type: 'success', message: t('contact.messageSent') });
|
|
||||||
setFormData({ name: '', email: '', phone: '', subject: '', message: '' });
|
|
||||||
},
|
|
||||||
onError: (error) => {
|
|
||||||
setSubmitStatus({
|
|
||||||
type: 'error',
|
|
||||||
message: error.response?.data?.message || 'Failed to send message'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleInputChange = (e) => {
|
const handleInputChange = (e) => {
|
||||||
setFormData({
|
setFormData((prev) => ({
|
||||||
...formData,
|
...prev,
|
||||||
[e.target.name]: e.target.value
|
[e.target.name]: e.target.value,
|
||||||
});
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const openWhatsApp = () => {
|
||||||
|
const lines = [
|
||||||
|
tf(
|
||||||
|
'contact.whatsappNewMessageHeader',
|
||||||
|
'New message from website:',
|
||||||
|
'رسالة جديدة من موقع الفندق:',
|
||||||
|
'Nouveau message du site web :'
|
||||||
|
),
|
||||||
|
`${tf('contact.whatsappLabelName', 'Name', 'الاسم', 'Nom')}: ${formData.name}`,
|
||||||
|
`${tf('contact.whatsappLabelEmail', 'Email', 'البريد الإلكتروني', 'E-mail')}: ${formData.email}`,
|
||||||
|
`${tf('contact.whatsappLabelPhone', 'Phone', 'الهاتف', 'Téléphone')}: ${formData.phone || '-'}`,
|
||||||
|
`${tf('contact.whatsappLabelSubject', 'Subject', 'الموضوع', 'Sujet')}: ${formData.subject || '-'}`,
|
||||||
|
`${tf('contact.whatsappLabelMessage', 'Message', 'الرسالة', 'Message')}: ${formData.message}`,
|
||||||
|
];
|
||||||
|
|
||||||
|
const text = encodeURIComponent(lines.join('\n'));
|
||||||
|
const url = `https://wa.me/${HOTEL_WHATSAPP}?text=${text}`;
|
||||||
|
window.open(url, '_blank', 'noopener,noreferrer');
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = (e) => {
|
const handleSubmit = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (formData.name && formData.email && formData.message) {
|
|
||||||
submitContactForm.mutate(formData);
|
if (!formData.name || !formData.email || !formData.message) {
|
||||||
|
setSubmitStatus({
|
||||||
|
type: 'error',
|
||||||
|
message: tf(
|
||||||
|
'contact.requiredFields',
|
||||||
|
'Please fill the required fields (name, email, message).',
|
||||||
|
'يرجى تعبئة الحقول المطلوبة (الاسم، البريد الإلكتروني، الرسالة).',
|
||||||
|
'Veuillez remplir les champs obligatoires (nom, e-mail, message).'
|
||||||
|
),
|
||||||
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openWhatsApp();
|
||||||
|
|
||||||
|
setSubmitStatus({
|
||||||
|
type: 'success',
|
||||||
|
message: tf(
|
||||||
|
'contact.whatsappOpened',
|
||||||
|
'WhatsApp opened. Press Send inside WhatsApp to deliver your message.',
|
||||||
|
'تم فتح واتساب. اضغط "إرسال" داخل واتساب لإرسال رسالتك.',
|
||||||
|
'WhatsApp s’est ouvert. Appuyez sur Envoyer داخل WhatsApp pour إرسال رسالتك.'
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
setFormData({ name: '', email: '', phone: '', subject: '', message: '' });
|
||||||
};
|
};
|
||||||
|
|
||||||
const contactCards = [
|
const contactCards = [
|
||||||
{
|
{
|
||||||
title: 'Phone',
|
title: tf('contact.cardPhoneTitle', 'Phone', 'الهاتف', 'Téléphone'),
|
||||||
icon: <Phone sx={{ fontSize: 40 }} />,
|
icon: <Phone sx={{ fontSize: 40 }} />,
|
||||||
primary: '0112241609',
|
primary: '0112241609',
|
||||||
secondary: '24/7 Available',
|
secondary: tf('contact.cardPhoneSecondary', '24/7 Available', 'متاح 24/7', 'Disponible 24/7'),
|
||||||
action: 'tel:0112241609'
|
action: 'tel:0112241609',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Email',
|
title: tf('contact.cardEmailTitle', 'Email', 'البريد الإلكتروني', 'E-mail'),
|
||||||
icon: <Email sx={{ fontSize: 40 }} />,
|
icon: <Email sx={{ fontSize: 40 }} />,
|
||||||
primary: 'reservations@oldvinehotel.com',
|
primary: 'reservations@oldvinehotel.com',
|
||||||
secondary: 'Response within 24 hours',
|
secondary: tf(
|
||||||
action: 'mailto:reservations@oldvinehotel.com'
|
'contact.cardEmailSecondary',
|
||||||
|
'Response within 24 hours',
|
||||||
|
'الرد خلال 24 ساعة',
|
||||||
|
'Réponse sous 24 heures'
|
||||||
|
),
|
||||||
|
action: 'mailto:reservations@oldvinehotel.com',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'WhatsApp',
|
title: tf('contact.cardWhatsAppTitle', 'WhatsApp', 'واتساب', 'WhatsApp'),
|
||||||
icon: <WhatsApp sx={{ fontSize: 40 }} />,
|
icon: <WhatsApp sx={{ fontSize: 40 }} />,
|
||||||
primary: '+963986105010',
|
primary: '+963986105010',
|
||||||
secondary: 'Quick responses',
|
secondary: tf('contact.cardWhatsAppSecondary', 'Quick responses', 'رد سريع', 'Réponses rapides'),
|
||||||
action: 'https://wa.me/963986105010'
|
action: `https://wa.me/${HOTEL_WHATSAPP}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Address',
|
title: tf('contact.cardAddressTitle', 'Address', 'العنوان', 'Adresse'),
|
||||||
icon: <LocationOn sx={{ fontSize: 40 }} />,
|
icon: <LocationOn sx={{ fontSize: 40 }} />,
|
||||||
primary: contactInfo?.hotel?.address?.formatted || 'Old Damascus City',
|
primary: contactInfo?.hotel?.address?.formatted || tf('contact.addressFallback', 'Old Vine Hotel, Damascus', 'فندق أولد فاين - دمشق', 'Old Vine Hotel, Damas'),
|
||||||
secondary: t('contact.directions'),
|
secondary: t('contact.directions'),
|
||||||
action: 'https://maps.google.com/?q=' + encodeURIComponent(contactInfo?.hotel?.address?.formatted || 'Old Damascus City')
|
action: 'https://www.google.com/maps/search/?api=1&query=Old%20Vine%20Hotel%20Damascus',
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const departments = [
|
|
||||||
{
|
|
||||||
name: 'Reservations',
|
|
||||||
phone: contactInfo?.departments?.reservations?.phone || '+1 (555) 123-4567',
|
|
||||||
email: contactInfo?.departments?.reservations?.email || 'reservations@oldvinehotel.com',
|
|
||||||
hours: contactInfo?.departments?.reservations?.hours || '24/7'
|
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: 'Concierge',
|
|
||||||
phone: contactInfo?.departments?.concierge?.phone || '+1 (555) 123-4568',
|
|
||||||
email: contactInfo?.departments?.concierge?.email || 'concierge@oldvinehotel.com',
|
|
||||||
hours: contactInfo?.departments?.concierge?.hours || '6:00 AM - 12:00 AM'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Restaurant',
|
|
||||||
phone: contactInfo?.departments?.restaurant?.phone || '+1 (555) 123-4569',
|
|
||||||
email: contactInfo?.departments?.restaurant?.email || 'restaurant@oldvinehotel.com',
|
|
||||||
hours: contactInfo?.departments?.restaurant?.hours || '6:30 AM - 11:00 PM'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Spa & Wellness',
|
|
||||||
phone: contactInfo?.departments?.spa?.phone || '+1 (555) 123-4570',
|
|
||||||
email: contactInfo?.departments?.spa?.email || 'spa@oldvinehotel.com',
|
|
||||||
hours: contactInfo?.departments?.spa?.hours || '8:00 AM - 9:00 PM'
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Helmet>
|
<Helmet>
|
||||||
<title>Contact Us - The Old Vine Hotel</title>
|
<title>{tf('contact.pageTitle', 'Contact Us - The Old Vine Hotel', 'تواصل معنا - فندق أولد فاين', 'Contact - The Old Vine Hotel')}</title>
|
||||||
<meta name="description" content="Get in touch with The Old Vine Hotel. Contact us for reservations, inquiries, or any assistance you need during your stay." />
|
<meta
|
||||||
|
name="description"
|
||||||
|
content={tf(
|
||||||
|
'contact.pageDescription',
|
||||||
|
'Get in touch with The Old Vine Hotel. Contact us for reservations, inquiries, or any assistance you need during your stay.',
|
||||||
|
'تواصل مع فندق أولد فاين للحجوزات والاستفسارات وأي مساعدة تحتاجها أثناء إقامتك.',
|
||||||
|
'Contactez The Old Vine Hotel pour les réservations, questions, ou toute assistance pendant votre séjour.'
|
||||||
|
)}
|
||||||
|
/>
|
||||||
</Helmet>
|
</Helmet>
|
||||||
|
|
||||||
{/* Hero Section */}
|
{/* Hero Section */}
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
minHeight: '60vh',
|
minHeight: '60vh',
|
||||||
background: 'linear-gradient(rgba(0,0,0,0.5), rgba(0,0,0,0.5)), url("/images/gallery/hotel-gallery/31.jpg") center/cover',
|
background:
|
||||||
|
'linear-gradient(rgba(0,0,0,0.5), rgba(0,0,0,0.5)), url("/images/gallery/hotel-gallery/31.jpg") center/cover',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
@@ -170,7 +188,6 @@ const Contact = () => {
|
|||||||
component="h1"
|
component="h1"
|
||||||
sx={{
|
sx={{
|
||||||
mb: 3,
|
mb: 3,
|
||||||
fontFamily: 'Playfair Display',
|
|
||||||
fontSize: { xs: '2.5rem', md: '3.5rem' },
|
fontSize: { xs: '2.5rem', md: '3.5rem' },
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -223,17 +240,10 @@ const Contact = () => {
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box sx={{ display: 'flex', justifyContent: 'center', mb: 2, color: 'primary.main' }}>
|
||||||
sx={{
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
mb: 2,
|
|
||||||
color: 'primary.main',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{card.icon}
|
{card.icon}
|
||||||
</Box>
|
</Box>
|
||||||
<Typography variant="h6" component="h3" sx={{ mb: 2, fontWeight: 600 }}>
|
<Typography variant="h6" sx={{ mb: 2, fontWeight: 600 }}>
|
||||||
{card.title}
|
{card.title}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="body1" sx={{ mb: 1, fontWeight: 500 }}>
|
<Typography variant="body1" sx={{ mb: 1, fontWeight: 500 }}>
|
||||||
@@ -248,9 +258,8 @@ const Contact = () => {
|
|||||||
))}
|
))}
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
{/* Contact Form and Departments */}
|
|
||||||
<Grid container spacing={6}>
|
|
||||||
{/* Contact Form */}
|
{/* Contact Form */}
|
||||||
|
<Grid container spacing={6}>
|
||||||
<Grid item xs={12} md={12}>
|
<Grid item xs={12} md={12}>
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0, x: -30 }}
|
initial={{ opacity: 0, x: -30 }}
|
||||||
@@ -259,15 +268,8 @@ const Contact = () => {
|
|||||||
viewport={{ once: true }}
|
viewport={{ once: true }}
|
||||||
>
|
>
|
||||||
<Card sx={{ p: 4 }}>
|
<Card sx={{ p: 4 }}>
|
||||||
<Typography
|
<Typography variant="h4" sx={{ mb: 3, color: 'primary.main' }}>
|
||||||
variant="h4"
|
{tf('contact.sendUsMessageTitle', 'Send us a Message', 'أرسل لنا رسالة', 'Envoyez-nous un message')}
|
||||||
component="h2"
|
|
||||||
sx={{
|
|
||||||
mb: 3,
|
|
||||||
color: 'primary.main',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Send us a Message
|
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
{submitStatus && (
|
{submitStatus && (
|
||||||
@@ -315,7 +317,7 @@ const Contact = () => {
|
|||||||
<Grid item xs={12} sm={6}>
|
<Grid item xs={12} sm={6}>
|
||||||
<TextField
|
<TextField
|
||||||
name="subject"
|
name="subject"
|
||||||
label="Subject"
|
label={tf('contact.subject', 'Subject', 'الموضوع', 'Sujet')}
|
||||||
fullWidth
|
fullWidth
|
||||||
value={formData.subject}
|
value={formData.subject}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
@@ -333,6 +335,7 @@ const Contact = () => {
|
|||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
@@ -340,10 +343,9 @@ const Contact = () => {
|
|||||||
color="primary"
|
color="primary"
|
||||||
size="large"
|
size="large"
|
||||||
startIcon={<Send />}
|
startIcon={<Send />}
|
||||||
disabled={submitContactForm.isLoading}
|
|
||||||
sx={{ px: 4, py: 2 }}
|
sx={{ px: 4, py: 2 }}
|
||||||
>
|
>
|
||||||
{submitContactForm.isLoading ? 'Sending...' : t('contact.sendMessage')}
|
{t('contact.sendMessage')}
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
@@ -352,7 +354,7 @@ const Contact = () => {
|
|||||||
</motion.div>
|
</motion.div>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
{/* Social Media Section */}
|
{/* Social Media */}
|
||||||
<Grid item xs={12} md={5}>
|
<Grid item xs={12} md={5}>
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0, x: 30 }}
|
initial={{ opacity: 0, x: 30 }}
|
||||||
@@ -360,17 +362,9 @@ const Contact = () => {
|
|||||||
transition={{ duration: 0.8 }}
|
transition={{ duration: 0.8 }}
|
||||||
viewport={{ once: true }}
|
viewport={{ once: true }}
|
||||||
>
|
>
|
||||||
{/* Social Media */}
|
|
||||||
<Card sx={{ p: 4 }}>
|
<Card sx={{ p: 4 }}>
|
||||||
<Typography
|
<Typography variant="h5" sx={{ mb: 3, color: 'primary.main' }}>
|
||||||
variant="h5"
|
{tf('contact.followUs', 'Follow Us', 'تابعنا', 'Suivez-nous')}
|
||||||
component="h3"
|
|
||||||
sx={{
|
|
||||||
mb: 3,
|
|
||||||
color: 'primary.main',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Follow Us
|
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Box sx={{ display: 'flex', gap: 2 }}>
|
<Box sx={{ display: 'flex', gap: 2 }}>
|
||||||
@@ -379,11 +373,7 @@ const Contact = () => {
|
|||||||
href={contactInfo?.socialMedia?.facebook || '#'}
|
href={contactInfo?.socialMedia?.facebook || '#'}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
sx={{
|
sx={{ backgroundColor: '#1877F2', color: 'white' }}
|
||||||
backgroundColor: '#1877F2',
|
|
||||||
color: 'white',
|
|
||||||
'&:hover': { backgroundColor: '#166FE5' },
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<Facebook />
|
<Facebook />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
@@ -392,11 +382,7 @@ const Contact = () => {
|
|||||||
href={contactInfo?.socialMedia?.instagram || '#'}
|
href={contactInfo?.socialMedia?.instagram || '#'}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
sx={{
|
sx={{ backgroundColor: '#E4405F', color: 'white' }}
|
||||||
backgroundColor: '#E4405F',
|
|
||||||
color: 'white',
|
|
||||||
'&:hover': { backgroundColor: '#D62D4A' },
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<Instagram />
|
<Instagram />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
@@ -405,24 +391,16 @@ const Contact = () => {
|
|||||||
href={contactInfo?.socialMedia?.twitter || '#'}
|
href={contactInfo?.socialMedia?.twitter || '#'}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
sx={{
|
sx={{ backgroundColor: '#1DA1F2', color: 'white' }}
|
||||||
backgroundColor: '#1DA1F2',
|
|
||||||
color: 'white',
|
|
||||||
'&:hover': { backgroundColor: '#1A91DA' },
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<Twitter />
|
<Twitter />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton
|
<IconButton
|
||||||
component="a"
|
component="a"
|
||||||
href="https://wa.me/963986105010"
|
href={`https://wa.me/${HOTEL_WHATSAPP}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
sx={{
|
sx={{ backgroundColor: '#25D366', color: 'white' }}
|
||||||
backgroundColor: '#25D366',
|
|
||||||
color: 'white',
|
|
||||||
'&:hover': { backgroundColor: '#22C55E' },
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<WhatsApp />
|
<WhatsApp />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
@@ -436,14 +414,14 @@ const Contact = () => {
|
|||||||
{/* Map Section */}
|
{/* Map Section */}
|
||||||
<Box sx={{ width: '100%', height: 400, bgcolor: 'grey.200' }}>
|
<Box sx={{ width: '100%', height: 400, bgcolor: 'grey.200' }}>
|
||||||
<iframe
|
<iframe
|
||||||
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3310.1234567890123!2d36.2765!3d33.5138!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x1518e6dc413cc6a7%3A0x6b9f3c2b8b8b8b8b!2sOld%20Damascus%20City!5e0!3m2!1sen!2ssy!4v1704067200000!5m2!1sen!2ssy&zoom=16"
|
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d881.089256494776!2d36.30748342144017!3d33.51308026272531!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x1518e728348b96bf%3A0x9a06409382325607!2sOld%20Vine%20Hotel!5e0!3m2!1$ar!2s!4v1766475597734!5m2!1$ar!2s"
|
||||||
width="100%"
|
width="100%"
|
||||||
height="100%"
|
height="100%"
|
||||||
style={{ border: 0 }}
|
style={{ border: 0 }}
|
||||||
allowFullScreen=""
|
allowFullScreen
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
referrerPolicy="no-referrer-when-downgrade"
|
referrerPolicy="no-referrer-when-downgrade"
|
||||||
title="Hotel Location"
|
title={tf('contact.mapTitle', 'Hotel Location', 'موقع الفندق', 'Emplacement de l’hôtel')}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -9,20 +9,14 @@ import {
|
|||||||
CardContent,
|
CardContent,
|
||||||
CardMedia,
|
CardMedia,
|
||||||
Chip,
|
Chip,
|
||||||
useTheme,
|
|
||||||
CircularProgress,
|
CircularProgress,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import {
|
import {
|
||||||
Hotel,
|
Hotel,
|
||||||
Restaurant,
|
Restaurant,
|
||||||
FitnessCenter,
|
|
||||||
LocationOn,
|
LocationOn,
|
||||||
Star,
|
|
||||||
CheckCircle,
|
|
||||||
Spa,
|
|
||||||
Pool,
|
|
||||||
BusinessCenter,
|
|
||||||
Deck,
|
Deck,
|
||||||
|
BusinessCenter,
|
||||||
} from '@mui/icons-material';
|
} from '@mui/icons-material';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@@ -32,22 +26,19 @@ import staticData from '../utils/staticData';
|
|||||||
|
|
||||||
const Home = () => {
|
const Home = () => {
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
const theme = useTheme();
|
|
||||||
const [content, setContent] = useState(null);
|
const [content, setContent] = useState(null);
|
||||||
const [roomCategories, setRoomCategories] = useState([]);
|
const [roomCategories, setRoomCategories] = useState([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const currentLanguage = i18n.language;
|
const currentLanguage = i18n.language;
|
||||||
|
|
||||||
// Fetch homepage content and room categories from static data
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchContent = async () => {
|
const fetchContent = async () => {
|
||||||
try {
|
try {
|
||||||
const [homeContent, categories] = await Promise.all([
|
const [homeContent, categories] = await Promise.all([
|
||||||
staticData.getHomeContent(),
|
staticData.getHomeContent(),
|
||||||
staticData.getRoomCategories()
|
staticData.getRoomCategories(),
|
||||||
]);
|
]);
|
||||||
setContent(homeContent);
|
setContent(homeContent);
|
||||||
// Get first 3 categories
|
|
||||||
setRoomCategories(categories.slice(0, 3));
|
setRoomCategories(categories.slice(0, 3));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading homepage content:', error);
|
console.error('Error loading homepage content:', error);
|
||||||
@@ -80,29 +71,41 @@ const Home = () => {
|
|||||||
title: t('home.feature5Title'),
|
title: t('home.feature5Title'),
|
||||||
description: t('home.feature5Description'),
|
description: t('home.feature5Description'),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
icon: <BusinessCenter sx={{ fontSize: 40 }} />,
|
||||||
|
title: t('home.feature6Title', 'Meeting Room'),
|
||||||
|
description: t(
|
||||||
|
'home.feature6Description',
|
||||||
|
'A unique business-friendly setting for meetings and conferences.'
|
||||||
|
),
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// Map room categories from API to display format
|
const heroImage = content?.hero?.backgroundImage || '/images/hero.jpg';
|
||||||
|
|
||||||
|
const welcomeSection = content?.sections?.find((s) => s.sectionId === 'welcome') || {};
|
||||||
|
const useTranslations = currentLanguage !== 'en';
|
||||||
|
|
||||||
|
const welcomeTitle = useTranslations
|
||||||
|
? t('home.welcomeTitle')
|
||||||
|
: (welcomeSection.title || t('home.welcomeTitle'));
|
||||||
|
|
||||||
|
const welcomeSubtitle = useTranslations
|
||||||
|
? t('home.welcomeSubtitle')
|
||||||
|
: (welcomeSection.subtitle || t('home.welcomeSubtitle'));
|
||||||
|
|
||||||
|
const welcomeContent = useTranslations
|
||||||
|
? t('home.welcomeDescription')
|
||||||
|
: (welcomeSection.content || t('home.welcomeDescription'));
|
||||||
|
|
||||||
const roomTypes = roomCategories.map((category) => ({
|
const roomTypes = roomCategories.map((category) => ({
|
||||||
id: category._id || category.slug,
|
id: category._id || category.slug,
|
||||||
name: category.name,
|
name: category.name,
|
||||||
image: category.primaryImage || '/images/room-default.jpg',
|
image: category.primaryImage || '/images/room-default.jpg',
|
||||||
price: category.priceRange?.min || 0,
|
features: category.features?.slice(0, 4) || [],
|
||||||
features: category.features?.slice(0, 4) || [], // Show first 4 features
|
|
||||||
slug: category.slug,
|
slug: category.slug,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Special offers - using translations
|
|
||||||
const specialOffers = [
|
|
||||||
{
|
|
||||||
title: t('home.offersTitle'),
|
|
||||||
description: t('home.offersSubtitle'),
|
|
||||||
discount: '25% OFF',
|
|
||||||
validUntil: '2025-12-31',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
// Show loading state
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: '100vh' }}>
|
<Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: '100vh' }}>
|
||||||
@@ -111,98 +114,59 @@ const Home = () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use translations for non-English languages, static data for English
|
const LOGO_BOTTOM = { xs: 40, sm: 55, md: 70 };
|
||||||
const useTranslations = currentLanguage !== 'en';
|
|
||||||
|
|
||||||
// Fallback content - prioritize translations for non-English
|
|
||||||
const heroTitle = useTranslations ? t('hero.hotelName') : (content?.hero?.title || t('hero.hotelName'));
|
|
||||||
const heroSubtitle = useTranslations ? t('hero.subtitle') : (content?.hero?.subtitle || t('hero.subtitle'));
|
|
||||||
const heroDescription = useTranslations ? '' : (content?.hero?.description || '');
|
|
||||||
const heroImage = content?.hero?.backgroundImage || '/images/hero.jpg';
|
|
||||||
const heroCTAText = useTranslations ? t('hero.exploreRooms') : (content?.hero?.ctaText || t('hero.exploreRooms'));
|
|
||||||
const heroCTALink = content?.hero?.ctaLink || '/rooms';
|
|
||||||
|
|
||||||
// Get welcome section from content
|
|
||||||
const welcomeSection = content?.sections?.find(s => s.sectionId === 'welcome') || {};
|
|
||||||
const welcomeTitle = useTranslations ? t('home.welcomeTitle') : (welcomeSection.title || t('home.welcomeTitle'));
|
|
||||||
const welcomeSubtitle = useTranslations ? t('home.welcomeSubtitle') : (welcomeSection.subtitle || t('home.welcomeSubtitle'));
|
|
||||||
const welcomeContent = useTranslations ? t('home.welcomeDescription') : (welcomeSection.content || t('home.welcomeDescription'));
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Helmet>
|
<Helmet>
|
||||||
<title>{content?.seo?.title || 'The Old Vine Hotel - Luxury Accommodation & Premium Hospitality'}</title>
|
<title>{content?.seo?.title || 'The Old Vine Hotel - Luxury Accommodation & Premium Hospitality'}</title>
|
||||||
<meta name="description" content={content?.seo?.description || 'Experience luxury and elegance at The Old Vine Hotel.'} />
|
<meta
|
||||||
<meta name="keywords" content={content?.seo?.keywords?.join(', ') || 'luxury hotel, premium accommodation'} />
|
name="description"
|
||||||
|
content={content?.seo?.description || 'Experience luxury and elegance at The Old Vine Hotel.'}
|
||||||
|
/>
|
||||||
|
<meta
|
||||||
|
name="keywords"
|
||||||
|
content={content?.seo?.keywords?.join(', ') || 'luxury hotel, premium accommodation'}
|
||||||
|
/>
|
||||||
</Helmet>
|
</Helmet>
|
||||||
|
|
||||||
{/* Hero Section - Logo and Image Only */}
|
{/* Hero Section - Logo and Image Only */}
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
minHeight: '100vh',
|
minHeight: '100vh',
|
||||||
background: `linear-gradient(rgba(0,0,0,0.35), rgba(0,0,0,0.35)), url("${heroImage}") center/cover`,
|
background: `linear-gradient(rgba(0,0,0,0.45), rgba(0,0,0,0.45)), url("${heroImage}") center/cover`,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'flex-end',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
|
||||||
color: 'white',
|
color: 'white',
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
|
pb: { xs: 25, md: 80},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Container maxWidth="lg">
|
<Container maxWidth="lg" sx={{ width: '100%' }}>
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0, y: 50 }}
|
initial={{ opacity: 0, y: 30 }}
|
||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1, y: 0 }}
|
||||||
transition={{ duration: 1, ease: 'easeOut' }}
|
transition={{ duration: 1, ease: 'easeOut' }}
|
||||||
>
|
>
|
||||||
{/* Logo Only */}
|
<Box sx={{ display: 'flex', justifyContent: 'center', width: '100%' }}>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
component="img"
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
mb: 4,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
src="/images/logo.png"
|
src="/images/logo.png"
|
||||||
alt="Old Vine Hotel"
|
alt="Old Vine Hotel"
|
||||||
style={{
|
sx={{
|
||||||
height: 'auto',
|
|
||||||
width: 'auto',
|
width: 'auto',
|
||||||
maxHeight: '200px',
|
maxWidth: '90%',
|
||||||
maxWidth: '100%',
|
maxHeight: { xs: 140, md: 250 },
|
||||||
|
filter: 'drop-shadow(0 10px 24px rgba(0,0,0,0.65))',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
{/* Scroll Indicator */}
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
position: 'absolute',
|
|
||||||
bottom: 30,
|
|
||||||
left: '50%',
|
|
||||||
transform: 'translateX(-50%)',
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
alignItems: 'center',
|
|
||||||
animation: 'bounce 2s infinite',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Typography variant="body2" sx={{ mb: 1, opacity: 0.8 }}>
|
|
||||||
Scroll Down
|
|
||||||
</Typography>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
width: 2,
|
|
||||||
height: 30,
|
|
||||||
backgroundColor: 'white',
|
|
||||||
opacity: 0.6,
|
|
||||||
borderRadius: 1,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{/* Welcome Section */}
|
{/* Welcome Section */}
|
||||||
@@ -214,28 +178,11 @@ const Home = () => {
|
|||||||
viewport={{ once: true }}
|
viewport={{ once: true }}
|
||||||
>
|
>
|
||||||
<Box textAlign="center" sx={{ mb: 6 }}>
|
<Box textAlign="center" sx={{ mb: 6 }}>
|
||||||
<Typography
|
<Typography variant="h2" component="h2" sx={{ mb: 3, color: 'primary.main', fontWeight: 400 }}>
|
||||||
variant="h2"
|
|
||||||
component="h2"
|
|
||||||
sx={{
|
|
||||||
mb: 3,
|
|
||||||
// Use theme h2 font (Calistoga Regular - not bold)
|
|
||||||
color: 'primary.main',
|
|
||||||
fontWeight: 400,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{welcomeTitle}
|
{welcomeTitle}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Typography
|
<Typography variant="h5" component="p" sx={{ mb: 3, color: 'text.secondary', fontWeight: 300 }}>
|
||||||
variant="h5"
|
|
||||||
component="p"
|
|
||||||
sx={{
|
|
||||||
mb: 3,
|
|
||||||
color: 'text.secondary',
|
|
||||||
fontWeight: 300,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{welcomeSubtitle}
|
{welcomeSubtitle}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
@@ -246,7 +193,7 @@ const Home = () => {
|
|||||||
mx: 'auto',
|
mx: 'auto',
|
||||||
lineHeight: 1.8,
|
lineHeight: 1.8,
|
||||||
fontSize: '1.1rem',
|
fontSize: '1.1rem',
|
||||||
whiteSpace: 'pre-line', // Preserve line breaks
|
whiteSpace: 'pre-line',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{welcomeContent}
|
{welcomeContent}
|
||||||
@@ -264,68 +211,74 @@ const Home = () => {
|
|||||||
transition={{ duration: 0.8 }}
|
transition={{ duration: 0.8 }}
|
||||||
viewport={{ once: true }}
|
viewport={{ once: true }}
|
||||||
>
|
>
|
||||||
<Typography
|
<Typography variant="h3" component="h2" textAlign="center" sx={{ mb: 6, color: 'primary.main' }}>
|
||||||
variant="h3"
|
|
||||||
component="h2"
|
|
||||||
textAlign="center"
|
|
||||||
sx={{
|
|
||||||
mb: 6,
|
|
||||||
color: 'primary.main',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('home.featuresTitle')}
|
{t('home.featuresTitle')}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Grid container spacing={4}>
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'grid',
|
||||||
|
gap: 4,
|
||||||
|
gridTemplateColumns: {
|
||||||
|
xs: '1fr',
|
||||||
|
sm: 'repeat(2, 1fr)',
|
||||||
|
md: 'repeat(5, 1fr)',
|
||||||
|
},
|
||||||
|
alignItems: 'stretch',
|
||||||
|
}}
|
||||||
|
>
|
||||||
{features.map((feature, index) => (
|
{features.map((feature, index) => (
|
||||||
<Grid item xs={12} sm={6} md={3} key={index}>
|
|
||||||
<motion.div
|
<motion.div
|
||||||
|
key={index}
|
||||||
initial={{ opacity: 0, y: 20 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
transition={{ duration: 0.6, delay: index * 0.1 }}
|
transition={{ duration: 0.6, delay: index * 0.08 }}
|
||||||
viewport={{ once: true }}
|
viewport={{ once: true }}
|
||||||
>
|
>
|
||||||
<Card
|
<Card
|
||||||
sx={{
|
sx={{
|
||||||
height: '100%',
|
height: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
p: 3,
|
p: 3,
|
||||||
border: 'none',
|
border: 'none',
|
||||||
boxShadow: 3,
|
boxShadow: 3,
|
||||||
'&:hover': {
|
|
||||||
transform: 'translateY(-8px)',
|
|
||||||
boxShadow: 6,
|
|
||||||
},
|
|
||||||
transition: 'all 0.3s ease',
|
transition: 'all 0.3s ease',
|
||||||
|
'&:hover': { transform: 'translateY(-8px)', boxShadow: 6 },
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box sx={{ display: 'flex', justifyContent: 'center', mb: 2, color: 'primary.main' }}>
|
||||||
sx={{
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
mb: 2,
|
|
||||||
color: 'primary.main',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{feature.icon}
|
{feature.icon}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Typography
|
<Typography
|
||||||
variant="h6"
|
variant="h6"
|
||||||
component="h3"
|
component="h3"
|
||||||
sx={{ mb: 2, fontWeight: 600 }}
|
sx={{
|
||||||
|
mb: 2,
|
||||||
|
fontWeight: 600,
|
||||||
|
lineHeight: 1.2,
|
||||||
|
minHeight: '2.4em',
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{feature.title}
|
{feature.title}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Typography variant="body2" color="text.secondary">
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
color="text.secondary"
|
||||||
|
sx={{
|
||||||
|
lineHeight: 1.6,
|
||||||
|
minHeight: '4.8em',
|
||||||
|
}}
|
||||||
|
>
|
||||||
{feature.description}
|
{feature.description}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Card>
|
</Card>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</Grid>
|
|
||||||
))}
|
))}
|
||||||
</Grid>
|
</Box>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</Container>
|
</Container>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -339,26 +292,11 @@ const Home = () => {
|
|||||||
viewport={{ once: true }}
|
viewport={{ once: true }}
|
||||||
>
|
>
|
||||||
<Box textAlign="center" sx={{ mb: 6 }}>
|
<Box textAlign="center" sx={{ mb: 6 }}>
|
||||||
<Typography
|
<Typography variant="h3" component="h2" sx={{ mb: 3, color: 'primary.main' }}>
|
||||||
variant="h3"
|
|
||||||
component="h2"
|
|
||||||
sx={{
|
|
||||||
mb: 3,
|
|
||||||
color: 'primary.main',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('home.roomsTitle')}
|
{t('home.roomsTitle')}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Typography
|
<Typography variant="h6" component="p" sx={{ mb: 4, color: 'text.secondary', fontWeight: 300 }}>
|
||||||
variant="h6"
|
|
||||||
component="p"
|
|
||||||
sx={{
|
|
||||||
mb: 4,
|
|
||||||
color: 'text.secondary',
|
|
||||||
fontWeight: 300,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('home.roomsSubtitle')}
|
{t('home.roomsSubtitle')}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -380,18 +318,12 @@ const Home = () => {
|
|||||||
alt={room.name}
|
alt={room.name}
|
||||||
sx={{
|
sx={{
|
||||||
transition: 'transform 0.3s ease',
|
transition: 'transform 0.3s ease',
|
||||||
'&:hover': {
|
'&:hover': { transform: 'scale(1.05)' },
|
||||||
transform: 'scale(1.05)',
|
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<CardContent sx={{ p: 3 }}>
|
<CardContent sx={{ p: 3 }}>
|
||||||
<Typography
|
<Typography variant="h5" component="h3" sx={{ mb: 2 }}>
|
||||||
variant="h5"
|
|
||||||
component="h3"
|
|
||||||
sx={{ mb: 2 }}
|
|
||||||
>
|
|
||||||
{room.name}
|
{room.name}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
@@ -401,12 +333,7 @@ const Home = () => {
|
|||||||
key={idx}
|
key={idx}
|
||||||
label={feature}
|
label={feature}
|
||||||
size="small"
|
size="small"
|
||||||
sx={{
|
sx={{ mr: 1, mb: 1, backgroundColor: 'primary.main', color: 'white' }}
|
||||||
mr: 1,
|
|
||||||
mb: 1,
|
|
||||||
backgroundColor: 'primary.main',
|
|
||||||
color: 'white',
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</Box>
|
</Box>
|
||||||
@@ -441,7 +368,6 @@ const Home = () => {
|
|||||||
</Box>
|
</Box>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user