This commit is contained in:
Iliyan Angelov
2025-12-07 20:36:17 +02:00
parent 876af48145
commit b818d645a9
91 changed files with 3692 additions and 4501 deletions

View File

@@ -1846,6 +1846,180 @@ async def upload_company_favicon(
logger.error(f"Error uploading favicon: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=str(e))
class UpdateThemeSettingsRequest(BaseModel):
theme_primary_color: Optional[str] = None
theme_primary_light: Optional[str] = None
theme_primary_dark: Optional[str] = None
theme_primary_accent: Optional[str] = None
@router.get("/theme")
async def get_theme_settings(
db: Session = Depends(get_db)
):
"""Get current theme color settings"""
try:
setting_keys = [
"theme_primary_color",
"theme_primary_light",
"theme_primary_dark",
"theme_primary_accent",
]
settings_dict = {}
for key in setting_keys:
setting = db.query(SystemSettings).filter(
SystemSettings.key == key
).first()
if setting:
settings_dict[key] = setting.value
else:
settings_dict[key] = None
# Get updated_at and updated_by from any theme setting
theme_setting = db.query(SystemSettings).filter(
SystemSettings.key == "theme_primary_color"
).first()
updated_at = None
updated_by = None
if theme_setting:
updated_at = theme_setting.updated_at.isoformat() if theme_setting.updated_at else None
updated_by = theme_setting.updated_by.full_name if theme_setting.updated_by else None
return {
"status": "success",
"data": {
"theme_primary_color": settings_dict.get("theme_primary_color", "#d4af37"),
"theme_primary_light": settings_dict.get("theme_primary_light", "#f5d76e"),
"theme_primary_dark": settings_dict.get("theme_primary_dark", "#c9a227"),
"theme_primary_accent": settings_dict.get("theme_primary_accent", "#e8c547"),
"updated_at": updated_at,
"updated_by": updated_by,
}
}
except Exception as e:
logger.error(f"Error getting theme settings: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=str(e))
@router.put("/theme")
async def update_theme_settings(
request_data: UpdateThemeSettingsRequest,
request: Request,
current_user: User = Depends(authorize_roles("admin")),
db: Session = Depends(get_db)
):
"""Update theme color settings (admin only)"""
import re
client_ip = request.client.host if request.client else None
user_agent = request.headers.get('User-Agent')
request_id = getattr(request.state, 'request_id', None)
try:
# Validate hex color format
hex_color_pattern = re.compile(r'^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$')
db_settings = {}
if request_data.theme_primary_color is not None:
if not hex_color_pattern.match(request_data.theme_primary_color):
raise HTTPException(
status_code=400,
detail="Invalid theme_primary_color format. Must be a valid hex color (e.g., #d4af37)"
)
db_settings["theme_primary_color"] = request_data.theme_primary_color
if request_data.theme_primary_light is not None:
if not hex_color_pattern.match(request_data.theme_primary_light):
raise HTTPException(
status_code=400,
detail="Invalid theme_primary_light format. Must be a valid hex color (e.g., #f5d76e)"
)
db_settings["theme_primary_light"] = request_data.theme_primary_light
if request_data.theme_primary_dark is not None:
if not hex_color_pattern.match(request_data.theme_primary_dark):
raise HTTPException(
status_code=400,
detail="Invalid theme_primary_dark format. Must be a valid hex color (e.g., #c9a227)"
)
db_settings["theme_primary_dark"] = request_data.theme_primary_dark
if request_data.theme_primary_accent is not None:
if not hex_color_pattern.match(request_data.theme_primary_accent):
raise HTTPException(
status_code=400,
detail="Invalid theme_primary_accent format. Must be a valid hex color (e.g., #e8c547)"
)
db_settings["theme_primary_accent"] = request_data.theme_primary_accent
# Update or create settings
for key, value in db_settings.items():
setting = db.query(SystemSettings).filter(
SystemSettings.key == key
).first()
if setting:
setting.value = value
setting.updated_at = datetime.utcnow()
setting.updated_by_id = current_user.id
else:
setting = SystemSettings(
key=key,
value=value,
updated_by_id=current_user.id
)
db.add(setting)
db.commit()
# Get updated settings
updated_settings = {}
for key in ["theme_primary_color", "theme_primary_light", "theme_primary_dark", "theme_primary_accent"]:
setting = db.query(SystemSettings).filter(
SystemSettings.key == key
).first()
if setting:
updated_settings[key] = setting.value
else:
# Return defaults if not set
defaults = {
"theme_primary_color": "#d4af37",
"theme_primary_light": "#f5d76e",
"theme_primary_dark": "#c9a227",
"theme_primary_accent": "#e8c547",
}
updated_settings[key] = defaults.get(key)
theme_setting = db.query(SystemSettings).filter(
SystemSettings.key == "theme_primary_color"
).first()
updated_at = None
updated_by = None
if theme_setting:
updated_at = theme_setting.updated_at.isoformat() if theme_setting.updated_at else None
updated_by = theme_setting.updated_by.full_name if theme_setting.updated_by else None
return {
"status": "success",
"message": "Theme settings updated successfully",
"data": {
"theme_primary_color": updated_settings.get("theme_primary_color", "#d4af37"),
"theme_primary_light": updated_settings.get("theme_primary_light", "#f5d76e"),
"theme_primary_dark": updated_settings.get("theme_primary_dark", "#c9a227"),
"theme_primary_accent": updated_settings.get("theme_primary_accent", "#e8c547"),
"updated_at": updated_at,
"updated_by": updated_by,
}
}
except HTTPException:
raise
except Exception as e:
db.rollback()
logger.error(f"Error updating theme settings: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=str(e))
@router.get("/recaptcha")
async def get_recaptcha_settings(
db: Session = Depends(get_db)

View File

@@ -12,6 +12,7 @@ import { LoadingProvider, useNavigationLoading, useLoading } from './shared/cont
import { CookieConsentProvider } from './shared/contexts/CookieConsentContext';
import { CurrencyProvider } from './features/payments/contexts/CurrencyContext';
import { CompanySettingsProvider } from './shared/contexts/CompanySettingsContext';
import { ThemeProvider } from './shared/contexts/ThemeContext';
import { AuthModalProvider } from './features/auth/contexts/AuthModalContext';
import { AntibotProvider } from './features/auth/contexts/AntibotContext';
import { RoomProvider } from './features/rooms/contexts/RoomContext';
@@ -91,7 +92,7 @@ const GroupBookingManagementPage = lazy(() => import('./pages/admin/GroupBooking
const AdminBookingManagementPage = lazy(() => import('./pages/admin/BookingManagementPage'));
const PageContentDashboardPage = lazy(() => import('./pages/admin/PageContentDashboard'));
const AnalyticsDashboardPage = lazy(() => import('./pages/admin/AnalyticsDashboardPage'));
const BusinessDashboardPage = lazy(() => import('./pages/admin/BusinessDashboardPage'));
const PromotionsManagementPage = lazy(() => import('./pages/admin/PromotionsManagementPage'));
const SettingsPage = lazy(() => import('./pages/admin/SettingsPage'));
const TaskManagementPage = lazy(() => import('./pages/admin/TaskManagementPage'));
const WorkflowManagementPage = lazy(() => import('./pages/admin/WorkflowManagementPage'));
@@ -249,7 +250,8 @@ function App() {
<LoadingProvider>
<CookieConsentProvider>
<CurrencyProvider>
<CompanySettingsProvider>
<ThemeProvider>
<CompanySettingsProvider>
<AntibotProvider>
<AuthModalProvider>
<StepUpAuthProvider>
@@ -600,8 +602,8 @@ function App() {
element={<UserManagementPage />}
/>
<Route
path="business"
element={<BusinessDashboardPage />}
path="promotions"
element={<PromotionsManagementPage />}
/>
<Route
path="reception"
@@ -974,6 +976,7 @@ function App() {
</AuthModalProvider>
</AntibotProvider>
</CompanySettingsProvider>
</ThemeProvider>
</CurrencyProvider>
</CookieConsentProvider>
</LoadingProvider>

View File

@@ -93,7 +93,7 @@ const ForgotPasswordModal: React.FC = () => {
<div className="absolute inset-0 bg-black/60 backdrop-blur-sm" />
{/* Modal */}
<div className="relative w-full max-w-md max-h-[95vh] overflow-y-auto bg-gradient-to-br from-gray-50 via-white to-gray-50 rounded-lg shadow-2xl border border-[#d4af37]/20">
<div className="relative w-full max-w-md max-h-[95vh] overflow-y-auto bg-gradient-to-br from-gray-50 via-white to-gray-50 rounded-lg shadow-2xl border border-[var(--luxury-gold)]/20">
{/* Close button */}
<button
onClick={closeModal}
@@ -117,13 +117,13 @@ const ForgotPasswordModal: React.FC = () => {
style={{ filter: 'drop-shadow(0 4px 6px rgba(0,0,0,0.1))' }}
/>
) : (
<div className="relative p-2.5 sm:p-3 bg-gradient-to-br from-[#d4af37] to-[#c9a227] rounded-full shadow-lg shadow-[#d4af37]/30">
<div className="relative p-2.5 sm:p-3 bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] rounded-full shadow-lg shadow-[var(--luxury-gold)]/30">
<Mail className="w-6 h-6 sm:w-8 sm:h-8 text-[#0f0f0f] relative z-10" />
</div>
)}
</div>
{settings.company_tagline && (
<p className="text-[10px] sm:text-xs text-[#d4af37] uppercase tracking-[1.5px] sm:tracking-[2px] mb-1 sm:mb-2 font-light">
<p className="text-[10px] sm:text-xs text-[var(--luxury-gold)] uppercase tracking-[1.5px] sm:tracking-[2px] mb-1 sm:mb-2 font-light">
{settings.company_tagline}
</p>
)}
@@ -150,7 +150,7 @@ const ForgotPasswordModal: React.FC = () => {
<p className="text-xs sm:text-sm text-gray-600">
We have sent a password reset link to
</p>
<p className="text-xs sm:text-sm font-medium text-[#d4af37] break-all">
<p className="text-xs sm:text-sm font-medium text-[var(--luxury-gold)] break-all">
{submittedEmail}
</p>
</div>
@@ -172,7 +172,7 @@ const ForgotPasswordModal: React.FC = () => {
setIsSuccess(false);
clearError();
}}
className="w-full flex items-center justify-center py-2.5 sm:py-3 px-4 border border-gray-300 rounded-lg text-xs sm:text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[#d4af37] transition-colors"
className="w-full flex items-center justify-center py-2.5 sm:py-3 px-4 border border-gray-300 rounded-lg text-xs sm:text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[var(--luxury-gold)] transition-colors"
>
<Mail className="-ml-1 mr-2 h-4 w-4 sm:h-5 sm:w-5" />
Resend Email
@@ -180,7 +180,7 @@ const ForgotPasswordModal: React.FC = () => {
<button
onClick={() => openModal('login')}
className="w-full flex items-center justify-center py-2.5 sm:py-3 px-4 border border-transparent rounded-lg text-xs sm:text-sm font-medium text-white bg-gradient-to-r from-[#d4af37] to-[#c9a227] hover:from-[#f5d76e] hover:to-[#d4af37] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[#d4af37] transition-colors"
className="w-full flex items-center justify-center py-2.5 sm:py-3 px-4 border border-transparent rounded-lg text-xs sm:text-sm font-medium text-white bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[var(--luxury-gold)] transition-colors"
>
<ArrowLeft className="-ml-1 mr-2 h-4 w-4 sm:h-5 sm:w-5" />
Back to Login
@@ -220,7 +220,7 @@ const ForgotPasswordModal: React.FC = () => {
className={`block w-full pl-9 sm:pl-10 pr-3 py-2.5 sm:py-3 border rounded-lg focus:outline-none focus:ring-2 transition-colors text-sm sm:text-base luxury-input ${
errors.email
? 'border-red-300 focus:ring-red-500'
: 'border-gray-300 focus:ring-[#d4af37]'
: 'border-gray-300 focus:ring-[var(--luxury-gold)]'
}`}
placeholder="email@example.com"
/>
@@ -235,7 +235,7 @@ const ForgotPasswordModal: React.FC = () => {
<button
type="submit"
disabled={isLoading}
className="w-full flex items-center justify-center py-2.5 sm:py-3 px-4 border border-transparent rounded-lg shadow-sm text-xs sm:text-sm font-medium text-white bg-gradient-to-r from-[#d4af37] to-[#c9a227] hover:from-[#f5d76e] hover:to-[#d4af37] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[#d4af37] disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
className="w-full flex items-center justify-center py-2.5 sm:py-3 px-4 border border-transparent rounded-lg shadow-sm text-xs sm:text-sm font-medium text-white bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[var(--luxury-gold)] disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
>
{isLoading ? (
<>
@@ -254,7 +254,7 @@ const ForgotPasswordModal: React.FC = () => {
<button
type="button"
onClick={() => openModal('login')}
className="inline-flex items-center text-xs sm:text-sm font-medium text-[#d4af37] hover:text-[#c9a227] transition-colors"
className="inline-flex items-center text-xs sm:text-sm font-medium text-[var(--luxury-gold)] hover:text-[var(--luxury-gold-dark)] transition-colors"
>
<ArrowLeft className="mr-1 h-3.5 w-3.5 sm:h-4 sm:w-4" />
Back to Login
@@ -269,7 +269,7 @@ const ForgotPasswordModal: React.FC = () => {
Don't have an account?{' '}
<button
onClick={() => openModal('register')}
className="font-medium text-[#d4af37] hover:text-[#c9a227] transition-colors"
className="font-medium text-[var(--luxury-gold)] hover:text-[var(--luxury-gold-dark)] transition-colors"
>
Register now
</button>
@@ -286,7 +286,7 @@ const ForgotPasswordModal: React.FC = () => {
If you're having trouble resetting your password, please contact our support team via email{' '}
<a
href={`mailto:${supportEmail}`}
className="text-[#d4af37] hover:underline break-all"
className="text-[var(--luxury-gold)] hover:underline break-all"
>
{supportEmail}
</a>
@@ -295,7 +295,7 @@ const ForgotPasswordModal: React.FC = () => {
{' '}or hotline{' '}
<a
href={`tel:${supportPhone.replace(/\s+/g, '').replace(/[()]/g, '')}`}
className="text-[#d4af37] hover:underline"
className="text-[var(--luxury-gold)] hover:underline"
>
{supportPhone}
</a>

View File

@@ -376,7 +376,7 @@ const LoginModal: React.FC = () => {
<div className="absolute inset-0 bg-black/60 backdrop-blur-sm" />
{/* Modal */}
<div className="relative w-full max-w-md max-h-[95vh] overflow-y-auto bg-gradient-to-br from-gray-50 via-white to-gray-50 rounded-lg shadow-2xl border border-[#d4af37]/20">
<div className="relative w-full max-w-md max-h-[95vh] overflow-y-auto bg-gradient-to-br from-gray-50 via-white to-gray-50 rounded-lg shadow-2xl border border-[var(--luxury-gold)]/20">
{/* Close button */}
<button
onClick={closeModal}
@@ -400,13 +400,13 @@ const LoginModal: React.FC = () => {
style={{ filter: 'drop-shadow(0 4px 6px rgba(0,0,0,0.1))' }}
/>
) : (
<div className="relative p-2.5 sm:p-3 bg-gradient-to-br from-[#d4af37] to-[#c9a227] rounded-full shadow-lg shadow-[#d4af37]/30">
<div className="relative p-2.5 sm:p-3 bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] rounded-full shadow-lg shadow-[var(--luxury-gold)]/30">
<Shield className="w-6 h-6 sm:w-8 sm:h-8 text-[#0f0f0f] relative z-10" />
</div>
)}
</div>
{settings.company_tagline && (
<p className="text-[10px] sm:text-xs text-[#d4af37] uppercase tracking-[1.5px] sm:tracking-[2px] mb-1 sm:mb-2 font-light">
<p className="text-[10px] sm:text-xs text-[var(--luxury-gold)] uppercase tracking-[1.5px] sm:tracking-[2px] mb-1 sm:mb-2 font-light">
{settings.company_tagline}
</p>
)}
@@ -555,7 +555,7 @@ const LoginModal: React.FC = () => {
<button
type="button"
onClick={() => setShowPassword(!showPassword)}
className="absolute inset-y-0 right-0 pr-3 flex items-center transition-colors hover:text-[#d4af37]"
className="absolute inset-y-0 right-0 pr-3 flex items-center transition-colors hover:text-[var(--luxury-gold)]"
>
{showPassword ? (
<EyeOff className="h-4 w-4 sm:h-5 sm:w-5 text-gray-400" />
@@ -577,7 +577,7 @@ const LoginModal: React.FC = () => {
{...register('rememberMe')}
id="rememberMe"
type="checkbox"
className="h-4 w-4 text-[#d4af37] focus:ring-[#d4af37]/50 border-gray-300 rounded-sm cursor-pointer accent-[#d4af37]"
className="h-4 w-4 text-[var(--luxury-gold)] focus:ring-[var(--luxury-gold)]/50 border-gray-300 rounded-sm cursor-pointer accent-[var(--luxury-gold)]"
/>
<label htmlFor="rememberMe" className="ml-2 block text-xs sm:text-sm text-gray-700 cursor-pointer font-light tracking-wide">
Remember me
@@ -587,7 +587,7 @@ const LoginModal: React.FC = () => {
<button
type="button"
onClick={() => openModal('forgot-password')}
className="text-xs sm:text-sm font-medium text-[#d4af37] hover:text-[#c9a227] transition-colors tracking-wide"
className="text-xs sm:text-sm font-medium text-[var(--luxury-gold)] hover:text-[var(--luxury-gold-dark)] transition-colors tracking-wide"
>
Forgot password?
</button>
@@ -633,7 +633,7 @@ const LoginModal: React.FC = () => {
Don't have an account?{' '}
<button
onClick={() => openModal('register')}
className="font-medium text-[#d4af37] hover:text-[#c9a227] transition-colors"
className="font-medium text-[var(--luxury-gold)] hover:text-[var(--luxury-gold-dark)] transition-colors"
>
Register now
</button>

View File

@@ -15,11 +15,11 @@ import HoneypotField from '../../../shared/components/HoneypotField';
const PasswordRequirement: React.FC<{ met: boolean; text: string }> = ({ met, text }) => (
<div className="flex items-center gap-1.5 sm:gap-2 text-[10px] sm:text-xs font-light">
{met ? (
<CheckCircle2 className="h-3.5 w-3.5 sm:h-4 sm:w-4 text-[#d4af37] flex-shrink-0" />
<CheckCircle2 className="h-3.5 w-3.5 sm:h-4 sm:w-4 text-[var(--luxury-gold)] flex-shrink-0" />
) : (
<XCircle className="h-3.5 w-3.5 sm:h-4 sm:w-4 text-gray-300 flex-shrink-0" />
)}
<span className={met ? 'text-[#c9a227] font-medium' : 'text-gray-500'}>
<span className={met ? 'text-[var(--luxury-gold-dark)] font-medium' : 'text-gray-500'}>
{text}
</span>
</div>
@@ -165,7 +165,7 @@ const RegisterModal: React.FC = () => {
<div className="absolute inset-0 bg-black/60 backdrop-blur-sm" />
{/* Modal */}
<div className="relative w-full max-w-md max-h-[95vh] overflow-y-auto bg-gradient-to-br from-gray-50 via-white to-gray-50 rounded-lg shadow-2xl border border-[#d4af37]/20">
<div className="relative w-full max-w-md max-h-[95vh] overflow-y-auto bg-gradient-to-br from-gray-50 via-white to-gray-50 rounded-lg shadow-2xl border border-[var(--luxury-gold)]/20">
{/* Close button */}
<button
onClick={closeModal}
@@ -189,13 +189,13 @@ const RegisterModal: React.FC = () => {
style={{ filter: 'drop-shadow(0 4px 6px rgba(0,0,0,0.1))' }}
/>
) : (
<div className="relative p-2.5 sm:p-3 bg-gradient-to-br from-[#d4af37] to-[#c9a227] rounded-full shadow-lg shadow-[#d4af37]/30">
<div className="relative p-2.5 sm:p-3 bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] rounded-full shadow-lg shadow-[var(--luxury-gold)]/30">
<UserPlus className="w-6 h-6 sm:w-8 sm:h-8 text-[#0f0f0f] relative z-10" />
</div>
)}
</div>
{settings.company_tagline && (
<p className="text-[10px] sm:text-xs text-[#d4af37] uppercase tracking-[1.5px] sm:tracking-[2px] mb-1 sm:mb-2 font-light">
<p className="text-[10px] sm:text-xs text-[var(--luxury-gold)] uppercase tracking-[1.5px] sm:tracking-[2px] mb-1 sm:mb-2 font-light">
{settings.company_tagline}
</p>
)}
@@ -322,7 +322,7 @@ const RegisterModal: React.FC = () => {
<button
type="button"
onClick={() => setShowPassword(!showPassword)}
className="absolute inset-y-0 right-0 pr-3 flex items-center transition-colors hover:text-[#d4af37]"
className="absolute inset-y-0 right-0 pr-3 flex items-center transition-colors hover:text-[var(--luxury-gold)]"
>
{showPassword ? (
<EyeOff className="h-4 w-4 sm:h-5 sm:w-5 text-gray-400" />
@@ -344,7 +344,7 @@ const RegisterModal: React.FC = () => {
<div
className={`h-full transition-all duration-300 ${
passwordStrength.strength >= 4
? 'bg-[#d4af37]'
? 'bg-[var(--luxury-gold)]'
: passwordStrength.strength >= 3
? 'bg-yellow-500'
: 'bg-red-500'
@@ -389,7 +389,7 @@ const RegisterModal: React.FC = () => {
<button
type="button"
onClick={() => setShowConfirmPassword(!showConfirmPassword)}
className="absolute inset-y-0 right-0 pr-3 flex items-center transition-colors hover:text-[#d4af37]"
className="absolute inset-y-0 right-0 pr-3 flex items-center transition-colors hover:text-[var(--luxury-gold)]"
>
{showConfirmPassword ? (
<EyeOff className="h-4 w-4 sm:h-5 sm:w-5 text-gray-400" />
@@ -443,7 +443,7 @@ const RegisterModal: React.FC = () => {
Already have an account?{' '}
<button
onClick={() => openModal('login')}
className="font-medium text-[#d4af37] hover:text-[#c9a227] transition-colors"
className="font-medium text-[var(--luxury-gold)] hover:text-[var(--luxury-gold-dark)] transition-colors"
>
Login now
</button>

View File

@@ -132,7 +132,7 @@ const ResetPasswordModal: React.FC<ResetPasswordModalProps> = ({ token }) => {
<div className="absolute inset-0 bg-black/60 backdrop-blur-sm" />
{/* Modal */}
<div className="relative w-full max-w-md max-h-[95vh] overflow-y-auto bg-gradient-to-br from-gray-50 via-white to-gray-50 rounded-lg shadow-2xl border border-[#d4af37]/20">
<div className="relative w-full max-w-md max-h-[95vh] overflow-y-auto bg-gradient-to-br from-gray-50 via-white to-gray-50 rounded-lg shadow-2xl border border-[var(--luxury-gold)]/20">
{/* Close button */}
{!isSuccess && (
<button
@@ -158,13 +158,13 @@ const ResetPasswordModal: React.FC<ResetPasswordModalProps> = ({ token }) => {
style={{ filter: 'drop-shadow(0 4px 6px rgba(0,0,0,0.1))' }}
/>
) : (
<div className="relative p-2.5 sm:p-3 bg-gradient-to-br from-[#d4af37] to-[#c9a227] rounded-full shadow-lg shadow-[#d4af37]/30">
<div className="relative p-2.5 sm:p-3 bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] rounded-full shadow-lg shadow-[var(--luxury-gold)]/30">
<KeyRound className="w-6 h-6 sm:w-8 sm:h-8 text-[#0f0f0f] relative z-10" />
</div>
)}
</div>
{settings.company_tagline && (
<p className="text-[10px] sm:text-xs text-[#d4af37] uppercase tracking-[1.5px] sm:tracking-[2px] mb-1 sm:mb-2 font-light">
<p className="text-[10px] sm:text-xs text-[var(--luxury-gold)] uppercase tracking-[1.5px] sm:tracking-[2px] mb-1 sm:mb-2 font-light">
{settings.company_tagline}
</p>
)}
@@ -203,7 +203,7 @@ const ResetPasswordModal: React.FC<ResetPasswordModalProps> = ({ token }) => {
Redirecting to login...
</p>
<div className="mt-2 flex justify-center">
<Loader2 className="animate-spin h-4 w-4 sm:h-5 sm:w-5 text-[#d4af37]" />
<Loader2 className="animate-spin h-4 w-4 sm:h-5 sm:w-5 text-[var(--luxury-gold)]" />
</div>
</div>
@@ -212,7 +212,7 @@ const ResetPasswordModal: React.FC<ResetPasswordModalProps> = ({ token }) => {
closeModal();
openModal('login');
}}
className="inline-flex items-center justify-center w-full py-2.5 sm:py-3 px-4 border border-transparent rounded-lg text-xs sm:text-sm font-medium text-white bg-gradient-to-r from-[#d4af37] to-[#c9a227] hover:from-[#f5d76e] hover:to-[#d4af37] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[#d4af37] transition-colors"
className="inline-flex items-center justify-center w-full py-2.5 sm:py-3 px-4 border border-transparent rounded-lg text-xs sm:text-sm font-medium text-white bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[var(--luxury-gold)] transition-colors"
>
<KeyRound className="-ml-1 mr-2 h-4 w-4 sm:h-5 sm:w-5" />
Login Now
@@ -267,7 +267,7 @@ const ResetPasswordModal: React.FC<ResetPasswordModalProps> = ({ token }) => {
className={`block w-full pl-9 sm:pl-10 pr-9 sm:pr-10 py-2.5 sm:py-3 border rounded-lg focus:outline-none focus:ring-2 transition-colors text-sm sm:text-base luxury-input ${
errors.password
? 'border-red-300 focus:ring-red-500'
: 'border-gray-300 focus:ring-[#d4af37]'
: 'border-gray-300 focus:ring-[var(--luxury-gold)]'
}`}
placeholder="••••••••"
/>
@@ -330,7 +330,7 @@ const ResetPasswordModal: React.FC<ResetPasswordModalProps> = ({ token }) => {
className={`block w-full pl-9 sm:pl-10 pr-9 sm:pr-10 py-2.5 sm:py-3 border rounded-lg focus:outline-none focus:ring-2 transition-colors text-sm sm:text-base luxury-input ${
errors.confirmPassword
? 'border-red-300 focus:ring-red-500'
: 'border-gray-300 focus:ring-[#d4af37]'
: 'border-gray-300 focus:ring-[var(--luxury-gold)]'
}`}
placeholder="••••••••"
/>
@@ -356,7 +356,7 @@ const ResetPasswordModal: React.FC<ResetPasswordModalProps> = ({ token }) => {
<button
type="submit"
disabled={isLoading}
className="w-full flex items-center justify-center py-2.5 sm:py-3 px-4 border border-transparent rounded-lg shadow-sm text-xs sm:text-sm font-medium text-white bg-gradient-to-r from-[#d4af37] to-[#c9a227] hover:from-[#f5d76e] hover:to-[#d4af37] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[#d4af37] disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
className="w-full flex items-center justify-center py-2.5 sm:py-3 px-4 border border-transparent rounded-lg shadow-sm text-xs sm:text-sm font-medium text-white bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[var(--luxury-gold)] disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
>
{isLoading ? (
<>
@@ -375,7 +375,7 @@ const ResetPasswordModal: React.FC<ResetPasswordModalProps> = ({ token }) => {
<button
type="button"
onClick={() => openModal('login')}
className="text-xs sm:text-sm font-medium text-[#d4af37] hover:text-[#c9a227] transition-colors"
className="text-xs sm:text-sm font-medium text-[var(--luxury-gold)] hover:text-[var(--luxury-gold-dark)] transition-colors"
>
Back to Login
</button>

View File

@@ -345,7 +345,7 @@ const HousekeepingLoginPage: React.FC = () => {
<div className="min-h-screen bg-gradient-to-br from-gray-50 via-white to-gray-50 flex items-center justify-center p-4">
<div className="w-full max-w-md">
<div className="bg-white rounded-2xl shadow-2xl border border-gray-200/50 overflow-hidden">
<div className="bg-gradient-to-r from-[#d4af37] via-[#c9a227] to-[#d4af37] p-6 sm:p-8 text-center">
<div className="bg-gradient-to-r from-[var(--luxury-gold)] via-[var(--luxury-gold-dark)] to-[var(--luxury-gold)] p-6 sm:p-8 text-center">
<div className="flex justify-center mb-4">
{settings.company_logo_url ? (
<img
@@ -389,7 +389,7 @@ const HousekeepingLoginPage: React.FC = () => {
autoComplete="one-time-code"
maxLength={8}
className={`w-full pl-10 pr-4 py-3 border rounded-lg text-center tracking-widest ${
mfaErrors.mfaToken ? 'border-red-300 focus:ring-red-500' : 'border-gray-300 focus:ring-[#d4af37]'
mfaErrors.mfaToken ? 'border-red-300 focus:ring-red-500' : 'border-gray-300 focus:ring-[var(--luxury-gold)]'
}`}
placeholder="000000"
/>
@@ -402,7 +402,7 @@ const HousekeepingLoginPage: React.FC = () => {
<button
type="submit"
disabled={isLoading}
className="w-full bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-white py-3 px-4 rounded-lg font-semibold hover:from-[#f5d76e] hover:to-[#d4af37] transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center"
className="w-full bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-white py-3 px-4 rounded-lg font-semibold hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center"
>
{isLoading ? (
<>
@@ -461,7 +461,7 @@ const HousekeepingLoginPage: React.FC = () => {
type="email"
autoComplete="email"
className={`w-full pl-10 pr-4 py-3 border rounded-lg ${
errors.email ? 'border-red-300 focus:ring-red-500' : 'border-gray-300 focus:ring-[#d4af37]'
errors.email ? 'border-red-300 focus:ring-red-500' : 'border-gray-300 focus:ring-[var(--luxury-gold)]'
}`}
placeholder="email@example.com"
/>
@@ -485,7 +485,7 @@ const HousekeepingLoginPage: React.FC = () => {
type={showPassword ? 'text' : 'password'}
autoComplete="current-password"
className={`w-full pl-10 pr-10 py-3 border rounded-lg ${
errors.password ? 'border-red-300 focus:ring-red-500' : 'border-gray-300 focus:ring-[#d4af37]'
errors.password ? 'border-red-300 focus:ring-red-500' : 'border-gray-300 focus:ring-[var(--luxury-gold)]'
}`}
placeholder="••••••••"
/>
@@ -511,7 +511,7 @@ const HousekeepingLoginPage: React.FC = () => {
{...register('rememberMe')}
id="rememberMe"
type="checkbox"
className="h-4 w-4 text-[#d4af37] focus:ring-[#d4af37] border-gray-300 rounded"
className="h-4 w-4 text-[var(--luxury-gold)] focus:ring-[var(--luxury-gold)] border-gray-300 rounded"
/>
<label htmlFor="rememberMe" className="ml-2 block text-sm text-gray-700">
Remember me
@@ -535,7 +535,7 @@ const HousekeepingLoginPage: React.FC = () => {
<button
type="submit"
disabled={isLoading}
className="w-full bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-white py-3 px-4 rounded-lg font-semibold hover:from-[#f5d76e] hover:to-[#d4af37] transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center"
className="w-full bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-white py-3 px-4 rounded-lg font-semibold hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center"
>
{isLoading ? (
<>

View File

@@ -44,19 +44,19 @@ const InvoiceInfoModal: React.FC<InvoiceInfoModalProps> = ({
className="fixed inset-0 bg-black/90 backdrop-blur-sm"
onClick={onClose}
/>
<div className="relative w-full max-w-lg max-h-[95vh] bg-gradient-to-br from-[#0a0a0a] via-[#1a1a1a] to-[#0a0a0a] rounded-xl sm:rounded-2xl border border-[#d4af37]/30 shadow-2xl shadow-[#d4af37]/20 overflow-hidden flex flex-col">
<div className="relative w-full max-w-lg max-h-[95vh] bg-gradient-to-br from-[#0a0a0a] via-[#1a1a1a] to-[#0a0a0a] rounded-xl sm:rounded-2xl border border-[var(--luxury-gold)]/30 shadow-2xl shadow-[var(--luxury-gold)]/20 overflow-hidden flex flex-col">
{/* Header */}
<div className="px-3 sm:px-4 md:px-6 py-3 sm:py-4 border-b border-[#d4af37]/20 bg-gradient-to-r from-[#1a1a1a] to-[#0a0a0a] flex-shrink-0">
<div className="px-3 sm:px-4 md:px-6 py-3 sm:py-4 border-b border-[var(--luxury-gold)]/20 bg-gradient-to-r from-[#1a1a1a] to-[#0a0a0a] flex-shrink-0">
<div className="flex items-center justify-between gap-2">
<div className="flex items-center gap-2 min-w-0 flex-1">
<Building2 className="w-4 h-4 sm:w-5 sm:h-5 text-[#d4af37] flex-shrink-0" />
<Building2 className="w-4 h-4 sm:w-5 sm:h-5 text-[var(--luxury-gold)] flex-shrink-0" />
<h2 className="text-base sm:text-lg md:text-xl font-serif font-bold text-white tracking-tight truncate">
Invoice Information
</h2>
</div>
<button
onClick={onClose}
className="p-1.5 sm:p-2 hover:bg-[#d4af37]/10 rounded-lg transition-colors text-gray-400 hover:text-white flex-shrink-0"
className="p-1.5 sm:p-2 hover:bg-[var(--luxury-gold)]/10 rounded-lg transition-colors text-gray-400 hover:text-white flex-shrink-0"
>
<X className="w-4 h-4 sm:w-5 sm:h-5" />
</button>
@@ -73,7 +73,7 @@ const InvoiceInfoModal: React.FC<InvoiceInfoModalProps> = ({
<input
{...register('company_name')}
type="text"
className="w-full px-3 py-2 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white text-sm focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37]"
className="w-full px-3 py-2 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white text-sm focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)]"
placeholder="Company Name"
/>
</div>
@@ -85,7 +85,7 @@ const InvoiceInfoModal: React.FC<InvoiceInfoModalProps> = ({
<textarea
{...register('company_address')}
rows={3}
className="w-full px-3 py-2 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white text-sm focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37] resize-none"
className="w-full px-3 py-2 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white text-sm focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)] resize-none"
placeholder="Company Address"
/>
</div>
@@ -98,7 +98,7 @@ const InvoiceInfoModal: React.FC<InvoiceInfoModalProps> = ({
<input
{...register('company_tax_id')}
type="text"
className="w-full px-3 py-2 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white text-sm focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37]"
className="w-full px-3 py-2 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white text-sm focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)]"
placeholder="Tax ID"
/>
</div>
@@ -110,7 +110,7 @@ const InvoiceInfoModal: React.FC<InvoiceInfoModalProps> = ({
<input
{...register('customer_tax_id')}
type="text"
className="w-full px-3 py-2 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white text-sm focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37]"
className="w-full px-3 py-2 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white text-sm focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)]"
placeholder="Tax ID"
/>
</div>
@@ -118,7 +118,7 @@ const InvoiceInfoModal: React.FC<InvoiceInfoModalProps> = ({
</div>
{/* Footer */}
<div className="mt-4 sm:mt-6 flex items-center justify-end gap-2 sm:gap-3 pt-3 sm:pt-4 border-t border-[#d4af37]/20 flex-shrink-0">
<div className="mt-4 sm:mt-6 flex items-center justify-end gap-2 sm:gap-3 pt-3 sm:pt-4 border-t border-[var(--luxury-gold)]/20 flex-shrink-0">
<button
type="button"
onClick={onClose}
@@ -128,7 +128,7 @@ const InvoiceInfoModal: React.FC<InvoiceInfoModalProps> = ({
</button>
<button
type="submit"
className="px-4 sm:px-6 py-2 bg-[#d4af37] text-black font-semibold rounded-lg hover:bg-[#c9a227] transition-all flex items-center gap-1.5 sm:gap-2 text-sm sm:text-base min-h-[44px]"
className="px-4 sm:px-6 py-2 bg-[var(--luxury-gold)] text-black font-semibold rounded-lg hover:bg-[var(--luxury-gold-dark)] transition-all flex items-center gap-1.5 sm:gap-2 text-sm sm:text-base min-h-[44px]"
>
<Save className="w-3.5 h-3.5 sm:w-4 sm:h-4" />
<span>Save</span>

View File

@@ -514,9 +514,9 @@ const LuxuryBookingModal: React.FC<LuxuryBookingModalProps> = ({
className="fixed inset-0 bg-black/80 backdrop-blur-sm"
onClick={onClose}
/>
<div className="relative w-full max-w-4xl max-h-[95vh] bg-gradient-to-br from-[#0a0a0a] via-[#1a1a1a] to-[#0a0a0a] rounded-xl sm:rounded-2xl border border-[#d4af37]/30 shadow-2xl shadow-[#d4af37]/20 overflow-hidden flex flex-col">
<div className="relative w-full max-w-4xl max-h-[95vh] bg-gradient-to-br from-[#0a0a0a] via-[#1a1a1a] to-[#0a0a0a] rounded-xl sm:rounded-2xl border border-[var(--luxury-gold)]/30 shadow-2xl shadow-[var(--luxury-gold)]/20 overflow-hidden flex flex-col">
{/* Header */}
<div className="relative px-3 sm:px-4 md:px-6 py-3 sm:py-4 border-b border-[#d4af37]/20 bg-gradient-to-r from-[#1a1a1a] to-[#0a0a0a] flex-shrink-0">
<div className="relative px-3 sm:px-4 md:px-6 py-3 sm:py-4 border-b border-[var(--luxury-gold)]/20 bg-gradient-to-r from-[#1a1a1a] to-[#0a0a0a] flex-shrink-0">
<div className="flex items-center justify-between gap-2">
<div className="min-w-0 flex-1">
<h2 className="text-base sm:text-lg md:text-xl lg:text-2xl font-serif font-bold text-white tracking-tight truncate">
@@ -528,7 +528,7 @@ const LuxuryBookingModal: React.FC<LuxuryBookingModalProps> = ({
</div>
<button
onClick={onClose}
className="p-1.5 sm:p-2 hover:bg-[#d4af37]/10 rounded-lg transition-colors text-gray-400 hover:text-white flex-shrink-0"
className="p-1.5 sm:p-2 hover:bg-[var(--luxury-gold)]/10 rounded-lg transition-colors text-gray-400 hover:text-white flex-shrink-0"
>
<X className="w-4 h-4 sm:w-5 sm:h-5" />
</button>
@@ -545,7 +545,7 @@ const LuxuryBookingModal: React.FC<LuxuryBookingModalProps> = ({
<div
className={`flex items-center justify-center w-6 h-6 sm:w-7 sm:h-7 md:w-8 md:h-8 rounded-full border-2 transition-all flex-shrink-0 ${
isActive
? 'bg-[#d4af37] border-[#d4af37] text-black'
? 'bg-[var(--luxury-gold)] border-[var(--luxury-gold)] text-black'
: isCompleted
? 'bg-green-500/20 border-green-500 text-green-400'
: 'bg-transparent border-gray-600 text-gray-500'
@@ -561,7 +561,7 @@ const LuxuryBookingModal: React.FC<LuxuryBookingModalProps> = ({
</div>
<span
className={`ml-1 sm:ml-2 text-[10px] sm:text-xs font-medium hidden md:block truncate ${
isActive ? 'text-[#d4af37]' : isCompleted ? 'text-green-400' : 'text-gray-500'
isActive ? 'text-[var(--luxury-gold)]' : isCompleted ? 'text-green-400' : 'text-gray-500'
}`}
>
{step.label}
@@ -585,7 +585,7 @@ const LuxuryBookingModal: React.FC<LuxuryBookingModalProps> = ({
<div className="h-full overflow-y-auto">
{loading ? (
<div className="flex items-center justify-center py-12">
<Loader2 className="w-8 h-8 animate-spin text-[#d4af37]" />
<Loader2 className="w-8 h-8 animate-spin text-[var(--luxury-gold)]" />
</div>
) : (
<form onSubmit={handleSubmit(onSubmit)} className="space-y-6 relative">
@@ -602,13 +602,13 @@ const LuxuryBookingModal: React.FC<LuxuryBookingModalProps> = ({
<div className="space-y-4">
<div>
<h3 className="text-lg font-serif font-semibold text-white mb-4 flex items-center gap-2">
<Calendar className="w-5 h-5 text-[#d4af37]" />
<Calendar className="w-5 h-5 text-[var(--luxury-gold)]" />
Select Dates
</h3>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div>
<label className="block text-xs font-medium text-gray-300 mb-2">
Check-in Date <span className="text-[#d4af37]">*</span>
Check-in Date <span className="text-[var(--luxury-gold)]">*</span>
</label>
<Controller
control={control}
@@ -631,7 +631,7 @@ const LuxuryBookingModal: React.FC<LuxuryBookingModalProps> = ({
}
field.onChange(date);
}}
className="w-full px-3 py-2 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white text-sm focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37]"
className="w-full px-3 py-2 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white text-sm focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)]"
wrapperClassName="w-full"
/>
)}
@@ -642,7 +642,7 @@ const LuxuryBookingModal: React.FC<LuxuryBookingModalProps> = ({
</div>
<div>
<label className="block text-xs font-medium text-gray-300 mb-2">
Check-out Date <span className="text-[#d4af37]">*</span>
Check-out Date <span className="text-[var(--luxury-gold)]">*</span>
</label>
<Controller
control={control}
@@ -668,7 +668,7 @@ const LuxuryBookingModal: React.FC<LuxuryBookingModalProps> = ({
}
field.onChange(date);
}}
className="w-full px-3 py-2 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white text-sm focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37]"
className="w-full px-3 py-2 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white text-sm focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)]"
wrapperClassName="w-full"
/>
)}
@@ -679,10 +679,10 @@ const LuxuryBookingModal: React.FC<LuxuryBookingModalProps> = ({
</div>
</div>
{checkInDate && checkOutDate && (
<div className="mt-4 p-3 bg-[#d4af37]/10 border border-[#d4af37]/20 rounded-lg">
<div className="mt-4 p-3 bg-[var(--luxury-gold)]/10 border border-[var(--luxury-gold)]/20 rounded-lg">
<p className="text-sm text-gray-300">
<span className="text-[#d4af37] font-semibold">{numberOfNights}</span> night{numberOfNights !== 1 ? 's' : ''}
<span className="text-[#d4af37] font-semibold ml-1">{formatCurrency(roomTotal)}</span>
<span className="text-[var(--luxury-gold)] font-semibold">{numberOfNights}</span> night{numberOfNights !== 1 ? 's' : ''}
<span className="text-[var(--luxury-gold)] font-semibold ml-1">{formatCurrency(roomTotal)}</span>
</p>
</div>
)}
@@ -695,18 +695,18 @@ const LuxuryBookingModal: React.FC<LuxuryBookingModalProps> = ({
<div className="space-y-4">
<div>
<h3 className="text-lg font-serif font-semibold text-white mb-4 flex items-center gap-2">
<Users className="w-5 h-5 text-[#d4af37]" />
<Users className="w-5 h-5 text-[var(--luxury-gold)]" />
Guest Information
</h3>
<div className="space-y-4">
<div>
<label className="block text-xs font-medium text-gray-300 mb-2">
Full Name <span className="text-[#d4af37]">*</span>
Full Name <span className="text-[var(--luxury-gold)]">*</span>
</label>
<input
{...register('fullName')}
type="text"
className="w-full px-3 py-2 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white text-sm focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37]"
className="w-full px-3 py-2 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white text-sm focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)]"
placeholder="John Doe"
/>
{errors.fullName && (
@@ -716,12 +716,12 @@ const LuxuryBookingModal: React.FC<LuxuryBookingModalProps> = ({
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div>
<label className="block text-xs font-medium text-gray-300 mb-2">
Email <span className="text-[#d4af37]">*</span>
Email <span className="text-[var(--luxury-gold)]">*</span>
</label>
<input
{...register('email')}
type="email"
className="w-full px-3 py-2 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white text-sm focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37]"
className="w-full px-3 py-2 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white text-sm focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)]"
placeholder="email@example.com"
/>
{errors.email && (
@@ -730,12 +730,12 @@ const LuxuryBookingModal: React.FC<LuxuryBookingModalProps> = ({
</div>
<div>
<label className="block text-xs font-medium text-gray-300 mb-2">
Phone <span className="text-[#d4af37]">*</span>
Phone <span className="text-[var(--luxury-gold)]">*</span>
</label>
<input
{...register('phone')}
type="tel"
className="w-full px-3 py-2 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white text-sm focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37]"
className="w-full px-3 py-2 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white text-sm focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)]"
placeholder="0123456789"
/>
{errors.phone && (
@@ -745,14 +745,14 @@ const LuxuryBookingModal: React.FC<LuxuryBookingModalProps> = ({
</div>
<div>
<label className="block text-xs font-medium text-gray-300 mb-2">
Number of Guests <span className="text-[#d4af37]">*</span>
Number of Guests <span className="text-[var(--luxury-gold)]">*</span>
</label>
<input
{...register('guestCount')}
type="number"
min="1"
max={room?.capacity || room?.room_type?.capacity || 10}
className="w-full px-3 py-2 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white text-sm focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37]"
className="w-full px-3 py-2 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white text-sm focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)]"
/>
{errors.guestCount && (
<p className="text-xs text-red-400 mt-1">{errors.guestCount.message}</p>
@@ -765,7 +765,7 @@ const LuxuryBookingModal: React.FC<LuxuryBookingModalProps> = ({
<textarea
{...register('notes')}
rows={2}
className="w-full px-3 py-2 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white text-sm focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37] resize-none"
className="w-full px-3 py-2 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white text-sm focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)] resize-none"
placeholder="Any special requests..."
/>
</div>
@@ -779,7 +779,7 @@ const LuxuryBookingModal: React.FC<LuxuryBookingModalProps> = ({
<div className="space-y-4">
<div>
<h3 className="text-lg font-serif font-semibold text-white mb-4 flex items-center gap-2">
<Sparkles className="w-5 h-5 text-[#d4af37]" />
<Sparkles className="w-5 h-5 text-[var(--luxury-gold)]" />
Additional Services
</h3>
{services.length > 0 ? (
@@ -790,7 +790,7 @@ const LuxuryBookingModal: React.FC<LuxuryBookingModalProps> = ({
return (
<div
key={service.id}
className="p-3 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg"
className="p-3 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg"
>
<div className="flex items-center justify-between">
<div className="flex-1">
@@ -815,7 +815,7 @@ const LuxuryBookingModal: React.FC<LuxuryBookingModalProps> = ({
}
}}
disabled={quantity === 0}
className="w-7 h-7 flex items-center justify-center bg-[#1a1a1a] border border-[#d4af37]/20 rounded text-[#d4af37] hover:bg-[#d4af37]/10 disabled:opacity-50"
className="w-7 h-7 flex items-center justify-center bg-[#1a1a1a] border border-[var(--luxury-gold)]/20 rounded text-[var(--luxury-gold)] hover:bg-[var(--luxury-gold)]/10 disabled:opacity-50"
>
<Minus className="w-3.5 h-3.5" />
</button>
@@ -833,13 +833,13 @@ const LuxuryBookingModal: React.FC<LuxuryBookingModalProps> = ({
));
}
}}
className="w-7 h-7 flex items-center justify-center bg-[#1a1a1a] border border-[#d4af37]/20 rounded text-[#d4af37] hover:bg-[#d4af37]/10"
className="w-7 h-7 flex items-center justify-center bg-[#1a1a1a] border border-[var(--luxury-gold)]/20 rounded text-[var(--luxury-gold)] hover:bg-[var(--luxury-gold)]/10"
>
<Plus className="w-3.5 h-3.5" />
</button>
</div>
{quantity > 0 && (
<span className="text-sm font-semibold text-[#d4af37] w-20 text-right">
<span className="text-sm font-semibold text-[var(--luxury-gold)] w-20 text-right">
{formatCurrency(service.price * quantity)}
</span>
)}
@@ -854,7 +854,7 @@ const LuxuryBookingModal: React.FC<LuxuryBookingModalProps> = ({
)}
{/* Promotion Code */}
<div className="mt-6 pt-6 border-t border-[#d4af37]/20">
<div className="mt-6 pt-6 border-t border-[var(--luxury-gold)]/20">
<h4 className="text-sm font-semibold text-white mb-3">Promotion Code</h4>
{!selectedPromotion ? (
<div className="flex gap-2">
@@ -866,14 +866,14 @@ const LuxuryBookingModal: React.FC<LuxuryBookingModalProps> = ({
setPromotionError(null);
}}
placeholder="Enter code"
className="flex-1 px-3 py-2 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white text-sm focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37]"
className="flex-1 px-3 py-2 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white text-sm focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)]"
disabled={validatingPromotion || subtotal === 0}
/>
<button
type="button"
onClick={handleValidatePromotion}
disabled={validatingPromotion || !promotionCode.trim() || subtotal === 0}
className="px-4 py-2 bg-[#d4af37] text-black font-semibold rounded-lg hover:bg-[#c9a227] disabled:opacity-50 disabled:cursor-not-allowed text-sm"
className="px-4 py-2 bg-[var(--luxury-gold)] text-black font-semibold rounded-lg hover:bg-[var(--luxury-gold-dark)] disabled:opacity-50 disabled:cursor-not-allowed text-sm"
>
{validatingPromotion ? <Loader2 className="w-4 h-4 animate-spin" /> : 'Apply'}
</button>
@@ -897,9 +897,9 @@ const LuxuryBookingModal: React.FC<LuxuryBookingModalProps> = ({
</div>
{/* Referral Code */}
<div className="mt-6 pt-6 border-t border-[#d4af37]/20">
<div className="mt-6 pt-6 border-t border-[var(--luxury-gold)]/20">
<div className="flex items-center gap-2 mb-3">
<Users className="w-4 h-4 text-[#d4af37]" />
<Users className="w-4 h-4 text-[var(--luxury-gold)]" />
<h4 className="text-sm font-semibold text-white">Referral Code (Optional)</h4>
</div>
<div className="space-y-2">
@@ -911,7 +911,7 @@ const LuxuryBookingModal: React.FC<LuxuryBookingModalProps> = ({
setReferralError(null);
}}
placeholder="Enter referral code from a friend"
className="w-full px-3 py-2 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white text-sm focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37]"
className="w-full px-3 py-2 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white text-sm focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)]"
/>
{referralCode && (
<p className="text-xs text-gray-400">
@@ -930,51 +930,51 @@ const LuxuryBookingModal: React.FC<LuxuryBookingModalProps> = ({
<div className="space-y-4">
<div>
<h3 className="text-lg font-serif font-semibold text-white mb-4 flex items-center gap-2">
<CreditCard className="w-5 h-5 text-[#d4af37]" />
<CreditCard className="w-5 h-5 text-[var(--luxury-gold)]" />
Payment Method
</h3>
<div className="space-y-3">
<label className="flex items-start p-4 bg-[#0a0a0a] border-2 border-[#d4af37]/20 rounded-lg cursor-pointer hover:border-[#d4af37]/40 transition-all">
<label className="flex items-start p-4 bg-[#0a0a0a] border-2 border-[var(--luxury-gold)]/20 rounded-lg cursor-pointer hover:border-[var(--luxury-gold)]/40 transition-all">
<input
{...register('paymentMethod')}
type="radio"
value="cash"
className="mt-1 mr-3 w-4 h-4 text-[#d4af37] border-[#d4af37]/30 focus:ring-[#d4af37]/50"
className="mt-1 mr-3 w-4 h-4 text-[var(--luxury-gold)] border-[var(--luxury-gold)]/30 focus:ring-[var(--luxury-gold)]/50"
/>
<div className="flex-1">
<div className="flex items-center gap-2 mb-1">
<CreditCard className="w-4 h-4 text-[#d4af37]" />
<CreditCard className="w-4 h-4 text-[var(--luxury-gold)]" />
<span className="font-semibold text-white text-sm">Pay on Arrival</span>
<span className="text-xs bg-orange-500/20 text-orange-300 px-2 py-0.5 rounded">20% deposit</span>
</div>
<p className="text-xs text-gray-400">Pay 20% deposit now, remaining on arrival</p>
</div>
</label>
<label className="flex items-start p-4 bg-[#0a0a0a] border-2 border-[#d4af37]/20 rounded-lg cursor-pointer hover:border-[#d4af37]/40 transition-all">
<label className="flex items-start p-4 bg-[#0a0a0a] border-2 border-[var(--luxury-gold)]/20 rounded-lg cursor-pointer hover:border-[var(--luxury-gold)]/40 transition-all">
<input
{...register('paymentMethod')}
type="radio"
value="stripe"
className="mt-1 mr-3 w-4 h-4 text-[#d4af37] border-[#d4af37]/30 focus:ring-[#d4af37]/50"
className="mt-1 mr-3 w-4 h-4 text-[var(--luxury-gold)] border-[var(--luxury-gold)]/30 focus:ring-[var(--luxury-gold)]/50"
/>
<div className="flex-1">
<div className="flex items-center gap-2 mb-1">
<CreditCard className="w-4 h-4 text-[#d4af37]" />
<CreditCard className="w-4 h-4 text-[var(--luxury-gold)]" />
<span className="font-semibold text-white text-sm">Credit/Debit Card</span>
</div>
<p className="text-xs text-gray-400">Secure payment via Stripe</p>
</div>
</label>
<label className="flex items-start p-4 bg-[#0a0a0a] border-2 border-[#d4af37]/20 rounded-lg cursor-pointer hover:border-[#d4af37]/40 transition-all">
<label className="flex items-start p-4 bg-[#0a0a0a] border-2 border-[var(--luxury-gold)]/20 rounded-lg cursor-pointer hover:border-[var(--luxury-gold)]/40 transition-all">
<input
{...register('paymentMethod')}
type="radio"
value="paypal"
className="mt-1 mr-3 w-4 h-4 text-[#d4af37] border-[#d4af37]/30 focus:ring-[#d4af37]/50"
className="mt-1 mr-3 w-4 h-4 text-[var(--luxury-gold)] border-[var(--luxury-gold)]/30 focus:ring-[var(--luxury-gold)]/50"
/>
<div className="flex-1">
<div className="flex items-center gap-2 mb-1">
<CreditCard className="w-4 h-4 text-[#d4af37]" />
<CreditCard className="w-4 h-4 text-[var(--luxury-gold)]" />
<span className="font-semibold text-white text-sm">PayPal</span>
</div>
<p className="text-xs text-gray-400">Pay securely with PayPal</p>
@@ -987,7 +987,7 @@ const LuxuryBookingModal: React.FC<LuxuryBookingModalProps> = ({
<button
type="button"
onClick={() => setShowInvoiceModal(true)}
className="flex items-center gap-2 px-4 py-2 text-sm text-[#d4af37] hover:text-[#f5d76e] transition-colors"
className="flex items-center gap-2 px-4 py-2 text-sm text-[var(--luxury-gold)] hover:text-[var(--luxury-gold-light)] transition-colors"
>
<Receipt className="w-4 h-4" />
Add Invoice Information (Optional)
@@ -995,7 +995,7 @@ const LuxuryBookingModal: React.FC<LuxuryBookingModalProps> = ({
</div>
{/* Summary */}
<div className="mt-6 p-4 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg">
<div className="mt-6 p-4 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg">
<div className="space-y-2 text-sm">
<div className="flex justify-between text-gray-300">
<span>Room ({numberOfNights} nights)</span>
@@ -1013,7 +1013,7 @@ const LuxuryBookingModal: React.FC<LuxuryBookingModalProps> = ({
<span>-{formatCurrency(promotionDiscount)}</span>
</div>
)}
<div className="flex justify-between text-lg font-bold text-[#d4af37] pt-2 border-t border-[#d4af37]/20">
<div className="flex justify-between text-lg font-bold text-[var(--luxury-gold)] pt-2 border-t border-[var(--luxury-gold)]/20">
<span>Total</span>
<span>{formatCurrency(totalPrice)}</span>
</div>
@@ -1057,7 +1057,7 @@ const LuxuryBookingModal: React.FC<LuxuryBookingModalProps> = ({
</div>
{/* Footer */}
<div className="px-3 sm:px-4 md:px-6 py-3 sm:py-4 border-t border-[#d4af37]/20 bg-gradient-to-r from-[#1a1a1a] to-[#0a0a0a] flex-shrink-0">
<div className="px-3 sm:px-4 md:px-6 py-3 sm:py-4 border-t border-[var(--luxury-gold)]/20 bg-gradient-to-r from-[#1a1a1a] to-[#0a0a0a] flex-shrink-0">
<div className="flex items-center justify-between gap-2 sm:gap-3">
<button
onClick={currentStep === 'dates' ? onClose : handleBack}
@@ -1071,7 +1071,7 @@ const LuxuryBookingModal: React.FC<LuxuryBookingModalProps> = ({
<button
onClick={handleNext}
disabled={!canGoToNextStep()}
className="px-4 sm:px-6 py-2 bg-[#d4af37] text-black font-semibold rounded-lg hover:bg-[#c9a227] disabled:opacity-50 disabled:cursor-not-allowed transition-all flex items-center gap-1.5 sm:gap-2 text-xs sm:text-sm sm:text-base min-h-[44px]"
className="px-4 sm:px-6 py-2 bg-[var(--luxury-gold)] text-black font-semibold rounded-lg hover:bg-[var(--luxury-gold-dark)] disabled:opacity-50 disabled:cursor-not-allowed transition-all flex items-center gap-1.5 sm:gap-2 text-xs sm:text-sm sm:text-base min-h-[44px]"
>
<span>Next</span>
<ArrowRight className="w-3.5 h-3.5 sm:w-4 sm:h-4" />
@@ -1102,7 +1102,7 @@ const LuxuryBookingModal: React.FC<LuxuryBookingModalProps> = ({
})();
}}
disabled={submitting || !paymentMethodForm}
className="px-4 sm:px-6 py-2 bg-[#d4af37] text-black font-semibold rounded-lg hover:bg-[#c9a227] disabled:opacity-50 disabled:cursor-not-allowed transition-all flex items-center gap-1.5 sm:gap-2 text-xs sm:text-sm sm:text-base min-h-[44px]"
className="px-4 sm:px-6 py-2 bg-[var(--luxury-gold)] text-black font-semibold rounded-lg hover:bg-[var(--luxury-gold-dark)] disabled:opacity-50 disabled:cursor-not-allowed transition-all flex items-center gap-1.5 sm:gap-2 text-xs sm:text-sm sm:text-base min-h-[44px]"
>
{submitting ? (
<>

View File

@@ -223,11 +223,11 @@ const PartnersCarousel: React.FC<PartnersCarouselProps> = ({
disabled={currentIndex === 0}
className="absolute left-0 top-1/2 -translate-y-1/2 z-10
w-10 h-10 sm:w-12 sm:h-12
bg-gradient-to-r from-[#d4af37] to-[#c9a227]
bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]
text-white rounded-full
flex items-center justify-center
shadow-lg shadow-[#d4af37]/40
hover:shadow-xl hover:shadow-[#d4af37]/50
shadow-lg shadow-[var(--luxury-gold)]/40
hover:shadow-xl hover:shadow-[var(--luxury-gold)]/50
hover:scale-110
active:scale-95
transition-all duration-300
@@ -243,11 +243,11 @@ const PartnersCarousel: React.FC<PartnersCarouselProps> = ({
disabled={currentIndex >= maxIndex}
className="absolute right-0 top-1/2 -translate-y-1/2 z-10
w-10 h-10 sm:w-12 sm:h-12
bg-gradient-to-r from-[#d4af37] to-[#c9a227]
bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]
text-white rounded-full
flex items-center justify-center
shadow-lg shadow-[#d4af37]/40
hover:shadow-xl hover:shadow-[#d4af37]/50
shadow-lg shadow-[var(--luxury-gold)]/40
hover:shadow-xl hover:shadow-[var(--luxury-gold)]/50
hover:scale-110
active:scale-95
transition-all duration-300
@@ -270,8 +270,8 @@ const PartnersCarousel: React.FC<PartnersCarouselProps> = ({
className={`transition-all duration-300 rounded-full
${
index === currentIndex
? 'w-8 h-2 sm:w-10 sm:h-2.5 bg-gradient-to-r from-[#d4af37] to-[#c9a227] shadow-lg shadow-[#d4af37]/40'
: 'w-2 h-2 sm:w-2.5 sm:h-2.5 bg-gray-300 hover:bg-[#d4af37]/50'
? 'w-8 h-2 sm:w-10 sm:h-2.5 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] shadow-lg shadow-[var(--luxury-gold)]/40'
: 'w-2 h-2 sm:w-2.5 sm:h-2.5 bg-gray-300 hover:bg-[var(--luxury-gold)]/50'
}
`}
aria-label={`Go to partners slide ${index + 1}`}

View File

@@ -178,7 +178,7 @@ const AboutPage: React.FC = () => {
className="w-full h-full object-cover scale-105 transition-transform duration-[20s] ease-out hover:scale-100"
/>
<div className="absolute inset-0 bg-gradient-to-b from-black/70 via-black/50 to-black/70"></div>
<div className="absolute inset-0 bg-gradient-to-r from-[#d4af37]/10 via-transparent to-[#d4af37]/10"></div>
<div className="absolute inset-0 bg-gradient-to-r from-[var(--luxury-gold)]/10 via-transparent to-[var(--luxury-gold)]/10"></div>
</div>
)}
{!pageContent?.about_hero_image && (
@@ -192,8 +192,8 @@ const AboutPage: React.FC = () => {
{!pageContent?.about_hero_image && (
<div className="flex justify-center mb-8">
<div className="relative">
<div className="absolute inset-0 bg-gradient-to-br from-[#d4af37] via-[#f5d76e] to-[#d4af37] rounded-full blur-3xl opacity-40 animate-pulse"></div>
<div className="relative bg-gradient-to-br from-[#d4af37] to-[#c9a227] p-6 rounded-2xl shadow-2xl shadow-[#d4af37]/30">
<div className="absolute inset-0 bg-gradient-to-br from-[var(--luxury-gold)] via-[var(--luxury-gold-light)] to-[var(--luxury-gold)] rounded-full blur-3xl opacity-40 animate-pulse"></div>
<div className="relative bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] p-6 rounded-2xl shadow-2xl shadow-[var(--luxury-gold)]/30">
<Hotel className="w-12 h-12 md:w-16 md:h-16 text-white drop-shadow-lg" />
</div>
</div>
@@ -201,11 +201,11 @@ const AboutPage: React.FC = () => {
)}
<div className="mb-6">
<div className="inline-block mb-4">
<div className="h-px w-20 bg-gradient-to-r from-transparent via-[#d4af37] to-transparent mx-auto"></div>
<div className="h-px w-20 bg-gradient-to-r from-transparent via-[var(--luxury-gold)] to-transparent mx-auto"></div>
</div>
</div>
<h1 className="text-5xl md:text-6xl lg:text-7xl font-serif font-light mb-6 tracking-[0.02em] leading-tight">
<span className="bg-gradient-to-b from-white via-[#f5d76e] to-[#d4af37] bg-clip-text text-transparent drop-shadow-2xl">
<span className="bg-gradient-to-b from-white via-[var(--luxury-gold-light)] to-[var(--luxury-gold)] bg-clip-text text-transparent drop-shadow-2xl">
{pageContent?.title || 'About Luxury Hotel'}
</span>
</h1>
@@ -214,7 +214,7 @@ const AboutPage: React.FC = () => {
</p>
<div className="mt-8">
<div className="inline-block">
<div className="h-px w-20 bg-gradient-to-r from-transparent via-[#d4af37] to-transparent mx-auto"></div>
<div className="h-px w-20 bg-gradient-to-r from-transparent via-[var(--luxury-gold)] to-transparent mx-auto"></div>
</div>
</div>
</div>
@@ -223,20 +223,20 @@ const AboutPage: React.FC = () => {
{}
<section className="py-20 md:py-28 bg-white relative overflow-hidden">
<div className="absolute top-0 left-0 w-full h-px bg-gradient-to-r from-transparent via-[#d4af37]/30 to-transparent"></div>
<div className="absolute top-0 left-0 w-full h-px bg-gradient-to-r from-transparent via-[var(--luxury-gold)]/30 to-transparent"></div>
<div className="container mx-auto px-4 sm:px-6 lg:px-8">
<div className="max-w-5xl mx-auto">
<div className="text-center mb-16">
<div className="inline-block mb-4">
<span className="text-sm font-semibold text-[#d4af37] tracking-[0.2em] uppercase">Our Heritage</span>
<span className="text-sm font-semibold text-[var(--luxury-gold)] tracking-[0.2em] uppercase">Our Heritage</span>
</div>
<h2 className="text-4xl md:text-5xl lg:text-6xl font-serif font-light text-gray-900 mb-6 tracking-tight">
Our Story
</h2>
<div className="flex items-center justify-center gap-4 mb-6">
<div className="h-px w-12 bg-gradient-to-r from-transparent to-[#d4af37]"></div>
<div className="w-2 h-2 bg-[#d4af37] rounded-full"></div>
<div className="h-px w-12 bg-gradient-to-l from-transparent to-[#d4af37]"></div>
<div className="h-px w-12 bg-gradient-to-r from-transparent to-[var(--luxury-gold)]"></div>
<div className="w-2 h-2 bg-[var(--luxury-gold)] rounded-full"></div>
<div className="h-px w-12 bg-gradient-to-l from-transparent to-[var(--luxury-gold)]"></div>
</div>
</div>
<div className="prose prose-lg md:prose-xl max-w-none text-gray-700 leading-relaxed space-y-8">
@@ -247,7 +247,7 @@ const AboutPage: React.FC = () => {
/>
) : (
<>
<p className="text-lg md:text-xl leading-relaxed font-light tracking-wide first-letter:text-5xl first-letter:font-serif first-letter:text-[#d4af37] first-letter:float-left first-letter:mr-2 first-letter:leading-none">
<p className="text-lg md:text-xl leading-relaxed font-light tracking-wide first-letter:text-5xl first-letter:font-serif first-letter:text-[var(--luxury-gold)] first-letter:float-left first-letter:mr-2 first-letter:leading-none">
Welcome to Luxury Hotel, where timeless elegance meets modern sophistication.
Since our founding, we have been dedicated to providing exceptional hospitality
and creating unforgettable memories for our guests.
@@ -267,7 +267,7 @@ const AboutPage: React.FC = () => {
</div>
</div>
</div>
<div className="absolute bottom-0 left-0 w-full h-px bg-gradient-to-r from-transparent via-[#d4af37]/30 to-transparent"></div>
<div className="absolute bottom-0 left-0 w-full h-px bg-gradient-to-r from-transparent via-[var(--luxury-gold)]/30 to-transparent"></div>
</section>
{}
@@ -278,33 +278,33 @@ const AboutPage: React.FC = () => {
<div className="max-w-7xl mx-auto">
<div className="text-center mb-16">
<div className="inline-block mb-4">
<span className="text-sm font-semibold text-[#d4af37] tracking-[0.2em] uppercase">Core Principles</span>
<span className="text-sm font-semibold text-[var(--luxury-gold)] tracking-[0.2em] uppercase">Core Principles</span>
</div>
<h2 className="text-4xl md:text-5xl lg:text-6xl font-serif font-light text-gray-900 mb-6 tracking-tight">
Our Values
</h2>
<div className="flex items-center justify-center gap-4 mb-6">
<div className="h-px w-12 bg-gradient-to-r from-transparent to-[#d4af37]"></div>
<div className="w-2 h-2 bg-[#d4af37] rounded-full"></div>
<div className="h-px w-12 bg-gradient-to-l from-transparent to-[#d4af37]"></div>
<div className="h-px w-12 bg-gradient-to-r from-transparent to-[var(--luxury-gold)]"></div>
<div className="w-2 h-2 bg-[var(--luxury-gold)] rounded-full"></div>
<div className="h-px w-12 bg-gradient-to-l from-transparent to-[var(--luxury-gold)]"></div>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 lg:gap-8">
{values.map((value, index) => (
<div
key={value.title}
className="group relative bg-white/80 backdrop-blur-sm p-8 rounded-2xl shadow-lg hover:shadow-2xl transition-all duration-500 border border-gray-100 hover:border-[#d4af37]/30 hover:-translate-y-2"
className="group relative bg-white/80 backdrop-blur-sm p-8 rounded-2xl shadow-lg hover:shadow-2xl transition-all duration-500 border border-gray-100 hover:border-[var(--luxury-gold)]/30 hover:-translate-y-2"
style={{ animationDelay: `${index * 0.1}s` }}
>
<div className="absolute top-0 right-0 w-32 h-32 bg-gradient-to-br from-[#d4af37]/5 to-transparent rounded-bl-full opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div className="absolute top-0 right-0 w-32 h-32 bg-gradient-to-br from-[var(--luxury-gold)]/5 to-transparent rounded-bl-full opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div className="relative">
<div className="w-16 h-16 bg-gradient-to-br from-[#d4af37] via-[#f5d76e] to-[#d4af37] rounded-xl flex items-center justify-center mb-6 shadow-lg shadow-[#d4af37]/20 group-hover:scale-110 group-hover:rotate-3 transition-transform duration-500">
<div className="w-16 h-16 bg-gradient-to-br from-[var(--luxury-gold)] via-[var(--luxury-gold-light)] to-[var(--luxury-gold)] rounded-xl flex items-center justify-center mb-6 shadow-lg shadow-[var(--luxury-gold)]/20 group-hover:scale-110 group-hover:rotate-3 transition-transform duration-500">
{(() => {
const ValueIcon = getIconComponent(value.icon);
return <ValueIcon className="w-8 h-8 text-white drop-shadow-md" />;
})()}
</div>
<h3 className="text-xl md:text-2xl font-serif font-semibold text-gray-900 mb-3 group-hover:text-[#d4af37] transition-colors duration-300">
<h3 className="text-xl md:text-2xl font-serif font-semibold text-gray-900 mb-3 group-hover:text-[var(--luxury-gold)] transition-colors duration-300">
{value.title}
</h3>
<p className="text-gray-600 leading-relaxed font-light text-sm md:text-base">
@@ -327,15 +327,15 @@ const AboutPage: React.FC = () => {
<div className="max-w-7xl mx-auto">
<div className="text-center mb-16">
<div className="inline-block mb-4">
<span className="text-sm font-semibold text-[#d4af37] tracking-[0.2em] uppercase">Excellence Defined</span>
<span className="text-sm font-semibold text-[var(--luxury-gold)] tracking-[0.2em] uppercase">Excellence Defined</span>
</div>
<h2 className="text-4xl md:text-5xl lg:text-6xl font-serif font-light text-gray-900 mb-6 tracking-tight">
Why Choose Us
</h2>
<div className="flex items-center justify-center gap-4 mb-6">
<div className="h-px w-12 bg-gradient-to-r from-transparent to-[#d4af37]"></div>
<div className="w-2 h-2 bg-[#d4af37] rounded-full"></div>
<div className="h-px w-12 bg-gradient-to-l from-transparent to-[#d4af37]"></div>
<div className="h-px w-12 bg-gradient-to-r from-transparent to-[var(--luxury-gold)]"></div>
<div className="w-2 h-2 bg-[var(--luxury-gold)] rounded-full"></div>
<div className="h-px w-12 bg-gradient-to-l from-transparent to-[var(--luxury-gold)]"></div>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 lg:gap-12">
@@ -347,12 +347,12 @@ const AboutPage: React.FC = () => {
className="group text-center p-8 relative"
style={{ animationDelay: `${index * 0.1}s` }}
>
<div className="absolute inset-0 bg-gradient-to-br from-[#d4af37]/5 to-transparent rounded-3xl opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div className="absolute inset-0 bg-gradient-to-br from-[var(--luxury-gold)]/5 to-transparent rounded-3xl opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div className="relative">
<div className="w-20 h-20 bg-gradient-to-br from-[#d4af37] via-[#f5d76e] to-[#d4af37] rounded-2xl flex items-center justify-center mx-auto mb-6 shadow-xl shadow-[#d4af37]/30 group-hover:scale-110 group-hover:shadow-2xl group-hover:shadow-[#d4af37]/40 transition-all duration-500">
<div className="w-20 h-20 bg-gradient-to-br from-[var(--luxury-gold)] via-[var(--luxury-gold-light)] to-[var(--luxury-gold)] rounded-2xl flex items-center justify-center mx-auto mb-6 shadow-xl shadow-[var(--luxury-gold)]/30 group-hover:scale-110 group-hover:shadow-2xl group-hover:shadow-[var(--luxury-gold)]/40 transition-all duration-500">
<FeatureIcon className="w-10 h-10 text-white drop-shadow-lg" />
</div>
<h3 className="text-xl md:text-2xl font-serif font-semibold text-gray-900 mb-4 group-hover:text-[#d4af37] transition-colors duration-300">
<h3 className="text-xl md:text-2xl font-serif font-semibold text-gray-900 mb-4 group-hover:text-[var(--luxury-gold)] transition-colors duration-300">
{feature.title}
</h3>
<p className="text-gray-600 leading-relaxed font-light text-sm md:text-base">
@@ -377,11 +377,11 @@ const AboutPage: React.FC = () => {
<div className="container mx-auto px-4 sm:px-6 lg:px-8 relative z-10">
<div className="max-w-7xl mx-auto grid grid-cols-1 md:grid-cols-2 gap-8 lg:gap-12">
{pageContent.mission && (
<div className="group relative bg-white/95 backdrop-blur-sm p-10 md:p-12 rounded-2xl shadow-2xl border border-[#d4af37]/20 hover:border-[#d4af37]/40 transition-all duration-500 hover:shadow-[#d4af37]/20 hover:-translate-y-1">
<div className="absolute top-0 right-0 w-40 h-40 bg-gradient-to-br from-[#d4af37]/10 to-transparent rounded-bl-full opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div className="group relative bg-white/95 backdrop-blur-sm p-10 md:p-12 rounded-2xl shadow-2xl border border-[var(--luxury-gold)]/20 hover:border-[var(--luxury-gold)]/40 transition-all duration-500 hover:shadow-[var(--luxury-gold)]/20 hover:-translate-y-1">
<div className="absolute top-0 right-0 w-40 h-40 bg-gradient-to-br from-[var(--luxury-gold)]/10 to-transparent rounded-bl-full opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div className="relative">
<div className="flex items-center gap-3 mb-6">
<div className="w-1 h-12 bg-gradient-to-b from-[#d4af37] to-[#f5d76e] rounded-full"></div>
<div className="w-1 h-12 bg-gradient-to-b from-[var(--luxury-gold)] to-[var(--luxury-gold-light)] rounded-full"></div>
<h2 className="text-3xl md:text-4xl font-serif font-light text-gray-900">Our Mission</h2>
</div>
<p className="text-gray-700 leading-relaxed text-base md:text-lg font-light tracking-wide">{pageContent.mission}</p>
@@ -389,11 +389,11 @@ const AboutPage: React.FC = () => {
</div>
)}
{pageContent.vision && (
<div className="group relative bg-white/95 backdrop-blur-sm p-10 md:p-12 rounded-2xl shadow-2xl border border-[#d4af37]/20 hover:border-[#d4af37]/40 transition-all duration-500 hover:shadow-[#d4af37]/20 hover:-translate-y-1">
<div className="absolute top-0 right-0 w-40 h-40 bg-gradient-to-br from-[#d4af37]/10 to-transparent rounded-bl-full opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div className="group relative bg-white/95 backdrop-blur-sm p-10 md:p-12 rounded-2xl shadow-2xl border border-[var(--luxury-gold)]/20 hover:border-[var(--luxury-gold)]/40 transition-all duration-500 hover:shadow-[var(--luxury-gold)]/20 hover:-translate-y-1">
<div className="absolute top-0 right-0 w-40 h-40 bg-gradient-to-br from-[var(--luxury-gold)]/10 to-transparent rounded-bl-full opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div className="relative">
<div className="flex items-center gap-3 mb-6">
<div className="w-1 h-12 bg-gradient-to-b from-[#d4af37] to-[#f5d76e] rounded-full"></div>
<div className="w-1 h-12 bg-gradient-to-b from-[var(--luxury-gold)] to-[var(--luxury-gold-light)] rounded-full"></div>
<h2 className="text-3xl md:text-4xl font-serif font-light text-gray-900">Our Vision</h2>
</div>
<p className="text-gray-700 leading-relaxed text-base md:text-lg font-light tracking-wide">{pageContent.vision}</p>
@@ -412,24 +412,24 @@ const AboutPage: React.FC = () => {
<div className="max-w-7xl mx-auto">
<div className="text-center mb-16">
<div className="inline-block mb-4">
<span className="text-sm font-semibold text-[#d4af37] tracking-[0.2em] uppercase">Meet The Experts</span>
<span className="text-sm font-semibold text-[var(--luxury-gold)] tracking-[0.2em] uppercase">Meet The Experts</span>
</div>
<h2 className="text-4xl md:text-5xl lg:text-6xl font-serif font-light text-gray-900 mb-6 tracking-tight">
Our Team
</h2>
<div className="flex items-center justify-center gap-4 mb-6">
<div className="h-px w-12 bg-gradient-to-r from-transparent to-[#d4af37]"></div>
<div className="w-2 h-2 bg-[#d4af37] rounded-full"></div>
<div className="h-px w-12 bg-gradient-to-l from-transparent to-[#d4af37]"></div>
<div className="h-px w-12 bg-gradient-to-r from-transparent to-[var(--luxury-gold)]"></div>
<div className="w-2 h-2 bg-[var(--luxury-gold)] rounded-full"></div>
<div className="h-px w-12 bg-gradient-to-l from-transparent to-[var(--luxury-gold)]"></div>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 lg:gap-10">
{team.map((member: any, index: number) => (
<div
key={index}
className="group relative bg-white rounded-2xl shadow-xl overflow-hidden hover:shadow-2xl transition-all duration-500 border border-gray-100 hover:border-[#d4af37]/30 hover:-translate-y-2"
className="group relative bg-white rounded-2xl shadow-xl overflow-hidden hover:shadow-2xl transition-all duration-500 border border-gray-100 hover:border-[var(--luxury-gold)]/30 hover:-translate-y-2"
>
<div className="absolute inset-0 bg-gradient-to-br from-[#d4af37]/5 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500 z-10"></div>
<div className="absolute inset-0 bg-gradient-to-br from-[var(--luxury-gold)]/5 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500 z-10"></div>
{member.image && (
<div className="relative overflow-hidden h-72">
<img
@@ -441,8 +441,8 @@ const AboutPage: React.FC = () => {
</div>
)}
<div className="p-8 relative z-10">
<h3 className="text-2xl font-serif font-semibold text-gray-900 mb-2 group-hover:text-[#d4af37] transition-colors duration-300">{member.name}</h3>
<p className="text-[#d4af37] font-medium mb-4 text-sm tracking-wide uppercase">{member.role}</p>
<h3 className="text-2xl font-serif font-semibold text-gray-900 mb-2 group-hover:text-[var(--luxury-gold)] transition-colors duration-300">{member.name}</h3>
<p className="text-[var(--luxury-gold)] font-medium mb-4 text-sm tracking-wide uppercase">{member.role}</p>
{member.bio && <p className="text-gray-600 text-sm mb-6 leading-relaxed font-light">{member.bio}</p>}
{member.social_links && (
<div className="flex gap-4 pt-4 border-t border-gray-100">
@@ -451,7 +451,7 @@ const AboutPage: React.FC = () => {
href={member.social_links.linkedin}
target="_blank"
rel="noopener noreferrer"
className="w-10 h-10 rounded-full bg-gray-100 flex items-center justify-center text-gray-600 hover:bg-[#d4af37] hover:text-white transition-all duration-300 group-hover:scale-110"
className="w-10 h-10 rounded-full bg-gray-100 flex items-center justify-center text-gray-600 hover:bg-[var(--luxury-gold)] hover:text-white transition-all duration-300 group-hover:scale-110"
>
<Linkedin className="w-5 h-5" />
</a>
@@ -461,7 +461,7 @@ const AboutPage: React.FC = () => {
href={member.social_links.twitter}
target="_blank"
rel="noopener noreferrer"
className="w-10 h-10 rounded-full bg-gray-100 flex items-center justify-center text-gray-600 hover:bg-[#d4af37] hover:text-white transition-all duration-300 group-hover:scale-110"
className="w-10 h-10 rounded-full bg-gray-100 flex items-center justify-center text-gray-600 hover:bg-[var(--luxury-gold)] hover:text-white transition-all duration-300 group-hover:scale-110"
>
<Twitter className="w-5 h-5" />
</a>
@@ -485,30 +485,30 @@ const AboutPage: React.FC = () => {
<div className="max-w-6xl mx-auto">
<div className="text-center mb-16">
<div className="inline-block mb-4">
<span className="text-sm font-semibold text-[#d4af37] tracking-[0.2em] uppercase">Our Journey</span>
<span className="text-sm font-semibold text-[var(--luxury-gold)] tracking-[0.2em] uppercase">Our Journey</span>
</div>
<h2 className="text-4xl md:text-5xl lg:text-6xl font-serif font-light text-gray-900 mb-6 tracking-tight">
Our History
</h2>
<div className="flex items-center justify-center gap-4 mb-6">
<div className="h-px w-12 bg-gradient-to-r from-transparent to-[#d4af37]"></div>
<div className="w-2 h-2 bg-[#d4af37] rounded-full"></div>
<div className="h-px w-12 bg-gradient-to-l from-transparent to-[#d4af37]"></div>
<div className="h-px w-12 bg-gradient-to-r from-transparent to-[var(--luxury-gold)]"></div>
<div className="w-2 h-2 bg-[var(--luxury-gold)] rounded-full"></div>
<div className="h-px w-12 bg-gradient-to-l from-transparent to-[var(--luxury-gold)]"></div>
</div>
</div>
<div className="relative">
<div className="absolute left-8 md:left-1/2 transform md:-translate-x-1/2 w-1 h-full bg-gradient-to-b from-[#d4af37] via-[#f5d76e] to-[#d4af37] shadow-lg"></div>
<div className="absolute left-8 md:left-1/2 transform md:-translate-x-1/2 w-1 h-full bg-gradient-to-b from-[var(--luxury-gold)] via-[var(--luxury-gold-light)] to-[var(--luxury-gold)] shadow-lg"></div>
<div className="space-y-12 md:space-y-16">
{timeline.map((event: any, index: number) => (
<div key={index} className={`relative flex items-center ${index % 2 === 0 ? 'md:flex-row' : 'md:flex-row-reverse'}`}>
<div className="absolute left-6 md:left-1/2 transform md:-translate-x-1/2 w-6 h-6 bg-gradient-to-br from-[#d4af37] to-[#c9a227] rounded-full border-4 border-white shadow-xl z-10 group-hover:scale-125 transition-transform duration-300"></div>
<div className="absolute left-6 md:left-1/2 transform md:-translate-x-1/2 w-6 h-6 bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] rounded-full border-4 border-white shadow-xl z-10 group-hover:scale-125 transition-transform duration-300"></div>
<div className={`ml-20 md:ml-0 md:w-5/12 ${index % 2 === 0 ? 'md:mr-auto md:pr-8' : 'md:ml-auto md:pl-8'}`}>
<div className="group bg-white/90 backdrop-blur-sm p-8 rounded-2xl shadow-xl hover:shadow-2xl transition-all duration-500 border border-gray-100 hover:border-[#d4af37]/30">
<div className="group bg-white/90 backdrop-blur-sm p-8 rounded-2xl shadow-xl hover:shadow-2xl transition-all duration-500 border border-gray-100 hover:border-[var(--luxury-gold)]/30">
<div className="flex items-center gap-3 mb-4">
<div className="text-[#d4af37] font-bold text-2xl md:text-3xl font-serif">{event.year}</div>
<div className="h-px flex-1 bg-gradient-to-r from-[#d4af37] to-transparent"></div>
<div className="text-[var(--luxury-gold)] font-bold text-2xl md:text-3xl font-serif">{event.year}</div>
<div className="h-px flex-1 bg-gradient-to-r from-[var(--luxury-gold)] to-transparent"></div>
</div>
<h3 className="text-2xl md:text-3xl font-serif font-semibold text-gray-900 mb-3 group-hover:text-[#d4af37] transition-colors duration-300">{event.title}</h3>
<h3 className="text-2xl md:text-3xl font-serif font-semibold text-gray-900 mb-3 group-hover:text-[var(--luxury-gold)] transition-colors duration-300">{event.title}</h3>
<p className="text-gray-600 leading-relaxed font-light mb-4">{event.description}</p>
{event.image && (
<div className="mt-6 overflow-hidden rounded-xl">
@@ -538,15 +538,15 @@ const AboutPage: React.FC = () => {
<div className="max-w-7xl mx-auto">
<div className="text-center mb-16">
<div className="inline-block mb-4">
<span className="text-sm font-semibold text-[#d4af37] tracking-[0.2em] uppercase">Recognition</span>
<span className="text-sm font-semibold text-[var(--luxury-gold)] tracking-[0.2em] uppercase">Recognition</span>
</div>
<h2 className="text-4xl md:text-5xl lg:text-6xl font-serif font-light text-gray-900 mb-6 tracking-tight">
Achievements & Awards
</h2>
<div className="flex items-center justify-center gap-4 mb-6">
<div className="h-px w-12 bg-gradient-to-r from-transparent to-[#d4af37]"></div>
<div className="w-2 h-2 bg-[#d4af37] rounded-full"></div>
<div className="h-px w-12 bg-gradient-to-l from-transparent to-[#d4af37]"></div>
<div className="h-px w-12 bg-gradient-to-r from-transparent to-[var(--luxury-gold)]"></div>
<div className="w-2 h-2 bg-[var(--luxury-gold)] rounded-full"></div>
<div className="h-px w-12 bg-gradient-to-l from-transparent to-[var(--luxury-gold)]"></div>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 lg:gap-10">
@@ -555,19 +555,19 @@ const AboutPage: React.FC = () => {
return (
<div
key={index}
className="group relative bg-gradient-to-br from-white to-slate-50 p-8 rounded-2xl shadow-xl hover:shadow-2xl transition-all duration-500 border border-gray-100 hover:border-[#d4af37]/40 hover:-translate-y-2"
className="group relative bg-gradient-to-br from-white to-slate-50 p-8 rounded-2xl shadow-xl hover:shadow-2xl transition-all duration-500 border border-gray-100 hover:border-[var(--luxury-gold)]/40 hover:-translate-y-2"
>
<div className="absolute top-0 right-0 w-32 h-32 bg-gradient-to-br from-[#d4af37]/10 to-transparent rounded-bl-full opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div className="absolute top-0 right-0 w-32 h-32 bg-gradient-to-br from-[var(--luxury-gold)]/10 to-transparent rounded-bl-full opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div className="relative">
<div className="flex items-center gap-4 mb-6">
<div className="w-16 h-16 bg-gradient-to-br from-[#d4af37] via-[#f5d76e] to-[#d4af37] rounded-xl flex items-center justify-center shadow-lg shadow-[#d4af37]/20 group-hover:scale-110 group-hover:rotate-3 transition-transform duration-500">
<div className="w-16 h-16 bg-gradient-to-br from-[var(--luxury-gold)] via-[var(--luxury-gold-light)] to-[var(--luxury-gold)] rounded-xl flex items-center justify-center shadow-lg shadow-[var(--luxury-gold)]/20 group-hover:scale-110 group-hover:rotate-3 transition-transform duration-500">
<AchievementIcon className="w-8 h-8 text-white drop-shadow-md" />
</div>
{achievement.year && (
<div className="text-[#d4af37] font-bold text-2xl font-serif">{achievement.year}</div>
<div className="text-[var(--luxury-gold)] font-bold text-2xl font-serif">{achievement.year}</div>
)}
</div>
<h3 className="text-xl md:text-2xl font-serif font-semibold text-gray-900 mb-3 group-hover:text-[#d4af37] transition-colors duration-300">{achievement.title}</h3>
<h3 className="text-xl md:text-2xl font-serif font-semibold text-gray-900 mb-3 group-hover:text-[var(--luxury-gold)] transition-colors duration-300">{achievement.title}</h3>
<p className="text-gray-600 text-sm md:text-base leading-relaxed font-light mb-4">{achievement.description}</p>
{achievement.image && (
<div className="mt-6 overflow-hidden rounded-xl">
@@ -595,15 +595,15 @@ const AboutPage: React.FC = () => {
<div className="max-w-6xl mx-auto">
<div className="text-center mb-16">
<div className="inline-block mb-4">
<span className="text-sm font-semibold text-[#d4af37] tracking-[0.2em] uppercase">Connect With Us</span>
<span className="text-sm font-semibold text-[var(--luxury-gold)] tracking-[0.2em] uppercase">Connect With Us</span>
</div>
<h2 className="text-4xl md:text-5xl lg:text-6xl font-serif font-light text-gray-900 mb-6 tracking-tight">
Get In Touch
</h2>
<div className="flex items-center justify-center gap-4 mb-6">
<div className="h-px w-12 bg-gradient-to-r from-transparent to-[#d4af37]"></div>
<div className="w-2 h-2 bg-[#d4af37] rounded-full"></div>
<div className="h-px w-12 bg-gradient-to-l from-transparent to-[#d4af37]"></div>
<div className="h-px w-12 bg-gradient-to-r from-transparent to-[var(--luxury-gold)]"></div>
<div className="w-2 h-2 bg-[var(--luxury-gold)] rounded-full"></div>
<div className="h-px w-12 bg-gradient-to-l from-transparent to-[var(--luxury-gold)]"></div>
</div>
<p className="text-gray-600 mt-6 text-lg font-light max-w-2xl mx-auto">
We'd love to hear from you. Contact us for reservations or inquiries.
@@ -612,11 +612,11 @@ const AboutPage: React.FC = () => {
{(displayAddress || displayPhone || displayEmail) && (
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 lg:gap-10 mb-16">
{displayAddress && (
<div className="group text-center p-8 bg-white/80 backdrop-blur-sm rounded-2xl shadow-xl hover:shadow-2xl transition-all duration-500 border border-gray-100 hover:border-[#d4af37]/40 hover:-translate-y-2">
<div className="w-16 h-16 bg-gradient-to-br from-[#d4af37] via-[#f5d76e] to-[#d4af37] rounded-2xl flex items-center justify-center mx-auto mb-6 shadow-lg shadow-[#d4af37]/20 group-hover:scale-110 group-hover:rotate-3 transition-transform duration-500">
<div className="group text-center p-8 bg-white/80 backdrop-blur-sm rounded-2xl shadow-xl hover:shadow-2xl transition-all duration-500 border border-gray-100 hover:border-[var(--luxury-gold)]/40 hover:-translate-y-2">
<div className="w-16 h-16 bg-gradient-to-br from-[var(--luxury-gold)] via-[var(--luxury-gold-light)] to-[var(--luxury-gold)] rounded-2xl flex items-center justify-center mx-auto mb-6 shadow-lg shadow-[var(--luxury-gold)]/20 group-hover:scale-110 group-hover:rotate-3 transition-transform duration-500">
<MapPin className="w-8 h-8 text-white drop-shadow-md" />
</div>
<h3 className="text-xl font-serif font-semibold text-gray-900 mb-4 group-hover:text-[#d4af37] transition-colors duration-300">
<h3 className="text-xl font-serif font-semibold text-gray-900 mb-4 group-hover:text-[var(--luxury-gold)] transition-colors duration-300">
Address
</h3>
<p className="text-gray-600 leading-relaxed font-light">
@@ -631,30 +631,30 @@ const AboutPage: React.FC = () => {
</div>
)}
{displayPhone && (
<div className="group text-center p-8 bg-white/80 backdrop-blur-sm rounded-2xl shadow-xl hover:shadow-2xl transition-all duration-500 border border-gray-100 hover:border-[#d4af37]/40 hover:-translate-y-2" style={{ animationDelay: '0.1s' }}>
<div className="w-16 h-16 bg-gradient-to-br from-[#d4af37] via-[#f5d76e] to-[#d4af37] rounded-2xl flex items-center justify-center mx-auto mb-6 shadow-lg shadow-[#d4af37]/20 group-hover:scale-110 group-hover:rotate-3 transition-transform duration-500">
<div className="group text-center p-8 bg-white/80 backdrop-blur-sm rounded-2xl shadow-xl hover:shadow-2xl transition-all duration-500 border border-gray-100 hover:border-[var(--luxury-gold)]/40 hover:-translate-y-2" style={{ animationDelay: '0.1s' }}>
<div className="w-16 h-16 bg-gradient-to-br from-[var(--luxury-gold)] via-[var(--luxury-gold-light)] to-[var(--luxury-gold)] rounded-2xl flex items-center justify-center mx-auto mb-6 shadow-lg shadow-[var(--luxury-gold)]/20 group-hover:scale-110 group-hover:rotate-3 transition-transform duration-500">
<Phone className="w-8 h-8 text-white drop-shadow-md" />
</div>
<h3 className="text-xl font-serif font-semibold text-gray-900 mb-4 group-hover:text-[#d4af37] transition-colors duration-300">
<h3 className="text-xl font-serif font-semibold text-gray-900 mb-4 group-hover:text-[var(--luxury-gold)] transition-colors duration-300">
Phone
</h3>
<p className="text-gray-600 font-light">
<a href={`tel:${displayPhone.replace(/\s+/g, '').replace(/[()]/g, '')}`} className="hover:text-[#d4af37] transition-colors duration-300">
<a href={`tel:${displayPhone.replace(/\s+/g, '').replace(/[()]/g, '')}`} className="hover:text-[var(--luxury-gold)] transition-colors duration-300">
{displayPhone}
</a>
</p>
</div>
)}
{displayEmail && (
<div className="group text-center p-8 bg-white/80 backdrop-blur-sm rounded-2xl shadow-xl hover:shadow-2xl transition-all duration-500 border border-gray-100 hover:border-[#d4af37]/40 hover:-translate-y-2" style={{ animationDelay: '0.2s' }}>
<div className="w-16 h-16 bg-gradient-to-br from-[#d4af37] via-[#f5d76e] to-[#d4af37] rounded-2xl flex items-center justify-center mx-auto mb-6 shadow-lg shadow-[#d4af37]/20 group-hover:scale-110 group-hover:rotate-3 transition-transform duration-500">
<div className="group text-center p-8 bg-white/80 backdrop-blur-sm rounded-2xl shadow-xl hover:shadow-2xl transition-all duration-500 border border-gray-100 hover:border-[var(--luxury-gold)]/40 hover:-translate-y-2" style={{ animationDelay: '0.2s' }}>
<div className="w-16 h-16 bg-gradient-to-br from-[var(--luxury-gold)] via-[var(--luxury-gold-light)] to-[var(--luxury-gold)] rounded-2xl flex items-center justify-center mx-auto mb-6 shadow-lg shadow-[var(--luxury-gold)]/20 group-hover:scale-110 group-hover:rotate-3 transition-transform duration-500">
<Mail className="w-8 h-8 text-white drop-shadow-md" />
</div>
<h3 className="text-xl font-serif font-semibold text-gray-900 mb-4 group-hover:text-[#d4af37] transition-colors duration-300">
<h3 className="text-xl font-serif font-semibold text-gray-900 mb-4 group-hover:text-[var(--luxury-gold)] transition-colors duration-300">
Email
</h3>
<p className="text-gray-600 font-light">
<a href={`mailto:${displayEmail}`} className="hover:text-[#d4af37] transition-colors duration-300">
<a href={`mailto:${displayEmail}`} className="hover:text-[var(--luxury-gold)] transition-colors duration-300">
{displayEmail}
</a>
</p>
@@ -665,11 +665,11 @@ const AboutPage: React.FC = () => {
<div className="text-center">
<Link
to="/rooms"
className="group inline-flex items-center space-x-3 px-10 py-4 bg-gradient-to-r from-[#d4af37] via-[#f5d76e] to-[#d4af37] text-white rounded-xl hover:shadow-2xl hover:shadow-[#d4af37]/40 transition-all duration-500 font-medium text-lg tracking-wide relative overflow-hidden"
className="group inline-flex items-center space-x-3 px-10 py-4 bg-gradient-to-r from-[var(--luxury-gold)] via-[var(--luxury-gold-light)] to-[var(--luxury-gold)] text-white rounded-xl hover:shadow-2xl hover:shadow-[var(--luxury-gold)]/40 transition-all duration-500 font-medium text-lg tracking-wide relative overflow-hidden"
>
<span className="relative z-10">Explore Our Rooms</span>
<Hotel className="w-5 h-5 relative z-10 group-hover:translate-x-1 transition-transform duration-300" />
<div className="absolute inset-0 bg-gradient-to-r from-[#f5d76e] to-[#d4af37] opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div className="absolute inset-0 bg-gradient-to-r from-[var(--luxury-gold-light)] to-[var(--luxury-gold)] opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
</Link>
</div>
</div>

View File

@@ -94,12 +94,12 @@ const AccessibilityPage: React.FC = () => {
}}
>
<div className="text-center">
<Accessibility className="w-16 h-16 text-[#d4af37]/50 mx-auto mb-4" />
<Accessibility className="w-16 h-16 text-[var(--luxury-gold)]/50 mx-auto mb-4" />
<h1 className="text-2xl font-elegant font-bold text-white mb-2">Accessibility</h1>
<p className="text-gray-400">This page is currently unavailable.</p>
<Link
to="/"
className="inline-flex items-center gap-2 text-[#d4af37]/80 hover:text-[#d4af37] mt-6 transition-all duration-300"
className="inline-flex items-center gap-2 text-[var(--luxury-gold)]/80 hover:text-[var(--luxury-gold)] mt-6 transition-all duration-300"
>
<ArrowLeft className="w-4 h-4" />
<span>Back to Home</span>
@@ -123,17 +123,17 @@ const AccessibilityPage: React.FC = () => {
<div className="w-full px-3 sm:px-4 md:px-6 lg:px-8 py-8 sm:py-12 max-w-5xl mx-auto">
<Link
to="/"
className="inline-flex items-center gap-2 text-[#d4af37]/80 hover:text-[#d4af37] mb-6 transition-all duration-300 group font-light tracking-wide text-xs sm:text-sm"
className="inline-flex items-center gap-2 text-[var(--luxury-gold)]/80 hover:text-[var(--luxury-gold)] mb-6 transition-all duration-300 group font-light tracking-wide text-xs sm:text-sm"
>
<ArrowLeft className="w-4 h-4 group-hover:-translate-x-1 transition-transform" />
<span>Back to Home</span>
</Link>
<div className="mb-8 sm:mb-12 text-center">
<div className="inline-flex items-center justify-center w-16 h-16 sm:w-20 sm:h-20 mb-4 sm:mb-6 bg-gradient-to-br from-[#d4af37]/20 to-[#c9a227]/10 rounded-full border border-[#d4af37]/30">
<Accessibility className="w-8 h-8 sm:w-10 sm:h-10 text-[#d4af37]" />
<div className="inline-flex items-center justify-center w-16 h-16 sm:w-20 sm:h-20 mb-4 sm:mb-6 bg-gradient-to-br from-[var(--luxury-gold)]/20 to-[var(--luxury-gold-dark)]/10 rounded-full border border-[var(--luxury-gold)]/30">
<Accessibility className="w-8 h-8 sm:w-10 sm:h-10 text-[var(--luxury-gold)]" />
</div>
<h1 className="text-3xl sm:text-4xl lg:text-5xl font-elegant font-bold text-white mb-3 sm:mb-4 tracking-tight leading-tight bg-gradient-to-r from-white via-[#d4af37] to-white bg-clip-text text-transparent">
<h1 className="text-3xl sm:text-4xl lg:text-5xl font-elegant font-bold text-white mb-3 sm:mb-4 tracking-tight leading-tight bg-gradient-to-r from-white via-[var(--luxury-gold)] to-white bg-clip-text text-transparent">
{pageContent.title || 'Accessibility'}
</h1>
{pageContent.subtitle && (
@@ -143,18 +143,18 @@ const AccessibilityPage: React.FC = () => {
)}
</div>
<div className="bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-xl border border-[#d4af37]/20 backdrop-blur-xl shadow-2xl shadow-[#d4af37]/5 p-6 sm:p-8 lg:p-12">
<div className="bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-xl border border-[var(--luxury-gold)]/20 backdrop-blur-xl shadow-2xl shadow-[var(--luxury-gold)]/5 p-6 sm:p-8 lg:p-12">
<div
className="prose prose-invert prose-lg max-w-none text-gray-300
prose-headings:text-white prose-headings:font-elegant prose-headings:font-semibold
prose-h2:text-2xl prose-h2:mt-8 prose-h2:mb-4 prose-h2:border-b prose-h2:border-[#d4af37]/20 prose-h2:pb-2
prose-h2:text-2xl prose-h2:mt-8 prose-h2:mb-4 prose-h2:border-b prose-h2:border-[var(--luxury-gold)]/20 prose-h2:pb-2
prose-p:text-gray-300 prose-p:font-light prose-p:leading-relaxed prose-p:mb-4
prose-ul:text-gray-300 prose-ul:font-light prose-ul:my-4
prose-li:text-gray-300 prose-li:mb-2 prose-li:ml-4
prose-strong:text-[#d4af37] prose-strong:font-medium
prose-a:text-[#d4af37] prose-a:no-underline hover:prose-a:underline
prose-strong:text-[var(--luxury-gold)] prose-strong:font-medium
prose-a:text-[var(--luxury-gold)] prose-a:no-underline hover:prose-a:underline
[&_*]:text-gray-300 [&_h1]:text-white [&_h2]:text-white [&_h3]:text-white [&_h4]:text-white [&_h5]:text-white [&_h6]:text-white
[&_strong]:text-[#d4af37] [&_b]:text-[#d4af37] [&_a]:text-[#d4af37]"
[&_strong]:text-[var(--luxury-gold)] [&_b]:text-[var(--luxury-gold)] [&_a]:text-[var(--luxury-gold)]"
style={{ color: '#d1d5db' }}
dangerouslySetInnerHTML={createSanitizedHtml(
pageContent.content || pageContent.description || '<p style="color: #d1d5db;">No content available.</p>'
@@ -166,7 +166,7 @@ const AccessibilityPage: React.FC = () => {
<div className="mt-8 text-center">
<p className="text-sm text-gray-400 font-light">
For accessibility inquiries, contact us at{' '}
<a href={`mailto:${settings.company_email}`} className="text-[#d4af37] hover:underline">
<a href={`mailto:${settings.company_email}`} className="text-[var(--luxury-gold)] hover:underline">
{settings.company_email}
</a>
</p>

View File

@@ -111,7 +111,7 @@ const BlogDetailPage: React.FC = () => {
<div className="min-h-screen bg-gradient-to-b from-[#0f0f0f] via-[#1a1a1a] to-black text-white flex items-center justify-center">
<div className="text-center">
<h1 className="text-2xl font-bold mb-4">Post not found</h1>
<Link to="/blog" className="text-[#d4af37] hover:underline">
<Link to="/blog" className="text-[var(--luxury-gold)] hover:underline">
Back to Blog
</Link>
</div>
@@ -140,7 +140,7 @@ const BlogDetailPage: React.FC = () => {
{/* Back Button */}
<Link
to="/blog"
className="inline-flex items-center gap-2 text-gray-400 hover:text-[#d4af37] transition-colors mb-8"
className="inline-flex items-center gap-2 text-gray-400 hover:text-[var(--luxury-gold)] transition-colors mb-8"
>
<ArrowLeft className="w-4 h-4" />
<span>Back to Blog</span>
@@ -154,7 +154,7 @@ const BlogDetailPage: React.FC = () => {
<Link
key={tag}
to={`/blog?tag=${encodeURIComponent(tag)}`}
className="inline-flex items-center gap-1 px-3 py-1 bg-[#d4af37]/10 text-[#d4af37] rounded-full text-sm font-medium hover:bg-[#d4af37]/20 transition-colors"
className="inline-flex items-center gap-1 px-3 py-1 bg-[var(--luxury-gold)]/10 text-[var(--luxury-gold)] rounded-full text-sm font-medium hover:bg-[var(--luxury-gold)]/20 transition-colors"
>
<Tag className="w-3 h-3" />
{tag}
@@ -173,7 +173,7 @@ const BlogDetailPage: React.FC = () => {
</p>
)}
<div className="flex flex-wrap items-center gap-6 text-sm text-gray-400 pb-6 border-b border-[#d4af37]/20">
<div className="flex flex-wrap items-center gap-6 text-sm text-gray-400 pb-6 border-b border-[var(--luxury-gold)]/20">
{post.published_at && (
<div className="flex items-center gap-2">
<Calendar className="w-4 h-4" />
@@ -192,7 +192,7 @@ const BlogDetailPage: React.FC = () => {
</div>
<button
onClick={handleShare}
className="flex items-center gap-2 text-[#d4af37] hover:text-[#f5d76e] transition-colors"
className="flex items-center gap-2 text-[var(--luxury-gold)] hover:text-[var(--luxury-gold-light)] transition-colors"
>
<Share2 className="w-4 h-4" />
<span>Share</span>
@@ -203,17 +203,17 @@ const BlogDetailPage: React.FC = () => {
{/* Article Content */}
<article className="prose prose-invert prose-lg max-w-none mb-12
prose-headings:text-white prose-headings:font-elegant prose-headings:font-semibold
prose-h2:text-3xl prose-h2:mt-12 prose-h2:mb-6 prose-h2:border-b prose-h2:border-[#d4af37]/20 prose-h2:pb-3
prose-h2:text-3xl prose-h2:mt-12 prose-h2:mb-6 prose-h2:border-b prose-h2:border-[var(--luxury-gold)]/20 prose-h2:pb-3
prose-h3:text-2xl prose-h3:mt-8 prose-h3:mb-4
prose-p:text-gray-300 prose-p:font-light prose-p:leading-relaxed prose-p:mb-6
prose-ul:text-gray-300 prose-ul:font-light prose-ul:my-6
prose-ol:text-gray-300 prose-ol:font-light prose-ol:my-6
prose-li:text-gray-300 prose-li:mb-2
prose-strong:text-[#d4af37] prose-strong:font-medium
prose-a:text-[#d4af37] prose-a:no-underline hover:prose-a:underline
prose-strong:text-[var(--luxury-gold)] prose-strong:font-medium
prose-a:text-[var(--luxury-gold)] prose-a:no-underline hover:prose-a:underline
prose-img:rounded-xl prose-img:shadow-2xl
[&_*]:text-gray-300 [&_h1]:text-white [&_h2]:text-white [&_h3]:text-white [&_h4]:text-white
[&_strong]:text-[#d4af37] [&_b]:text-[#d4af37] [&_a]:text-[#d4af37]"
[&_strong]:text-[var(--luxury-gold)] [&_b]:text-[var(--luxury-gold)] [&_a]:text-[var(--luxury-gold)]"
>
<div
dangerouslySetInnerHTML={createSanitizedHtml(
@@ -231,7 +231,7 @@ const BlogDetailPage: React.FC = () => {
<div key={index}>
{/* Hero Section */}
{section.type === 'hero' && (
<div className="relative rounded-3xl overflow-hidden border-2 border-[#d4af37]/20 shadow-2xl">
<div className="relative rounded-3xl overflow-hidden border-2 border-[var(--luxury-gold)]/20 shadow-2xl">
{section.image && (
<div className="absolute inset-0">
<img src={section.image} alt={section.title} className="w-full h-full object-cover" />
@@ -255,7 +255,7 @@ const BlogDetailPage: React.FC = () => {
{/* Text Section */}
{section.type === 'text' && (
<div className={`bg-gradient-to-br from-[#1a1a1a] to-[#0f0f0f] rounded-3xl border-2 border-[#d4af37]/20 p-8 md:p-12 shadow-xl ${
<div className={`bg-gradient-to-br from-[#1a1a1a] to-[#0f0f0f] rounded-3xl border-2 border-[var(--luxury-gold)]/20 p-8 md:p-12 shadow-xl ${
section.alignment === 'center' ? 'text-center' : section.alignment === 'right' ? 'text-right' : 'text-left'
}`}>
{section.title && (
@@ -274,10 +274,10 @@ const BlogDetailPage: React.FC = () => {
{/* Image Section */}
{section.type === 'image' && section.image && (
<div className="rounded-3xl overflow-hidden border-2 border-[#d4af37]/20 shadow-2xl">
<div className="rounded-3xl overflow-hidden border-2 border-[var(--luxury-gold)]/20 shadow-2xl">
<img src={section.image} alt={section.title || 'Blog image'} className="w-full h-auto" />
{section.title && (
<div className="bg-gradient-to-br from-[#1a1a1a] to-[#0f0f0f] px-6 py-4 border-t border-[#d4af37]/20">
<div className="bg-gradient-to-br from-[#1a1a1a] to-[#0f0f0f] px-6 py-4 border-t border-[var(--luxury-gold)]/20">
<p className="text-gray-400 text-sm font-light italic text-center">{section.title}</p>
</div>
)}
@@ -288,7 +288,7 @@ const BlogDetailPage: React.FC = () => {
{section.type === 'gallery' && section.images && section.images.length > 0 && (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{section.images.map((img, imgIndex) => (
<div key={imgIndex} className="rounded-2xl overflow-hidden border-2 border-[#d4af37]/20 shadow-xl group hover:border-[#d4af37]/50 transition-all">
<div key={imgIndex} className="rounded-2xl overflow-hidden border-2 border-[var(--luxury-gold)]/20 shadow-xl group hover:border-[var(--luxury-gold)]/50 transition-all">
<img src={img} alt={`Gallery image ${imgIndex + 1}`} className="w-full h-64 object-cover group-hover:scale-110 transition-transform duration-500" />
</div>
))}
@@ -297,15 +297,15 @@ const BlogDetailPage: React.FC = () => {
{/* Quote Section */}
{section.type === 'quote' && (
<div className="relative bg-gradient-to-br from-[#1a1a1a] to-[#0f0f0f] rounded-3xl border-2 border-[#d4af37]/30 p-8 md:p-12 shadow-2xl">
<div className="absolute top-6 left-6 text-6xl text-[#d4af37]/20 font-serif">"</div>
<div className="relative bg-gradient-to-br from-[#1a1a1a] to-[#0f0f0f] rounded-3xl border-2 border-[var(--luxury-gold)]/30 p-8 md:p-12 shadow-2xl">
<div className="absolute top-6 left-6 text-6xl text-[var(--luxury-gold)]/20 font-serif">"</div>
{section.quote && (
<blockquote className="text-2xl md:text-3xl font-serif font-light text-white italic mb-6 relative z-10 pl-8">
{section.quote}
</blockquote>
)}
{section.author && (
<cite className="text-[#d4af37] text-lg font-medium not-italic block text-right">
<cite className="text-[var(--luxury-gold)] text-lg font-medium not-italic block text-right">
— {section.author}
</cite>
)}
@@ -316,7 +316,7 @@ const BlogDetailPage: React.FC = () => {
{section.type === 'features' && section.features && (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{section.features.map((feature, featIndex) => (
<div key={featIndex} className="bg-gradient-to-br from-[#1a1a1a] to-[#0f0f0f] rounded-2xl border-2 border-[#d4af37]/20 p-6 shadow-xl hover:border-[#d4af37]/50 transition-all">
<div key={featIndex} className="bg-gradient-to-br from-[#1a1a1a] to-[#0f0f0f] rounded-2xl border-2 border-[var(--luxury-gold)]/20 p-6 shadow-xl hover:border-[var(--luxury-gold)]/50 transition-all">
{feature.icon && (
<div className="text-4xl mb-4">{feature.icon}</div>
)}
@@ -329,7 +329,7 @@ const BlogDetailPage: React.FC = () => {
{/* CTA Section */}
{section.type === 'cta' && (
<div className="relative bg-gradient-to-br from-[#d4af37]/10 via-[#c9a227]/5 to-[#d4af37]/10 rounded-3xl border-2 border-[#d4af37]/30 p-8 md:p-12 text-center shadow-2xl">
<div className="relative bg-gradient-to-br from-[var(--luxury-gold)]/10 via-[var(--luxury-gold-dark)]/5 to-[var(--luxury-gold)]/10 rounded-3xl border-2 border-[var(--luxury-gold)]/30 p-8 md:p-12 text-center shadow-2xl">
{section.title && (
<h3 className="text-3xl md:text-4xl font-serif font-bold text-white mb-4">
{section.title}
@@ -343,7 +343,7 @@ const BlogDetailPage: React.FC = () => {
{section.cta_text && section.cta_link && (
<a
href={section.cta_link}
className="inline-flex items-center gap-3 px-8 py-4 bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-[#0f0f0f] font-semibold rounded-xl hover:from-[#f5d76e] hover:to-[#d4af37] transition-all shadow-lg hover:shadow-xl hover:scale-105"
className="inline-flex items-center gap-3 px-8 py-4 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-[#0f0f0f] font-semibold rounded-xl hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] transition-all shadow-lg hover:shadow-xl hover:scale-105"
>
{section.cta_text}
<ArrowRight className="w-5 h-5" />
@@ -354,7 +354,7 @@ const BlogDetailPage: React.FC = () => {
{/* Video Section */}
{section.type === 'video' && section.video_url && (
<div className="rounded-3xl overflow-hidden border-2 border-[#d4af37]/20 shadow-2xl bg-black">
<div className="rounded-3xl overflow-hidden border-2 border-[var(--luxury-gold)]/20 shadow-2xl bg-black">
<div className="aspect-video">
<iframe
src={section.video_url.replace('watch?v=', 'embed/').replace('vimeo.com/', 'player.vimeo.com/video/')}
@@ -372,14 +372,14 @@ const BlogDetailPage: React.FC = () => {
{/* Related Posts */}
{relatedPosts.length > 0 && (
<div className="mt-16 pt-12 border-t border-[#d4af37]/20">
<div className="mt-16 pt-12 border-t border-[var(--luxury-gold)]/20">
<h2 className="text-2xl sm:text-3xl font-bold text-white mb-8">Related Posts</h2>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{relatedPosts.map((relatedPost) => (
<Link
key={relatedPost.id}
to={`/blog/${relatedPost.slug}`}
className="group bg-gradient-to-br from-[#1a1a1a] to-[#0f0f0f] rounded-xl border border-[#d4af37]/20 overflow-hidden hover:border-[#d4af37]/50 transition-all duration-300"
className="group bg-gradient-to-br from-[#1a1a1a] to-[#0f0f0f] rounded-xl border border-[var(--luxury-gold)]/20 overflow-hidden hover:border-[var(--luxury-gold)]/50 transition-all duration-300"
>
{relatedPost.featured_image && (
<div className="relative h-40 overflow-hidden">
@@ -391,7 +391,7 @@ const BlogDetailPage: React.FC = () => {
</div>
)}
<div className="p-4">
<h3 className="text-lg font-bold text-white mb-2 group-hover:text-[#d4af37] transition-colors line-clamp-2">
<h3 className="text-lg font-bold text-white mb-2 group-hover:text-[var(--luxury-gold)] transition-colors line-clamp-2">
{relatedPost.title}
</h3>
{relatedPost.excerpt && (

View File

@@ -70,41 +70,41 @@ const BlogPage: React.FC = () => {
return (
<div className="min-h-screen bg-gradient-to-b from-[#0f0f0f] via-[#1a1a1a] to-[#0f0f0f] w-full" style={{ width: '100vw', position: 'relative', left: '50%', right: '50%', marginLeft: '-50vw', marginRight: '-50vw', marginTop: '-1.5rem', marginBottom: '-1.5rem' }}>
{/* Hero Section */}
<div className="w-full bg-gradient-to-br from-[#1a1a1a] via-[#0f0f0f] to-[#1a1a1a] border-b border-[#d4af37]/10 pt-6 sm:pt-7 md:pt-8 overflow-hidden relative">
<div className="w-full bg-gradient-to-br from-[#1a1a1a] via-[#0f0f0f] to-[#1a1a1a] border-b border-[var(--luxury-gold)]/10 pt-6 sm:pt-7 md:pt-8 overflow-hidden relative">
{/* Background Effects */}
<div className="absolute inset-0 opacity-10">
<div className="absolute top-10 left-10 w-32 sm:w-48 h-32 sm:h-48 bg-[#d4af37] rounded-full blur-3xl"></div>
<div className="absolute bottom-10 right-10 w-40 sm:w-64 h-40 sm:h-64 bg-[#c9a227] rounded-full blur-3xl"></div>
<div className="absolute top-10 left-10 w-32 sm:w-48 h-32 sm:h-48 bg-[var(--luxury-gold)] rounded-full blur-3xl"></div>
<div className="absolute bottom-10 right-10 w-40 sm:w-64 h-40 sm:h-64 bg-[var(--luxury-gold-dark)] rounded-full blur-3xl"></div>
</div>
<div className="absolute top-0 left-0 w-full h-px bg-gradient-to-r from-transparent via-[#d4af37]/50 to-transparent"></div>
<div className="absolute top-0 left-0 w-full h-px bg-gradient-to-r from-transparent via-[var(--luxury-gold)]/50 to-transparent"></div>
<div className="w-full max-w-[1920px] mx-auto px-3 sm:px-4 md:px-6 lg:px-8 xl:px-12 2xl:px-16 3xl:px-20 py-4 sm:py-5 md:py-6 relative z-10">
<div className="max-w-2xl mx-auto text-center px-2">
<div className="flex justify-center mb-2 sm:mb-3 md:mb-4">
<div className="relative group">
<div className="absolute inset-0 bg-gradient-to-br from-[#d4af37] via-[#f5d76e] to-[#c9a227] rounded-xl blur-lg opacity-40 group-hover:opacity-60 transition-opacity duration-500"></div>
<div className="relative p-2 sm:p-2.5 md:p-3 bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-lg border-2 border-[#d4af37]/40 backdrop-blur-sm shadow-xl shadow-[#d4af37]/20 group-hover:border-[#d4af37]/60 transition-all duration-300">
<BookOpen className="w-5 h-5 sm:w-6 sm:h-6 md:w-7 md:h-7 text-[#d4af37] drop-shadow-lg" />
<div className="absolute inset-0 bg-gradient-to-br from-[var(--luxury-gold)] via-[var(--luxury-gold-light)] to-[var(--luxury-gold-dark)] rounded-xl blur-lg opacity-40 group-hover:opacity-60 transition-opacity duration-500"></div>
<div className="relative p-2 sm:p-2.5 md:p-3 bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-lg border-2 border-[var(--luxury-gold)]/40 backdrop-blur-sm shadow-xl shadow-[var(--luxury-gold)]/20 group-hover:border-[var(--luxury-gold)]/60 transition-all duration-300">
<BookOpen className="w-5 h-5 sm:w-6 sm:h-6 md:w-7 md:h-7 text-[var(--luxury-gold)] drop-shadow-lg" />
</div>
</div>
</div>
<h1 className="text-2xl xs:text-3xl sm:text-4xl md:text-5xl font-serif font-semibold mb-2 sm:mb-3 tracking-tight leading-tight px-2">
<span className="bg-gradient-to-r from-white via-[#d4af37] to-white bg-clip-text text-transparent">
<span className="bg-gradient-to-r from-white via-[var(--luxury-gold)] to-white bg-clip-text text-transparent">
Our Blog
</span>
</h1>
<div className="w-12 sm:w-16 md:w-20 h-0.5 bg-gradient-to-r from-transparent via-[#d4af37] to-transparent mx-auto mb-2 sm:mb-3"></div>
<div className="w-12 sm:w-16 md:w-20 h-0.5 bg-gradient-to-r from-transparent via-[var(--luxury-gold)] to-transparent mx-auto mb-2 sm:mb-3"></div>
<p className="text-sm sm:text-base md:text-lg text-gray-300 font-light leading-relaxed max-w-xl mx-auto tracking-wide px-2 sm:px-4">
Discover stories, insights, and updates from our luxury hotel
</p>
<div className="mt-4 flex items-center justify-center gap-2 text-[#d4af37]/60">
<div className="mt-4 flex items-center justify-center gap-2 text-[var(--luxury-gold)]/60">
<Sparkles className="w-4 h-4 animate-pulse" />
<span className="text-xs sm:text-sm font-light tracking-wider uppercase">Premium Content</span>
<Sparkles className="w-4 h-4 animate-pulse" style={{ animationDelay: '0.5s' }} />
</div>
</div>
</div>
<div className="absolute bottom-0 left-0 w-full h-px bg-gradient-to-r from-transparent via-[#d4af37]/30 to-transparent"></div>
<div className="absolute bottom-0 left-0 w-full h-px bg-gradient-to-r from-transparent via-[var(--luxury-gold)]/30 to-transparent"></div>
</div>
{/* Main Content - Full Width */}
@@ -114,9 +114,9 @@ const BlogPage: React.FC = () => {
<div className="mb-12 sm:mb-16">
<div className="flex flex-col lg:flex-row gap-6 mb-8">
<div className="flex-1 relative group">
<div className="absolute inset-0 bg-gradient-to-r from-[#d4af37]/10 to-transparent rounded-xl blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div className="absolute inset-0 bg-gradient-to-r from-[var(--luxury-gold)]/10 to-transparent rounded-xl blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div className="relative">
<Search className="absolute left-5 top-1/2 transform -translate-y-1/2 text-[#d4af37] w-5 h-5 z-10" />
<Search className="absolute left-5 top-1/2 transform -translate-y-1/2 text-[var(--luxury-gold)] w-5 h-5 z-10" />
<input
type="text"
placeholder="Search blog posts..."
@@ -125,7 +125,7 @@ const BlogPage: React.FC = () => {
setSearchTerm(e.target.value);
setCurrentPage(1);
}}
className="w-full pl-14 pr-5 py-4 bg-gradient-to-br from-[#1a1a1a] to-[#0f0f0f] border border-[#d4af37]/20 rounded-xl text-white placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37]/50 transition-all duration-300 backdrop-blur-sm font-light"
className="w-full pl-14 pr-5 py-4 bg-gradient-to-br from-[#1a1a1a] to-[#0f0f0f] border border-[var(--luxury-gold)]/20 rounded-xl text-white placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)]/50 transition-all duration-300 backdrop-blur-sm font-light"
/>
</div>
</div>
@@ -147,8 +147,8 @@ const BlogPage: React.FC = () => {
{/* Blog Posts Grid - Luxury Design */}
{posts.length === 0 ? (
<div className="text-center py-20">
<div className="inline-flex items-center justify-center w-20 h-20 rounded-full bg-[#d4af37]/10 mb-6">
<BookOpen className="w-10 h-10 text-[#d4af37]" />
<div className="inline-flex items-center justify-center w-20 h-20 rounded-full bg-[var(--luxury-gold)]/10 mb-6">
<BookOpen className="w-10 h-10 text-[var(--luxury-gold)]" />
</div>
<p className="text-gray-400 text-xl font-light">No blog posts found</p>
<p className="text-gray-500 text-sm mt-2">Try adjusting your search or filters</p>
@@ -160,12 +160,12 @@ const BlogPage: React.FC = () => {
<Link
key={post.id}
to={`/blog/${post.slug}`}
className="group relative bg-gradient-to-br from-[#1a1a1a] via-[#0f0f0f] to-[#0a0a0a] rounded-3xl border-2 border-[#d4af37]/20 overflow-hidden hover:border-[#d4af37]/60 transition-all duration-700 hover:shadow-2xl hover:shadow-[#d4af37]/30 hover:-translate-y-3"
className="group relative bg-gradient-to-br from-[#1a1a1a] via-[#0f0f0f] to-[#0a0a0a] rounded-3xl border-2 border-[var(--luxury-gold)]/20 overflow-hidden hover:border-[var(--luxury-gold)]/60 transition-all duration-700 hover:shadow-2xl hover:shadow-[var(--luxury-gold)]/30 hover:-translate-y-3"
style={{ animationDelay: `${index * 50}ms` }}
>
{/* Premium Glow Effects */}
<div className="absolute inset-0 bg-gradient-to-br from-[#d4af37]/0 via-[#d4af37]/0 to-[#d4af37]/0 group-hover:from-[#d4af37]/10 group-hover:via-[#d4af37]/5 group-hover:to-[#d4af37]/10 transition-all duration-700 rounded-3xl blur-2xl opacity-0 group-hover:opacity-100"></div>
<div className="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-transparent via-[#d4af37]/50 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div className="absolute inset-0 bg-gradient-to-br from-[var(--luxury-gold)]/0 via-[var(--luxury-gold)]/0 to-[var(--luxury-gold)]/0 group-hover:from-[var(--luxury-gold)]/10 group-hover:via-[var(--luxury-gold)]/5 group-hover:to-[var(--luxury-gold)]/10 transition-all duration-700 rounded-3xl blur-2xl opacity-0 group-hover:opacity-100"></div>
<div className="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-transparent via-[var(--luxury-gold)]/50 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
{/* Content */}
<div className="relative z-10">
@@ -179,15 +179,15 @@ const BlogPage: React.FC = () => {
/>
{/* Premium Badge Overlay */}
<div className="absolute top-6 left-6 z-20">
<div className="bg-gradient-to-br from-[#d4af37]/20 to-[#c9a227]/10 backdrop-blur-md rounded-2xl px-4 py-2 border border-[#d4af37]/40 shadow-xl">
<div className="flex items-center gap-2 text-[#d4af37]">
<div className="bg-gradient-to-br from-[var(--luxury-gold)]/20 to-[var(--luxury-gold-dark)]/10 backdrop-blur-md rounded-2xl px-4 py-2 border border-[var(--luxury-gold)]/40 shadow-xl">
<div className="flex items-center gap-2 text-[var(--luxury-gold)]">
<Eye className="w-4 h-4" />
<span className="text-sm font-semibold">{post.views_count}</span>
</div>
</div>
</div>
{/* Luxury Corner Accent */}
<div className="absolute top-0 right-0 w-32 h-32 bg-gradient-to-br from-[#d4af37]/20 to-transparent rounded-bl-full opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div className="absolute top-0 right-0 w-32 h-32 bg-gradient-to-br from-[var(--luxury-gold)]/20 to-transparent rounded-bl-full opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
</div>
)}
<div className="p-8">
@@ -196,7 +196,7 @@ const BlogPage: React.FC = () => {
{post.tags.slice(0, 2).map((tag) => (
<span
key={tag}
className="inline-flex items-center gap-1.5 px-4 py-1.5 bg-gradient-to-br from-[#d4af37]/15 to-[#d4af37]/5 text-[#d4af37] rounded-full text-xs font-semibold border border-[#d4af37]/30 backdrop-blur-sm shadow-lg"
className="inline-flex items-center gap-1.5 px-4 py-1.5 bg-gradient-to-br from-[var(--luxury-gold)]/15 to-[var(--luxury-gold)]/5 text-[var(--luxury-gold)] rounded-full text-xs font-semibold border border-[var(--luxury-gold)]/30 backdrop-blur-sm shadow-lg"
>
<Tag className="w-3 h-3" />
{tag}
@@ -204,7 +204,7 @@ const BlogPage: React.FC = () => {
))}
</div>
)}
<h2 className="text-2xl sm:text-3xl font-serif font-bold text-white mb-4 group-hover:text-[#d4af37] transition-colors duration-500 line-clamp-2 leading-tight tracking-tight">
<h2 className="text-2xl sm:text-3xl font-serif font-bold text-white mb-4 group-hover:text-[var(--luxury-gold)] transition-colors duration-500 line-clamp-2 leading-tight tracking-tight">
{post.title}
</h2>
{post.excerpt && (
@@ -212,28 +212,28 @@ const BlogPage: React.FC = () => {
{post.excerpt}
</p>
)}
<div className="flex items-center justify-between text-sm text-gray-400 pt-6 border-t border-[#d4af37]/20 mb-6">
<div className="flex items-center justify-between text-sm text-gray-400 pt-6 border-t border-[var(--luxury-gold)]/20 mb-6">
<div className="flex items-center gap-4">
{post.published_at && (
<div className="flex items-center gap-2">
<Calendar className="w-4 h-4 text-[#d4af37]" />
<Calendar className="w-4 h-4 text-[var(--luxury-gold)]" />
<span className="font-light">{formatDate(post.published_at)}</span>
</div>
)}
</div>
{post.author_name && (
<div className="flex items-center gap-2">
<User className="w-4 h-4 text-[#d4af37]" />
<User className="w-4 h-4 text-[var(--luxury-gold)]" />
<span className="font-light">{post.author_name}</span>
</div>
)}
</div>
<div className="flex items-center justify-between pt-4 border-t border-[#d4af37]/10">
<div className="flex items-center gap-3 text-[#d4af37] group-hover:gap-4 transition-all duration-300">
<div className="flex items-center justify-between pt-4 border-t border-[var(--luxury-gold)]/10">
<div className="flex items-center gap-3 text-[var(--luxury-gold)] group-hover:gap-4 transition-all duration-300">
<span className="text-sm font-semibold tracking-wide uppercase">Read Article</span>
<ArrowRight className="w-5 h-5 group-hover:translate-x-2 transition-transform duration-300" />
</div>
<div className="w-12 h-0.5 bg-gradient-to-r from-[#d4af37] to-transparent group-hover:w-20 transition-all duration-500"></div>
<div className="w-12 h-0.5 bg-gradient-to-r from-[var(--luxury-gold)] to-transparent group-hover:w-20 transition-all duration-500"></div>
</div>
</div>
</div>
@@ -259,9 +259,9 @@ const BlogPage: React.FC = () => {
<div className="lg:col-span-3">
{allTags.length > 0 && (
<div className="sticky top-8">
<div className="bg-gradient-to-br from-[#1a1a1a] via-[#0f0f0f] to-[#0a0a0a] rounded-3xl border-2 border-[#d4af37]/20 p-8 backdrop-blur-xl shadow-2xl">
<div className="flex items-center gap-3 mb-6 pb-6 border-b border-[#d4af37]/20">
<div className="w-1 h-8 bg-gradient-to-b from-[#d4af37] to-[#c9a227] rounded-full"></div>
<div className="bg-gradient-to-br from-[#1a1a1a] via-[#0f0f0f] to-[#0a0a0a] rounded-3xl border-2 border-[var(--luxury-gold)]/20 p-8 backdrop-blur-xl shadow-2xl">
<div className="flex items-center gap-3 mb-6 pb-6 border-b border-[var(--luxury-gold)]/20">
<div className="w-1 h-8 bg-gradient-to-b from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] rounded-full"></div>
<h3 className="text-xl font-serif font-bold text-white">Filter by Tags</h3>
</div>
<div className="space-y-3">
@@ -272,8 +272,8 @@ const BlogPage: React.FC = () => {
}}
className={`group relative w-full text-left px-5 py-4 rounded-2xl text-sm font-medium transition-all duration-300 overflow-hidden ${
selectedTag === null
? 'bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-[#0f0f0f] shadow-lg shadow-[#d4af37]/40'
: 'bg-gradient-to-br from-[#0f0f0f] to-[#0a0a0a] text-gray-300 border-2 border-[#d4af37]/20 hover:border-[#d4af37]/50 hover:text-[#d4af37] hover:bg-[#1a1a1a]'
? 'bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-[#0f0f0f] shadow-lg shadow-[var(--luxury-gold)]/40'
: 'bg-gradient-to-br from-[#0f0f0f] to-[#0a0a0a] text-gray-300 border-2 border-[var(--luxury-gold)]/20 hover:border-[var(--luxury-gold)]/50 hover:text-[var(--luxury-gold)] hover:bg-[#1a1a1a]'
}`}
>
<span className="relative z-10 flex items-center gap-2">
@@ -293,8 +293,8 @@ const BlogPage: React.FC = () => {
}}
className={`group relative w-full text-left px-5 py-4 rounded-2xl text-sm font-medium transition-all duration-300 overflow-hidden ${
selectedTag === tag
? 'bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-[#0f0f0f] shadow-lg shadow-[#d4af37]/40'
: 'bg-gradient-to-br from-[#0f0f0f] to-[#0a0a0a] text-gray-300 border-2 border-[#d4af37]/20 hover:border-[#d4af37]/50 hover:text-[#d4af37] hover:bg-[#1a1a1a]'
? 'bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-[#0f0f0f] shadow-lg shadow-[var(--luxury-gold)]/40'
: 'bg-gradient-to-br from-[#0f0f0f] to-[#0a0a0a] text-gray-300 border-2 border-[var(--luxury-gold)]/20 hover:border-[var(--luxury-gold)]/50 hover:text-[var(--luxury-gold)] hover:bg-[#1a1a1a]'
}`}
>
<span className="relative z-10 flex items-center gap-2">

View File

@@ -94,12 +94,12 @@ const CancellationPolicyPage: React.FC = () => {
}}
>
<div className="text-center">
<XCircle className="w-16 h-16 text-[#d4af37]/50 mx-auto mb-4" />
<XCircle className="w-16 h-16 text-[var(--luxury-gold)]/50 mx-auto mb-4" />
<h1 className="text-2xl font-elegant font-bold text-white mb-2">Cancellation Policy</h1>
<p className="text-gray-400">This page is currently unavailable.</p>
<Link
to="/"
className="inline-flex items-center gap-2 text-[#d4af37]/80 hover:text-[#d4af37] mt-6 transition-all duration-300"
className="inline-flex items-center gap-2 text-[var(--luxury-gold)]/80 hover:text-[var(--luxury-gold)] mt-6 transition-all duration-300"
>
<ArrowLeft className="w-4 h-4" />
<span>Back to Home</span>
@@ -123,17 +123,17 @@ const CancellationPolicyPage: React.FC = () => {
<div className="w-full px-3 sm:px-4 md:px-6 lg:px-8 py-8 sm:py-12 max-w-5xl mx-auto">
<Link
to="/"
className="inline-flex items-center gap-2 text-[#d4af37]/80 hover:text-[#d4af37] mb-6 transition-all duration-300 group font-light tracking-wide text-xs sm:text-sm"
className="inline-flex items-center gap-2 text-[var(--luxury-gold)]/80 hover:text-[var(--luxury-gold)] mb-6 transition-all duration-300 group font-light tracking-wide text-xs sm:text-sm"
>
<ArrowLeft className="w-4 h-4 group-hover:-translate-x-1 transition-transform" />
<span>Back to Home</span>
</Link>
<div className="mb-8 sm:mb-12 text-center">
<div className="inline-flex items-center justify-center w-16 h-16 sm:w-20 sm:h-20 mb-4 sm:mb-6 bg-gradient-to-br from-[#d4af37]/20 to-[#c9a227]/10 rounded-full border border-[#d4af37]/30">
<XCircle className="w-8 h-8 sm:w-10 sm:h-10 text-[#d4af37]" />
<div className="inline-flex items-center justify-center w-16 h-16 sm:w-20 sm:h-20 mb-4 sm:mb-6 bg-gradient-to-br from-[var(--luxury-gold)]/20 to-[var(--luxury-gold-dark)]/10 rounded-full border border-[var(--luxury-gold)]/30">
<XCircle className="w-8 h-8 sm:w-10 sm:h-10 text-[var(--luxury-gold)]" />
</div>
<h1 className="text-3xl sm:text-4xl lg:text-5xl font-elegant font-bold text-white mb-3 sm:mb-4 tracking-tight leading-tight bg-gradient-to-r from-white via-[#d4af37] to-white bg-clip-text text-transparent">
<h1 className="text-3xl sm:text-4xl lg:text-5xl font-elegant font-bold text-white mb-3 sm:mb-4 tracking-tight leading-tight bg-gradient-to-r from-white via-[var(--luxury-gold)] to-white bg-clip-text text-transparent">
{pageContent.title || 'Cancellation Policy'}
</h1>
{pageContent.subtitle && (
@@ -143,18 +143,18 @@ const CancellationPolicyPage: React.FC = () => {
)}
</div>
<div className="bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-xl border border-[#d4af37]/20 backdrop-blur-xl shadow-2xl shadow-[#d4af37]/5 p-6 sm:p-8 lg:p-12">
<div className="bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-xl border border-[var(--luxury-gold)]/20 backdrop-blur-xl shadow-2xl shadow-[var(--luxury-gold)]/5 p-6 sm:p-8 lg:p-12">
<div
className="prose prose-invert prose-lg max-w-none text-gray-300
prose-headings:text-white prose-headings:font-elegant prose-headings:font-semibold
prose-h2:text-2xl prose-h2:mt-8 prose-h2:mb-4 prose-h2:border-b prose-h2:border-[#d4af37]/20 prose-h2:pb-2
prose-h2:text-2xl prose-h2:mt-8 prose-h2:mb-4 prose-h2:border-b prose-h2:border-[var(--luxury-gold)]/20 prose-h2:pb-2
prose-p:text-gray-300 prose-p:font-light prose-p:leading-relaxed prose-p:mb-4
prose-ul:text-gray-300 prose-ul:font-light prose-ul:my-4
prose-li:text-gray-300 prose-li:mb-2 prose-li:ml-4
prose-strong:text-[#d4af37] prose-strong:font-medium
prose-a:text-[#d4af37] prose-a:no-underline hover:prose-a:underline
prose-strong:text-[var(--luxury-gold)] prose-strong:font-medium
prose-a:text-[var(--luxury-gold)] prose-a:no-underline hover:prose-a:underline
[&_*]:text-gray-300 [&_h1]:text-white [&_h2]:text-white [&_h3]:text-white [&_h4]:text-white [&_h5]:text-white [&_h6]:text-white
[&_strong]:text-[#d4af37] [&_b]:text-[#d4af37] [&_a]:text-[#d4af37]"
[&_strong]:text-[var(--luxury-gold)] [&_b]:text-[var(--luxury-gold)] [&_a]:text-[var(--luxury-gold)]"
style={{ color: '#d1d5db' }}
dangerouslySetInnerHTML={createSanitizedHtml(
pageContent.content || pageContent.description || '<p style="color: #d1d5db;">No content available.</p>'
@@ -166,7 +166,7 @@ const CancellationPolicyPage: React.FC = () => {
<div className="mt-8 text-center">
<p className="text-sm text-gray-400 font-light">
For questions about cancellations, contact us at{' '}
<a href={`mailto:${settings.company_email}`} className="text-[#d4af37] hover:underline">
<a href={`mailto:${settings.company_email}`} className="text-[var(--luxury-gold)] hover:underline">
{settings.company_email}
</a>
</p>

View File

@@ -174,36 +174,36 @@ const ContactPage: React.FC = () => {
return (
<div className="min-h-screen bg-gradient-to-b from-[#0f0f0f] via-[#1a1a1a] to-[#0f0f0f] w-full" style={{ width: '100vw', position: 'relative', left: '50%', right: '50%', marginLeft: '-50vw', marginRight: '-50vw', marginTop: '-1.5rem', marginBottom: '-1.5rem' }}>
{}
<div className="w-full bg-gradient-to-br from-[#1a1a1a] via-[#0f0f0f] to-[#1a1a1a] border-b border-[#d4af37]/10 pt-6 sm:pt-7 md:pt-8 overflow-hidden relative">
<div className="w-full bg-gradient-to-br from-[#1a1a1a] via-[#0f0f0f] to-[#1a1a1a] border-b border-[var(--luxury-gold)]/10 pt-6 sm:pt-7 md:pt-8 overflow-hidden relative">
{}
<div className="absolute inset-0 opacity-10">
<div className="absolute top-10 left-10 w-32 sm:w-48 h-32 sm:h-48 bg-[#d4af37] rounded-full blur-3xl"></div>
<div className="absolute bottom-10 right-10 w-40 sm:w-64 h-40 sm:h-64 bg-[#c9a227] rounded-full blur-3xl"></div>
<div className="absolute top-10 left-10 w-32 sm:w-48 h-32 sm:h-48 bg-[var(--luxury-gold)] rounded-full blur-3xl"></div>
<div className="absolute bottom-10 right-10 w-40 sm:w-64 h-40 sm:h-64 bg-[var(--luxury-gold-dark)] rounded-full blur-3xl"></div>
</div>
<div className="absolute top-0 left-0 w-full h-px bg-gradient-to-r from-transparent via-[#d4af37]/50 to-transparent"></div>
<div className="absolute top-0 left-0 w-full h-px bg-gradient-to-r from-transparent via-[var(--luxury-gold)]/50 to-transparent"></div>
<div className="w-full max-w-[1920px] mx-auto px-3 sm:px-4 md:px-6 lg:px-8 xl:px-12 2xl:px-16 3xl:px-20 py-4 sm:py-5 md:py-6 relative z-10">
<div className="max-w-2xl mx-auto text-center px-2">
<div className="flex justify-center mb-2 sm:mb-3 md:mb-4">
<div className="relative group">
<div className="absolute inset-0 bg-gradient-to-br from-[#d4af37] via-[#f5d76e] to-[#c9a227] rounded-xl blur-lg opacity-40 group-hover:opacity-60 transition-opacity duration-500"></div>
<div className="relative p-2 sm:p-2.5 md:p-3 bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-lg border-2 border-[#d4af37]/40 backdrop-blur-sm shadow-xl shadow-[#d4af37]/20 group-hover:border-[#d4af37]/60 transition-all duration-300">
<Mail className="w-5 h-5 sm:w-6 sm:h-6 md:w-7 md:h-7 text-[#d4af37] drop-shadow-lg" />
<div className="absolute inset-0 bg-gradient-to-br from-[var(--luxury-gold)] via-[var(--luxury-gold-light)] to-[var(--luxury-gold-dark)] rounded-xl blur-lg opacity-40 group-hover:opacity-60 transition-opacity duration-500"></div>
<div className="relative p-2 sm:p-2.5 md:p-3 bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-lg border-2 border-[var(--luxury-gold)]/40 backdrop-blur-sm shadow-xl shadow-[var(--luxury-gold)]/20 group-hover:border-[var(--luxury-gold)]/60 transition-all duration-300">
<Mail className="w-5 h-5 sm:w-6 sm:h-6 md:w-7 md:h-7 text-[var(--luxury-gold)] drop-shadow-lg" />
</div>
</div>
</div>
<h1 className="text-2xl xs:text-3xl sm:text-4xl md:text-5xl font-serif font-semibold mb-2 sm:mb-3 tracking-tight leading-tight px-2">
<span className="bg-gradient-to-r from-white via-[#d4af37] to-white bg-clip-text text-transparent">
<span className="bg-gradient-to-r from-white via-[var(--luxury-gold)] to-white bg-clip-text text-transparent">
{pageContent?.title || 'Contact Us'}
</span>
</h1>
<div className="w-12 sm:w-16 md:w-20 h-0.5 bg-gradient-to-r from-transparent via-[#d4af37] to-transparent mx-auto mb-2 sm:mb-3"></div>
<div className="w-12 sm:w-16 md:w-20 h-0.5 bg-gradient-to-r from-transparent via-[var(--luxury-gold)] to-transparent mx-auto mb-2 sm:mb-3"></div>
<p className="text-sm sm:text-base md:text-lg text-gray-300 font-light leading-relaxed max-w-xl mx-auto tracking-wide px-2 sm:px-4">
{pageContent?.subtitle || pageContent?.description || "Experience the pinnacle of hospitality. We're here to make your stay extraordinary."}
</p>
</div>
</div>
<div className="absolute bottom-0 left-0 w-full h-px bg-gradient-to-r from-transparent via-[#d4af37]/30 to-transparent"></div>
<div className="absolute bottom-0 left-0 w-full h-px bg-gradient-to-r from-transparent via-[var(--luxury-gold)]/30 to-transparent"></div>
</div>
{}
@@ -213,15 +213,15 @@ const ContactPage: React.FC = () => {
{}
<div className="lg:col-span-4">
<div className="bg-gradient-to-br from-[#1a1a1a] via-[#0f0f0f] to-[#0a0a0a]
rounded-xl sm:rounded-2xl border-2 border-[#d4af37]/30 p-5 sm:p-6 md:p-8 lg:p-10
shadow-2xl shadow-[#d4af37]/10 backdrop-blur-xl
relative overflow-hidden h-full group hover:border-[#d4af37]/50 transition-all duration-500">
rounded-xl sm:rounded-2xl border-2 border-[var(--luxury-gold)]/30 p-5 sm:p-6 md:p-8 lg:p-10
shadow-2xl shadow-[var(--luxury-gold)]/10 backdrop-blur-xl
relative overflow-hidden h-full group hover:border-[var(--luxury-gold)]/50 transition-all duration-500">
{}
<div className="absolute inset-0 bg-gradient-to-br from-[#d4af37]/5 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div className="absolute inset-0 bg-gradient-to-br from-[var(--luxury-gold)]/5 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div className="relative z-10">
<div className="flex items-center gap-2 sm:gap-3 mb-6 sm:mb-7 md:mb-8">
<div className="w-0.5 sm:w-1 h-6 sm:h-8 bg-gradient-to-b from-[#d4af37] to-[#c9a227] rounded-full"></div>
<div className="w-0.5 sm:w-1 h-6 sm:h-8 bg-gradient-to-b from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] rounded-full"></div>
<h2 className="text-xl sm:text-2xl md:text-3xl font-serif font-semibold
text-white tracking-tight">
Get in Touch
@@ -230,35 +230,35 @@ const ContactPage: React.FC = () => {
<div className="space-y-5 sm:space-y-6 md:space-y-7">
<div className="flex items-start gap-3 sm:gap-4 md:gap-5 group/item hover:translate-x-1 transition-transform duration-300">
<div className="p-2.5 sm:p-3 md:p-4 bg-gradient-to-br from-[#d4af37]/20 to-[#d4af37]/10 rounded-lg sm:rounded-xl border border-[#d4af37]/40 flex-shrink-0 group-hover/item:bg-gradient-to-br group-hover/item:from-[#d4af37]/30 group-hover/item:to-[#d4af37]/20 group-hover/item:border-[#d4af37]/60 transition-all duration-300 shadow-lg shadow-[#d4af37]/10">
<Mail className="w-5 h-5 sm:w-6 sm:h-6 text-[#d4af37] drop-shadow-lg" />
<div className="p-2.5 sm:p-3 md:p-4 bg-gradient-to-br from-[var(--luxury-gold)]/20 to-[var(--luxury-gold)]/10 rounded-lg sm:rounded-xl border border-[var(--luxury-gold)]/40 flex-shrink-0 group-hover/item:bg-gradient-to-br group-hover/item:from-[var(--luxury-gold)]/30 group-hover/item:to-[var(--luxury-gold)]/20 group-hover/item:border-[var(--luxury-gold)]/60 transition-all duration-300 shadow-lg shadow-[var(--luxury-gold)]/10">
<Mail className="w-5 h-5 sm:w-6 sm:h-6 text-[var(--luxury-gold)] drop-shadow-lg" />
</div>
<div>
<h3 className="text-sm sm:text-base font-medium text-[#d4af37] mb-1 sm:mb-2 tracking-wide">Email</h3>
<a href={`mailto:${displayEmail}`} className="text-gray-300 font-light text-xs sm:text-sm leading-relaxed hover:text-[#d4af37] transition-colors">
<h3 className="text-sm sm:text-base font-medium text-[var(--luxury-gold)] mb-1 sm:mb-2 tracking-wide">Email</h3>
<a href={`mailto:${displayEmail}`} className="text-gray-300 font-light text-xs sm:text-sm leading-relaxed hover:text-[var(--luxury-gold)] transition-colors">
{displayEmail}
</a>
</div>
</div>
<div className="flex items-start gap-3 sm:gap-4 md:gap-5 group/item hover:translate-x-1 transition-transform duration-300">
<div className="p-2.5 sm:p-3 md:p-4 bg-gradient-to-br from-[#d4af37]/20 to-[#d4af37]/10 rounded-lg sm:rounded-xl border border-[#d4af37]/40 flex-shrink-0 group-hover/item:bg-gradient-to-br group-hover/item:from-[#d4af37]/30 group-hover/item:to-[#d4af37]/20 group-hover/item:border-[#d4af37]/60 transition-all duration-300 shadow-lg shadow-[#d4af37]/10">
<Phone className="w-5 h-5 sm:w-6 sm:h-6 text-[#d4af37] drop-shadow-lg" />
<div className="p-2.5 sm:p-3 md:p-4 bg-gradient-to-br from-[var(--luxury-gold)]/20 to-[var(--luxury-gold)]/10 rounded-lg sm:rounded-xl border border-[var(--luxury-gold)]/40 flex-shrink-0 group-hover/item:bg-gradient-to-br group-hover/item:from-[var(--luxury-gold)]/30 group-hover/item:to-[var(--luxury-gold)]/20 group-hover/item:border-[var(--luxury-gold)]/60 transition-all duration-300 shadow-lg shadow-[var(--luxury-gold)]/10">
<Phone className="w-5 h-5 sm:w-6 sm:h-6 text-[var(--luxury-gold)] drop-shadow-lg" />
</div>
<div>
<h3 className="text-sm sm:text-base font-medium text-[#d4af37] mb-1 sm:mb-2 tracking-wide">Phone</h3>
<a href={`tel:${displayPhone.replace(/\s+/g, '').replace(/[()]/g, '')}`} className="text-gray-300 font-light text-xs sm:text-sm leading-relaxed hover:text-[#d4af37] transition-colors">
<h3 className="text-sm sm:text-base font-medium text-[var(--luxury-gold)] mb-1 sm:mb-2 tracking-wide">Phone</h3>
<a href={`tel:${displayPhone.replace(/\s+/g, '').replace(/[()]/g, '')}`} className="text-gray-300 font-light text-xs sm:text-sm leading-relaxed hover:text-[var(--luxury-gold)] transition-colors">
{displayPhone}
</a>
</div>
</div>
<div className="flex items-start gap-3 sm:gap-4 md:gap-5 group/item hover:translate-x-1 transition-transform duration-300">
<div className="p-2.5 sm:p-3 md:p-4 bg-gradient-to-br from-[#d4af37]/20 to-[#d4af37]/10 rounded-lg sm:rounded-xl border border-[#d4af37]/40 flex-shrink-0 group-hover/item:bg-gradient-to-br group-hover/item:from-[#d4af37]/30 group-hover/item:to-[#d4af37]/20 group-hover/item:border-[#d4af37]/60 transition-all duration-300 shadow-lg shadow-[#d4af37]/10">
<MapPin className="w-5 h-5 sm:w-6 sm:h-6 text-[#d4af37] drop-shadow-lg" />
<div className="p-2.5 sm:p-3 md:p-4 bg-gradient-to-br from-[var(--luxury-gold)]/20 to-[var(--luxury-gold)]/10 rounded-lg sm:rounded-xl border border-[var(--luxury-gold)]/40 flex-shrink-0 group-hover/item:bg-gradient-to-br group-hover/item:from-[var(--luxury-gold)]/30 group-hover/item:to-[var(--luxury-gold)]/20 group-hover/item:border-[var(--luxury-gold)]/60 transition-all duration-300 shadow-lg shadow-[var(--luxury-gold)]/10">
<MapPin className="w-5 h-5 sm:w-6 sm:h-6 text-[var(--luxury-gold)] drop-shadow-lg" />
</div>
<div>
<h3 className="text-sm sm:text-base font-medium text-[#d4af37] mb-1 sm:mb-2 tracking-wide">Location</h3>
<h3 className="text-sm sm:text-base font-medium text-[var(--luxury-gold)] mb-1 sm:mb-2 tracking-wide">Location</h3>
<p className="text-gray-300 font-light text-xs sm:text-sm leading-relaxed whitespace-pre-line">
{displayAddress}
</p>
@@ -268,11 +268,11 @@ const ContactPage: React.FC = () => {
{}
{pageContent?.map_url && (
<div className="mt-6 sm:mt-7 md:mt-8 pt-6 sm:pt-7 md:pt-8 border-t border-[#d4af37]/30">
<h3 className="text-sm sm:text-base font-medium text-[#d4af37] mb-3 sm:mb-4 tracking-wide">
<div className="mt-6 sm:mt-7 md:mt-8 pt-6 sm:pt-7 md:pt-8 border-t border-[var(--luxury-gold)]/30">
<h3 className="text-sm sm:text-base font-medium text-[var(--luxury-gold)] mb-3 sm:mb-4 tracking-wide">
Find Us
</h3>
<div className="relative rounded-lg overflow-hidden border-2 border-[#d4af37]/30 shadow-lg shadow-[#d4af37]/10 group hover:border-[#d4af37]/50 transition-all duration-300">
<div className="relative rounded-lg overflow-hidden border-2 border-[var(--luxury-gold)]/30 shadow-lg shadow-[var(--luxury-gold)]/10 group hover:border-[var(--luxury-gold)]/50 transition-all duration-300">
<iframe
src={pageContent.map_url}
width="100%"
@@ -288,7 +288,7 @@ const ContactPage: React.FC = () => {
</div>
)}
<div className="mt-5 sm:mt-6 md:mt-7 pt-5 sm:pt-6 md:pt-7 border-t border-[#d4af37]/30">
<div className="mt-5 sm:mt-6 md:mt-7 pt-5 sm:pt-6 md:pt-7 border-t border-[var(--luxury-gold)]/30">
<p className="text-gray-400 font-light text-xs sm:text-sm leading-relaxed tracking-wide">
{pageContent?.content || "Our team is here to help you with any questions about your stay, bookings, or special requests. We're committed to exceeding your expectations."}
</p>
@@ -300,17 +300,17 @@ const ContactPage: React.FC = () => {
{}
<div className="lg:col-span-8">
<div className="bg-gradient-to-br from-[#1a1a1a] via-[#0f0f0f] to-[#0a0a0a]
rounded-xl sm:rounded-2xl border-2 border-[#d4af37]/30 p-5 sm:p-6 md:p-8 lg:p-10
shadow-2xl shadow-[#d4af37]/10 backdrop-blur-xl
rounded-xl sm:rounded-2xl border-2 border-[var(--luxury-gold)]/30 p-5 sm:p-6 md:p-8 lg:p-10
shadow-2xl shadow-[var(--luxury-gold)]/10 backdrop-blur-xl
relative overflow-hidden">
{}
<div className="absolute inset-0 opacity-5">
<div className="absolute top-0 right-0 w-48 sm:w-64 md:w-96 h-48 sm:h-64 md:h-96 bg-[#d4af37] rounded-full blur-3xl"></div>
<div className="absolute top-0 right-0 w-48 sm:w-64 md:w-96 h-48 sm:h-64 md:h-96 bg-[var(--luxury-gold)] rounded-full blur-3xl"></div>
</div>
<div className="relative z-10">
<div className="flex items-center gap-2 sm:gap-3 mb-6 sm:mb-7 md:mb-8">
<div className="w-0.5 sm:w-1 h-6 sm:h-8 bg-gradient-to-b from-[#d4af37] to-[#c9a227] rounded-full"></div>
<div className="w-0.5 sm:w-1 h-6 sm:h-8 bg-gradient-to-b from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] rounded-full"></div>
<h2 className="text-xl sm:text-2xl md:text-3xl font-serif font-semibold
text-white tracking-tight">
Send Us a Message
@@ -330,8 +330,8 @@ const ContactPage: React.FC = () => {
<div>
<label htmlFor="name" className="block text-xs sm:text-sm font-medium text-gray-300 mb-2 sm:mb-3 tracking-wide">
<span className="flex items-center gap-1.5 sm:gap-2">
<User className="w-3.5 h-3.5 sm:w-4 sm:h-4 text-[#d4af37] drop-shadow-lg" />
Full Name <span className="text-[#d4af37] font-semibold">*</span>
<User className="w-3.5 h-3.5 sm:w-4 sm:h-4 text-[var(--luxury-gold)] drop-shadow-lg" />
Full Name <span className="text-[var(--luxury-gold)] font-semibold">*</span>
</span>
</label>
<input
@@ -342,9 +342,9 @@ const ContactPage: React.FC = () => {
onChange={handleChange}
className={`w-full px-4 sm:px-5 py-3 sm:py-4 bg-gradient-to-br from-[#0f0f0f] to-[#0a0a0a] border-2 rounded-lg
text-white text-sm sm:text-base placeholder-gray-500/60
focus:outline-none focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37] focus:shadow-lg focus:shadow-[#d4af37]/20
transition-all duration-300 hover:border-[#d4af37]/40
${errors.name ? 'border-red-500/50 focus:border-red-500 focus:ring-red-500/50' : 'border-[#d4af37]/30'}`}
focus:outline-none focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)] focus:shadow-lg focus:shadow-[var(--luxury-gold)]/20
transition-all duration-300 hover:border-[var(--luxury-gold)]/40
${errors.name ? 'border-red-500/50 focus:border-red-500 focus:ring-red-500/50' : 'border-[var(--luxury-gold)]/30'}`}
placeholder="Enter your full name"
/>
{errors.name && (
@@ -358,8 +358,8 @@ const ContactPage: React.FC = () => {
<div>
<label htmlFor="email" className="block text-xs sm:text-sm font-medium text-gray-300 mb-2 sm:mb-3 tracking-wide">
<span className="flex items-center gap-1.5 sm:gap-2">
<Mail className="w-3.5 h-3.5 sm:w-4 sm:h-4 text-[#d4af37] drop-shadow-lg" />
Email <span className="text-[#d4af37] font-semibold">*</span>
<Mail className="w-3.5 h-3.5 sm:w-4 sm:h-4 text-[var(--luxury-gold)] drop-shadow-lg" />
Email <span className="text-[var(--luxury-gold)] font-semibold">*</span>
</span>
</label>
<input
@@ -370,9 +370,9 @@ const ContactPage: React.FC = () => {
onChange={handleChange}
className={`w-full px-4 sm:px-5 py-3 sm:py-4 bg-gradient-to-br from-[#0f0f0f] to-[#0a0a0a] border-2 rounded-lg
text-white text-sm sm:text-base placeholder-gray-500/60
focus:outline-none focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37] focus:shadow-lg focus:shadow-[#d4af37]/20
transition-all duration-300 hover:border-[#d4af37]/40
${errors.email ? 'border-red-500/50 focus:border-red-500 focus:ring-red-500/50' : 'border-[#d4af37]/30'}`}
focus:outline-none focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)] focus:shadow-lg focus:shadow-[var(--luxury-gold)]/20
transition-all duration-300 hover:border-[var(--luxury-gold)]/40
${errors.email ? 'border-red-500/50 focus:border-red-500 focus:ring-red-500/50' : 'border-[var(--luxury-gold)]/30'}`}
placeholder="your.email@example.com"
/>
{errors.email && (
@@ -384,7 +384,7 @@ const ContactPage: React.FC = () => {
<div>
<label htmlFor="phone" className="block text-xs sm:text-sm font-medium text-gray-300 mb-2 sm:mb-3 tracking-wide">
<span className="flex items-center gap-1.5 sm:gap-2">
<Phone className="w-3.5 h-3.5 sm:w-4 sm:h-4 text-[#d4af37] drop-shadow-lg" />
<Phone className="w-3.5 h-3.5 sm:w-4 sm:h-4 text-[var(--luxury-gold)] drop-shadow-lg" />
Phone <span className="text-gray-500 text-xs">(Optional)</span>
</span>
</label>
@@ -394,10 +394,10 @@ const ContactPage: React.FC = () => {
name="phone"
value={formData.phone}
onChange={handleChange}
className="w-full px-4 sm:px-5 py-3 sm:py-4 bg-gradient-to-br from-[#0f0f0f] to-[#0a0a0a] border-2 border-[#d4af37]/30 rounded-lg
className="w-full px-4 sm:px-5 py-3 sm:py-4 bg-gradient-to-br from-[#0f0f0f] to-[#0a0a0a] border-2 border-[var(--luxury-gold)]/30 rounded-lg
text-white text-sm sm:text-base placeholder-gray-500/60
focus:outline-none focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37] focus:shadow-lg focus:shadow-[#d4af37]/20
transition-all duration-300 hover:border-[#d4af37]/40"
focus:outline-none focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)] focus:shadow-lg focus:shadow-[var(--luxury-gold)]/20
transition-all duration-300 hover:border-[var(--luxury-gold)]/40"
placeholder="+1 (555) 123-4567"
/>
</div>
@@ -407,8 +407,8 @@ const ContactPage: React.FC = () => {
<div>
<label htmlFor="subject" className="block text-xs sm:text-sm font-medium text-gray-300 mb-2 sm:mb-3 tracking-wide">
<span className="flex items-center gap-1.5 sm:gap-2">
<MessageSquare className="w-3.5 h-3.5 sm:w-4 sm:h-4 text-[#d4af37] drop-shadow-lg" />
Subject <span className="text-[#d4af37] font-semibold">*</span>
<MessageSquare className="w-3.5 h-3.5 sm:w-4 sm:h-4 text-[var(--luxury-gold)] drop-shadow-lg" />
Subject <span className="text-[var(--luxury-gold)] font-semibold">*</span>
</span>
</label>
<input
@@ -419,9 +419,9 @@ const ContactPage: React.FC = () => {
onChange={handleChange}
className={`w-full px-4 sm:px-5 py-3 sm:py-4 bg-gradient-to-br from-[#0f0f0f] to-[#0a0a0a] border-2 rounded-lg
text-white text-sm sm:text-base placeholder-gray-500/60
focus:outline-none focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37] focus:shadow-lg focus:shadow-[#d4af37]/20
transition-all duration-300 hover:border-[#d4af37]/40
${errors.subject ? 'border-red-500/50 focus:border-red-500 focus:ring-red-500/50' : 'border-[#d4af37]/30'}`}
focus:outline-none focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)] focus:shadow-lg focus:shadow-[var(--luxury-gold)]/20
transition-all duration-300 hover:border-[var(--luxury-gold)]/40
${errors.subject ? 'border-red-500/50 focus:border-red-500 focus:ring-red-500/50' : 'border-[var(--luxury-gold)]/30'}`}
placeholder="What is this regarding?"
/>
{errors.subject && (
@@ -433,8 +433,8 @@ const ContactPage: React.FC = () => {
<div>
<label htmlFor="message" className="block text-xs sm:text-sm font-medium text-gray-300 mb-2 sm:mb-3 tracking-wide">
<span className="flex items-center gap-1.5 sm:gap-2">
<MessageSquare className="w-3.5 h-3.5 sm:w-4 sm:h-4 text-[#d4af37] drop-shadow-lg" />
Message <span className="text-[#d4af37] font-semibold">*</span>
<MessageSquare className="w-3.5 h-3.5 sm:w-4 sm:h-4 text-[var(--luxury-gold)] drop-shadow-lg" />
Message <span className="text-[var(--luxury-gold)] font-semibold">*</span>
</span>
</label>
<textarea
@@ -445,9 +445,9 @@ const ContactPage: React.FC = () => {
rows={6}
className={`w-full px-4 sm:px-5 py-3 sm:py-4 bg-gradient-to-br from-[#0f0f0f] to-[#0a0a0a] border-2 rounded-lg
text-white text-sm sm:text-base placeholder-gray-500/60 resize-none
focus:outline-none focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37] focus:shadow-lg focus:shadow-[#d4af37]/20
transition-all duration-300 hover:border-[#d4af37]/40
${errors.message ? 'border-red-500/50 focus:border-red-500 focus:ring-red-500/50' : 'border-[#d4af37]/30'}`}
focus:outline-none focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)] focus:shadow-lg focus:shadow-[var(--luxury-gold)]/20
transition-all duration-300 hover:border-[var(--luxury-gold)]/40
${errors.message ? 'border-red-500/50 focus:border-red-500 focus:ring-red-500/50' : 'border-[var(--luxury-gold)]/30'}`}
placeholder="Tell us more about your inquiry..."
/>
{errors.message && (
@@ -475,14 +475,14 @@ const ContactPage: React.FC = () => {
type="submit"
disabled={loading}
className="group w-full sm:w-auto inline-flex items-center justify-center gap-2 sm:gap-3
bg-gradient-to-r from-[#d4af37] via-[#f5d76e] to-[#d4af37]
bg-gradient-to-r from-[var(--luxury-gold)] via-[var(--luxury-gold-light)] to-[var(--luxury-gold)]
text-[#0f0f0f] font-semibold
active:scale-[0.98]
disabled:opacity-50 disabled:cursor-not-allowed
transition-all duration-500
tracking-wide text-sm sm:text-base
px-6 sm:px-8 md:px-10 py-3 sm:py-3.5 md:py-4 rounded-lg
shadow-2xl shadow-[#d4af37]/40 hover:shadow-[#d4af37]/60 hover:scale-[1.02]
shadow-2xl shadow-[var(--luxury-gold)]/40 hover:shadow-[var(--luxury-gold)]/60 hover:scale-[1.02]
relative overflow-hidden
touch-manipulation min-h-[44px] sm:min-h-[48px] md:min-h-[52px]"
>

View File

@@ -94,12 +94,12 @@ const FAQPage: React.FC = () => {
}}
>
<div className="text-center">
<HelpCircle className="w-16 h-16 text-[#d4af37]/50 mx-auto mb-4" />
<HelpCircle className="w-16 h-16 text-[var(--luxury-gold)]/50 mx-auto mb-4" />
<h1 className="text-2xl font-elegant font-bold text-white mb-2">Frequently Asked Questions</h1>
<p className="text-gray-400">This page is currently unavailable.</p>
<Link
to="/"
className="inline-flex items-center gap-2 text-[#d4af37]/80 hover:text-[#d4af37] mt-6 transition-all duration-300"
className="inline-flex items-center gap-2 text-[var(--luxury-gold)]/80 hover:text-[var(--luxury-gold)] mt-6 transition-all duration-300"
>
<ArrowLeft className="w-4 h-4" />
<span>Back to Home</span>
@@ -123,17 +123,17 @@ const FAQPage: React.FC = () => {
<div className="w-full px-3 sm:px-4 md:px-6 lg:px-8 py-8 sm:py-12 max-w-5xl mx-auto">
<Link
to="/"
className="inline-flex items-center gap-2 text-[#d4af37]/80 hover:text-[#d4af37] mb-6 transition-all duration-300 group font-light tracking-wide text-xs sm:text-sm"
className="inline-flex items-center gap-2 text-[var(--luxury-gold)]/80 hover:text-[var(--luxury-gold)] mb-6 transition-all duration-300 group font-light tracking-wide text-xs sm:text-sm"
>
<ArrowLeft className="w-4 h-4 group-hover:-translate-x-1 transition-transform" />
<span>Back to Home</span>
</Link>
<div className="mb-8 sm:mb-12 text-center">
<div className="inline-flex items-center justify-center w-16 h-16 sm:w-20 sm:h-20 mb-4 sm:mb-6 bg-gradient-to-br from-[#d4af37]/20 to-[#c9a227]/10 rounded-full border border-[#d4af37]/30">
<HelpCircle className="w-8 h-8 sm:w-10 sm:h-10 text-[#d4af37]" />
<div className="inline-flex items-center justify-center w-16 h-16 sm:w-20 sm:h-20 mb-4 sm:mb-6 bg-gradient-to-br from-[var(--luxury-gold)]/20 to-[var(--luxury-gold-dark)]/10 rounded-full border border-[var(--luxury-gold)]/30">
<HelpCircle className="w-8 h-8 sm:w-10 sm:h-10 text-[var(--luxury-gold)]" />
</div>
<h1 className="text-3xl sm:text-4xl lg:text-5xl font-elegant font-bold text-white mb-3 sm:mb-4 tracking-tight leading-tight bg-gradient-to-r from-white via-[#d4af37] to-white bg-clip-text text-transparent">
<h1 className="text-3xl sm:text-4xl lg:text-5xl font-elegant font-bold text-white mb-3 sm:mb-4 tracking-tight leading-tight bg-gradient-to-r from-white via-[var(--luxury-gold)] to-white bg-clip-text text-transparent">
{pageContent.title || 'Frequently Asked Questions'}
</h1>
{pageContent.subtitle && (
@@ -143,18 +143,18 @@ const FAQPage: React.FC = () => {
)}
</div>
<div className="bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-xl border border-[#d4af37]/20 backdrop-blur-xl shadow-2xl shadow-[#d4af37]/5 p-6 sm:p-8 lg:p-12">
<div className="bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-xl border border-[var(--luxury-gold)]/20 backdrop-blur-xl shadow-2xl shadow-[var(--luxury-gold)]/5 p-6 sm:p-8 lg:p-12">
<div
className="prose prose-invert prose-lg max-w-none text-gray-300
prose-headings:text-white prose-headings:font-elegant prose-headings:font-semibold
prose-h2:text-2xl prose-h2:mt-8 prose-h2:mb-4 prose-h2:border-b prose-h2:border-[#d4af37]/20 prose-h2:pb-2
prose-h2:text-2xl prose-h2:mt-8 prose-h2:mb-4 prose-h2:border-b prose-h2:border-[var(--luxury-gold)]/20 prose-h2:pb-2
prose-p:text-gray-300 prose-p:font-light prose-p:leading-relaxed prose-p:mb-4
prose-ul:text-gray-300 prose-ul:font-light prose-ul:my-4
prose-li:text-gray-300 prose-li:mb-2 prose-li:ml-4
prose-strong:text-[#d4af37] prose-strong:font-medium
prose-a:text-[#d4af37] prose-a:no-underline hover:prose-a:underline
prose-strong:text-[var(--luxury-gold)] prose-strong:font-medium
prose-a:text-[var(--luxury-gold)] prose-a:no-underline hover:prose-a:underline
[&_*]:text-gray-300 [&_h1]:text-white [&_h2]:text-white [&_h3]:text-white [&_h4]:text-white [&_h5]:text-white [&_h6]:text-white
[&_strong]:text-[#d4af37] [&_b]:text-[#d4af37] [&_a]:text-[#d4af37]"
[&_strong]:text-[var(--luxury-gold)] [&_b]:text-[var(--luxury-gold)] [&_a]:text-[var(--luxury-gold)]"
style={{ color: '#d1d5db' }}
dangerouslySetInnerHTML={createSanitizedHtml(
pageContent.content || pageContent.description || '<p style="color: #d1d5db;">No content available.</p>'
@@ -166,7 +166,7 @@ const FAQPage: React.FC = () => {
<div className="mt-8 text-center">
<p className="text-sm text-gray-400 font-light">
Still have questions? Contact us at{' '}
<a href={`mailto:${settings.company_email}`} className="text-[#d4af37] hover:underline">
<a href={`mailto:${settings.company_email}`} className="text-[var(--luxury-gold)] hover:underline">
{settings.company_email}
</a>
</p>

View File

@@ -708,7 +708,7 @@ const HomePage: React.FC = () => {
<div className="min-h-screen bg-gradient-to-br from-gray-50 via-white to-gray-50/30 relative overflow-hidden">
{}
<div className="fixed inset-0 opacity-[0.015] bg-[radial-gradient(circle_at_1px_1px,#d4af37_1px,transparent_0)] bg-[length:60px_60px] pointer-events-none"></div>
<div className="fixed inset-0 opacity-[0.015] bg-[radial-gradient(circle_at_1px_1px,var(--luxury-gold)_1px,transparent_0)] bg-[length:60px_60px] pointer-events-none"></div>
<div className="relative z-10">
{}
@@ -717,7 +717,7 @@ const HomePage: React.FC = () => {
{}
<div className="text-center animate-fade-in mb-6 md:mb-8">
<div className="inline-block mb-3">
<div className="h-0.5 w-16 bg-gradient-to-r from-[#d4af37] to-[#f5d76e] mx-auto rounded-full"></div>
<div className="h-0.5 w-16 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-light)] mx-auto rounded-full"></div>
</div>
<h2 className="text-2xl sm:text-3xl md:text-4xl font-serif font-bold text-gray-900 tracking-tight mb-3 md:mb-4">
{pageContent?.rooms_section_title || pageContent?.hero_title || (apiError ? '' : 'Featured & Newest Rooms')}
@@ -730,9 +730,9 @@ const HomePage: React.FC = () => {
<div className="mt-6 md:mt-8 flex justify-center">
<Link
to={pageContent?.rooms_section_button_link || '/rooms'}
className="group relative inline-flex items-center gap-2 px-6 py-2.5 md:px-8 md:py-3 bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-[#0f0f0f] rounded-lg font-semibold tracking-wide text-sm md:text-base shadow-md shadow-[#d4af37]/20 hover:shadow-lg hover:shadow-[#d4af37]/30 hover:-translate-y-0.5 transition-all duration-300 overflow-hidden"
className="group relative inline-flex items-center gap-2 px-6 py-2.5 md:px-8 md:py-3 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-[#0f0f0f] rounded-lg font-semibold tracking-wide text-sm md:text-base shadow-md shadow-[var(--luxury-gold)]/20 hover:shadow-lg hover:shadow-[var(--luxury-gold)]/30 hover:-translate-y-0.5 transition-all duration-300 overflow-hidden"
>
<span className="absolute inset-0 bg-gradient-to-r from-[#f5d76e] to-[#d4af37] opacity-0 group-hover:opacity-100 transition-opacity duration-300"></span>
<span className="absolute inset-0 bg-gradient-to-r from-[var(--luxury-gold-light)] to-[var(--luxury-gold)] opacity-0 group-hover:opacity-100 transition-opacity duration-300"></span>
<span className="relative z-10">{pageContent?.rooms_section_button_text || 'View All Rooms'}</span>
<ArrowRight className="w-4 h-4 md:w-5 md:h-5 relative z-10 group-hover:translate-x-1 transition-transform duration-300" />
</Link>
@@ -810,18 +810,18 @@ const HomePage: React.FC = () => {
// Only show section if we have features from API, or if pageContent was loaded but is empty (not if API failed)
return validFeatures.length > 0 && (
<section className="container mx-auto px-4 sm:px-6 lg:px-8 py-12 md:py-16">
<div className="relative bg-white rounded-xl md:rounded-2xl shadow-xl shadow-[#d4af37]/5 p-6 md:p-8 lg:p-10 animate-fade-in overflow-hidden border border-gray-100/50">
<div className="relative bg-white rounded-xl md:rounded-2xl shadow-xl shadow-[var(--luxury-gold)]/5 p-6 md:p-8 lg:p-10 animate-fade-in overflow-hidden border border-gray-100/50">
{}
<div className="absolute top-0 left-0 right-0 h-1 bg-gradient-to-r from-[#d4af37] via-[#f5d76e] to-[#d4af37]"></div>
<div className="absolute bottom-0 left-0 right-0 h-1 bg-gradient-to-r from-[#d4af37] via-[#f5d76e] to-[#d4af37]"></div>
<div className="absolute top-0 left-0 right-0 h-1 bg-gradient-to-r from-[var(--luxury-gold)] via-[var(--luxury-gold-light)] to-[var(--luxury-gold)]"></div>
<div className="absolute bottom-0 left-0 right-0 h-1 bg-gradient-to-r from-[var(--luxury-gold)] via-[var(--luxury-gold-light)] to-[var(--luxury-gold)]"></div>
{}
<div className="absolute inset-0 opacity-[0.015] bg-[radial-gradient(circle_at_1px_1px,#d4af37_1px,transparent_0)] bg-[length:40px_40px]"></div>
<div className="absolute inset-0 opacity-[0.015] bg-[radial-gradient(circle_at_1px_1px,var(--luxury-gold)_1px,transparent_0)] bg-[length:40px_40px]"></div>
{(pageContent?.features_section_title || pageContent?.features_section_subtitle) && (
<div className="text-center mb-8 md:mb-10 animate-fade-in">
<div className="inline-block mb-3">
<div className="h-0.5 w-16 md:w-20 bg-gradient-to-r from-[#d4af37] to-[#f5d76e] mx-auto rounded-full"></div>
<div className="h-0.5 w-16 md:w-20 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-light)] mx-auto rounded-full"></div>
</div>
{pageContent.features_section_title && (
<h2 className="text-2xl sm:text-3xl md:text-4xl font-serif font-bold text-gray-900 tracking-tight mb-3 md:mb-4 px-4">
@@ -841,20 +841,20 @@ const HomePage: React.FC = () => {
validFeatures.map((feature: any, index: number) => (
<div key={`feature-${index}-${feature.title || index}`} className="text-center group relative">
{feature.image ? (
<div className="w-16 h-16 md:w-20 md:h-20 mx-auto mb-4 md:mb-5 rounded-lg overflow-hidden shadow-lg shadow-[#d4af37]/15 group-hover:scale-110 group-hover:shadow-xl group-hover:shadow-[#d4af37]/25 transition-all duration-300 border border-[#d4af37]/20">
<div className="w-16 h-16 md:w-20 md:h-20 mx-auto mb-4 md:mb-5 rounded-lg overflow-hidden shadow-lg shadow-[var(--luxury-gold)]/15 group-hover:scale-110 group-hover:shadow-xl group-hover:shadow-[var(--luxury-gold)]/25 transition-all duration-300 border border-[var(--luxury-gold)]/20">
<img src={feature.image} alt={feature.title || 'Feature'} className="w-full h-full object-cover" />
</div>
) : (
<div
className="w-16 h-16 md:w-18 md:h-18 bg-gradient-to-br from-[#d4af37]/15 via-[#f5d76e]/10 to-[#d4af37]/15
className="w-16 h-16 md:w-18 md:h-18 bg-gradient-to-br from-[var(--luxury-gold)]/15 via-[var(--luxury-gold-light)]/10 to-[var(--luxury-gold)]/15
rounded-lg flex items-center justify-center mx-auto mb-4 md:mb-5
shadow-lg shadow-[#d4af37]/15 border border-[#d4af37]/25
group-hover:scale-110 group-hover:shadow-xl group-hover:shadow-[#d4af37]/30 group-hover:border-[#d4af37]/40
shadow-lg shadow-[var(--luxury-gold)]/15 border border-[var(--luxury-gold)]/25
group-hover:scale-110 group-hover:shadow-xl group-hover:shadow-[var(--luxury-gold)]/30 group-hover:border-[var(--luxury-gold)]/40
transition-all duration-300 backdrop-blur-sm"
>
{feature.icon && (LucideIcons as any)[feature.icon] ? (
React.createElement((LucideIcons as any)[feature.icon], {
className: 'w-7 h-7 md:w-8 md:h-8 text-[#d4af37] drop-shadow-md'
className: 'w-7 h-7 md:w-8 md:h-8 text-[var(--luxury-gold)] drop-shadow-md'
})
) : (
<span className="text-3xl"></span>
@@ -864,7 +864,7 @@ const HomePage: React.FC = () => {
{feature.title && (
<h3
className="text-lg md:text-xl font-serif font-semibold mb-2 md:mb-3
text-gray-900 group-hover:text-[#d4af37] transition-colors duration-300 tracking-tight leading-tight"
text-gray-900 group-hover:text-[var(--luxury-gold)] transition-colors duration-300 tracking-tight leading-tight"
>
{feature.title}
</h3>
@@ -888,7 +888,7 @@ const HomePage: React.FC = () => {
<section className="container mx-auto px-4 sm:px-6 lg:px-8 py-12 md:py-16 bg-gradient-to-b from-white via-gray-50/20 to-white">
<div className="text-center mb-8 md:mb-10 animate-fade-in">
<div className="inline-block mb-3">
<div className="h-0.5 w-16 md:w-20 bg-gradient-to-r from-[#d4af37] to-[#f5d76e] mx-auto rounded-full"></div>
<div className="h-0.5 w-16 md:w-20 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-light)] mx-auto rounded-full"></div>
</div>
<h2 className="text-2xl sm:text-3xl md:text-4xl font-serif font-bold text-gray-900 tracking-tight mb-3 md:mb-4 px-4">
{pageContent.luxury_section_title || 'Experience Unparalleled Luxury'}
@@ -901,7 +901,7 @@ const HomePage: React.FC = () => {
</div>
{pageContent.luxury_section_image && (
<div className="mb-8 md:mb-10 animate-fade-in px-4">
<div className="relative rounded-xl md:rounded-2xl overflow-hidden shadow-xl shadow-[#d4af37]/10 group">
<div className="relative rounded-xl md:rounded-2xl overflow-hidden shadow-xl shadow-[var(--luxury-gold)]/10 group">
<img
src={pageContent.luxury_section_image}
alt="Luxury Experience"
@@ -914,18 +914,18 @@ const HomePage: React.FC = () => {
{pageContent.luxury_features && pageContent.luxury_features.length > 0 && (
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-5 md:gap-6 px-4">
{pageContent.luxury_features.map((feature, index) => (
<div key={index} className="relative bg-white rounded-lg md:rounded-xl p-5 md:p-6 group hover:shadow-xl hover:shadow-[#d4af37]/10 transition-all duration-300 animate-fade-in border border-gray-100/50 hover:border-[#d4af37]/25 hover:-translate-y-1" style={{ animationDelay: `${index * 0.1}s` }}>
<div className="absolute top-0 left-0 w-full h-0.5 bg-gradient-to-r from-[#d4af37] to-[#f5d76e] opacity-0 group-hover:opacity-100 transition-opacity duration-300 rounded-t-lg md:rounded-t-xl"></div>
<div className="w-14 h-14 md:w-16 md:h-16 bg-gradient-to-br from-[#d4af37]/15 via-[#f5d76e]/10 to-[#d4af37]/15 rounded-lg flex items-center justify-center mb-4 md:mb-5 mx-auto group-hover:scale-110 group-hover:shadow-lg group-hover:shadow-[#d4af37]/20 transition-all duration-300 border border-[#d4af37]/25 group-hover:border-[#d4af37]/40">
<div key={index} className="relative bg-white rounded-lg md:rounded-xl p-5 md:p-6 group hover:shadow-xl hover:shadow-[var(--luxury-gold)]/10 transition-all duration-300 animate-fade-in border border-gray-100/50 hover:border-[var(--luxury-gold)]/25 hover:-translate-y-1" style={{ animationDelay: `${index * 0.1}s` }}>
<div className="absolute top-0 left-0 w-full h-0.5 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-light)] opacity-0 group-hover:opacity-100 transition-opacity duration-300 rounded-t-lg md:rounded-t-xl"></div>
<div className="w-14 h-14 md:w-16 md:h-16 bg-gradient-to-br from-[var(--luxury-gold)]/15 via-[var(--luxury-gold-light)]/10 to-[var(--luxury-gold)]/15 rounded-lg flex items-center justify-center mb-4 md:mb-5 mx-auto group-hover:scale-110 group-hover:shadow-lg group-hover:shadow-[var(--luxury-gold)]/20 transition-all duration-300 border border-[var(--luxury-gold)]/25 group-hover:border-[var(--luxury-gold)]/40">
{feature.icon && (LucideIcons as any)[feature.icon] ? (
React.createElement((LucideIcons as any)[feature.icon], {
className: 'w-7 h-7 md:w-8 md:h-8 text-[#d4af37] drop-shadow-md'
className: 'w-7 h-7 md:w-8 md:h-8 text-[var(--luxury-gold)] drop-shadow-md'
})
) : (
<span className="text-2xl md:text-3xl"></span>
)}
</div>
<h3 className="text-lg md:text-xl font-serif font-semibold mb-2 md:mb-3 text-gray-900 group-hover:text-[#d4af37] transition-colors duration-300 text-center tracking-tight leading-tight">
<h3 className="text-lg md:text-xl font-serif font-semibold mb-2 md:mb-3 text-gray-900 group-hover:text-[var(--luxury-gold)] transition-colors duration-300 text-center tracking-tight leading-tight">
{feature.title}
</h3>
<p className="text-sm md:text-base text-gray-600 leading-relaxed font-light text-center tracking-wide">
@@ -943,7 +943,7 @@ const HomePage: React.FC = () => {
<section className="container mx-auto px-4 sm:px-6 lg:px-8 py-12 md:py-16">
<div className="text-center mb-8 md:mb-10 animate-fade-in">
<div className="inline-block mb-3">
<div className="h-0.5 w-16 md:w-20 bg-gradient-to-r from-[#d4af37] to-[#f5d76e] mx-auto rounded-full"></div>
<div className="h-0.5 w-16 md:w-20 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-light)] mx-auto rounded-full"></div>
</div>
<h2 className="text-2xl sm:text-3xl md:text-4xl font-serif font-bold text-gray-900 tracking-tight mb-3 md:mb-4 px-4">
{pageContent.luxury_gallery_section_title || 'Luxury Gallery'}
@@ -968,7 +968,7 @@ const HomePage: React.FC = () => {
return (
<div
key={`luxury-gallery-${index}-${image}`}
className="relative group overflow-hidden rounded-lg md:rounded-xl aspect-square animate-fade-in shadow-md shadow-gray-900/5 hover:shadow-xl hover:shadow-[#d4af37]/15 transition-all duration-300 cursor-pointer"
className="relative group overflow-hidden rounded-lg md:rounded-xl aspect-square animate-fade-in shadow-md shadow-gray-900/5 hover:shadow-xl hover:shadow-[var(--luxury-gold)]/15 transition-all duration-300 cursor-pointer"
style={{ animationDelay: `${index * 0.05}s` }}
onClick={() => {
const normalizedImages = (pageContent.luxury_gallery || [])
@@ -998,7 +998,7 @@ const HomePage: React.FC = () => {
<ZoomIn className="w-8 h-8 md:w-10 md:h-10 text-white drop-shadow-2xl" />
</div>
</div>
<div className="absolute inset-0 border-2 border-transparent group-hover:border-[#d4af37]/60 transition-colors duration-300 rounded-lg md:rounded-xl"></div>
<div className="absolute inset-0 border-2 border-transparent group-hover:border-[var(--luxury-gold)]/60 transition-colors duration-300 rounded-lg md:rounded-xl"></div>
</div>
);
})}
@@ -1011,7 +1011,7 @@ const HomePage: React.FC = () => {
<section className="container mx-auto px-4 sm:px-6 lg:px-8 py-12 md:py-16 bg-gradient-to-b from-white via-gray-50/20 to-white">
<div className="text-center mb-8 md:mb-10 animate-fade-in">
<div className="inline-block mb-3">
<div className="h-0.5 w-16 md:w-20 bg-gradient-to-r from-[#d4af37] to-[#f5d76e] mx-auto rounded-full"></div>
<div className="h-0.5 w-16 md:w-20 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-light)] mx-auto rounded-full"></div>
</div>
<h2 className="text-2xl sm:text-3xl md:text-4xl font-serif font-bold text-gray-900 tracking-tight mb-3 md:mb-4 px-4">
{pageContent.luxury_testimonials_section_title || 'Guest Experiences'}
@@ -1024,16 +1024,16 @@ const HomePage: React.FC = () => {
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-5 md:gap-6 px-4">
{pageContent.luxury_testimonials.map((testimonial, index) => (
<div key={index} className="relative bg-white rounded-lg md:rounded-xl p-5 md:p-6 shadow-lg shadow-gray-900/5 hover:shadow-xl hover:shadow-[#d4af37]/8 transition-all duration-300 animate-fade-in border border-gray-100/50 hover:border-[#d4af37]/25 hover:-translate-y-1" style={{ animationDelay: `${index * 0.1}s` }}>
<div className="absolute top-0 left-0 w-full h-0.5 bg-gradient-to-r from-[#d4af37] to-[#f5d76e] opacity-0 hover:opacity-100 transition-opacity duration-300 rounded-t-lg md:rounded-t-xl"></div>
<div key={index} className="relative bg-white rounded-lg md:rounded-xl p-5 md:p-6 shadow-lg shadow-gray-900/5 hover:shadow-xl hover:shadow-[var(--luxury-gold)]/8 transition-all duration-300 animate-fade-in border border-gray-100/50 hover:border-[var(--luxury-gold)]/25 hover:-translate-y-1" style={{ animationDelay: `${index * 0.1}s` }}>
<div className="absolute top-0 left-0 w-full h-0.5 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-light)] opacity-0 hover:opacity-100 transition-opacity duration-300 rounded-t-lg md:rounded-t-xl"></div>
<div className="flex items-center mb-4 md:mb-5">
{testimonial.image ? (
<div className="relative">
<img src={testimonial.image} alt={testimonial.name} className="w-12 h-12 md:w-14 md:h-14 rounded-full object-cover mr-3 md:mr-4 border-2 border-[#d4af37]/20 shadow-md" />
<div className="absolute inset-0 rounded-full border border-[#d4af37]/40"></div>
<img src={testimonial.image} alt={testimonial.name} className="w-12 h-12 md:w-14 md:h-14 rounded-full object-cover mr-3 md:mr-4 border-2 border-[var(--luxury-gold)]/20 shadow-md" />
<div className="absolute inset-0 rounded-full border border-[var(--luxury-gold)]/40"></div>
</div>
) : (
<div className="w-12 h-12 md:w-14 md:h-14 rounded-full bg-gradient-to-br from-[#d4af37] to-[#f5d76e] flex items-center justify-center text-white font-bold text-base md:text-lg mr-3 md:mr-4 shadow-md border-2 border-white">
<div className="w-12 h-12 md:w-14 md:h-14 rounded-full bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-light)] flex items-center justify-center text-white font-bold text-base md:text-lg mr-3 md:mr-4 shadow-md border-2 border-white">
{testimonial.name.charAt(0).toUpperCase()}
</div>
)}
@@ -1045,7 +1045,7 @@ const HomePage: React.FC = () => {
</div>
</div>
<div className="relative">
<div className="absolute -top-1 -left-1 text-4xl md:text-5xl text-[#d4af37]/8 font-serif">"</div>
<div className="absolute -top-1 -left-1 text-4xl md:text-5xl text-[var(--luxury-gold)]/8 font-serif">"</div>
<p className="text-sm md:text-base text-gray-700 leading-relaxed italic relative z-10 font-light">{testimonial.quote}</p>
</div>
</div>
@@ -1057,15 +1057,15 @@ const HomePage: React.FC = () => {
{}
{(pageContent?.sections_enabled?.stats !== false) && pageContent?.stats && Array.isArray(pageContent.stats) && pageContent.stats.length > 0 && (
<section className="container mx-auto px-4 sm:px-6 lg:px-8 py-12 md:py-16">
<div className="relative bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900 rounded-xl md:rounded-2xl p-6 md:p-8 lg:p-10 shadow-xl shadow-black/30 animate-fade-in overflow-hidden border border-[#d4af37]/15">
<div className="relative bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900 rounded-xl md:rounded-2xl p-6 md:p-8 lg:p-10 shadow-xl shadow-black/30 animate-fade-in overflow-hidden border border-[var(--luxury-gold)]/15">
{}
<div className="absolute top-0 left-0 right-0 h-0.5 bg-gradient-to-r from-[#d4af37] via-[#f5d76e] to-[#d4af37]"></div>
<div className="absolute inset-0 opacity-8 bg-[radial-gradient(circle_at_1px_1px,#d4af37_1px,transparent_0)] bg-[length:40px_40px]"></div>
<div className="absolute top-0 left-0 right-0 h-0.5 bg-gradient-to-r from-[var(--luxury-gold)] via-[var(--luxury-gold-light)] to-[var(--luxury-gold)]"></div>
<div className="absolute inset-0 opacity-8 bg-[radial-gradient(circle_at_1px_1px,var(--luxury-gold)_1px,transparent_0)] bg-[length:40px_40px]"></div>
{(pageContent?.stats_section_title || pageContent?.stats_section_subtitle) && (
<div className="text-center mb-8 md:mb-10 animate-fade-in relative z-10">
<div className="inline-block mb-3">
<div className="h-0.5 w-16 md:w-20 bg-gradient-to-r from-[#d4af37] to-[#f5d76e] mx-auto rounded-full"></div>
<div className="h-0.5 w-16 md:w-20 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-light)] mx-auto rounded-full"></div>
</div>
{pageContent.stats_section_title && (
<h2 className="text-2xl sm:text-3xl md:text-4xl font-serif font-bold text-white tracking-tight mb-3 md:mb-4 px-4">
@@ -1087,7 +1087,7 @@ const HomePage: React.FC = () => {
<div className="mb-3 md:mb-4 group-hover:scale-110 transition-transform duration-300 flex items-center justify-center">
{stat.icon && (LucideIcons as any)[stat.icon] ? (
React.createElement((LucideIcons as any)[stat.icon], {
className: 'w-8 h-8 md:w-10 md:h-10 text-[#d4af37] drop-shadow-md'
className: 'w-8 h-8 md:w-10 md:h-10 text-[var(--luxury-gold)] drop-shadow-md'
})
) : (
<span className="text-3xl md:text-4xl">{stat.icon}</span>
@@ -1095,7 +1095,7 @@ const HomePage: React.FC = () => {
</div>
)}
{stat?.number && (
<div className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold text-[#d4af37] mb-1 md:mb-2 font-serif tracking-tight">
<div className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold text-[var(--luxury-gold)] mb-1 md:mb-2 font-serif tracking-tight">
{stat.number}
</div>
)}
@@ -1116,7 +1116,7 @@ const HomePage: React.FC = () => {
<section className="container mx-auto px-4 sm:px-6 lg:px-8 py-12 md:py-16">
<div className="text-center mb-8 md:mb-10 animate-fade-in">
<div className="inline-block mb-3">
<div className="h-0.5 w-16 md:w-20 bg-gradient-to-r from-[#d4af37] to-[#f5d76e] mx-auto rounded-full"></div>
<div className="h-0.5 w-16 md:w-20 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-light)] mx-auto rounded-full"></div>
</div>
<h2 className="text-2xl sm:text-3xl md:text-4xl font-serif font-bold text-gray-900 tracking-tight mb-3 md:mb-4 px-4">
{pageContent.amenities_section_title || 'Luxury Amenities'}
@@ -1127,24 +1127,24 @@ const HomePage: React.FC = () => {
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-5 md:gap-6 px-4">
{pageContent.amenities.map((amenity, index) => (
<div key={index} className="relative bg-white rounded-lg md:rounded-xl p-5 md:p-6 group hover:shadow-xl hover:shadow-[#d4af37]/10 transition-all duration-300 animate-fade-in border border-gray-100/50 hover:border-[#d4af37]/25 hover:-translate-y-1" style={{ animationDelay: `${index * 0.1}s` }}>
<div className="absolute top-0 left-0 w-full h-0.5 bg-gradient-to-r from-[#d4af37] to-[#f5d76e] opacity-0 group-hover:opacity-100 transition-opacity duration-300 rounded-t-lg md:rounded-t-xl"></div>
<div key={index} className="relative bg-white rounded-lg md:rounded-xl p-5 md:p-6 group hover:shadow-xl hover:shadow-[var(--luxury-gold)]/10 transition-all duration-300 animate-fade-in border border-gray-100/50 hover:border-[var(--luxury-gold)]/25 hover:-translate-y-1" style={{ animationDelay: `${index * 0.1}s` }}>
<div className="absolute top-0 left-0 w-full h-0.5 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-light)] opacity-0 group-hover:opacity-100 transition-opacity duration-300 rounded-t-lg md:rounded-t-xl"></div>
{amenity.image ? (
<div className="w-full h-40 md:h-48 mb-4 md:mb-5 rounded-lg md:rounded-xl overflow-hidden shadow-lg group-hover:scale-105 transition-transform duration-300 border border-gray-100 group-hover:border-[#d4af37]/25">
<div className="w-full h-40 md:h-48 mb-4 md:mb-5 rounded-lg md:rounded-xl overflow-hidden shadow-lg group-hover:scale-105 transition-transform duration-300 border border-gray-100 group-hover:border-[var(--luxury-gold)]/25">
<img src={amenity.image} alt={amenity.title} className="w-full h-full object-cover" />
</div>
) : (
<div className="w-14 h-14 md:w-16 md:h-16 bg-gradient-to-br from-[#d4af37]/15 via-[#f5d76e]/10 to-[#d4af37]/15 rounded-lg flex items-center justify-center mb-4 md:mb-5 mx-auto group-hover:scale-110 group-hover:shadow-lg group-hover:shadow-[#d4af37]/20 transition-all duration-300 border border-[#d4af37]/25 group-hover:border-[#d4af37]/40">
<div className="w-14 h-14 md:w-16 md:h-16 bg-gradient-to-br from-[var(--luxury-gold)]/15 via-[var(--luxury-gold-light)]/10 to-[var(--luxury-gold)]/15 rounded-lg flex items-center justify-center mb-4 md:mb-5 mx-auto group-hover:scale-110 group-hover:shadow-lg group-hover:shadow-[var(--luxury-gold)]/20 transition-all duration-300 border border-[var(--luxury-gold)]/25 group-hover:border-[var(--luxury-gold)]/40">
{amenity.icon && (LucideIcons as any)[amenity.icon] ? (
React.createElement((LucideIcons as any)[amenity.icon], {
className: 'w-7 h-7 md:w-8 md:h-8 text-[#d4af37] drop-shadow-md'
className: 'w-7 h-7 md:w-8 md:h-8 text-[var(--luxury-gold)] drop-shadow-md'
})
) : (
<span className="text-2xl md:text-3xl">✨</span>
)}
</div>
)}
<h3 className="text-lg md:text-xl font-serif font-semibold mb-2 md:mb-3 text-gray-900 group-hover:text-[#d4af37] transition-colors duration-300 tracking-tight">
<h3 className="text-lg md:text-xl font-serif font-semibold mb-2 md:mb-3 text-gray-900 group-hover:text-[var(--luxury-gold)] transition-colors duration-300 tracking-tight">
{amenity.title}
</h3>
<p className="text-sm md:text-base text-gray-600 leading-relaxed font-light tracking-wide">
@@ -1161,10 +1161,10 @@ const HomePage: React.FC = () => {
{}
{(pageContent?.sections_enabled?.about_preview !== false) && (pageContent?.about_preview_title || pageContent?.about_preview_content) && (
<section className="container mx-auto px-4 sm:px-6 lg:px-8 py-12 md:py-16">
<div className="relative bg-white rounded-xl md:rounded-2xl shadow-xl shadow-[#d4af37]/5 overflow-hidden animate-fade-in border border-gray-100/50">
<div className="relative bg-white rounded-xl md:rounded-2xl shadow-xl shadow-[var(--luxury-gold)]/5 overflow-hidden animate-fade-in border border-gray-100/50">
{}
<div className="absolute top-0 left-0 right-0 h-1 bg-gradient-to-r from-[#d4af37] via-[#f5d76e] to-[#d4af37]"></div>
<div className="absolute bottom-0 left-0 right-0 h-1 bg-gradient-to-r from-[#d4af37] via-[#f5d76e] to-[#d4af37]"></div>
<div className="absolute top-0 left-0 right-0 h-1 bg-gradient-to-r from-[var(--luxury-gold)] via-[var(--luxury-gold-light)] to-[var(--luxury-gold)]"></div>
<div className="absolute bottom-0 left-0 right-0 h-1 bg-gradient-to-r from-[var(--luxury-gold)] via-[var(--luxury-gold-light)] to-[var(--luxury-gold)]"></div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-0">
{pageContent.about_preview_image && (
@@ -1179,7 +1179,7 @@ const HomePage: React.FC = () => {
)}
<div className="p-6 md:p-8 lg:p-10 xl:p-12 flex flex-col justify-center bg-gradient-to-br from-white to-gray-50/20">
<div className="inline-block mb-3 md:mb-4">
<div className="h-0.5 w-12 md:w-16 bg-gradient-to-r from-[#d4af37] to-[#f5d76e] rounded-full"></div>
<div className="h-0.5 w-12 md:w-16 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-light)] rounded-full"></div>
</div>
<h2 className="text-2xl sm:text-3xl md:text-4xl font-serif font-bold text-gray-900 mb-3 md:mb-4 tracking-tight leading-tight">
{pageContent.about_preview_title || 'About Our Hotel'}
@@ -1196,9 +1196,9 @@ const HomePage: React.FC = () => {
)}
<Link
to="/about"
className="group relative inline-flex items-center gap-2 px-6 py-2.5 md:px-8 md:py-3 bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-[#0f0f0f] rounded-lg font-semibold tracking-wide text-sm md:text-base shadow-md shadow-[#d4af37]/20 hover:shadow-lg hover:shadow-[#d4af37]/30 hover:-translate-y-0.5 transition-all duration-300 overflow-hidden w-fit"
className="group relative inline-flex items-center gap-2 px-6 py-2.5 md:px-8 md:py-3 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-[#0f0f0f] rounded-lg font-semibold tracking-wide text-sm md:text-base shadow-md shadow-[var(--luxury-gold)]/20 hover:shadow-lg hover:shadow-[var(--luxury-gold)]/30 hover:-translate-y-0.5 transition-all duration-300 overflow-hidden w-fit"
>
<span className="absolute inset-0 bg-gradient-to-r from-[#f5d76e] to-[#d4af37] opacity-0 group-hover:opacity-100 transition-opacity duration-300"></span>
<span className="absolute inset-0 bg-gradient-to-r from-[var(--luxury-gold-light)] to-[var(--luxury-gold)] opacity-0 group-hover:opacity-100 transition-opacity duration-300"></span>
<span className="relative z-10">Learn More</span>
<ArrowRight className="w-4 h-4 md:w-5 md:h-5 relative z-10 group-hover:translate-x-1 transition-transform duration-300" />
</Link>
@@ -1213,7 +1213,7 @@ const HomePage: React.FC = () => {
<section className="container mx-auto px-4 sm:px-6 lg:px-8 py-12 md:py-16">
<div className="text-center mb-8 md:mb-10 animate-fade-in">
<div className="inline-block mb-3">
<div className="h-0.5 w-16 md:w-20 bg-gradient-to-r from-[#d4af37] to-[#f5d76e] mx-auto rounded-full"></div>
<div className="h-0.5 w-16 md:w-20 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-light)] mx-auto rounded-full"></div>
</div>
<h2 className="text-2xl sm:text-3xl md:text-4xl font-serif font-bold text-gray-900 tracking-tight mb-3 md:mb-4 px-4">
{pageContent?.luxury_services_section_title || 'Luxury Services'}
@@ -1231,27 +1231,27 @@ const HomePage: React.FC = () => {
<Link
key={service.id}
to={`/services/${serviceSlug}`}
className="relative bg-white rounded-lg md:rounded-xl p-5 md:p-6 group hover:shadow-xl hover:shadow-[#d4af37]/10 transition-all duration-300 animate-fade-in border border-gray-100/50 hover:border-[#d4af37]/25 hover:-translate-y-1 block"
className="relative bg-white rounded-lg md:rounded-xl p-5 md:p-6 group hover:shadow-xl hover:shadow-[var(--luxury-gold)]/10 transition-all duration-300 animate-fade-in border border-gray-100/50 hover:border-[var(--luxury-gold)]/25 hover:-translate-y-1 block"
style={{ animationDelay: `${index * 0.1}s` }}
>
<div className="absolute top-0 left-0 w-full h-0.5 bg-gradient-to-r from-[#d4af37] to-[#f5d76e] opacity-0 group-hover:opacity-100 transition-opacity duration-300 rounded-t-lg md:rounded-t-xl"></div>
<div className="absolute top-0 left-0 w-full h-0.5 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-light)] opacity-0 group-hover:opacity-100 transition-opacity duration-300 rounded-t-lg md:rounded-t-xl"></div>
{service.image ? (
<div className="w-full h-40 md:h-48 mb-4 md:mb-5 rounded-lg md:rounded-xl overflow-hidden shadow-lg group-hover:scale-105 transition-transform duration-300 border border-gray-100 group-hover:border-[#d4af37]/25">
<div className="w-full h-40 md:h-48 mb-4 md:mb-5 rounded-lg md:rounded-xl overflow-hidden shadow-lg group-hover:scale-105 transition-transform duration-300 border border-gray-100 group-hover:border-[var(--luxury-gold)]/25">
<img src={service.image} alt={service.name} className="w-full h-full object-cover" />
</div>
) : (
<div className="w-14 h-14 md:w-16 md:h-16 bg-gradient-to-br from-[#d4af37]/15 via-[#f5d76e]/10 to-[#d4af37]/15 rounded-lg flex items-center justify-center mb-4 md:mb-5 mx-auto group-hover:scale-110 group-hover:shadow-lg group-hover:shadow-[#d4af37]/20 transition-all duration-300 border border-[#d4af37]/25 group-hover:border-[#d4af37]/40">
<div className="w-14 h-14 md:w-16 md:h-16 bg-gradient-to-br from-[var(--luxury-gold)]/15 via-[var(--luxury-gold-light)]/10 to-[var(--luxury-gold)]/15 rounded-lg flex items-center justify-center mb-4 md:mb-5 mx-auto group-hover:scale-110 group-hover:shadow-lg group-hover:shadow-[var(--luxury-gold)]/20 transition-all duration-300 border border-[var(--luxury-gold)]/25 group-hover:border-[var(--luxury-gold)]/40">
<span className="text-2xl md:text-3xl">✨</span>
</div>
)}
<h3 className="text-lg md:text-xl font-serif font-semibold mb-2 md:mb-3 text-gray-900 group-hover:text-[#d4af37] transition-colors duration-300 tracking-tight">
<h3 className="text-lg md:text-xl font-serif font-semibold mb-2 md:mb-3 text-gray-900 group-hover:text-[var(--luxury-gold)] transition-colors duration-300 tracking-tight">
{service.name}
</h3>
<p className="text-sm md:text-base text-gray-600 leading-relaxed font-light tracking-wide">
{service.description || 'Premium service for your comfort'}
</p>
{service.price && (
<div className="mt-3 text-sm font-semibold text-[#d4af37]">
<div className="mt-3 text-sm font-semibold text-[var(--luxury-gold)]">
Starting from {formatCurrency(service.price)}
</div>
)}
@@ -1262,7 +1262,7 @@ const HomePage: React.FC = () => {
<div className="text-center mt-8 md:mt-10">
<Link
to={pageContent?.services_section_button_link || '/services'}
className="inline-flex items-center gap-2 px-6 py-3 bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-[#0f0f0f] rounded-lg font-medium hover:from-[#f5d76e] hover:to-[#d4af37] transition-all duration-300 shadow-lg shadow-[#d4af37]/30 hover:shadow-xl hover:shadow-[#d4af37]/40 hover:-translate-y-0.5"
className="inline-flex items-center gap-2 px-6 py-3 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-[#0f0f0f] rounded-lg font-medium hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] transition-all duration-300 shadow-lg shadow-[var(--luxury-gold)]/30 hover:shadow-xl hover:shadow-[var(--luxury-gold)]/40 hover:-translate-y-0.5"
>
<span>{pageContent?.services_section_button_text || 'View All Services'}</span>
<ArrowRight className="w-5 h-5" />
@@ -1276,7 +1276,7 @@ const HomePage: React.FC = () => {
<section className="container mx-auto px-4 sm:px-6 lg:px-8 py-12 md:py-16 bg-gradient-to-b from-white via-gray-50/20 to-white">
<div className="text-center mb-8 md:mb-10 animate-fade-in">
<div className="inline-block mb-3">
<div className="h-0.5 w-16 md:w-20 bg-gradient-to-r from-[#d4af37] to-[#f5d76e] mx-auto rounded-full"></div>
<div className="h-0.5 w-16 md:w-20 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-light)] mx-auto rounded-full"></div>
</div>
<h2 className="text-2xl sm:text-3xl md:text-4xl font-serif font-bold text-gray-900 tracking-tight mb-3 md:mb-4 px-4">
{pageContent.luxury_experiences_section_title || 'Unique Experiences'}
@@ -1289,24 +1289,24 @@ const HomePage: React.FC = () => {
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-5 md:gap-6 px-4">
{pageContent.luxury_experiences.map((experience: any, index: number) => (
<div key={index} className="relative bg-white rounded-lg md:rounded-xl p-5 md:p-6 group hover:shadow-xl hover:shadow-[#d4af37]/10 transition-all duration-300 animate-fade-in border border-gray-100/50 hover:border-[#d4af37]/25 hover:-translate-y-1" style={{ animationDelay: `${index * 0.1}s` }}>
<div className="absolute top-0 left-0 w-full h-0.5 bg-gradient-to-r from-[#d4af37] to-[#f5d76e] opacity-0 group-hover:opacity-100 transition-opacity duration-300 rounded-t-lg md:rounded-t-xl"></div>
<div key={index} className="relative bg-white rounded-lg md:rounded-xl p-5 md:p-6 group hover:shadow-xl hover:shadow-[var(--luxury-gold)]/10 transition-all duration-300 animate-fade-in border border-gray-100/50 hover:border-[var(--luxury-gold)]/25 hover:-translate-y-1" style={{ animationDelay: `${index * 0.1}s` }}>
<div className="absolute top-0 left-0 w-full h-0.5 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-light)] opacity-0 group-hover:opacity-100 transition-opacity duration-300 rounded-t-lg md:rounded-t-xl"></div>
{experience.image ? (
<div className="w-full h-40 md:h-48 mb-4 md:mb-5 rounded-lg md:rounded-xl overflow-hidden shadow-lg group-hover:scale-105 transition-transform duration-300 border border-gray-100 group-hover:border-[#d4af37]/25">
<div className="w-full h-40 md:h-48 mb-4 md:mb-5 rounded-lg md:rounded-xl overflow-hidden shadow-lg group-hover:scale-105 transition-transform duration-300 border border-gray-100 group-hover:border-[var(--luxury-gold)]/25">
<img src={experience.image} alt={experience.title} className="w-full h-full object-cover" />
</div>
) : (
<div className="w-14 h-14 md:w-16 md:h-16 bg-gradient-to-br from-[#d4af37]/15 via-[#f5d76e]/10 to-[#d4af37]/15 rounded-lg flex items-center justify-center mb-4 md:mb-5 mx-auto group-hover:scale-110 group-hover:shadow-lg group-hover:shadow-[#d4af37]/20 transition-all duration-300 border border-[#d4af37]/25 group-hover:border-[#d4af37]/40">
<div className="w-14 h-14 md:w-16 md:h-16 bg-gradient-to-br from-[var(--luxury-gold)]/15 via-[var(--luxury-gold-light)]/10 to-[var(--luxury-gold)]/15 rounded-lg flex items-center justify-center mb-4 md:mb-5 mx-auto group-hover:scale-110 group-hover:shadow-lg group-hover:shadow-[var(--luxury-gold)]/20 transition-all duration-300 border border-[var(--luxury-gold)]/25 group-hover:border-[var(--luxury-gold)]/40">
{experience.icon && (LucideIcons as any)[experience.icon] ? (
React.createElement((LucideIcons as any)[experience.icon], {
className: 'w-7 h-7 md:w-8 md:h-8 text-[#d4af37] drop-shadow-md'
className: 'w-7 h-7 md:w-8 md:h-8 text-[var(--luxury-gold)] drop-shadow-md'
})
) : (
<span className="text-2xl md:text-3xl">✨</span>
)}
</div>
)}
<h3 className="text-lg md:text-xl font-serif font-semibold mb-2 md:mb-3 text-gray-900 group-hover:text-[#d4af37] transition-colors duration-300 tracking-tight">
<h3 className="text-lg md:text-xl font-serif font-semibold mb-2 md:mb-3 text-gray-900 group-hover:text-[var(--luxury-gold)] transition-colors duration-300 tracking-tight">
{experience.title}
</h3>
<p className="text-sm md:text-base text-gray-600 leading-relaxed font-light tracking-wide">
@@ -1323,7 +1323,7 @@ const HomePage: React.FC = () => {
<section className="container mx-auto px-4 sm:px-6 lg:px-8 py-12 md:py-16">
<div className="text-center mb-8 md:mb-10 animate-fade-in">
<div className="inline-block mb-3">
<div className="h-0.5 w-16 md:w-20 bg-gradient-to-r from-[#d4af37] to-[#f5d76e] mx-auto rounded-full"></div>
<div className="h-0.5 w-16 md:w-20 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-light)] mx-auto rounded-full"></div>
</div>
<h2 className="text-2xl sm:text-3xl md:text-4xl font-serif font-bold text-gray-900 tracking-tight mb-3 md:mb-4 px-4">
{pageContent.awards_section_title || 'Awards & Recognition'}
@@ -1336,17 +1336,17 @@ const HomePage: React.FC = () => {
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-5 md:gap-6 px-4">
{pageContent.awards.map((award: any, index: number) => (
<div key={index} className="relative bg-white rounded-lg md:rounded-xl p-5 md:p-6 group hover:shadow-xl hover:shadow-[#d4af37]/10 transition-all duration-300 animate-fade-in border border-gray-100/50 hover:border-[#d4af37]/25 hover:-translate-y-1 text-center" style={{ animationDelay: `${index * 0.1}s` }}>
<div className="absolute top-0 left-0 w-full h-0.5 bg-gradient-to-r from-[#d4af37] to-[#f5d76e] opacity-0 group-hover:opacity-100 transition-opacity duration-300 rounded-t-lg md:rounded-t-xl"></div>
<div key={index} className="relative bg-white rounded-lg md:rounded-xl p-5 md:p-6 group hover:shadow-xl hover:shadow-[var(--luxury-gold)]/10 transition-all duration-300 animate-fade-in border border-gray-100/50 hover:border-[var(--luxury-gold)]/25 hover:-translate-y-1 text-center" style={{ animationDelay: `${index * 0.1}s` }}>
<div className="absolute top-0 left-0 w-full h-0.5 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-light)] opacity-0 group-hover:opacity-100 transition-opacity duration-300 rounded-t-lg md:rounded-t-xl"></div>
{award.image ? (
<div className="w-20 h-20 md:w-24 md:h-24 mx-auto mb-4 md:mb-5 rounded-lg overflow-hidden shadow-lg">
<img src={award.image} alt={award.title} className="w-full h-full object-cover" />
</div>
) : (
<div className="w-16 h-16 md:w-20 md:h-20 bg-gradient-to-br from-[#d4af37]/15 via-[#f5d76e]/10 to-[#d4af37]/15 rounded-lg flex items-center justify-center mx-auto mb-4 md:mb-5 group-hover:scale-110 group-hover:shadow-lg group-hover:shadow-[#d4af37]/20 transition-all duration-300 border border-[#d4af37]/25 group-hover:border-[#d4af37]/40">
<div className="w-16 h-16 md:w-20 md:h-20 bg-gradient-to-br from-[var(--luxury-gold)]/15 via-[var(--luxury-gold-light)]/10 to-[var(--luxury-gold)]/15 rounded-lg flex items-center justify-center mx-auto mb-4 md:mb-5 group-hover:scale-110 group-hover:shadow-lg group-hover:shadow-[var(--luxury-gold)]/20 transition-all duration-300 border border-[var(--luxury-gold)]/25 group-hover:border-[var(--luxury-gold)]/40">
{award.icon && (LucideIcons as any)[award.icon] ? (
React.createElement((LucideIcons as any)[award.icon], {
className: 'w-8 h-8 md:w-10 md:h-10 text-[#d4af37] drop-shadow-md'
className: 'w-8 h-8 md:w-10 md:h-10 text-[var(--luxury-gold)] drop-shadow-md'
})
) : (
<span className="text-3xl">🏆</span>
@@ -1354,9 +1354,9 @@ const HomePage: React.FC = () => {
</div>
)}
{award.year && (
<div className="text-xs md:text-sm text-[#d4af37] font-semibold mb-2">{award.year}</div>
<div className="text-xs md:text-sm text-[var(--luxury-gold)] font-semibold mb-2">{award.year}</div>
)}
<h3 className="text-base md:text-lg font-serif font-semibold mb-2 text-gray-900 group-hover:text-[#d4af37] transition-colors duration-300 tracking-tight">
<h3 className="text-base md:text-lg font-serif font-semibold mb-2 text-gray-900 group-hover:text-[var(--luxury-gold)] transition-colors duration-300 tracking-tight">
{award.title}
</h3>
{award.description && (
@@ -1373,7 +1373,7 @@ const HomePage: React.FC = () => {
{}
{(pageContent?.cta_title || pageContent?.cta_subtitle) && (
<section className="container mx-auto px-4 sm:px-6 lg:px-8 py-12 md:py-16">
<div className="relative bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900 rounded-xl md:rounded-2xl p-8 md:p-12 lg:p-16 shadow-xl shadow-black/30 animate-fade-in overflow-hidden border border-[#d4af37]/15">
<div className="relative bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900 rounded-xl md:rounded-2xl p-8 md:p-12 lg:p-16 shadow-xl shadow-black/30 animate-fade-in overflow-hidden border border-[var(--luxury-gold)]/15">
{pageContent.cta_image && (
<div className="absolute inset-0 opacity-20">
<img src={pageContent.cta_image} alt="CTA Background" className="w-full h-full object-cover" />
@@ -1382,7 +1382,7 @@ const HomePage: React.FC = () => {
<div className="absolute inset-0 bg-gradient-to-r from-black/60 via-black/40 to-black/60"></div>
<div className="relative z-10 text-center">
<div className="inline-block mb-4">
<div className="h-0.5 w-16 md:w-20 bg-gradient-to-r from-[#d4af37] to-[#f5d76e] mx-auto rounded-full"></div>
<div className="h-0.5 w-16 md:w-20 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-light)] mx-auto rounded-full"></div>
</div>
<h2 className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-serif font-bold text-white mb-4 md:mb-6 tracking-tight">
{pageContent.cta_title}
@@ -1395,9 +1395,9 @@ const HomePage: React.FC = () => {
{pageContent.cta_button_text && pageContent.cta_button_link && (
<Link
to={pageContent.cta_button_link}
className="group relative inline-flex items-center gap-2 px-8 py-3 md:px-10 md:py-4 bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-[#0f0f0f] rounded-lg font-semibold tracking-wide text-base md:text-lg shadow-lg shadow-[#d4af37]/30 hover:shadow-xl hover:shadow-[#d4af37]/40 hover:-translate-y-1 transition-all duration-300 overflow-hidden"
className="group relative inline-flex items-center gap-2 px-8 py-3 md:px-10 md:py-4 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-[#0f0f0f] rounded-lg font-semibold tracking-wide text-base md:text-lg shadow-lg shadow-[var(--luxury-gold)]/30 hover:shadow-xl hover:shadow-[var(--luxury-gold)]/40 hover:-translate-y-1 transition-all duration-300 overflow-hidden"
>
<span className="absolute inset-0 bg-gradient-to-r from-[#f5d76e] to-[#d4af37] opacity-0 group-hover:opacity-100 transition-opacity duration-300"></span>
<span className="absolute inset-0 bg-gradient-to-r from-[var(--luxury-gold-light)] to-[var(--luxury-gold)] opacity-0 group-hover:opacity-100 transition-opacity duration-300"></span>
<span className="relative z-10">{pageContent.cta_button_text}</span>
<ArrowRight className="w-5 h-5 md:w-6 md:h-6 relative z-10 group-hover:translate-x-1 transition-transform duration-300" />
</Link>
@@ -1413,7 +1413,7 @@ const HomePage: React.FC = () => {
<div className="container mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-8 md:mb-10 animate-fade-in">
<div className="inline-block mb-3">
<div className="h-0.5 w-16 md:w-20 bg-gradient-to-r from-[#d4af37] to-[#f5d76e] mx-auto rounded-full"></div>
<div className="h-0.5 w-16 md:w-20 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-light)] mx-auto rounded-full"></div>
</div>
<h2 className="text-2xl sm:text-3xl md:text-4xl font-serif font-bold text-gray-900 tracking-tight mb-3 md:mb-4 px-4">
{pageContent.partners_section_title || 'Our Partners'}
@@ -1439,7 +1439,7 @@ const HomePage: React.FC = () => {
<section className="container mx-auto px-4 sm:px-6 lg:px-8 py-12 md:py-16 bg-gradient-to-b from-white via-gray-50/20 to-white">
<div className="text-center mb-8 md:mb-10 animate-fade-in">
<div className="inline-block mb-3">
<div className="h-0.5 w-16 md:w-20 bg-gradient-to-r from-[#d4af37] to-[#f5d76e] mx-auto rounded-full"></div>
<div className="h-0.5 w-16 md:w-20 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-light)] mx-auto rounded-full"></div>
</div>
{pageContent.promotions_section_title && (
<h2 className="text-2xl sm:text-3xl md:text-4xl font-serif font-bold text-gray-900 tracking-tight mb-3 md:mb-4 px-4">
@@ -1524,7 +1524,7 @@ const HomePage: React.FC = () => {
<div className="p-6">
<div className="flex items-start justify-between mb-2">
<h3 className={`text-xl font-bold mb-2 transition-colors ${
isValid ? 'text-gray-900 group-hover:text-[#d4af37]' : 'text-gray-500'
isValid ? 'text-gray-900 group-hover:text-[var(--luxury-gold)]' : 'text-gray-500'
}`}>
{promo.title}
</h3>
@@ -1561,7 +1561,7 @@ const HomePage: React.FC = () => {
}}
className={`inline-flex items-center gap-2 px-6 py-2 rounded-lg font-semibold transition-all duration-300 ${
isValid
? 'bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-[#0f0f0f] hover:from-[#f5d76e] hover:to-[#d4af37] cursor-pointer group-hover:shadow-lg'
? 'bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-[#0f0f0f] hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] cursor-pointer group-hover:shadow-lg'
: 'bg-gray-300 text-gray-500 cursor-not-allowed'
}`}
role="button"
@@ -1587,7 +1587,7 @@ const HomePage: React.FC = () => {
<section className="container mx-auto px-4 sm:px-6 lg:px-8 py-12 md:py-16 bg-gradient-to-b from-white via-gray-50/20 to-white">
<div className="text-center mb-8 md:mb-10 animate-fade-in">
<div className="inline-block mb-3">
<div className="h-0.5 w-16 md:w-20 bg-gradient-to-r from-[#d4af37] to-[#f5d76e] mx-auto rounded-full"></div>
<div className="h-0.5 w-16 md:w-20 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-light)] mx-auto rounded-full"></div>
</div>
{pageContent.blog_section_title && (
<h2 className="text-2xl sm:text-3xl md:text-4xl font-serif font-bold text-gray-900 tracking-tight mb-3 md:mb-4 px-4">
@@ -1636,13 +1636,13 @@ const HomePage: React.FC = () => {
{new Date(post.published_at).toLocaleDateString()}
</p>
)}
<h3 className="text-xl font-bold text-gray-900 mb-2 group-hover:text-[#d4af37] transition-colors">
<h3 className="text-xl font-bold text-gray-900 mb-2 group-hover:text-[var(--luxury-gold)] transition-colors">
{post.title}
</h3>
{post.excerpt && (
<p className="text-gray-600 mb-4 line-clamp-3">{post.excerpt}</p>
)}
<div className="flex items-center gap-2 text-[#d4af37] font-semibold group-hover:gap-3 transition-all">
<div className="flex items-center gap-2 text-[var(--luxury-gold)] font-semibold group-hover:gap-3 transition-all">
Read More
<ArrowRight className="w-4 h-4" />
</div>
@@ -1655,7 +1655,7 @@ const HomePage: React.FC = () => {
<div className="text-center mt-8 md:mt-10">
<Link
to="/blog"
className="inline-flex items-center gap-2 px-8 py-3 bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-[#0f0f0f] rounded-lg font-semibold hover:from-[#f5d76e] hover:to-[#d4af37] transition-all duration-300 shadow-lg shadow-[#d4af37]/30 hover:shadow-xl hover:shadow-[#d4af37]/40 hover:-translate-y-0.5"
className="inline-flex items-center gap-2 px-8 py-3 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-[#0f0f0f] rounded-lg font-semibold hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] transition-all duration-300 shadow-lg shadow-[var(--luxury-gold)]/30 hover:shadow-xl hover:shadow-[var(--luxury-gold)]/40 hover:-translate-y-0.5"
>
View All Posts
<ArrowRight className="w-5 h-5" />
@@ -1680,7 +1680,7 @@ const HomePage: React.FC = () => {
e.stopPropagation();
setLightboxOpen(false);
}}
className="absolute top-4 right-4 md:top-6 md:right-6 z-50 p-3 bg-black/50 hover:bg-black/70 rounded-full text-white hover:text-[#d4af37] transition-all duration-300 backdrop-blur-sm border border-white/10 hover:border-[#d4af37]/50"
className="absolute top-4 right-4 md:top-6 md:right-6 z-50 p-3 bg-black/50 hover:bg-black/70 rounded-full text-white hover:text-[var(--luxury-gold)] transition-all duration-300 backdrop-blur-sm border border-white/10 hover:border-[var(--luxury-gold)]/50"
aria-label="Close"
>
<X className="w-6 h-6 md:w-7 md:h-7" />
@@ -1693,7 +1693,7 @@ const HomePage: React.FC = () => {
e.stopPropagation();
setLightboxIndex((prev) => (prev === 0 ? lightboxImages.length - 1 : prev - 1));
}}
className="absolute left-4 md:left-6 z-50 p-3 bg-black/50 hover:bg-black/70 rounded-full text-white hover:text-[#d4af37] transition-all duration-300 backdrop-blur-sm border border-white/10 hover:border-[#d4af37]/50"
className="absolute left-4 md:left-6 z-50 p-3 bg-black/50 hover:bg-black/70 rounded-full text-white hover:text-[var(--luxury-gold)] transition-all duration-300 backdrop-blur-sm border border-white/10 hover:border-[var(--luxury-gold)]/50"
aria-label="Previous image"
>
<ChevronLeft className="w-6 h-6 md:w-7 md:h-7" />
@@ -1707,7 +1707,7 @@ const HomePage: React.FC = () => {
e.stopPropagation();
setLightboxIndex((prev) => (prev === lightboxImages.length - 1 ? 0 : prev + 1));
}}
className="absolute right-4 md:right-6 z-50 p-3 bg-black/50 hover:bg-black/70 rounded-full text-white hover:text-[#d4af37] transition-all duration-300 backdrop-blur-sm border border-white/10 hover:border-[#d4af37]/50"
className="absolute right-4 md:right-6 z-50 p-3 bg-black/50 hover:bg-black/70 rounded-full text-white hover:text-[var(--luxury-gold)] transition-all duration-300 backdrop-blur-sm border border-white/10 hover:border-[var(--luxury-gold)]/50"
aria-label="Next image"
>
<ChevronRight className="w-6 h-6 md:w-7 md:h-7" />
@@ -1748,7 +1748,7 @@ const HomePage: React.FC = () => {
}}
className={`flex-shrink-0 w-16 h-16 md:w-20 md:h-20 rounded-lg overflow-hidden border-2 transition-all duration-300 ${
idx === lightboxIndex
? 'border-[#d4af37] shadow-lg shadow-[#d4af37]/50 scale-110'
? 'border-[var(--luxury-gold)] shadow-lg shadow-[var(--luxury-gold)]/50 scale-110'
: 'border-white/30 hover:border-white/60 opacity-70 hover:opacity-100'
}`}
>

View File

@@ -99,12 +99,12 @@ const PrivacyPolicyPage: React.FC = () => {
}}
>
<div className="text-center">
<Shield className="w-16 h-16 text-[#d4af37]/50 mx-auto mb-4" />
<Shield className="w-16 h-16 text-[var(--luxury-gold)]/50 mx-auto mb-4" />
<h1 className="text-2xl font-elegant font-bold text-white mb-2">Privacy Policy</h1>
<p className="text-gray-400">This page is currently unavailable.</p>
<Link
to="/"
className="inline-flex items-center gap-2 text-[#d4af37]/80 hover:text-[#d4af37] mt-6 transition-all duration-300"
className="inline-flex items-center gap-2 text-[var(--luxury-gold)]/80 hover:text-[var(--luxury-gold)] mt-6 transition-all duration-300"
>
<ArrowLeft className="w-4 h-4" />
<span>Back to Home</span>
@@ -129,7 +129,7 @@ const PrivacyPolicyPage: React.FC = () => {
{/* Back Link */}
<Link
to="/"
className="inline-flex items-center gap-2 text-[#d4af37]/80 hover:text-[#d4af37] mb-6 transition-all duration-300 group font-light tracking-wide text-xs sm:text-sm"
className="inline-flex items-center gap-2 text-[var(--luxury-gold)]/80 hover:text-[var(--luxury-gold)] mb-6 transition-all duration-300 group font-light tracking-wide text-xs sm:text-sm"
>
<ArrowLeft className="w-4 h-4 group-hover:-translate-x-1 transition-transform" />
<span>Back to Home</span>
@@ -137,10 +137,10 @@ const PrivacyPolicyPage: React.FC = () => {
{/* Header */}
<div className="mb-8 sm:mb-12 text-center">
<div className="inline-flex items-center justify-center w-16 h-16 sm:w-20 sm:h-20 mb-4 sm:mb-6 bg-gradient-to-br from-[#d4af37]/20 to-[#c9a227]/10 rounded-full border border-[#d4af37]/30">
<Shield className="w-8 h-8 sm:w-10 sm:h-10 text-[#d4af37]" />
<div className="inline-flex items-center justify-center w-16 h-16 sm:w-20 sm:h-20 mb-4 sm:mb-6 bg-gradient-to-br from-[var(--luxury-gold)]/20 to-[var(--luxury-gold-dark)]/10 rounded-full border border-[var(--luxury-gold)]/30">
<Shield className="w-8 h-8 sm:w-10 sm:h-10 text-[var(--luxury-gold)]" />
</div>
<h1 className="text-3xl sm:text-4xl lg:text-5xl font-elegant font-bold text-white mb-3 sm:mb-4 tracking-tight leading-tight bg-gradient-to-r from-white via-[#d4af37] to-white bg-clip-text text-transparent">
<h1 className="text-3xl sm:text-4xl lg:text-5xl font-elegant font-bold text-white mb-3 sm:mb-4 tracking-tight leading-tight bg-gradient-to-r from-white via-[var(--luxury-gold)] to-white bg-clip-text text-transparent">
{pageContent.title || 'Privacy Policy'}
</h1>
{pageContent.subtitle && (
@@ -151,18 +151,18 @@ const PrivacyPolicyPage: React.FC = () => {
</div>
{/* Content */}
<div className="bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-xl border border-[#d4af37]/20 backdrop-blur-xl shadow-2xl shadow-[#d4af37]/5 p-6 sm:p-8 lg:p-12">
<div className="bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-xl border border-[var(--luxury-gold)]/20 backdrop-blur-xl shadow-2xl shadow-[var(--luxury-gold)]/5 p-6 sm:p-8 lg:p-12">
<div
className="prose prose-invert prose-lg max-w-none text-gray-300
prose-headings:text-white prose-headings:font-elegant prose-headings:font-semibold
prose-h2:text-2xl prose-h2:mt-8 prose-h2:mb-4 prose-h2:border-b prose-h2:border-[#d4af37]/20 prose-h2:pb-2
prose-h2:text-2xl prose-h2:mt-8 prose-h2:mb-4 prose-h2:border-b prose-h2:border-[var(--luxury-gold)]/20 prose-h2:pb-2
prose-p:text-gray-300 prose-p:font-light prose-p:leading-relaxed prose-p:mb-4
prose-ul:text-gray-300 prose-ul:font-light prose-ul:my-4
prose-li:text-gray-300 prose-li:mb-2 prose-li:ml-4
prose-strong:text-[#d4af37] prose-strong:font-medium
prose-a:text-[#d4af37] prose-a:no-underline hover:prose-a:underline
prose-strong:text-[var(--luxury-gold)] prose-strong:font-medium
prose-a:text-[var(--luxury-gold)] prose-a:no-underline hover:prose-a:underline
[&_*]:text-gray-300 [&_h1]:text-white [&_h2]:text-white [&_h3]:text-white [&_h4]:text-white [&_h5]:text-white [&_h6]:text-white
[&_strong]:text-[#d4af37] [&_b]:text-[#d4af37] [&_a]:text-[#d4af37]"
[&_strong]:text-[var(--luxury-gold)] [&_b]:text-[var(--luxury-gold)] [&_a]:text-[var(--luxury-gold)]"
style={{ color: '#d1d5db' }}
dangerouslySetInnerHTML={createSanitizedHtml(
pageContent.content || pageContent.description || '<p style="color: #d1d5db;">No content available.</p>'
@@ -176,7 +176,7 @@ const PrivacyPolicyPage: React.FC = () => {
<div className="text-center">
<p className="text-sm text-gray-400 font-light">
For questions about this policy, contact us at{' '}
<a href={`mailto:${settings.company_email}`} className="text-[#d4af37] hover:underline">
<a href={`mailto:${settings.company_email}`} className="text-[var(--luxury-gold)] hover:underline">
{settings.company_email}
</a>
</p>
@@ -185,7 +185,7 @@ const PrivacyPolicyPage: React.FC = () => {
<div className="text-center">
<Link
to="/gdpr"
className="inline-flex items-center gap-2 text-sm text-[#d4af37] hover:text-[#f5d76e] transition-colors font-light"
className="inline-flex items-center gap-2 text-sm text-[var(--luxury-gold)] hover:text-[var(--luxury-gold-light)] transition-colors font-light"
>
<Shield className="w-4 h-4" />
<span>Manage Your Data Privacy (GDPR)</span>

View File

@@ -99,12 +99,12 @@ const RefundsPolicyPage: React.FC = () => {
}}
>
<div className="text-center">
<RefreshCw className="w-16 h-16 text-[#d4af37]/50 mx-auto mb-4" />
<RefreshCw className="w-16 h-16 text-[var(--luxury-gold)]/50 mx-auto mb-4" />
<h1 className="text-2xl font-elegant font-bold text-white mb-2">Refunds Policy</h1>
<p className="text-gray-400">This page is currently unavailable.</p>
<Link
to="/"
className="inline-flex items-center gap-2 text-[#d4af37]/80 hover:text-[#d4af37] mt-6 transition-all duration-300"
className="inline-flex items-center gap-2 text-[var(--luxury-gold)]/80 hover:text-[var(--luxury-gold)] mt-6 transition-all duration-300"
>
<ArrowLeft className="w-4 h-4" />
<span>Back to Home</span>
@@ -129,7 +129,7 @@ const RefundsPolicyPage: React.FC = () => {
{/* Back Link */}
<Link
to="/"
className="inline-flex items-center gap-2 text-[#d4af37]/80 hover:text-[#d4af37] mb-6 transition-all duration-300 group font-light tracking-wide text-xs sm:text-sm"
className="inline-flex items-center gap-2 text-[var(--luxury-gold)]/80 hover:text-[var(--luxury-gold)] mb-6 transition-all duration-300 group font-light tracking-wide text-xs sm:text-sm"
>
<ArrowLeft className="w-4 h-4 group-hover:-translate-x-1 transition-transform" />
<span>Back to Home</span>
@@ -137,10 +137,10 @@ const RefundsPolicyPage: React.FC = () => {
{/* Header */}
<div className="mb-8 sm:mb-12 text-center">
<div className="inline-flex items-center justify-center w-16 h-16 sm:w-20 sm:h-20 mb-4 sm:mb-6 bg-gradient-to-br from-[#d4af37]/20 to-[#c9a227]/10 rounded-full border border-[#d4af37]/30">
<RefreshCw className="w-8 h-8 sm:w-10 sm:h-10 text-[#d4af37]" />
<div className="inline-flex items-center justify-center w-16 h-16 sm:w-20 sm:h-20 mb-4 sm:mb-6 bg-gradient-to-br from-[var(--luxury-gold)]/20 to-[var(--luxury-gold-dark)]/10 rounded-full border border-[var(--luxury-gold)]/30">
<RefreshCw className="w-8 h-8 sm:w-10 sm:h-10 text-[var(--luxury-gold)]" />
</div>
<h1 className="text-3xl sm:text-4xl lg:text-5xl font-elegant font-bold text-white mb-3 sm:mb-4 tracking-tight leading-tight bg-gradient-to-r from-white via-[#d4af37] to-white bg-clip-text text-transparent">
<h1 className="text-3xl sm:text-4xl lg:text-5xl font-elegant font-bold text-white mb-3 sm:mb-4 tracking-tight leading-tight bg-gradient-to-r from-white via-[var(--luxury-gold)] to-white bg-clip-text text-transparent">
{pageContent.title || 'Refunds Policy'}
</h1>
{pageContent.subtitle && (
@@ -151,18 +151,18 @@ const RefundsPolicyPage: React.FC = () => {
</div>
{/* Content */}
<div className="bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-xl border border-[#d4af37]/20 backdrop-blur-xl shadow-2xl shadow-[#d4af37]/5 p-6 sm:p-8 lg:p-12">
<div className="bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-xl border border-[var(--luxury-gold)]/20 backdrop-blur-xl shadow-2xl shadow-[var(--luxury-gold)]/5 p-6 sm:p-8 lg:p-12">
<div
className="prose prose-invert prose-lg max-w-none text-gray-300
prose-headings:text-white prose-headings:font-elegant prose-headings:font-semibold
prose-h2:text-2xl prose-h2:mt-8 prose-h2:mb-4 prose-h2:border-b prose-h2:border-[#d4af37]/20 prose-h2:pb-2
prose-h2:text-2xl prose-h2:mt-8 prose-h2:mb-4 prose-h2:border-b prose-h2:border-[var(--luxury-gold)]/20 prose-h2:pb-2
prose-p:text-gray-300 prose-p:font-light prose-p:leading-relaxed prose-p:mb-4
prose-ul:text-gray-300 prose-ul:font-light prose-ul:my-4
prose-li:text-gray-300 prose-li:mb-2 prose-li:ml-4
prose-strong:text-[#d4af37] prose-strong:font-medium
prose-a:text-[#d4af37] prose-a:no-underline hover:prose-a:underline
prose-strong:text-[var(--luxury-gold)] prose-strong:font-medium
prose-a:text-[var(--luxury-gold)] prose-a:no-underline hover:prose-a:underline
[&_*]:text-gray-300 [&_h1]:text-white [&_h2]:text-white [&_h3]:text-white [&_h4]:text-white [&_h5]:text-white [&_h6]:text-white
[&_strong]:text-[#d4af37] [&_b]:text-[#d4af37] [&_a]:text-[#d4af37]"
[&_strong]:text-[var(--luxury-gold)] [&_b]:text-[var(--luxury-gold)] [&_a]:text-[var(--luxury-gold)]"
style={{ color: '#d1d5db' }}
dangerouslySetInnerHTML={createSanitizedHtml(
pageContent.content || pageContent.description || '<p style="color: #d1d5db;">No content available.</p>'
@@ -175,7 +175,7 @@ const RefundsPolicyPage: React.FC = () => {
<div className="mt-8 text-center">
<p className="text-sm text-gray-400 font-light">
For refund inquiries, contact us at{' '}
<a href={`mailto:${settings.company_email}`} className="text-[#d4af37] hover:underline">
<a href={`mailto:${settings.company_email}`} className="text-[var(--luxury-gold)] hover:underline">
{settings.company_email}
</a>
</p>

View File

@@ -291,7 +291,7 @@ const ServiceDetailPage: React.FC = () => {
<div className="min-h-screen bg-gradient-to-b from-[#0f0f0f] via-[#1a1a1a] to-black text-white flex items-center justify-center">
<div className="text-center">
<h1 className="text-2xl font-bold mb-4">Service not found</h1>
<Link to="/services" className="text-[#d4af37] hover:underline">
<Link to="/services" className="text-[var(--luxury-gold)] hover:underline">
Back to Services
</Link>
</div>
@@ -316,8 +316,8 @@ const ServiceDetailPage: React.FC = () => {
{/* Luxury Overlay Pattern */}
<div className="absolute inset-0 opacity-10">
<div className="absolute top-0 left-0 w-96 h-96 bg-[#d4af37] rounded-full blur-3xl"></div>
<div className="absolute bottom-0 right-0 w-96 h-96 bg-[#c9a227] rounded-full blur-3xl"></div>
<div className="absolute top-0 left-0 w-96 h-96 bg-[var(--luxury-gold)] rounded-full blur-3xl"></div>
<div className="absolute bottom-0 right-0 w-96 h-96 bg-[var(--luxury-gold-dark)] rounded-full blur-3xl"></div>
</div>
{/* Hero Content Overlay */}
@@ -326,12 +326,12 @@ const ServiceDetailPage: React.FC = () => {
<div className="max-w-5xl mx-auto">
{service.category && (
<div className="flex flex-wrap gap-3 mb-6">
<span className="inline-flex items-center gap-2 px-5 py-2.5 bg-gradient-to-br from-[#d4af37]/20 to-[#c9a227]/10 backdrop-blur-md rounded-xl text-[#d4af37] text-sm font-semibold border border-[#d4af37]/40 shadow-xl">
<span className="inline-flex items-center gap-2 px-5 py-2.5 bg-gradient-to-br from-[var(--luxury-gold)]/20 to-[var(--luxury-gold-dark)]/10 backdrop-blur-md rounded-xl text-[var(--luxury-gold)] text-sm font-semibold border border-[var(--luxury-gold)]/40 shadow-xl">
<Tag className="w-4 h-4" />
{service.category}
</span>
{service.type === 'luxury' && (
<span className="inline-flex items-center gap-2 px-5 py-2.5 bg-gradient-to-br from-[#d4af37]/30 to-[#c9a227]/20 backdrop-blur-md rounded-xl text-[#0f0f0f] text-sm font-bold border border-[#d4af37]/50 shadow-xl">
<span className="inline-flex items-center gap-2 px-5 py-2.5 bg-gradient-to-br from-[var(--luxury-gold)]/30 to-[var(--luxury-gold-dark)]/20 backdrop-blur-md rounded-xl text-[#0f0f0f] text-sm font-bold border border-[var(--luxury-gold)]/50 shadow-xl">
<Star className="w-4 h-4 fill-[#0f0f0f]" />
Premium
</span>
@@ -348,7 +348,7 @@ const ServiceDetailPage: React.FC = () => {
)}
{service.price !== undefined && (
<div className="flex items-baseline gap-3 mb-8">
<span className="text-4xl sm:text-5xl lg:text-6xl font-serif font-bold bg-gradient-to-r from-[#d4af37] via-[#f5d76e] to-[#d4af37] bg-clip-text text-transparent drop-shadow-lg">
<span className="text-4xl sm:text-5xl lg:text-6xl font-serif font-bold bg-gradient-to-r from-[var(--luxury-gold)] via-[var(--luxury-gold-light)] to-[var(--luxury-gold)] bg-clip-text text-transparent drop-shadow-lg">
{formatCurrency(service.price)}
</span>
{service.unit && (
@@ -363,7 +363,7 @@ const ServiceDetailPage: React.FC = () => {
</div>
{/* Decorative Bottom Border */}
<div className="absolute bottom-0 left-0 w-full h-1 bg-gradient-to-r from-transparent via-[#d4af37]/50 to-transparent"></div>
<div className="absolute bottom-0 left-0 w-full h-1 bg-gradient-to-r from-transparent via-[var(--luxury-gold)]/50 to-transparent"></div>
</div>
)}
@@ -375,7 +375,7 @@ const ServiceDetailPage: React.FC = () => {
{!service.image && (
<Link
to="/services"
className="inline-flex items-center gap-3 px-6 py-3 bg-gradient-to-br from-[#1a1a1a] to-[#0f0f0f] border-2 border-[#d4af37]/20 rounded-xl text-gray-300 hover:text-[#d4af37] hover:border-[#d4af37]/50 transition-all duration-300 mb-12 group"
className="inline-flex items-center gap-3 px-6 py-3 bg-gradient-to-br from-[#1a1a1a] to-[#0f0f0f] border-2 border-[var(--luxury-gold)]/20 rounded-xl text-gray-300 hover:text-[var(--luxury-gold)] hover:border-[var(--luxury-gold)]/50 transition-all duration-300 mb-12 group"
>
<ArrowLeft className="w-5 h-5 group-hover:-translate-x-1 transition-transform" />
<span className="font-medium">Back to Services</span>
@@ -389,13 +389,13 @@ const ServiceDetailPage: React.FC = () => {
<div className="flex flex-wrap gap-3 mb-6">
<Link
to={`/services?category=${encodeURIComponent(service.category)}`}
className="inline-flex items-center gap-2 px-5 py-2.5 bg-gradient-to-br from-[#d4af37]/15 to-[#d4af37]/5 text-[#d4af37] rounded-xl text-sm font-semibold border border-[#d4af37]/30 hover:border-[#d4af37]/50 transition-all"
className="inline-flex items-center gap-2 px-5 py-2.5 bg-gradient-to-br from-[var(--luxury-gold)]/15 to-[var(--luxury-gold)]/5 text-[var(--luxury-gold)] rounded-xl text-sm font-semibold border border-[var(--luxury-gold)]/30 hover:border-[var(--luxury-gold)]/50 transition-all"
>
<Tag className="w-4 h-4" />
{service.category}
</Link>
{service.type === 'luxury' && (
<span className="inline-flex items-center gap-2 px-5 py-2.5 bg-gradient-to-br from-[#d4af37]/20 to-[#c9a227]/10 text-[#d4af37] rounded-xl text-sm font-bold border border-[#d4af37]/40">
<span className="inline-flex items-center gap-2 px-5 py-2.5 bg-gradient-to-br from-[var(--luxury-gold)]/20 to-[var(--luxury-gold-dark)]/10 text-[var(--luxury-gold)] rounded-xl text-sm font-bold border border-[var(--luxury-gold)]/40">
<Star className="w-4 h-4" />
Premium
</span>
@@ -406,9 +406,9 @@ const ServiceDetailPage: React.FC = () => {
<div className="flex items-start gap-6 mb-6">
{service.icon && (LucideIcons as any)[service.icon] && (
<div className="relative flex-shrink-0">
<div className="absolute inset-0 bg-[#d4af37]/20 rounded-full blur-3xl"></div>
<div className="absolute inset-0 bg-[var(--luxury-gold)]/20 rounded-full blur-3xl"></div>
{React.createElement((LucideIcons as any)[service.icon], {
className: 'w-20 h-20 sm:w-24 sm:h-24 text-[#d4af37] relative z-10 drop-shadow-2xl'
className: 'w-20 h-20 sm:w-24 sm:h-24 text-[var(--luxury-gold)] relative z-10 drop-shadow-2xl'
})}
</div>
)}
@@ -418,7 +418,7 @@ const ServiceDetailPage: React.FC = () => {
</h1>
{service.price !== undefined && (
<div className="flex items-baseline gap-3 mb-6">
<span className="text-4xl sm:text-5xl font-serif font-bold bg-gradient-to-r from-[#d4af37] to-[#f5d76e] bg-clip-text text-transparent">
<span className="text-4xl sm:text-5xl font-serif font-bold bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-light)] bg-clip-text text-transparent">
{formatCurrency(service.price)}
</span>
{service.unit && (
@@ -437,10 +437,10 @@ const ServiceDetailPage: React.FC = () => {
</p>
)}
<div className="flex flex-wrap items-center gap-6 pt-8 border-t border-[#d4af37]/20">
<div className="flex flex-wrap items-center gap-6 pt-8 border-t border-[var(--luxury-gold)]/20">
<button
onClick={handleShare}
className="flex items-center gap-3 px-6 py-3 bg-gradient-to-br from-[#1a1a1a] to-[#0f0f0f] border-2 border-[#d4af37]/20 rounded-xl text-[#d4af37] hover:border-[#d4af37]/50 hover:bg-[#d4af37]/5 transition-all duration-300 group"
className="flex items-center gap-3 px-6 py-3 bg-gradient-to-br from-[#1a1a1a] to-[#0f0f0f] border-2 border-[var(--luxury-gold)]/20 rounded-xl text-[var(--luxury-gold)] hover:border-[var(--luxury-gold)]/50 hover:bg-[var(--luxury-gold)]/5 transition-all duration-300 group"
>
<Share2 className="w-5 h-5 group-hover:scale-110 transition-transform" />
<span className="font-medium">Share</span>
@@ -454,7 +454,7 @@ const ServiceDetailPage: React.FC = () => {
<div className="flex justify-end mb-12">
<button
onClick={handleShare}
className="flex items-center gap-3 px-6 py-3 bg-gradient-to-br from-[#1a1a1a] to-[#0f0f0f] border-2 border-[#d4af37]/20 rounded-xl text-[#d4af37] hover:border-[#d4af37]/50 hover:bg-[#d4af37]/5 transition-all duration-300 group"
className="flex items-center gap-3 px-6 py-3 bg-gradient-to-br from-[#1a1a1a] to-[#0f0f0f] border-2 border-[var(--luxury-gold)]/20 rounded-xl text-[var(--luxury-gold)] hover:border-[var(--luxury-gold)]/50 hover:bg-[var(--luxury-gold)]/5 transition-all duration-300 group"
>
<Share2 className="w-5 h-5 group-hover:scale-110 transition-transform" />
<span className="font-medium">Share</span>
@@ -466,23 +466,23 @@ const ServiceDetailPage: React.FC = () => {
{service.content && (
<article className="prose prose-invert prose-xl max-w-none mb-16
prose-headings:text-white prose-headings:font-serif prose-headings:font-bold
prose-h2:text-4xl prose-h2:mt-16 prose-h2:mb-8 prose-h2:border-b-2 prose-h2:border-[#d4af37]/30 prose-h2:pb-4 prose-h2:pt-2
prose-h3:text-3xl prose-h3:mt-12 prose-h3:mb-6 prose-h3:text-[#d4af37]
prose-h2:text-4xl prose-h2:mt-16 prose-h2:mb-8 prose-h2:border-b-2 prose-h2:border-[var(--luxury-gold)]/30 prose-h2:pb-4 prose-h2:pt-2
prose-h3:text-3xl prose-h3:mt-12 prose-h3:mb-6 prose-h3:text-[var(--luxury-gold)]
prose-h4:text-2xl prose-h4:mt-10 prose-h4:mb-5
prose-p:text-gray-300 prose-p:font-light prose-p:leading-relaxed prose-p:mb-8 prose-p:text-lg
prose-ul:text-gray-300 prose-ul:font-light prose-ul:my-8 prose-ul:text-lg
prose-ol:text-gray-300 prose-ol:font-light prose-ol:my-8 prose-ol:text-lg
prose-li:text-gray-300 prose-li:mb-4 prose-li:leading-relaxed
prose-strong:text-[#d4af37] prose-strong:font-semibold
prose-a:text-[#d4af37] prose-a:no-underline hover:prose-a:underline prose-a:font-medium
prose-img:rounded-2xl prose-img:shadow-2xl prose-img:border-2 prose-img:border-[#d4af37]/20 prose-img:my-12
prose-blockquote:border-l-4 prose-blockquote:border-[#d4af37] prose-blockquote:pl-6 prose-blockquote:italic prose-blockquote:text-gray-300
[&_*]:text-gray-300 [&_h1]:text-white [&_h2]:text-white [&_h3]:text-[#d4af37] [&_h4]:text-white
[&_strong]:text-[#d4af37] [&_b]:text-[#d4af37] [&_a]:text-[#d4af37]
prose-strong:text-[var(--luxury-gold)] prose-strong:font-semibold
prose-a:text-[var(--luxury-gold)] prose-a:no-underline hover:prose-a:underline prose-a:font-medium
prose-img:rounded-2xl prose-img:shadow-2xl prose-img:border-2 prose-img:border-[var(--luxury-gold)]/20 prose-img:my-12
prose-blockquote:border-l-4 prose-blockquote:border-[var(--luxury-gold)] prose-blockquote:pl-6 prose-blockquote:italic prose-blockquote:text-gray-300
[&_*]:text-gray-300 [&_h1]:text-white [&_h2]:text-white [&_h3]:text-[var(--luxury-gold)] [&_h4]:text-white
[&_strong]:text-[var(--luxury-gold)] [&_b]:text-[var(--luxury-gold)] [&_a]:text-[var(--luxury-gold)]
[&_ul]:space-y-3 [&_ol]:space-y-3"
>
<div
className="bg-gradient-to-br from-[#1a1a1a]/50 to-[#0f0f0f]/50 rounded-3xl border-2 border-[#d4af37]/10 p-8 md:p-12 lg:p-16 backdrop-blur-sm"
className="bg-gradient-to-br from-[#1a1a1a]/50 to-[#0f0f0f]/50 rounded-3xl border-2 border-[var(--luxury-gold)]/10 p-8 md:p-12 lg:p-16 backdrop-blur-sm"
dangerouslySetInnerHTML={createSanitizedHtml(
service.content || '<p>No content available.</p>'
)}
@@ -499,7 +499,7 @@ const ServiceDetailPage: React.FC = () => {
<div key={index}>
{/* Hero Section - Enhanced */}
{section.type === 'hero' && (
<div className="relative rounded-3xl overflow-hidden border-2 border-[#d4af37]/30 shadow-2xl group">
<div className="relative rounded-3xl overflow-hidden border-2 border-[var(--luxury-gold)]/30 shadow-2xl group">
{section.image && (
<div className="absolute inset-0">
<img src={section.image} alt={section.title} className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-1000" />
@@ -508,8 +508,8 @@ const ServiceDetailPage: React.FC = () => {
</div>
)}
<div className="absolute inset-0 opacity-10">
<div className="absolute top-0 left-0 w-96 h-96 bg-[#d4af37] rounded-full blur-3xl"></div>
<div className="absolute bottom-0 right-0 w-96 h-96 bg-[#c9a227] rounded-full blur-3xl"></div>
<div className="absolute top-0 left-0 w-96 h-96 bg-[var(--luxury-gold)] rounded-full blur-3xl"></div>
<div className="absolute bottom-0 right-0 w-96 h-96 bg-[var(--luxury-gold-dark)] rounded-full blur-3xl"></div>
</div>
<div className="relative px-8 py-20 md:px-16 md:py-32 text-center">
{section.title && (
@@ -523,13 +523,13 @@ const ServiceDetailPage: React.FC = () => {
</p>
)}
</div>
<div className="absolute bottom-0 left-0 w-full h-1 bg-gradient-to-r from-transparent via-[#d4af37]/50 to-transparent"></div>
<div className="absolute bottom-0 left-0 w-full h-1 bg-gradient-to-r from-transparent via-[var(--luxury-gold)]/50 to-transparent"></div>
</div>
)}
{/* Text Section */}
{section.type === 'text' && (
<div className={`bg-gradient-to-br from-[#1a1a1a] to-[#0f0f0f] rounded-3xl border-2 border-[#d4af37]/20 p-8 md:p-12 shadow-xl ${
<div className={`bg-gradient-to-br from-[#1a1a1a] to-[#0f0f0f] rounded-3xl border-2 border-[var(--luxury-gold)]/20 p-8 md:p-12 shadow-xl ${
section.alignment === 'center' ? 'text-center' : section.alignment === 'right' ? 'text-right' : 'text-left'
}`}>
{section.title && (
@@ -548,10 +548,10 @@ const ServiceDetailPage: React.FC = () => {
{/* Image Section */}
{section.type === 'image' && section.image && (
<div className="rounded-3xl overflow-hidden border-2 border-[#d4af37]/20 shadow-2xl">
<div className="rounded-3xl overflow-hidden border-2 border-[var(--luxury-gold)]/20 shadow-2xl">
<img src={section.image} alt={section.title || 'Service image'} className="w-full h-auto" />
{section.title && (
<div className="bg-gradient-to-br from-[#1a1a1a] to-[#0f0f0f] px-6 py-4 border-t border-[#d4af37]/20">
<div className="bg-gradient-to-br from-[#1a1a1a] to-[#0f0f0f] px-6 py-4 border-t border-[var(--luxury-gold)]/20">
<p className="text-gray-400 text-sm font-light italic text-center">{section.title}</p>
</div>
)}
@@ -562,7 +562,7 @@ const ServiceDetailPage: React.FC = () => {
{section.type === 'gallery' && section.images && section.images.length > 0 && (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{section.images.map((img, imgIndex) => (
<div key={imgIndex} className="rounded-2xl overflow-hidden border-2 border-[#d4af37]/20 shadow-xl group hover:border-[#d4af37]/50 transition-all">
<div key={imgIndex} className="rounded-2xl overflow-hidden border-2 border-[var(--luxury-gold)]/20 shadow-xl group hover:border-[var(--luxury-gold)]/50 transition-all">
<img src={img} alt={`Gallery image ${imgIndex + 1}`} className="w-full h-64 object-cover group-hover:scale-110 transition-transform duration-500" />
</div>
))}
@@ -571,15 +571,15 @@ const ServiceDetailPage: React.FC = () => {
{/* Quote Section */}
{section.type === 'quote' && (
<div className="relative bg-gradient-to-br from-[#1a1a1a] to-[#0f0f0f] rounded-3xl border-2 border-[#d4af37]/30 p-8 md:p-12 shadow-2xl">
<div className="absolute top-6 left-6 text-6xl text-[#d4af37]/20 font-serif">"</div>
<div className="relative bg-gradient-to-br from-[#1a1a1a] to-[#0f0f0f] rounded-3xl border-2 border-[var(--luxury-gold)]/30 p-8 md:p-12 shadow-2xl">
<div className="absolute top-6 left-6 text-6xl text-[var(--luxury-gold)]/20 font-serif">"</div>
{section.quote && (
<blockquote className="text-2xl md:text-3xl font-serif font-light text-white italic mb-6 relative z-10 pl-8">
{section.quote}
</blockquote>
)}
{section.author && (
<cite className="text-[#d4af37] text-lg font-medium not-italic block text-right">
<cite className="text-[var(--luxury-gold)] text-lg font-medium not-italic block text-right">
— {section.author}
</cite>
)}
@@ -590,7 +590,7 @@ const ServiceDetailPage: React.FC = () => {
{section.type === 'features' && section.features && (
<div>
{section.title && (
<h3 className="text-4xl md:text-5xl font-serif font-bold text-white mb-12 text-center border-b-2 border-[#d4af37]/30 pb-6">
<h3 className="text-4xl md:text-5xl font-serif font-bold text-white mb-12 text-center border-b-2 border-[var(--luxury-gold)]/30 pb-6">
{section.title}
</h3>
)}
@@ -600,18 +600,18 @@ const ServiceDetailPage: React.FC = () => {
? (LucideIcons as any)[feature.icon]
: null;
return (
<div key={featIndex} className="group relative bg-gradient-to-br from-[#1a1a1a] via-[#0f0f0f] to-[#0a0a0a] rounded-3xl border-2 border-[#d4af37]/20 p-8 shadow-2xl hover:border-[#d4af37]/60 hover:shadow-[#d4af37]/20 transition-all duration-500 hover:-translate-y-2">
<div className="absolute inset-0 bg-gradient-to-br from-[#d4af37]/0 to-[#d4af37]/0 group-hover:from-[#d4af37]/5 group-hover:to-transparent rounded-3xl transition-all duration-500"></div>
<div key={featIndex} className="group relative bg-gradient-to-br from-[#1a1a1a] via-[#0f0f0f] to-[#0a0a0a] rounded-3xl border-2 border-[var(--luxury-gold)]/20 p-8 shadow-2xl hover:border-[var(--luxury-gold)]/60 hover:shadow-[var(--luxury-gold)]/20 transition-all duration-500 hover:-translate-y-2">
<div className="absolute inset-0 bg-gradient-to-br from-[var(--luxury-gold)]/0 to-[var(--luxury-gold)]/0 group-hover:from-[var(--luxury-gold)]/5 group-hover:to-transparent rounded-3xl transition-all duration-500"></div>
<div className="relative z-10">
{IconComponent && (
<div className="mb-6 relative">
<div className="absolute inset-0 bg-[#d4af37]/20 rounded-full blur-2xl group-hover:blur-3xl transition-all"></div>
<div className="absolute inset-0 bg-[var(--luxury-gold)]/20 rounded-full blur-2xl group-hover:blur-3xl transition-all"></div>
{React.createElement(IconComponent, {
className: 'w-12 h-12 text-[#d4af37] relative z-10 group-hover:scale-110 transition-transform duration-300'
className: 'w-12 h-12 text-[var(--luxury-gold)] relative z-10 group-hover:scale-110 transition-transform duration-300'
})}
</div>
)}
<h4 className="text-2xl font-bold text-white mb-4 group-hover:text-[#d4af37] transition-colors">{feature.title}</h4>
<h4 className="text-2xl font-bold text-white mb-4 group-hover:text-[var(--luxury-gold)] transition-colors">{feature.title}</h4>
<p className="text-gray-300 font-light leading-relaxed text-base">{feature.description}</p>
</div>
</div>
@@ -623,7 +623,7 @@ const ServiceDetailPage: React.FC = () => {
{/* CTA Section */}
{section.type === 'cta' && (
<div className="relative bg-gradient-to-br from-[#d4af37]/10 via-[#c9a227]/5 to-[#d4af37]/10 rounded-3xl border-2 border-[#d4af37]/30 p-8 md:p-12 text-center shadow-2xl">
<div className="relative bg-gradient-to-br from-[var(--luxury-gold)]/10 via-[var(--luxury-gold-dark)]/5 to-[var(--luxury-gold)]/10 rounded-3xl border-2 border-[var(--luxury-gold)]/30 p-8 md:p-12 text-center shadow-2xl">
{section.title && (
<h3 className="text-3xl md:text-4xl font-serif font-bold text-white mb-4">
{section.title}
@@ -637,7 +637,7 @@ const ServiceDetailPage: React.FC = () => {
{section.cta_text && section.cta_link && (
<a
href={section.cta_link}
className="inline-flex items-center gap-3 px-8 py-4 bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-[#0f0f0f] font-semibold rounded-xl hover:from-[#f5d76e] hover:to-[#d4af37] transition-all shadow-lg hover:shadow-xl hover:scale-105"
className="inline-flex items-center gap-3 px-8 py-4 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-[#0f0f0f] font-semibold rounded-xl hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] transition-all shadow-lg hover:shadow-xl hover:scale-105"
>
{section.cta_text}
</a>
@@ -647,7 +647,7 @@ const ServiceDetailPage: React.FC = () => {
{/* Video Section */}
{section.type === 'video' && section.video_url && (
<div className="rounded-3xl overflow-hidden border-2 border-[#d4af37]/20 shadow-2xl bg-black">
<div className="rounded-3xl overflow-hidden border-2 border-[var(--luxury-gold)]/20 shadow-2xl bg-black">
<div className="aspect-video">
<iframe
src={section.video_url.replace('watch?v=', 'embed/').replace('vimeo.com/', 'player.vimeo.com/video/')}
@@ -665,14 +665,14 @@ const ServiceDetailPage: React.FC = () => {
{/* Related Services */}
{relatedServices.length > 0 && (
<div className="mt-16 pt-12 border-t border-[#d4af37]/20">
<div className="mt-16 pt-12 border-t border-[var(--luxury-gold)]/20">
<h2 className="text-2xl sm:text-3xl font-bold text-white mb-8">Related Services</h2>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{relatedServices.map((relatedService) => (
<Link
key={relatedService.id}
to={`/services/${relatedService.slug}`}
className="group bg-gradient-to-br from-[#1a1a1a] to-[#0f0f0f] rounded-xl border border-[#d4af37]/20 overflow-hidden hover:border-[#d4af37]/50 transition-all duration-300"
className="group bg-gradient-to-br from-[#1a1a1a] to-[#0f0f0f] rounded-xl border border-[var(--luxury-gold)]/20 overflow-hidden hover:border-[var(--luxury-gold)]/50 transition-all duration-300"
>
{relatedService.image && (
<div className="relative h-40 overflow-hidden">
@@ -684,7 +684,7 @@ const ServiceDetailPage: React.FC = () => {
</div>
)}
<div className="p-4">
<h3 className="text-lg font-bold text-white mb-2 group-hover:text-[#d4af37] transition-colors line-clamp-2">
<h3 className="text-lg font-bold text-white mb-2 group-hover:text-[var(--luxury-gold)] transition-colors line-clamp-2">
{relatedService.title}
</h3>
{relatedService.description && (

View File

@@ -159,41 +159,41 @@ const ServicesPage: React.FC = () => {
return (
<div className="min-h-screen bg-gradient-to-b from-[#0f0f0f] via-[#1a1a1a] to-[#0f0f0f] w-full" style={{ width: '100vw', position: 'relative', left: '50%', right: '50%', marginLeft: '-50vw', marginRight: '-50vw', marginTop: '-1.5rem', marginBottom: '-1.5rem' }}>
{/* Hero Section */}
<div className="w-full bg-gradient-to-br from-[#1a1a1a] via-[#0f0f0f] to-[#1a1a1a] border-b border-[#d4af37]/10 pt-6 sm:pt-7 md:pt-8 overflow-hidden relative">
<div className="w-full bg-gradient-to-br from-[#1a1a1a] via-[#0f0f0f] to-[#1a1a1a] border-b border-[var(--luxury-gold)]/10 pt-6 sm:pt-7 md:pt-8 overflow-hidden relative">
{/* Background Effects */}
<div className="absolute inset-0 opacity-10">
<div className="absolute top-10 left-10 w-32 sm:w-48 h-32 sm:h-48 bg-[#d4af37] rounded-full blur-3xl"></div>
<div className="absolute bottom-10 right-10 w-40 sm:w-64 h-40 sm:h-64 bg-[#c9a227] rounded-full blur-3xl"></div>
<div className="absolute top-10 left-10 w-32 sm:w-48 h-32 sm:h-48 bg-[var(--luxury-gold)] rounded-full blur-3xl"></div>
<div className="absolute bottom-10 right-10 w-40 sm:w-64 h-40 sm:h-64 bg-[var(--luxury-gold-dark)] rounded-full blur-3xl"></div>
</div>
<div className="absolute top-0 left-0 w-full h-px bg-gradient-to-r from-transparent via-[#d4af37]/50 to-transparent"></div>
<div className="absolute top-0 left-0 w-full h-px bg-gradient-to-r from-transparent via-[var(--luxury-gold)]/50 to-transparent"></div>
<div className="w-full max-w-[1920px] mx-auto px-3 sm:px-4 md:px-6 lg:px-8 xl:px-12 2xl:px-16 3xl:px-20 py-4 sm:py-5 md:py-6 relative z-10">
<div className="max-w-2xl mx-auto text-center px-2">
<div className="flex justify-center mb-2 sm:mb-3 md:mb-4">
<div className="relative group">
<div className="absolute inset-0 bg-gradient-to-br from-[#d4af37] via-[#f5d76e] to-[#c9a227] rounded-xl blur-lg opacity-40 group-hover:opacity-60 transition-opacity duration-500"></div>
<div className="relative p-2 sm:p-2.5 md:p-3 bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-lg border-2 border-[#d4af37]/40 backdrop-blur-sm shadow-xl shadow-[#d4af37]/20 group-hover:border-[#d4af37]/60 transition-all duration-300">
<Award className="w-5 h-5 sm:w-6 sm:h-6 md:w-7 md:h-7 text-[#d4af37] drop-shadow-lg" />
<div className="absolute inset-0 bg-gradient-to-br from-[var(--luxury-gold)] via-[var(--luxury-gold-light)] to-[var(--luxury-gold-dark)] rounded-xl blur-lg opacity-40 group-hover:opacity-60 transition-opacity duration-500"></div>
<div className="relative p-2 sm:p-2.5 md:p-3 bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-lg border-2 border-[var(--luxury-gold)]/40 backdrop-blur-sm shadow-xl shadow-[var(--luxury-gold)]/20 group-hover:border-[var(--luxury-gold)]/60 transition-all duration-300">
<Award className="w-5 h-5 sm:w-6 sm:h-6 md:w-7 md:h-7 text-[var(--luxury-gold)] drop-shadow-lg" />
</div>
</div>
</div>
<h1 className="text-2xl xs:text-3xl sm:text-4xl md:text-5xl font-serif font-semibold mb-2 sm:mb-3 tracking-tight leading-tight px-2">
<span className="bg-gradient-to-r from-white via-[#d4af37] to-white bg-clip-text text-transparent">
<span className="bg-gradient-to-r from-white via-[var(--luxury-gold)] to-white bg-clip-text text-transparent">
{pageContent?.luxury_services_section_title || 'Our Services'}
</span>
</h1>
<div className="w-12 sm:w-16 md:w-20 h-0.5 bg-gradient-to-r from-transparent via-[#d4af37] to-transparent mx-auto mb-2 sm:mb-3"></div>
<div className="w-12 sm:w-16 md:w-20 h-0.5 bg-gradient-to-r from-transparent via-[var(--luxury-gold)] to-transparent mx-auto mb-2 sm:mb-3"></div>
<p className="text-sm sm:text-base md:text-lg text-gray-300 font-light leading-relaxed max-w-xl mx-auto tracking-wide px-2 sm:px-4">
{pageContent?.luxury_services_section_subtitle || 'Discover our premium services designed to enhance your stay'}
</p>
<div className="mt-4 flex items-center justify-center gap-2 text-[#d4af37]/60">
<div className="mt-4 flex items-center justify-center gap-2 text-[var(--luxury-gold)]/60">
<Sparkles className="w-4 h-4 animate-pulse" />
<span className="text-xs sm:text-sm font-light tracking-wider uppercase">Premium Services</span>
<Sparkles className="w-4 h-4 animate-pulse" style={{ animationDelay: '0.5s' }} />
</div>
</div>
</div>
<div className="absolute bottom-0 left-0 w-full h-px bg-gradient-to-r from-transparent via-[#d4af37]/30 to-transparent"></div>
<div className="absolute bottom-0 left-0 w-full h-px bg-gradient-to-r from-transparent via-[var(--luxury-gold)]/30 to-transparent"></div>
</div>
{/* Main Content - Full Width */}
@@ -203,15 +203,15 @@ const ServicesPage: React.FC = () => {
<div className="mb-12 sm:mb-16">
<div className="flex flex-col lg:flex-row gap-6 mb-8">
<div className="flex-1 relative group">
<div className="absolute inset-0 bg-gradient-to-r from-[#d4af37]/10 to-transparent rounded-xl blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div className="absolute inset-0 bg-gradient-to-r from-[var(--luxury-gold)]/10 to-transparent rounded-xl blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div className="relative">
<Search className="absolute left-5 top-1/2 transform -translate-y-1/2 text-[#d4af37] w-5 h-5 z-10" />
<Search className="absolute left-5 top-1/2 transform -translate-y-1/2 text-[var(--luxury-gold)] w-5 h-5 z-10" />
<input
type="text"
placeholder="Search services..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="w-full pl-14 pr-5 py-4 bg-gradient-to-br from-[#1a1a1a] to-[#0f0f0f] border border-[#d4af37]/20 rounded-xl text-white placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37]/50 transition-all duration-300 backdrop-blur-sm font-light"
className="w-full pl-14 pr-5 py-4 bg-gradient-to-br from-[#1a1a1a] to-[#0f0f0f] border border-[var(--luxury-gold)]/20 rounded-xl text-white placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)]/50 transition-all duration-300 backdrop-blur-sm font-light"
/>
</div>
</div>
@@ -221,13 +221,13 @@ const ServicesPage: React.FC = () => {
{/* Categories Filter - Top Center */}
{allCategories.length > 0 && (
<div className="mb-12 flex justify-center">
<div className="inline-flex flex-wrap items-center gap-3 bg-gradient-to-br from-[#1a1a1a] via-[#0f0f0f] to-[#0a0a0a] rounded-2xl border-2 border-[#d4af37]/20 p-4 backdrop-blur-xl shadow-2xl">
<div className="inline-flex flex-wrap items-center gap-3 bg-gradient-to-br from-[#1a1a1a] via-[#0f0f0f] to-[#0a0a0a] rounded-2xl border-2 border-[var(--luxury-gold)]/20 p-4 backdrop-blur-xl shadow-2xl">
<button
onClick={() => setSelectedCategory(null)}
className={`group relative px-6 py-3 rounded-xl text-sm font-medium transition-all duration-300 overflow-hidden ${
selectedCategory === null
? 'bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-[#0f0f0f] shadow-lg shadow-[#d4af37]/40'
: 'bg-gradient-to-br from-[#0f0f0f] to-[#0a0a0a] text-gray-300 border-2 border-[#d4af37]/20 hover:border-[#d4af37]/50 hover:text-[#d4af37]'
? 'bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-[#0f0f0f] shadow-lg shadow-[var(--luxury-gold)]/40'
: 'bg-gradient-to-br from-[#0f0f0f] to-[#0a0a0a] text-gray-300 border-2 border-[var(--luxury-gold)]/20 hover:border-[var(--luxury-gold)]/50 hover:text-[var(--luxury-gold)]'
}`}
>
<span className="relative z-10 flex items-center gap-2">
@@ -241,8 +241,8 @@ const ServicesPage: React.FC = () => {
onClick={() => setSelectedCategory(category)}
className={`group relative px-6 py-3 rounded-xl text-sm font-medium transition-all duration-300 overflow-hidden ${
selectedCategory === category
? 'bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-[#0f0f0f] shadow-lg shadow-[#d4af37]/40'
: 'bg-gradient-to-br from-[#0f0f0f] to-[#0a0a0a] text-gray-300 border-2 border-[#d4af37]/20 hover:border-[#d4af37]/50 hover:text-[#d4af37]'
? 'bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-[#0f0f0f] shadow-lg shadow-[var(--luxury-gold)]/40'
: 'bg-gradient-to-br from-[#0f0f0f] to-[#0a0a0a] text-gray-300 border-2 border-[var(--luxury-gold)]/20 hover:border-[var(--luxury-gold)]/50 hover:text-[var(--luxury-gold)]'
}`}
>
<span className="relative z-10 flex items-center gap-2">
@@ -267,8 +267,8 @@ const ServicesPage: React.FC = () => {
{/* Services Grid - Luxury Design - Centered */}
{filteredServices.length === 0 ? (
<div className="text-center py-20">
<div className="inline-flex items-center justify-center w-20 h-20 rounded-full bg-[#d4af37]/10 mb-6">
<Award className="w-10 h-10 text-[#d4af37]" />
<div className="inline-flex items-center justify-center w-20 h-20 rounded-full bg-[var(--luxury-gold)]/10 mb-6">
<Award className="w-10 h-10 text-[var(--luxury-gold)]" />
</div>
<p className="text-gray-400 text-xl font-light">No services found</p>
<p className="text-gray-500 text-sm mt-2">Try adjusting your search or filters</p>
@@ -288,12 +288,12 @@ const ServicesPage: React.FC = () => {
<Link
key={service.id}
to={`/services/${serviceSlug}`}
className="group relative bg-gradient-to-br from-[#1a1a1a] via-[#0f0f0f] to-[#0a0a0a] rounded-3xl border-2 border-[#d4af37]/20 overflow-hidden hover:border-[#d4af37]/60 transition-all duration-700 hover:shadow-2xl hover:shadow-[#d4af37]/30 hover:-translate-y-3 block"
className="group relative bg-gradient-to-br from-[#1a1a1a] via-[#0f0f0f] to-[#0a0a0a] rounded-3xl border-2 border-[var(--luxury-gold)]/20 overflow-hidden hover:border-[var(--luxury-gold)]/60 transition-all duration-700 hover:shadow-2xl hover:shadow-[var(--luxury-gold)]/30 hover:-translate-y-3 block"
style={{ animationDelay: `${index * 50}ms` }}
>
{/* Premium Glow Effects */}
<div className="absolute inset-0 bg-gradient-to-br from-[#d4af37]/0 via-[#d4af37]/0 to-[#d4af37]/0 group-hover:from-[#d4af37]/10 group-hover:via-[#d4af37]/5 group-hover:to-[#d4af37]/10 transition-all duration-700 rounded-3xl blur-2xl opacity-0 group-hover:opacity-100"></div>
<div className="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-transparent via-[#d4af37]/50 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div className="absolute inset-0 bg-gradient-to-br from-[var(--luxury-gold)]/0 via-[var(--luxury-gold)]/0 to-[var(--luxury-gold)]/0 group-hover:from-[var(--luxury-gold)]/10 group-hover:via-[var(--luxury-gold)]/5 group-hover:to-[var(--luxury-gold)]/10 transition-all duration-700 rounded-3xl blur-2xl opacity-0 group-hover:opacity-100"></div>
<div className="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-transparent via-[var(--luxury-gold)]/50 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
{/* Content */}
<div className="relative z-10">
@@ -308,8 +308,8 @@ const ServicesPage: React.FC = () => {
{/* Premium Badge Overlay */}
{service.type === 'luxury' && (
<div className="absolute top-6 left-6 z-20">
<div className="bg-gradient-to-br from-[#d4af37]/20 to-[#c9a227]/10 backdrop-blur-md rounded-2xl px-4 py-2 border border-[#d4af37]/40 shadow-xl">
<div className="flex items-center gap-2 text-[#d4af37]">
<div className="bg-gradient-to-br from-[var(--luxury-gold)]/20 to-[var(--luxury-gold-dark)]/10 backdrop-blur-md rounded-2xl px-4 py-2 border border-[var(--luxury-gold)]/40 shadow-xl">
<div className="flex items-center gap-2 text-[var(--luxury-gold)]">
<Star className="w-4 h-4" />
<span className="text-sm font-semibold">Premium</span>
</div>
@@ -317,21 +317,21 @@ const ServicesPage: React.FC = () => {
</div>
)}
{/* Luxury Corner Accent */}
<div className="absolute top-0 right-0 w-32 h-32 bg-gradient-to-br from-[#d4af37]/20 to-transparent rounded-bl-full opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div className="absolute top-0 right-0 w-32 h-32 bg-gradient-to-br from-[var(--luxury-gold)]/20 to-transparent rounded-bl-full opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
</div>
) : (
<div className="h-48 sm:h-56 bg-gradient-to-br from-[#1a1a1a] to-[#0f0f0f] flex items-center justify-center p-8">
{service.icon && (LucideIcons as any)[service.icon] ? (
<div className="relative">
<div className="absolute inset-0 bg-[#d4af37]/20 rounded-full blur-2xl"></div>
<div className="absolute inset-0 bg-[var(--luxury-gold)]/20 rounded-full blur-2xl"></div>
{React.createElement((LucideIcons as any)[service.icon], {
className: 'w-16 h-16 sm:w-20 sm:h-20 text-[#d4af37] relative z-10 drop-shadow-lg'
className: 'w-16 h-16 sm:w-20 sm:h-20 text-[var(--luxury-gold)] relative z-10 drop-shadow-lg'
})}
</div>
) : (
<div className="relative">
<div className="absolute inset-0 bg-[#d4af37]/20 rounded-full blur-2xl"></div>
<Award className="w-16 h-16 sm:w-20 sm:h-20 text-[#d4af37] relative z-10 drop-shadow-lg" />
<div className="absolute inset-0 bg-[var(--luxury-gold)]/20 rounded-full blur-2xl"></div>
<Award className="w-16 h-16 sm:w-20 sm:h-20 text-[var(--luxury-gold)] relative z-10 drop-shadow-lg" />
</div>
)}
</div>
@@ -339,13 +339,13 @@ const ServicesPage: React.FC = () => {
<div className="p-8">
{service.category && (
<div className="flex flex-wrap gap-2 mb-5">
<span className="inline-flex items-center gap-1.5 px-4 py-1.5 bg-gradient-to-br from-[#d4af37]/15 to-[#d4af37]/5 text-[#d4af37] rounded-full text-xs font-semibold border border-[#d4af37]/30 backdrop-blur-sm shadow-lg">
<span className="inline-flex items-center gap-1.5 px-4 py-1.5 bg-gradient-to-br from-[var(--luxury-gold)]/15 to-[var(--luxury-gold)]/5 text-[var(--luxury-gold)] rounded-full text-xs font-semibold border border-[var(--luxury-gold)]/30 backdrop-blur-sm shadow-lg">
<Tag className="w-3 h-3" />
{service.category}
</span>
</div>
)}
<h2 className="text-2xl sm:text-3xl font-serif font-bold text-white mb-4 group-hover:text-[#d4af37] transition-colors duration-500 line-clamp-2 leading-tight tracking-tight">
<h2 className="text-2xl sm:text-3xl font-serif font-bold text-white mb-4 group-hover:text-[var(--luxury-gold)] transition-colors duration-500 line-clamp-2 leading-tight tracking-tight">
{service.title}
</h2>
{service.description && (
@@ -354,9 +354,9 @@ const ServicesPage: React.FC = () => {
</p>
)}
{service.price !== undefined && (
<div className="mb-6 pb-6 border-b border-[#d4af37]/20">
<div className="mb-6 pb-6 border-b border-[var(--luxury-gold)]/20">
<div className="flex items-baseline gap-2">
<span className="text-2xl sm:text-3xl font-serif font-semibold bg-gradient-to-r from-[#d4af37] to-[#f5d76e] bg-clip-text text-transparent">
<span className="text-2xl sm:text-3xl font-serif font-semibold bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-light)] bg-clip-text text-transparent">
{formatCurrency(service.price)}
</span>
{service.unit && (
@@ -367,12 +367,12 @@ const ServicesPage: React.FC = () => {
</div>
</div>
)}
<div className="flex items-center justify-between pt-4 border-t border-[#d4af37]/10">
<div className="flex items-center gap-3 text-[#d4af37] group-hover:gap-4 transition-all duration-300">
<div className="flex items-center justify-between pt-4 border-t border-[var(--luxury-gold)]/10">
<div className="flex items-center gap-3 text-[var(--luxury-gold)] group-hover:gap-4 transition-all duration-300">
<span className="text-sm font-semibold tracking-wide uppercase">Learn More</span>
<ArrowRight className="w-5 h-5 group-hover:translate-x-2 transition-transform duration-300" />
</div>
<div className="w-12 h-0.5 bg-gradient-to-r from-[#d4af37] to-transparent group-hover:w-20 transition-all duration-500"></div>
<div className="w-12 h-0.5 bg-gradient-to-r from-[var(--luxury-gold)] to-transparent group-hover:w-20 transition-all duration-500"></div>
</div>
</div>
</div>

View File

@@ -99,12 +99,12 @@ const TermsPage: React.FC = () => {
}}
>
<div className="text-center">
<Scale className="w-16 h-16 text-[#d4af37]/50 mx-auto mb-4" />
<Scale className="w-16 h-16 text-[var(--luxury-gold)]/50 mx-auto mb-4" />
<h1 className="text-2xl font-elegant font-bold text-white mb-2">Terms & Conditions</h1>
<p className="text-gray-400">This page is currently unavailable.</p>
<Link
to="/"
className="inline-flex items-center gap-2 text-[#d4af37]/80 hover:text-[#d4af37] mt-6 transition-all duration-300"
className="inline-flex items-center gap-2 text-[var(--luxury-gold)]/80 hover:text-[var(--luxury-gold)] mt-6 transition-all duration-300"
>
<ArrowLeft className="w-4 h-4" />
<span>Back to Home</span>
@@ -129,7 +129,7 @@ const TermsPage: React.FC = () => {
{/* Back Link */}
<Link
to="/"
className="inline-flex items-center gap-2 text-[#d4af37]/80 hover:text-[#d4af37] mb-6 transition-all duration-300 group font-light tracking-wide text-xs sm:text-sm"
className="inline-flex items-center gap-2 text-[var(--luxury-gold)]/80 hover:text-[var(--luxury-gold)] mb-6 transition-all duration-300 group font-light tracking-wide text-xs sm:text-sm"
>
<ArrowLeft className="w-4 h-4 group-hover:-translate-x-1 transition-transform" />
<span>Back to Home</span>
@@ -137,10 +137,10 @@ const TermsPage: React.FC = () => {
{/* Header */}
<div className="mb-8 sm:mb-12 text-center">
<div className="inline-flex items-center justify-center w-16 h-16 sm:w-20 sm:h-20 mb-4 sm:mb-6 bg-gradient-to-br from-[#d4af37]/20 to-[#c9a227]/10 rounded-full border border-[#d4af37]/30">
<Scale className="w-8 h-8 sm:w-10 sm:h-10 text-[#d4af37]" />
<div className="inline-flex items-center justify-center w-16 h-16 sm:w-20 sm:h-20 mb-4 sm:mb-6 bg-gradient-to-br from-[var(--luxury-gold)]/20 to-[var(--luxury-gold-dark)]/10 rounded-full border border-[var(--luxury-gold)]/30">
<Scale className="w-8 h-8 sm:w-10 sm:h-10 text-[var(--luxury-gold)]" />
</div>
<h1 className="text-3xl sm:text-4xl lg:text-5xl font-elegant font-bold text-white mb-3 sm:mb-4 tracking-tight leading-tight bg-gradient-to-r from-white via-[#d4af37] to-white bg-clip-text text-transparent">
<h1 className="text-3xl sm:text-4xl lg:text-5xl font-elegant font-bold text-white mb-3 sm:mb-4 tracking-tight leading-tight bg-gradient-to-r from-white via-[var(--luxury-gold)] to-white bg-clip-text text-transparent">
{pageContent.title || 'Terms & Conditions'}
</h1>
{pageContent.subtitle && (
@@ -151,18 +151,18 @@ const TermsPage: React.FC = () => {
</div>
{/* Content */}
<div className="bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-xl border border-[#d4af37]/20 backdrop-blur-xl shadow-2xl shadow-[#d4af37]/5 p-6 sm:p-8 lg:p-12">
<div className="bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-xl border border-[var(--luxury-gold)]/20 backdrop-blur-xl shadow-2xl shadow-[var(--luxury-gold)]/5 p-6 sm:p-8 lg:p-12">
<div
className="prose prose-invert prose-lg max-w-none text-gray-300
prose-headings:text-white prose-headings:font-elegant prose-headings:font-semibold
prose-h2:text-2xl prose-h2:mt-8 prose-h2:mb-4 prose-h2:border-b prose-h2:border-[#d4af37]/20 prose-h2:pb-2
prose-h2:text-2xl prose-h2:mt-8 prose-h2:mb-4 prose-h2:border-b prose-h2:border-[var(--luxury-gold)]/20 prose-h2:pb-2
prose-p:text-gray-300 prose-p:font-light prose-p:leading-relaxed prose-p:mb-4
prose-ul:text-gray-300 prose-ul:font-light prose-ul:my-4
prose-li:text-gray-300 prose-li:mb-2 prose-li:ml-4
prose-strong:text-[#d4af37] prose-strong:font-medium
prose-a:text-[#d4af37] prose-a:no-underline hover:prose-a:underline
prose-strong:text-[var(--luxury-gold)] prose-strong:font-medium
prose-a:text-[var(--luxury-gold)] prose-a:no-underline hover:prose-a:underline
[&_*]:text-gray-300 [&_h1]:text-white [&_h2]:text-white [&_h3]:text-white [&_h4]:text-white [&_h5]:text-white [&_h6]:text-white
[&_strong]:text-[#d4af37] [&_b]:text-[#d4af37] [&_a]:text-[#d4af37]"
[&_strong]:text-[var(--luxury-gold)] [&_b]:text-[var(--luxury-gold)] [&_a]:text-[var(--luxury-gold)]"
style={{ color: '#d1d5db' }}
dangerouslySetInnerHTML={createSanitizedHtml(
pageContent.content || pageContent.description || '<p style="color: #d1d5db;">No content available.</p>'
@@ -175,7 +175,7 @@ const TermsPage: React.FC = () => {
<div className="mt-8 text-center">
<p className="text-sm text-gray-400 font-light">
For questions about these terms, contact us at{' '}
<a href={`mailto:${settings.company_email}`} className="text-[#d4af37] hover:underline">
<a href={`mailto:${settings.company_email}`} className="text-[var(--luxury-gold)] hover:underline">
{settings.company_email}
</a>
</p>

View File

@@ -368,10 +368,10 @@ const ChatWidget: React.FC<ChatWidgetProps> = ({ onClose }) => {
{!isOpen ? (
<button
onClick={handleOpen}
className="bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-slate-900 p-5 rounded-full shadow-2xl shadow-[#d4af37]/40 hover:from-[#c9a227] hover:to-[#d4af37] transition-all duration-300 hover:scale-110 flex items-center justify-center group relative"
className="bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-slate-900 p-5 rounded-full shadow-2xl shadow-[var(--luxury-gold)]/40 hover:from-[var(--luxury-gold-dark)] hover:to-[var(--luxury-gold)] transition-all duration-300 hover:scale-110 flex items-center justify-center group relative"
aria-label="Open chat"
>
<div className="absolute inset-0 bg-gradient-to-r from-[#d4af37] to-[#c9a227] rounded-full blur-xl opacity-50 group-hover:opacity-70 transition-opacity"></div>
<div className="absolute inset-0 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] rounded-full blur-xl opacity-50 group-hover:opacity-70 transition-opacity"></div>
<MessageCircle className="w-6 h-6 group-hover:scale-110 transition-transform relative z-10" strokeWidth={2.5} />
{chat && chat.status === 'pending' && (
<span className="absolute -top-1 -right-1 w-4 h-4 bg-red-500 rounded-full animate-pulse border-2 border-white shadow-lg z-10"></span>
@@ -379,14 +379,14 @@ const ChatWidget: React.FC<ChatWidgetProps> = ({ onClose }) => {
</button>
) : (
<div
className={`luxury-glass rounded-2xl shadow-2xl border border-[#d4af37]/30 flex flex-col transition-all duration-300 ${
className={`luxury-glass rounded-2xl shadow-2xl border border-[var(--luxury-gold)]/30 flex flex-col transition-all duration-300 ${
isMinimized ? 'w-80 h-16' : 'w-96 h-[600px]'
}`}
style={{ transformOrigin: 'bottom right' }}
>
{}
<div className="bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-slate-900 p-4 rounded-t-2xl flex items-center justify-between relative overflow-hidden">
<div className="absolute inset-0 bg-gradient-to-r from-[#d4af37]/20 to-[#c9a227]/20"></div>
<div className="bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-slate-900 p-4 rounded-t-2xl flex items-center justify-between relative overflow-hidden">
<div className="absolute inset-0 bg-gradient-to-r from-[var(--luxury-gold)]/20 to-[var(--luxury-gold-dark)]/20"></div>
<div className="absolute top-0 left-0 right-0 h-0.5 bg-gradient-to-r from-transparent via-slate-900/20 to-transparent"></div>
<div className="flex items-center gap-3 relative z-10">
<div className="bg-slate-900/10 p-2 rounded-lg backdrop-blur-sm">
@@ -453,9 +453,9 @@ const ChatWidget: React.FC<ChatWidgetProps> = ({ onClose }) => {
{!isWithinBusinessHours ? (
<div className="flex-1 overflow-y-auto p-4 bg-gradient-to-b from-slate-50/50 to-white">
<div className="max-w-md mx-auto">
<div className="mb-6 p-4 bg-gradient-to-r from-[#d4af37]/10 to-[#c9a227]/10 rounded-xl border border-[#d4af37]/20">
<div className="mb-6 p-4 bg-gradient-to-r from-[var(--luxury-gold)]/10 to-[var(--luxury-gold-dark)]/10 rounded-xl border border-[var(--luxury-gold)]/20">
<div className="flex items-start gap-3">
<Clock className="w-5 h-5 text-[#d4af37] mt-0.5 flex-shrink-0" />
<Clock className="w-5 h-5 text-[var(--luxury-gold)] mt-0.5 flex-shrink-0" />
<div>
<p className="text-sm font-semibold text-slate-900 mb-1">Chat Hours</p>
<p className="text-xs text-slate-600 font-light">
@@ -474,7 +474,7 @@ const ChatWidget: React.FC<ChatWidgetProps> = ({ onClose }) => {
type="email"
value={inquiryEmail}
onChange={(e) => setInquiryEmail(e.target.value)}
className="w-full px-4 py-2.5 border-2 border-slate-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-[#d4af37]/30 focus:border-[#d4af37] transition-all duration-200 font-light"
className="w-full px-4 py-2.5 border-2 border-slate-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-[var(--luxury-gold)]/30 focus:border-[var(--luxury-gold)] transition-all duration-200 font-light"
placeholder="your.email@example.com"
/>
</div>
@@ -486,14 +486,14 @@ const ChatWidget: React.FC<ChatWidgetProps> = ({ onClose }) => {
value={inquiry}
onChange={(e) => setInquiry(e.target.value)}
rows={6}
className="w-full px-4 py-2.5 border-2 border-slate-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-[#d4af37]/30 focus:border-[#d4af37] transition-all duration-200 font-light resize-none"
className="w-full px-4 py-2.5 border-2 border-slate-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-[var(--luxury-gold)]/30 focus:border-[var(--luxury-gold)] transition-all duration-200 font-light resize-none"
placeholder="Please describe your inquiry or question..."
/>
</div>
<button
onClick={handleSubmitInquiry}
disabled={submittingInquiry || !inquiryEmail.trim() || !inquiry.trim()}
className="w-full bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-slate-900 px-4 py-3 rounded-xl hover:from-[#c9a227] hover:to-[#d4af37] disabled:bg-gray-300 disabled:text-gray-500 disabled:cursor-not-allowed transition-all duration-300 font-semibold shadow-lg shadow-[#d4af37]/30 hover:shadow-xl disabled:shadow-none"
className="w-full bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-slate-900 px-4 py-3 rounded-xl hover:from-[var(--luxury-gold-dark)] hover:to-[var(--luxury-gold)] disabled:bg-gray-300 disabled:text-gray-500 disabled:cursor-not-allowed transition-all duration-300 font-semibold shadow-lg shadow-[var(--luxury-gold)]/30 hover:shadow-xl disabled:shadow-none"
>
{submittingInquiry ? 'Sending...' : 'Send Inquiry'}
</button>
@@ -521,8 +521,8 @@ const ChatWidget: React.FC<ChatWidgetProps> = ({ onClose }) => {
setVisitorInfo({ ...visitorInfo, name: e.target.value });
if (formErrors.name) setFormErrors({ ...formErrors, name: '' });
}}
className={`w-full px-4 py-2.5 border-2 rounded-xl focus:outline-none focus:ring-2 focus:ring-[#d4af37]/30 transition-all duration-200 font-light ${
formErrors.name ? 'border-red-500 focus:border-red-500' : 'border-slate-200 focus:border-[#d4af37]'
className={`w-full px-4 py-2.5 border-2 rounded-xl focus:outline-none focus:ring-2 focus:ring-[var(--luxury-gold)]/30 transition-all duration-200 font-light ${
formErrors.name ? 'border-red-500 focus:border-red-500' : 'border-slate-200 focus:border-[var(--luxury-gold)]'
}`}
placeholder="Your full name"
/>
@@ -541,8 +541,8 @@ const ChatWidget: React.FC<ChatWidgetProps> = ({ onClose }) => {
setVisitorInfo({ ...visitorInfo, email: e.target.value });
if (formErrors.email) setFormErrors({ ...formErrors, email: '' });
}}
className={`w-full px-4 py-2.5 border-2 rounded-xl focus:outline-none focus:ring-2 focus:ring-[#d4af37]/30 transition-all duration-200 font-light ${
formErrors.email ? 'border-red-500 focus:border-red-500' : 'border-slate-200 focus:border-[#d4af37]'
className={`w-full px-4 py-2.5 border-2 rounded-xl focus:outline-none focus:ring-2 focus:ring-[var(--luxury-gold)]/30 transition-all duration-200 font-light ${
formErrors.email ? 'border-red-500 focus:border-red-500' : 'border-slate-200 focus:border-[var(--luxury-gold)]'
}`}
placeholder="your.email@example.com"
/>
@@ -561,8 +561,8 @@ const ChatWidget: React.FC<ChatWidgetProps> = ({ onClose }) => {
setVisitorInfo({ ...visitorInfo, phone: e.target.value });
if (formErrors.phone) setFormErrors({ ...formErrors, phone: '' });
}}
className={`w-full px-4 py-2.5 border-2 rounded-xl focus:outline-none focus:ring-2 focus:ring-[#d4af37]/30 transition-all duration-200 font-light ${
formErrors.phone ? 'border-red-500 focus:border-red-500' : 'border-slate-200 focus:border-[#d4af37]'
className={`w-full px-4 py-2.5 border-2 rounded-xl focus:outline-none focus:ring-2 focus:ring-[var(--luxury-gold)]/30 transition-all duration-200 font-light ${
formErrors.phone ? 'border-red-500 focus:border-red-500' : 'border-slate-200 focus:border-[var(--luxury-gold)]'
}`}
placeholder="+1 (555) 123-4567"
/>
@@ -573,7 +573,7 @@ const ChatWidget: React.FC<ChatWidgetProps> = ({ onClose }) => {
<button
onClick={createChat}
disabled={loading}
className="w-full bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-slate-900 px-4 py-3 rounded-xl hover:from-[#c9a227] hover:to-[#d4af37] disabled:bg-gray-300 disabled:text-gray-500 disabled:cursor-not-allowed transition-all duration-300 font-semibold shadow-lg shadow-[#d4af37]/30 hover:shadow-xl disabled:shadow-none"
className="w-full bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-slate-900 px-4 py-3 rounded-xl hover:from-[var(--luxury-gold-dark)] hover:to-[var(--luxury-gold)] disabled:bg-gray-300 disabled:text-gray-500 disabled:cursor-not-allowed transition-all duration-300 font-semibold shadow-lg shadow-[var(--luxury-gold)]/30 hover:shadow-xl disabled:shadow-none"
>
{loading ? 'Starting chat...' : 'Start Chat'}
</button>
@@ -617,7 +617,7 @@ const ChatWidget: React.FC<ChatWidgetProps> = ({ onClose }) => {
}
}}
disabled={loading}
className="bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-slate-900 px-8 py-3 rounded-xl hover:from-[#c9a227] hover:to-[#d4af37] transition-all duration-300 font-semibold shadow-lg shadow-[#d4af37]/30 hover:shadow-xl disabled:opacity-50 disabled:cursor-not-allowed"
className="bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-slate-900 px-8 py-3 rounded-xl hover:from-[var(--luxury-gold-dark)] hover:to-[var(--luxury-gold)] transition-all duration-300 font-semibold shadow-lg shadow-[var(--luxury-gold)]/30 hover:shadow-xl disabled:opacity-50 disabled:cursor-not-allowed"
>
{loading ? 'Starting...' : 'Start New Chat'}
</button>
@@ -637,12 +637,12 @@ const ChatWidget: React.FC<ChatWidgetProps> = ({ onClose }) => {
<div
className={`max-w-[80%] rounded-xl p-4 shadow-lg ${
message.sender_type === 'visitor'
? 'bg-gradient-to-br from-[#d4af37] to-[#c9a227] text-slate-900 border border-[#d4af37]/30'
? 'bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-slate-900 border border-[var(--luxury-gold)]/30'
: 'bg-white text-slate-800 border border-slate-200/60 shadow-sm'
}`}
>
{message.sender_type === 'staff' && (
<div className="text-xs font-semibold mb-1.5 text-[#d4af37] tracking-wide">
<div className="text-xs font-semibold mb-1.5 text-[var(--luxury-gold)] tracking-wide">
{message.sender_name || 'Staff'}
</div>
)}
@@ -671,7 +671,7 @@ const ChatWidget: React.FC<ChatWidgetProps> = ({ onClose }) => {
{}
{!showVisitorForm && chat && chat.status !== 'closed' && (
<div className="p-4 border-t border-[#d4af37]/20 bg-white/90 backdrop-blur-sm rounded-b-2xl">
<div className="p-4 border-t border-[var(--luxury-gold)]/20 bg-white/90 backdrop-blur-sm rounded-b-2xl">
<div className="flex gap-3">
<input
type="text"
@@ -679,12 +679,12 @@ const ChatWidget: React.FC<ChatWidgetProps> = ({ onClose }) => {
onChange={(e) => setNewMessage(e.target.value)}
onKeyPress={handleKeyPress}
placeholder="Type your message..."
className="flex-1 px-4 py-3 border-2 border-slate-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-[#d4af37]/30 focus:border-[#d4af37] transition-all duration-200 font-light"
className="flex-1 px-4 py-3 border-2 border-slate-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-[var(--luxury-gold)]/30 focus:border-[var(--luxury-gold)] transition-all duration-200 font-light"
/>
<button
onClick={handleSend}
disabled={!newMessage.trim()}
className="bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-slate-900 px-5 py-3 rounded-xl hover:from-[#c9a227] hover:to-[#d4af37] disabled:bg-gray-300 disabled:text-gray-500 disabled:cursor-not-allowed transition-all duration-300 flex items-center gap-2 font-semibold shadow-lg shadow-[#d4af37]/30 hover:shadow-xl disabled:shadow-none"
className="bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-slate-900 px-5 py-3 rounded-xl hover:from-[var(--luxury-gold-dark)] hover:to-[var(--luxury-gold)] disabled:bg-gray-300 disabled:text-gray-500 disabled:cursor-not-allowed transition-all duration-300 flex items-center gap-2 font-semibold shadow-lg shadow-[var(--luxury-gold)]/30 hover:shadow-xl disabled:shadow-none"
>
<Send className="w-4 h-4" />
</button>

View File

@@ -112,16 +112,16 @@ const BoricaPaymentModal: React.FC<BoricaPaymentModalProps> = ({
className="fixed inset-0 bg-black/90 backdrop-blur-sm"
onClick={onClose}
/>
<div className="relative w-full max-w-md max-h-[95vh] bg-gradient-to-br from-[#0a0a0a] via-[#1a1a1a] to-[#0a0a0a] rounded-xl sm:rounded-2xl border border-[#d4af37]/30 shadow-2xl shadow-[#d4af37]/20 overflow-hidden flex flex-col">
<div className="relative w-full max-w-md max-h-[95vh] bg-gradient-to-br from-[#0a0a0a] via-[#1a1a1a] to-[#0a0a0a] rounded-xl sm:rounded-2xl border border-[var(--luxury-gold)]/30 shadow-2xl shadow-[var(--luxury-gold)]/20 overflow-hidden flex flex-col">
{/* Header */}
<div className="px-3 sm:px-4 md:px-6 py-3 sm:py-4 border-b border-[#d4af37]/20 bg-gradient-to-r from-[#1a1a1a] to-[#0a0a0a] flex-shrink-0">
<div className="px-3 sm:px-4 md:px-6 py-3 sm:py-4 border-b border-[var(--luxury-gold)]/20 bg-gradient-to-r from-[#1a1a1a] to-[#0a0a0a] flex-shrink-0">
<div className="flex items-center justify-between gap-2">
<h2 className="text-base sm:text-lg md:text-xl font-serif font-bold text-white tracking-tight truncate flex-1">
Borica Payment
</h2>
<button
onClick={onClose}
className="p-1.5 sm:p-2 hover:bg-[#d4af37]/10 rounded-lg transition-colors text-gray-400 hover:text-white flex-shrink-0"
className="p-1.5 sm:p-2 hover:bg-[var(--luxury-gold)]/10 rounded-lg transition-colors text-gray-400 hover:text-white flex-shrink-0"
>
<X className="w-4 h-4 sm:w-5 sm:h-5" />
</button>
@@ -132,7 +132,7 @@ const BoricaPaymentModal: React.FC<BoricaPaymentModalProps> = ({
<div className="flex-1 overflow-y-auto p-3 sm:p-4 md:p-6">
{loading ? (
<div className="flex flex-col items-center justify-center py-8 sm:py-12">
<Loader2 className="w-10 h-10 sm:w-12 sm:h-12 animate-spin text-[#d4af37] mb-3 sm:mb-4" />
<Loader2 className="w-10 h-10 sm:w-12 sm:h-12 animate-spin text-[var(--luxury-gold)] mb-3 sm:mb-4" />
<p className="text-xs sm:text-sm text-gray-400">Initializing Borica payment...</p>
</div>
) : error ? (
@@ -153,14 +153,14 @@ const BoricaPaymentModal: React.FC<BoricaPaymentModalProps> = ({
<div className="space-y-4 sm:space-y-6">
<div className="text-center">
<div className="mb-3 sm:mb-4 flex justify-center">
<CreditCard className="w-12 h-12 sm:w-16 sm:h-16 text-[#d4af37]" />
<CreditCard className="w-12 h-12 sm:w-16 sm:h-16 text-[var(--luxury-gold)]" />
</div>
<h3 className="text-base sm:text-lg font-serif font-semibold text-white mb-1.5 sm:mb-2">
Complete Payment with Borica
</h3>
<p className="text-xs sm:text-sm text-gray-400 mb-3 sm:mb-4 leading-relaxed px-2">
You will be redirected to Borica payment gateway to securely complete your payment of{' '}
<span className="font-semibold text-[#d4af37]">
<span className="font-semibold text-[var(--luxury-gold)]">
{new Intl.NumberFormat('en-US', {
style: 'currency',
currency: currency,
@@ -169,14 +169,14 @@ const BoricaPaymentModal: React.FC<BoricaPaymentModalProps> = ({
</p>
</div>
<div className="bg-[#1a1a1a]/50 border border-[#d4af37]/20 rounded-lg p-3 sm:p-4 space-y-2 sm:space-y-3">
<div className="bg-[#1a1a1a]/50 border border-[var(--luxury-gold)]/20 rounded-lg p-3 sm:p-4 space-y-2 sm:space-y-3">
<div className="flex justify-between items-center text-xs sm:text-sm">
<span className="text-gray-400">Order ID:</span>
<span className="text-white font-mono">{paymentRequest.order_id}</span>
</div>
<div className="flex justify-between items-center text-xs sm:text-sm">
<span className="text-gray-400">Amount:</span>
<span className="text-[#d4af37] font-semibold">
<span className="text-[var(--luxury-gold)] font-semibold">
{new Intl.NumberFormat('en-US', {
style: 'currency',
currency: currency,
@@ -202,7 +202,7 @@ const BoricaPaymentModal: React.FC<BoricaPaymentModalProps> = ({
{/* Footer */}
{!loading && !error && paymentRequest && (
<div className="px-3 sm:px-4 md:px-6 py-3 sm:py-4 border-t border-[#d4af37]/20 bg-gradient-to-r from-[#1a1a1a] to-[#0a0a0a] flex-shrink-0 flex gap-2 sm:gap-3">
<div className="px-3 sm:px-4 md:px-6 py-3 sm:py-4 border-t border-[var(--luxury-gold)]/20 bg-gradient-to-r from-[#1a1a1a] to-[#0a0a0a] flex-shrink-0 flex gap-2 sm:gap-3">
<button
onClick={onClose}
className="flex-1 px-3 sm:px-4 py-2 sm:py-2.5 text-xs sm:text-sm font-medium text-gray-300 bg-[#1a1a1a] border border-gray-700 rounded-lg hover:bg-[#2a2a2a] hover:border-gray-600 transition-colors"
@@ -211,7 +211,7 @@ const BoricaPaymentModal: React.FC<BoricaPaymentModalProps> = ({
</button>
<button
onClick={handleSubmitPayment}
className="flex-1 px-3 sm:px-4 py-2 sm:py-2.5 text-xs sm:text-sm font-medium text-white bg-gradient-to-r from-[#d4af37] to-[#b8941f] rounded-lg hover:from-[#e5c048] hover:to-[#c9a428] transition-all shadow-lg shadow-[#d4af37]/20 flex items-center justify-center gap-2"
className="flex-1 px-3 sm:px-4 py-2 sm:py-2.5 text-xs sm:text-sm font-medium text-white bg-gradient-to-r from-[var(--luxury-gold)] to-[#b8941f] rounded-lg hover:from-[#e5c048] hover:to-[#c9a428] transition-all shadow-lg shadow-[var(--luxury-gold)]/20 flex items-center justify-center gap-2"
>
<CreditCard className="w-4 h-4" />
Proceed to Payment

View File

@@ -41,16 +41,16 @@ const CashPaymentModal: React.FC<CashPaymentModalProps> = ({
className="fixed inset-0 bg-black/90 backdrop-blur-sm"
onClick={onClose}
/>
<div className="relative w-full max-w-md max-h-[95vh] bg-gradient-to-br from-[#0a0a0a] via-[#1a1a1a] to-[#0a0a0a] rounded-xl sm:rounded-2xl border border-[#d4af37]/30 shadow-2xl shadow-[#d4af37]/20 overflow-hidden flex flex-col">
<div className="relative w-full max-w-md max-h-[95vh] bg-gradient-to-br from-[#0a0a0a] via-[#1a1a1a] to-[#0a0a0a] rounded-xl sm:rounded-2xl border border-[var(--luxury-gold)]/30 shadow-2xl shadow-[var(--luxury-gold)]/20 overflow-hidden flex flex-col">
{/* Header */}
<div className="px-3 sm:px-4 md:px-6 py-3 sm:py-4 border-b border-[#d4af37]/20 bg-gradient-to-r from-[#1a1a1a] to-[#0a0a0a] flex-shrink-0">
<div className="px-3 sm:px-4 md:px-6 py-3 sm:py-4 border-b border-[var(--luxury-gold)]/20 bg-gradient-to-r from-[#1a1a1a] to-[#0a0a0a] flex-shrink-0">
<div className="flex items-center justify-between gap-2">
<h2 className="text-base sm:text-lg md:text-xl font-serif font-bold text-white tracking-tight truncate flex-1">
Booking Created
</h2>
<button
onClick={onClose}
className="p-1.5 sm:p-2 hover:bg-[#d4af37]/10 rounded-lg transition-colors text-gray-400 hover:text-white flex-shrink-0"
className="p-1.5 sm:p-2 hover:bg-[var(--luxury-gold)]/10 rounded-lg transition-colors text-gray-400 hover:text-white flex-shrink-0"
>
<X className="w-4 h-4 sm:w-5 sm:h-5" />
</button>
@@ -72,16 +72,16 @@ const CashPaymentModal: React.FC<CashPaymentModalProps> = ({
</p>
</div>
<div className="bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg p-3 sm:p-4 space-y-2 sm:space-y-3">
<div className="bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg p-3 sm:p-4 space-y-2 sm:space-y-3">
<div className="flex items-center justify-between text-xs sm:text-sm">
<span className="text-gray-400">Total Amount</span>
<span className="text-white font-semibold">{formatCurrency(amount)}</span>
</div>
<div className="flex items-center justify-between text-xs sm:text-sm">
<span className="text-gray-400 break-words pr-2">Deposit Required (20%)</span>
<span className="text-[#d4af37] font-bold flex-shrink-0">{formatCurrency(depositAmount)}</span>
<span className="text-[var(--luxury-gold)] font-bold flex-shrink-0">{formatCurrency(depositAmount)}</span>
</div>
<div className="pt-2 sm:pt-3 border-t border-[#d4af37]/20">
<div className="pt-2 sm:pt-3 border-t border-[var(--luxury-gold)]/20">
<p className="text-xs text-gray-400 leading-relaxed">
Pay the remaining balance on arrival at the hotel.
</p>
@@ -91,7 +91,7 @@ const CashPaymentModal: React.FC<CashPaymentModalProps> = ({
<div className="flex flex-col gap-2 sm:gap-3 pt-2">
<button
onClick={handlePayDeposit}
className="w-full bg-[#d4af37] text-black font-semibold py-2.5 sm:py-3 px-4 sm:px-6 rounded-lg hover:bg-[#c9a227] transition-all flex items-center justify-center gap-2 text-sm sm:text-base min-h-[44px]"
className="w-full bg-[var(--luxury-gold)] text-black font-semibold py-2.5 sm:py-3 px-4 sm:px-6 rounded-lg hover:bg-[var(--luxury-gold-dark)] transition-all flex items-center justify-center gap-2 text-sm sm:text-base min-h-[44px]"
>
<CreditCard className="w-4 h-4 sm:w-5 sm:h-5" />
<span>Pay Deposit Now</span>

View File

@@ -177,9 +177,9 @@ const DepositPaymentModal: React.FC<DepositPaymentModalProps> = ({
className="fixed inset-0 bg-black/90 backdrop-blur-sm"
onClick={onClose}
/>
<div className="relative w-full max-w-3xl max-h-[95vh] bg-gradient-to-br from-[#0a0a0a] via-[#1a1a1a] to-[#0a0a0a] rounded-xl sm:rounded-2xl border border-[#d4af37]/30 shadow-2xl shadow-[#d4af37]/20 overflow-hidden flex flex-col">
<div className="relative w-full max-w-3xl max-h-[95vh] bg-gradient-to-br from-[#0a0a0a] via-[#1a1a1a] to-[#0a0a0a] rounded-xl sm:rounded-2xl border border-[var(--luxury-gold)]/30 shadow-2xl shadow-[var(--luxury-gold)]/20 overflow-hidden flex flex-col">
{/* Header */}
<div className="px-3 sm:px-4 md:px-6 py-3 sm:py-4 border-b border-[#d4af37]/20 bg-gradient-to-r from-[#1a1a1a] to-[#0a0a0a] flex-shrink-0">
<div className="px-3 sm:px-4 md:px-6 py-3 sm:py-4 border-b border-[var(--luxury-gold)]/20 bg-gradient-to-r from-[#1a1a1a] to-[#0a0a0a] flex-shrink-0">
<div className="flex items-center justify-between gap-2">
<div className="min-w-0 flex-1">
<h2 className="text-base sm:text-lg md:text-xl font-serif font-bold text-white tracking-tight truncate">
@@ -204,7 +204,7 @@ const DepositPaymentModal: React.FC<DepositPaymentModalProps> = ({
)}
<button
onClick={onClose}
className="p-1.5 sm:p-2 hover:bg-[#d4af37]/10 rounded-lg transition-colors text-gray-400 hover:text-white flex-shrink-0"
className="p-1.5 sm:p-2 hover:bg-[var(--luxury-gold)]/10 rounded-lg transition-colors text-gray-400 hover:text-white flex-shrink-0"
>
<X className="w-4 h-4 sm:w-5 sm:h-5" />
</button>
@@ -216,7 +216,7 @@ const DepositPaymentModal: React.FC<DepositPaymentModalProps> = ({
<div className="flex-1 overflow-y-auto px-3 sm:px-4 md:px-6 py-4 sm:py-6">
{loading ? (
<div className="flex flex-col items-center justify-center py-8 sm:py-12">
<Loader2 className="w-10 h-10 sm:w-12 sm:h-12 animate-spin text-[#d4af37] mb-3 sm:mb-4" />
<Loader2 className="w-10 h-10 sm:w-12 sm:h-12 animate-spin text-[var(--luxury-gold)] mb-3 sm:mb-4" />
<p className="text-xs sm:text-sm text-gray-400">Loading payment information...</p>
</div>
) : error || !booking || !depositPayment ? (
@@ -227,7 +227,7 @@ const DepositPaymentModal: React.FC<DepositPaymentModalProps> = ({
</p>
<button
onClick={onClose}
className="px-4 py-2 sm:py-2.5 bg-[#d4af37] text-black font-semibold rounded-lg hover:bg-[#c9a227] transition-all text-sm sm:text-base min-h-[44px]"
className="px-4 py-2 sm:py-2.5 bg-[var(--luxury-gold)] text-black font-semibold rounded-lg hover:bg-[var(--luxury-gold-dark)] transition-all text-sm sm:text-base min-h-[44px]"
>
Close
</button>
@@ -260,17 +260,17 @@ const DepositPaymentModal: React.FC<DepositPaymentModalProps> = ({
{/* Payment Required Message */}
{!isDepositPaid && (
<div className="bg-[#d4af37]/10 border border-[#d4af37]/30 rounded-lg p-3 sm:p-4">
<div className="bg-[var(--luxury-gold)]/10 border border-[var(--luxury-gold)]/30 rounded-lg p-3 sm:p-4">
<div className="flex items-start gap-2 sm:gap-3">
<div className="w-10 h-10 sm:w-12 sm:h-12 bg-[#d4af37]/20 rounded-full flex items-center justify-center border border-[#d4af37]/30 flex-shrink-0">
<CreditCard className="w-5 h-5 sm:w-6 sm:h-6 md:w-7 md:h-7 text-[#d4af37]" />
<div className="w-10 h-10 sm:w-12 sm:h-12 bg-[var(--luxury-gold)]/20 rounded-full flex items-center justify-center border border-[var(--luxury-gold)]/30 flex-shrink-0">
<CreditCard className="w-5 h-5 sm:w-6 sm:h-6 md:w-7 md:h-7 text-[var(--luxury-gold)]" />
</div>
<div className="flex-1 min-w-0">
<h3 className="text-base sm:text-lg font-serif font-semibold text-[#d4af37] mb-1">
<h3 className="text-base sm:text-lg font-serif font-semibold text-[var(--luxury-gold)] mb-1">
Deposit Payment Required
</h3>
<p className="text-xs sm:text-sm text-gray-300 leading-relaxed">
Please pay <strong className="text-[#d4af37]">20% deposit</strong> to confirm your booking. Pay the remaining balance on arrival at the hotel.
Please pay <strong className="text-[var(--luxury-gold)]">20% deposit</strong> to confirm your booking. Pay the remaining balance on arrival at the hotel.
</p>
</div>
</div>
@@ -278,14 +278,14 @@ const DepositPaymentModal: React.FC<DepositPaymentModalProps> = ({
)}
{/* Payment Information */}
<div className="bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg p-3 sm:p-4">
<h3 className="text-xs sm:text-sm font-semibold text-[#d4af37] mb-2 sm:mb-3">Payment Information</h3>
<div className="bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg p-3 sm:p-4">
<h3 className="text-xs sm:text-sm font-semibold text-[var(--luxury-gold)] mb-2 sm:mb-3">Payment Information</h3>
<div className="space-y-1.5 sm:space-y-2 text-xs sm:text-sm">
<div className="flex justify-between text-gray-300">
<span>Total Room Price</span>
<span>{formatCurrency(booking.total_price)}</span>
</div>
<div className="flex justify-between text-base sm:text-lg font-bold text-[#d4af37] pt-2 border-t border-[#d4af37]/20">
<div className="flex justify-between text-base sm:text-lg font-bold text-[var(--luxury-gold)] pt-2 border-t border-[var(--luxury-gold)]/20">
<span className="break-words pr-2">Deposit Amount (20%)</span>
<span className="flex-shrink-0">{formatCurrency(depositAmount)}</span>
</div>
@@ -298,18 +298,18 @@ const DepositPaymentModal: React.FC<DepositPaymentModalProps> = ({
{/* Payment Method Selection */}
{!isDepositPaid && !selectedPaymentMethod && (
<div className="bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg p-3 sm:p-4">
<h3 className="text-xs sm:text-sm font-semibold text-[#d4af37] mb-2 sm:mb-3">Choose Payment Method</h3>
<div className="bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg p-3 sm:p-4">
<h3 className="text-xs sm:text-sm font-semibold text-[var(--luxury-gold)] mb-2 sm:mb-3">Choose Payment Method</h3>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-2 sm:gap-3">
<button
onClick={() => handlePaymentMethodSelect('stripe')}
className="p-3 sm:p-4 bg-[#1a1a1a] border-2 border-gray-600/30 rounded-lg hover:border-[#d4af37]/50 transition-all text-left group min-h-[80px] sm:min-h-[100px]"
className="p-3 sm:p-4 bg-[#1a1a1a] border-2 border-gray-600/30 rounded-lg hover:border-[var(--luxury-gold)]/50 transition-all text-left group min-h-[80px] sm:min-h-[100px]"
>
<div className="flex items-center justify-between mb-1.5 sm:mb-2">
<div className="w-8 h-8 sm:w-10 sm:h-10 bg-indigo-500/20 rounded-lg flex items-center justify-center border border-indigo-500/30 flex-shrink-0">
<CreditCard className="w-4 h-4 sm:w-5 sm:h-5 text-indigo-400 group-hover:text-[#d4af37] transition-colors" />
<CreditCard className="w-4 h-4 sm:w-5 sm:h-5 text-indigo-400 group-hover:text-[var(--luxury-gold)] transition-colors" />
</div>
<span className="text-xs font-semibold text-indigo-400 group-hover:text-[#d4af37] transition-colors">
<span className="text-xs font-semibold text-indigo-400 group-hover:text-[var(--luxury-gold)] transition-colors">
Card Payment
</span>
</div>
@@ -320,19 +320,19 @@ const DepositPaymentModal: React.FC<DepositPaymentModalProps> = ({
<button
onClick={() => handlePaymentMethodSelect('paypal')}
className="p-3 sm:p-4 bg-[#1a1a1a] border-2 border-gray-600/30 rounded-lg hover:border-[#d4af37]/50 transition-all text-left group min-h-[80px] sm:min-h-[100px]"
className="p-3 sm:p-4 bg-[#1a1a1a] border-2 border-gray-600/30 rounded-lg hover:border-[var(--luxury-gold)]/50 transition-all text-left group min-h-[80px] sm:min-h-[100px]"
>
<div className="flex items-center justify-between mb-1.5 sm:mb-2">
<div className="w-8 h-8 sm:w-10 sm:h-10 bg-blue-500/20 rounded-lg flex items-center justify-center border border-blue-500/30 flex-shrink-0">
<svg
className="w-4 h-4 sm:w-5 sm:h-5 text-blue-400 group-hover:text-[#d4af37] transition-colors"
className="w-4 h-4 sm:w-5 sm:h-5 text-blue-400 group-hover:text-[var(--luxury-gold)] transition-colors"
viewBox="0 0 24 24"
fill="currentColor"
>
<path d="M7.076 21.337H2.47a.641.641 0 0 1-.633-.74L4.944.901C5.026.382 5.474 0 5.998 0h7.46c2.57 0 4.578.543 5.69 1.81 1.01 1.15 1.304 2.42 1.012 4.287-.023.143-.047.288-.077.437-.983 5.05-4.349 6.797-8.647 6.797h-2.19c-.524 0-.968.382-1.05.9l-1.12 7.203zm14.146-14.42a.477.477 0 0 0-.414-.24h-3.84c-.48 0-.856.355-.932.826-.075.47-.232 1.21-.232 1.21s-.156-.74-.232-1.21a.957.957 0 0 0-.932-.826H5.342a.957.957 0 0 0-.932.826c-.076.47-.232 1.21-.232 1.21s-.156-.74-.232-1.21a.957.957 0 0 0-.932-.826H.477a.477.477 0 0 0-.414.24c-.11.19-.14.426-.08.643.06.217.2.4.388.51l.04.02c.19.11.426.14.643.08.217-.06.4-.2.51-.388l.01-.02c.11-.19.14-.426.08-.643a.955.955 0 0 0-.388-.51l-.01-.01a.955.955 0 0 0-.51-.388.955.955 0 0 0-.643.08l-.01.01a.955.955 0 0 0-.388.51c-.06.217-.03.453.08.643l.01.02c.11.188.293.328.51.388.217.06.453.03.643-.08l.01-.02c.188-.11.328-.293.388-.51.06-.217.03-.453-.08-.643l-.01-.01z"/>
</svg>
</div>
<span className="text-xs font-semibold text-blue-400 group-hover:text-[#d4af37] transition-colors">
<span className="text-xs font-semibold text-blue-400 group-hover:text-[var(--luxury-gold)] transition-colors">
PayPal
</span>
</div>
@@ -346,10 +346,10 @@ const DepositPaymentModal: React.FC<DepositPaymentModalProps> = ({
{/* Change Payment Method */}
{!isDepositPaid && selectedPaymentMethod && (
<div className="bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg p-3 sm:p-4">
<div className="bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg p-3 sm:p-4">
<div className="flex items-center justify-between gap-2 mb-2 sm:mb-3">
<div className="min-w-0 flex-1">
<h3 className="text-xs sm:text-sm font-semibold text-[#d4af37]">
<h3 className="text-xs sm:text-sm font-semibold text-[var(--luxury-gold)]">
{selectedPaymentMethod === 'stripe' ? 'Card Payment' : 'PayPal Payment'}
</h3>
<p className="text-xs text-gray-400 mt-0.5 sm:mt-1">
@@ -361,7 +361,7 @@ const DepositPaymentModal: React.FC<DepositPaymentModalProps> = ({
setSelectedPaymentMethod(null);
setShowPaymentModal(false);
}}
className="text-xs text-gray-400 hover:text-[#d4af37] underline transition-colors flex-shrink-0 whitespace-nowrap"
className="text-xs text-gray-400 hover:text-[var(--luxury-gold)] underline transition-colors flex-shrink-0 whitespace-nowrap"
>
Change method
</button>

View File

@@ -89,16 +89,16 @@ const PayPalPaymentModal: React.FC<PayPalPaymentModalProps> = ({
className="fixed inset-0 bg-black/90 backdrop-blur-sm"
onClick={onClose}
/>
<div className="relative w-full max-w-md max-h-[95vh] bg-gradient-to-br from-[#0a0a0a] via-[#1a1a1a] to-[#0a0a0a] rounded-xl sm:rounded-2xl border border-[#d4af37]/30 shadow-2xl shadow-[#d4af37]/20 overflow-hidden flex flex-col">
<div className="relative w-full max-w-md max-h-[95vh] bg-gradient-to-br from-[#0a0a0a] via-[#1a1a1a] to-[#0a0a0a] rounded-xl sm:rounded-2xl border border-[var(--luxury-gold)]/30 shadow-2xl shadow-[var(--luxury-gold)]/20 overflow-hidden flex flex-col">
{/* Header */}
<div className="px-3 sm:px-4 md:px-6 py-3 sm:py-4 border-b border-[#d4af37]/20 bg-gradient-to-r from-[#1a1a1a] to-[#0a0a0a] flex-shrink-0">
<div className="px-3 sm:px-4 md:px-6 py-3 sm:py-4 border-b border-[var(--luxury-gold)]/20 bg-gradient-to-r from-[#1a1a1a] to-[#0a0a0a] flex-shrink-0">
<div className="flex items-center justify-between gap-2">
<h2 className="text-base sm:text-lg md:text-xl font-serif font-bold text-white tracking-tight truncate flex-1">
PayPal Payment
</h2>
<button
onClick={onClose}
className="p-1.5 sm:p-2 hover:bg-[#d4af37]/10 rounded-lg transition-colors text-gray-400 hover:text-white flex-shrink-0"
className="p-1.5 sm:p-2 hover:bg-[var(--luxury-gold)]/10 rounded-lg transition-colors text-gray-400 hover:text-white flex-shrink-0"
>
<X className="w-4 h-4 sm:w-5 sm:h-5" />
</button>
@@ -109,7 +109,7 @@ const PayPalPaymentModal: React.FC<PayPalPaymentModalProps> = ({
<div className="flex-1 overflow-y-auto p-3 sm:p-4 md:p-6">
{loading ? (
<div className="flex flex-col items-center justify-center py-8 sm:py-12">
<Loader2 className="w-10 h-10 sm:w-12 sm:h-12 animate-spin text-[#d4af37] mb-3 sm:mb-4" />
<Loader2 className="w-10 h-10 sm:w-12 sm:h-12 animate-spin text-[var(--luxury-gold)] mb-3 sm:mb-4" />
<p className="text-xs sm:text-sm text-gray-400">Initializing PayPal payment...</p>
</div>
) : error ? (
@@ -147,7 +147,7 @@ const PayPalPaymentModal: React.FC<PayPalPaymentModalProps> = ({
</h3>
<p className="text-xs sm:text-sm text-gray-400 mb-3 sm:mb-4 leading-relaxed px-2">
You will be redirected to PayPal to securely complete your payment of{' '}
<span className="font-semibold text-[#d4af37]">
<span className="font-semibold text-[var(--luxury-gold)]">
{new Intl.NumberFormat('en-US', {
style: 'currency',
currency: currency,
@@ -178,7 +178,7 @@ const PayPalPaymentModal: React.FC<PayPalPaymentModalProps> = ({
</div>
) : (
<div className="flex flex-col items-center justify-center py-8 sm:py-12">
<Loader2 className="w-10 h-10 sm:w-12 sm:h-12 animate-spin text-[#d4af37] mb-3 sm:mb-4" />
<Loader2 className="w-10 h-10 sm:w-12 sm:h-12 animate-spin text-[var(--luxury-gold)] mb-3 sm:mb-4" />
<p className="text-xs sm:text-sm text-gray-400">Loading PayPal...</p>
</div>
)}

View File

@@ -83,10 +83,10 @@ const PayPalPaymentWrapper: React.FC<PayPalPaymentWrapperProps> = ({
if (loading) {
return (
<div className="flex items-center justify-center p-8">
<div className="w-16 h-16 bg-gradient-to-br from-[#d4af37]/20 to-[#f5d76e]/20
<div className="w-16 h-16 bg-gradient-to-br from-[var(--luxury-gold)]/20 to-[var(--luxury-gold-light)]/20
rounded-full flex items-center justify-center
border border-[#d4af37]/30 shadow-lg shadow-[#d4af37]/20">
<Loader2 className="w-8 h-8 animate-spin text-[#d4af37]" />
border border-[var(--luxury-gold)]/30 shadow-lg shadow-[var(--luxury-gold)]/20">
<Loader2 className="w-8 h-8 animate-spin text-[var(--luxury-gold)]" />
</div>
<span className="ml-4 text-gray-300 font-light tracking-wide">
Initializing PayPal payment...
@@ -117,10 +117,10 @@ const PayPalPaymentWrapper: React.FC<PayPalPaymentWrapperProps> = ({
if (!approvalUrl) {
return (
<div className="flex items-center justify-center p-8">
<div className="w-16 h-16 bg-gradient-to-br from-[#d4af37]/20 to-[#f5d76e]/20
<div className="w-16 h-16 bg-gradient-to-br from-[var(--luxury-gold)]/20 to-[var(--luxury-gold-light)]/20
rounded-full flex items-center justify-center
border border-[#d4af37]/30 shadow-lg shadow-[#d4af37]/20">
<Loader2 className="w-8 h-8 animate-spin text-[#d4af37]" />
border border-[var(--luxury-gold)]/30 shadow-lg shadow-[var(--luxury-gold)]/20">
<Loader2 className="w-8 h-8 animate-spin text-[var(--luxury-gold)]" />
</div>
<span className="ml-4 text-gray-300 font-light tracking-wide">
Loading PayPal...
@@ -144,12 +144,12 @@ const PayPalPaymentWrapper: React.FC<PayPalPaymentWrapperProps> = ({
/>
</svg>
</div>
<h3 className="text-xl font-serif font-semibold text-[#d4af37] mb-3 tracking-wide">
<h3 className="text-xl font-serif font-semibold text-[var(--luxury-gold)] mb-3 tracking-wide">
Complete Payment with PayPal
</h3>
<p className="text-gray-300/80 font-light text-lg mb-8 tracking-wide">
You will be redirected to PayPal to securely complete your payment of{' '}
<span className="font-semibold text-[#d4af37]">
<span className="font-semibold text-[var(--luxury-gold)]">
{new Intl.NumberFormat('en-US', {
style: 'currency',
currency: currency,

View File

@@ -75,7 +75,7 @@ const StripePaymentForm: React.FC<StripePaymentFormProps> = ({
if (!stripe || !elements) {
return (
<div className="flex items-center justify-center p-8">
<Loader2 className="w-8 h-8 animate-spin text-[#d4af37]" />
<Loader2 className="w-8 h-8 animate-spin text-[var(--luxury-gold)]" />
<span className="ml-2 text-gray-300">Loading payment form...</span>
</div>
);
@@ -88,12 +88,12 @@ const StripePaymentForm: React.FC<StripePaymentFormProps> = ({
autoComplete="off"
// SECURITY: Prevent form caching and autocomplete for payment forms
>
<div className="mb-4 p-4 bg-[#d4af37]/10 border border-[#d4af37]/20 rounded-lg">
<div className="mb-4 p-4 bg-[var(--luxury-gold)]/10 border border-[var(--luxury-gold)]/20 rounded-lg">
<div className="flex justify-between items-center">
<span className="text-sm font-medium text-gray-300">
Amount to Pay
</span>
<span className="text-xl font-bold text-[#d4af37]">
<span className="text-xl font-bold text-[var(--luxury-gold)]">
${amount.toFixed(2)}
</span>
</div>
@@ -141,8 +141,8 @@ const StripePaymentForm: React.FC<StripePaymentFormProps> = ({
<button
type="submit"
disabled={isProcessing || !stripe || !elements}
className="w-full bg-[#d4af37] text-black py-3 px-4 rounded-lg
hover:bg-[#c9a227] transition-colors font-semibold
className="w-full bg-[var(--luxury-gold)] text-black py-3 px-4 rounded-lg
hover:bg-[var(--luxury-gold-dark)] transition-colors font-semibold
disabled:bg-gray-600 disabled:cursor-not-allowed disabled:text-gray-400
flex items-center justify-center gap-2"
>

View File

@@ -123,16 +123,16 @@ const StripePaymentModal: React.FC<StripePaymentModalProps> = ({
className="fixed inset-0 bg-black/90 backdrop-blur-sm"
onClick={onClose}
/>
<div className="relative w-full max-w-md max-h-[95vh] bg-gradient-to-br from-[#0a0a0a] via-[#1a1a1a] to-[#0a0a0a] rounded-xl sm:rounded-2xl border border-[#d4af37]/30 shadow-2xl shadow-[#d4af37]/20 overflow-hidden flex flex-col">
<div className="relative w-full max-w-md max-h-[95vh] bg-gradient-to-br from-[#0a0a0a] via-[#1a1a1a] to-[#0a0a0a] rounded-xl sm:rounded-2xl border border-[var(--luxury-gold)]/30 shadow-2xl shadow-[var(--luxury-gold)]/20 overflow-hidden flex flex-col">
{/* Header */}
<div className="px-3 sm:px-4 md:px-6 py-3 sm:py-4 border-b border-[#d4af37]/20 bg-gradient-to-r from-[#1a1a1a] to-[#0a0a0a] flex-shrink-0">
<div className="px-3 sm:px-4 md:px-6 py-3 sm:py-4 border-b border-[var(--luxury-gold)]/20 bg-gradient-to-r from-[#1a1a1a] to-[#0a0a0a] flex-shrink-0">
<div className="flex items-center justify-between gap-2">
<h2 className="text-base sm:text-lg md:text-xl font-serif font-bold text-white tracking-tight truncate flex-1">
Complete Payment
</h2>
<button
onClick={onClose}
className="p-1.5 sm:p-2 hover:bg-[#d4af37]/10 rounded-lg transition-colors text-gray-400 hover:text-white flex-shrink-0"
className="p-1.5 sm:p-2 hover:bg-[var(--luxury-gold)]/10 rounded-lg transition-colors text-gray-400 hover:text-white flex-shrink-0"
>
<X className="w-4 h-4 sm:w-5 sm:h-5" />
</button>
@@ -143,7 +143,7 @@ const StripePaymentModal: React.FC<StripePaymentModalProps> = ({
<div className="flex-1 overflow-y-auto p-3 sm:p-4 md:p-6">
{loading ? (
<div className="flex flex-col items-center justify-center py-8 sm:py-12">
<Loader2 className="w-10 h-10 sm:w-12 sm:h-12 animate-spin text-[#d4af37] mb-3 sm:mb-4" />
<Loader2 className="w-10 h-10 sm:w-12 sm:h-12 animate-spin text-[var(--luxury-gold)] mb-3 sm:mb-4" />
<p className="text-xs sm:text-sm text-gray-400">Initializing payment...</p>
</div>
) : error ? (
@@ -171,7 +171,7 @@ const StripePaymentModal: React.FC<StripePaymentModalProps> = ({
</Elements>
) : (
<div className="flex flex-col items-center justify-center py-8 sm:py-12">
<Loader2 className="w-10 h-10 sm:w-12 sm:h-12 animate-spin text-[#d4af37] mb-3 sm:mb-4" />
<Loader2 className="w-10 h-10 sm:w-12 sm:h-12 animate-spin text-[var(--luxury-gold)] mb-3 sm:mb-4" />
<p className="text-xs sm:text-sm text-gray-400">Loading payment form...</p>
</div>
)}

View File

@@ -143,7 +143,7 @@ const BannerCarousel: React.FC<BannerCarouselProps> = ({
<div className="relative w-full flex flex-col items-center">
{}
<div
className="w-0 h-0.5 bg-gradient-to-r from-transparent via-[#d4af37] to-transparent mb-4 sm:mb-6 opacity-90
className="w-0 h-0.5 bg-gradient-to-r from-transparent via-[var(--luxury-gold)] to-transparent mb-4 sm:mb-6 opacity-90
animate-lineExpand"
style={{
animation: 'lineExpand 1.2s cubic-bezier(0.4, 0, 0.2, 1) 0.3s forwards',
@@ -168,7 +168,7 @@ const BannerCarousel: React.FC<BannerCarouselProps> = ({
}}
>
<span
className="bg-gradient-to-b from-white via-white via-[#f5d76e] to-[#d4af37] bg-clip-text text-transparent
className="bg-gradient-to-b from-white via-white via-[var(--luxury-gold-light)] to-[var(--luxury-gold)] bg-clip-text text-transparent
animate-gradientShift"
style={{
backgroundSize: '200% 200%',
@@ -201,7 +201,7 @@ const BannerCarousel: React.FC<BannerCarouselProps> = ({
{}
<div
className="w-0 h-0.5 bg-gradient-to-r from-transparent via-[#d4af37] to-transparent mt-3 sm:mt-4 opacity-90
className="w-0 h-0.5 bg-gradient-to-r from-transparent via-[var(--luxury-gold)] to-transparent mt-3 sm:mt-4 opacity-90
animate-lineExpand"
style={{
animation: 'lineExpand 1.2s cubic-bezier(0.4, 0, 0.2, 1) 0.9s forwards',
@@ -229,7 +229,7 @@ const BannerCarousel: React.FC<BannerCarouselProps> = ({
{[...Array(3)].map((_, i) => (
<div
key={i}
className="absolute w-1 h-1 bg-[#d4af37] rounded-full opacity-40"
className="absolute w-1 h-1 bg-[var(--luxury-gold)] rounded-full opacity-40"
style={{
left: `${20 + i * 30}%`,
top: `${30 + i * 20}%`,
@@ -314,7 +314,7 @@ const BannerCarousel: React.FC<BannerCarouselProps> = ({
transition-all duration-300 cursor-pointer
${
index === currentIndex
? 'bg-gradient-to-r from-[#d4af37] to-[#f5d76e] w-8 sm:w-10 shadow-lg shadow-[#d4af37]/50'
? 'bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-light)] w-8 sm:w-10 shadow-lg shadow-[var(--luxury-gold)]/50'
: 'bg-white/40 hover:bg-white/70 w-2 sm:h-2.5 hover:scale-125'
}`}
aria-label={`Go to banner ${index + 1}`}

View File

@@ -77,9 +77,9 @@ const Pagination: React.FC<PaginationProps> = ({
<button
onClick={() => handlePageChange(currentPage - 1)}
disabled={currentPage === 1}
className="px-4 py-2 border border-[#d4af37]/30
className="px-4 py-2 border border-[var(--luxury-gold)]/30
rounded-lg bg-[#0a0a0a] text-gray-300
hover:bg-[#1a1a1a] hover:border-[#d4af37] hover:text-[#d4af37]
hover:bg-[#1a1a1a] hover:border-[var(--luxury-gold)] hover:text-[var(--luxury-gold)]
disabled:opacity-50 disabled:cursor-not-allowed
transition-all duration-300 font-medium tracking-wide"
aria-label="Previous page"
@@ -110,8 +110,8 @@ const Pagination: React.FC<PaginationProps> = ({
className={`px-5 py-2 rounded-lg transition-all duration-300
font-medium tracking-wide ${
isActive
? 'bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-[#0f0f0f] shadow-lg shadow-[#d4af37]/30'
: 'border border-[#d4af37]/30 bg-[#0a0a0a] text-gray-300 hover:bg-[#1a1a1a] hover:border-[#d4af37] hover:text-[#d4af37]'
? 'bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-[#0f0f0f] shadow-lg shadow-[var(--luxury-gold)]/30'
: 'border border-[var(--luxury-gold)]/30 bg-[#0a0a0a] text-gray-300 hover:bg-[#1a1a1a] hover:border-[var(--luxury-gold)] hover:text-[var(--luxury-gold)]'
}`}
aria-label={`Page ${pageNum}`}
aria-current={isActive ? 'page' : undefined}
@@ -125,9 +125,9 @@ const Pagination: React.FC<PaginationProps> = ({
<button
onClick={() => handlePageChange(currentPage + 1)}
disabled={currentPage === totalPages}
className="px-4 py-2 border border-[#d4af37]/30
className="px-4 py-2 border border-[var(--luxury-gold)]/30
rounded-lg bg-[#0a0a0a] text-gray-300
hover:bg-[#1a1a1a] hover:border-[#d4af37] hover:text-[#d4af37]
hover:bg-[#1a1a1a] hover:border-[var(--luxury-gold)] hover:text-[var(--luxury-gold)]
disabled:opacity-50 disabled:cursor-not-allowed
transition-all duration-300 font-medium tracking-wide"
aria-label="Next page"

View File

@@ -71,7 +71,7 @@ const RatingStars: React.FC<RatingStarsProps> = ({
<Star
className={`${sizeClasses[size]} ${
isFilled
? 'text-[#d4af37] fill-[#d4af37]'
? 'text-[var(--luxury-gold)] fill-[var(--luxury-gold)]'
: 'text-gray-500'
}`}
/>

View File

@@ -184,13 +184,13 @@ const ReviewSection: React.FC<ReviewSectionProps> = ({
return (
<div className="space-y-4">
{}
<div className="bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-lg border border-[#d4af37]/20 p-3 sm:p-4 backdrop-blur-xl shadow-lg shadow-[#d4af37]/5">
<div className="bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-lg border border-[var(--luxury-gold)]/20 p-3 sm:p-4 backdrop-blur-xl shadow-lg shadow-[var(--luxury-gold)]/5">
<h3 className="text-sm sm:text-base font-serif font-semibold text-white mb-3 tracking-wide">
Customer Reviews
</h3>
<div className="flex items-center gap-4">
<div className="text-center">
<div className="text-2xl sm:text-3xl font-serif font-bold bg-gradient-to-r from-[#d4af37] to-[#f5d76e] bg-clip-text text-transparent">
<div className="text-2xl sm:text-3xl font-serif font-bold bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-light)] bg-clip-text text-transparent">
{totalReviews > 0 && averageRating > 0
? averageRating.toFixed(1)
: totalReviews === 0
@@ -214,7 +214,7 @@ const ReviewSection: React.FC<ReviewSectionProps> = ({
{}
{isAuthenticated ? (
<div className="bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-lg border border-[#d4af37]/20 p-3 sm:p-4 backdrop-blur-xl shadow-lg shadow-[#d4af37]/5">
<div className="bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-lg border border-[var(--luxury-gold)]/20 p-3 sm:p-4 backdrop-blur-xl shadow-lg shadow-[var(--luxury-gold)]/5">
<h4 className="text-xs sm:text-sm font-serif font-semibold text-white mb-3 tracking-wide">
Write Your Review
</h4>
@@ -263,9 +263,9 @@ const ReviewSection: React.FC<ReviewSectionProps> = ({
id="comment"
rows={3}
className="w-full px-2.5 py-1.5 bg-[#0a0a0a] border
border-[#d4af37]/20 rounded-lg text-white placeholder-gray-500 text-xs sm:text-sm
focus:ring-2 focus:ring-[#d4af37]/50
focus:border-[#d4af37] transition-all duration-300
border-[var(--luxury-gold)]/20 rounded-lg text-white placeholder-gray-500 text-xs sm:text-sm
focus:ring-2 focus:ring-[var(--luxury-gold)]/50
focus:border-[var(--luxury-gold)] transition-all duration-300
font-light tracking-wide resize-none"
placeholder="Share your experience..."
/>
@@ -292,27 +292,27 @@ const ReviewSection: React.FC<ReviewSectionProps> = ({
<button
type="submit"
disabled={submitting}
className="px-4 py-2 bg-gradient-to-r from-[#d4af37] to-[#c9a227]
text-[#0f0f0f] rounded-sm hover:from-[#f5d76e] hover:to-[#d4af37]
className="px-4 py-2 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]
text-[#0f0f0f] rounded-sm hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)]
disabled:bg-gray-800 disabled:text-gray-500
disabled:cursor-not-allowed
transition-all duration-300 font-medium text-xs sm:text-sm
shadow-sm shadow-[#d4af37]/30 tracking-wide"
shadow-sm shadow-[var(--luxury-gold)]/30 tracking-wide"
>
{submitting ? 'Submitting...' : 'Submit Review'}
</button>
</form>
</div>
) : (
<div className="bg-gradient-to-br from-[#d4af37]/10 to-[#c9a227]/5 border border-[#d4af37]/30
<div className="bg-gradient-to-br from-[var(--luxury-gold)]/10 to-[var(--luxury-gold-dark)]/5 border border-[var(--luxury-gold)]/30
rounded-lg p-3 sm:p-4 text-center backdrop-blur-sm"
>
<p className="text-[#d4af37] text-xs sm:text-sm font-light">
<p className="text-[var(--luxury-gold)] text-xs sm:text-sm font-light">
Please{' '}
<button
onClick={() => openModal('login')}
className="font-semibold underline
hover:text-[#f5d76e] transition-colors"
hover:text-[var(--luxury-gold-light)] transition-colors"
>
login
</button>{' '}
@@ -332,7 +332,7 @@ const ReviewSection: React.FC<ReviewSectionProps> = ({
{Array.from({ length: 3 }).map((_, index) => (
<div
key={index}
className="bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-lg border border-[#d4af37]/20 p-3
className="bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-lg border border-[var(--luxury-gold)]/20 p-3
animate-pulse"
>
<div className="h-3 bg-gray-700
@@ -345,7 +345,7 @@ const ReviewSection: React.FC<ReviewSectionProps> = ({
))}
</div>
) : reviews.length === 0 ? (
<div className="text-center py-6 sm:py-8 bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-lg border border-[#d4af37]/20 p-4"
<div className="text-center py-6 sm:py-8 bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-lg border border-[var(--luxury-gold)]/20 p-4"
>
<p className="text-gray-300 text-sm sm:text-base font-light">
No reviews yet
@@ -359,8 +359,8 @@ const ReviewSection: React.FC<ReviewSectionProps> = ({
{reviews.map((review) => (
<div
key={review.id}
className="bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-lg border border-[#d4af37]/20
p-3 sm:p-4 backdrop-blur-xl shadow-sm shadow-[#d4af37]/5"
className="bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-lg border border-[var(--luxury-gold)]/20
p-3 sm:p-4 backdrop-blur-xl shadow-sm shadow-[var(--luxury-gold)]/5"
>
<div className="flex items-start
justify-between mb-2"

View File

@@ -75,8 +75,8 @@ const RoomCard: React.FC<RoomCardProps> = ({ room, compact = false }) => {
className={`luxury-card overflow-hidden group h-full flex flex-col
border-t-2 transition-all duration-300
${room.featured
? 'border-[#d4af37] shadow-lg shadow-[#d4af37]/20 hover:border-[#d4af37] hover:shadow-luxury-gold'
: 'border-transparent hover:border-[#d4af37] hover:shadow-luxury-gold'
? 'border-[var(--luxury-gold)] shadow-lg shadow-[var(--luxury-gold)]/20 hover:border-[var(--luxury-gold)] hover:shadow-luxury-gold'
: 'border-transparent hover:border-[var(--luxury-gold)] hover:shadow-luxury-gold'
}`}
>
{}
@@ -112,10 +112,10 @@ const RoomCard: React.FC<RoomCardProps> = ({ room, compact = false }) => {
{room.featured && (
<div
className="absolute top-3 left-3 z-20
bg-gradient-to-r from-[#d4af37] to-[#c9a227]
bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]
text-[#0f0f0f] px-3 py-1.5
rounded-sm text-xs font-medium tracking-wide
shadow-lg shadow-[#d4af37]/30 backdrop-blur-sm
shadow-lg shadow-[var(--luxury-gold)]/30 backdrop-blur-sm
flex items-center gap-1.5"
>
<Crown className="w-4 h-4 fill-[#0f0f0f] text-[#0f0f0f]" />
@@ -153,7 +153,7 @@ const RoomCard: React.FC<RoomCardProps> = ({ room, compact = false }) => {
{room.featured && (
<Crown
className={`${compact ? 'w-4 h-4' : 'w-5 h-5'}
text-[#d4af37] fill-[#d4af37]
text-[var(--luxury-gold)] fill-[var(--luxury-gold)]
drop-shadow-lg animate-pulse`}
/>
)}
@@ -165,7 +165,7 @@ const RoomCard: React.FC<RoomCardProps> = ({ room, compact = false }) => {
className={`flex items-center text-gray-600 font-light tracking-wide
${compact ? 'text-xs mb-1.5' : 'text-xs sm:text-sm mb-2'}`}
>
<MapPin className={`${compact ? 'w-3 h-3' : 'w-4 h-4'} mr-1.5 text-[#d4af37]`} />
<MapPin className={`${compact ? 'w-3 h-3' : 'w-4 h-4'} mr-1.5 text-[var(--luxury-gold)]`} />
<span>
Room {room.room_number} - Floor {room.floor}
</span>
@@ -182,7 +182,7 @@ const RoomCard: React.FC<RoomCardProps> = ({ room, compact = false }) => {
{}
<div className={`flex items-center justify-between ${compact ? 'mb-1.5' : 'mb-3'}`}>
<div className="flex items-center text-gray-700">
<Users className={`${compact ? 'w-3 h-3' : 'w-4 h-4'} mr-1.5 text-[#d4af37]`} />
<Users className={`${compact ? 'w-3 h-3' : 'w-4 h-4'} mr-1.5 text-[var(--luxury-gold)]`} />
<span className={`font-light tracking-wide ${compact ? 'text-xs' : 'text-sm'}`}>
{room.capacity || roomType.capacity} guests
</span>
@@ -191,7 +191,7 @@ const RoomCard: React.FC<RoomCardProps> = ({ room, compact = false }) => {
{room.average_rating != null && (
<div className="flex items-center">
<Star
className={`${compact ? 'w-3 h-3' : 'w-4 h-4'} text-[#d4af37] mr-1`}
className={`${compact ? 'w-3 h-3' : 'w-4 h-4'} text-[var(--luxury-gold)] mr-1`}
fill="#d4af37"
/>
<span className={`font-semibold text-gray-900 ${compact ? 'text-xs' : 'text-sm'}`}>
@@ -213,13 +213,13 @@ const RoomCard: React.FC<RoomCardProps> = ({ room, compact = false }) => {
<div
key={index}
className="flex items-center gap-1
text-gray-700 text-xs bg-[#d4af37]/10
border border-[#d4af37]/20
text-gray-700 text-xs bg-[var(--luxury-gold)]/10
border border-[var(--luxury-gold)]/20
px-2 sm:px-2.5 py-1 sm:py-1.5 rounded-sm
font-light tracking-wide"
title={amenity}
>
<span className="text-[#d4af37]">
<span className="text-[var(--luxury-gold)]">
{amenityIcons[amenity.toLowerCase()] ||
<span></span>}
</span>

View File

@@ -4,8 +4,8 @@ const RoomCardSkeleton: React.FC = () => {
return (
<div
className="bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a]
rounded-xl border border-[#d4af37]/20
overflow-hidden animate-pulse shadow-lg shadow-[#d4af37]/5"
rounded-xl border border-[var(--luxury-gold)]/20
overflow-hidden animate-pulse shadow-lg shadow-[var(--luxury-gold)]/5"
>
{}
<div className="h-40 sm:h-44 md:h-48 lg:h-52 bg-gradient-to-br from-gray-800 to-gray-900" />
@@ -40,7 +40,7 @@ const RoomCardSkeleton: React.FC = () => {
{}
<div
className="flex items-center justify-between
pt-3 border-t border-[#d4af37]/20"
pt-3 border-t border-[var(--luxury-gold)]/20"
>
<div>
<div className="h-3 bg-gray-800 rounded w-12 mb-1" />

View File

@@ -150,11 +150,11 @@ const RoomCarousel: React.FC<RoomCarouselProps> = ({
disabled={isAnimating || currentIndex === 0}
className="absolute left-0 top-1/2 -translate-y-1/2 -translate-x-2 sm:-translate-x-4
z-10 w-8 h-8 sm:w-9 sm:h-9
bg-gradient-to-r from-[#d4af37] to-[#c9a227]
bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]
text-white rounded-full
flex items-center justify-center
shadow-lg shadow-[#d4af37]/40
hover:shadow-xl hover:shadow-[#d4af37]/50
shadow-lg shadow-[var(--luxury-gold)]/40
hover:shadow-xl hover:shadow-[var(--luxury-gold)]/50
hover:scale-110
active:scale-95
transition-all duration-300
@@ -170,11 +170,11 @@ const RoomCarousel: React.FC<RoomCarouselProps> = ({
disabled={isAnimating || currentIndex >= rooms.length - 1}
className="absolute right-0 top-1/2 -translate-y-1/2 translate-x-2 sm:translate-x-4
z-10 w-8 h-8 sm:w-9 sm:h-9
bg-gradient-to-r from-[#d4af37] to-[#c9a227]
bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]
text-white rounded-full
flex items-center justify-center
shadow-lg shadow-[#d4af37]/40
hover:shadow-xl hover:shadow-[#d4af37]/50
shadow-lg shadow-[var(--luxury-gold)]/40
hover:shadow-xl hover:shadow-[var(--luxury-gold)]/50
hover:scale-110
active:scale-95
transition-all duration-300
@@ -198,8 +198,8 @@ const RoomCarousel: React.FC<RoomCarouselProps> = ({
className={`transition-all duration-300 rounded-full
${
index === currentIndex
? 'w-6 h-1.5 sm:w-7 sm:h-2 bg-gradient-to-r from-[#d4af37] to-[#c9a227] shadow-lg shadow-[#d4af37]/40'
: 'w-1.5 h-1.5 sm:w-2 sm:h-2 bg-gray-300 hover:bg-[#d4af37]/50'
? 'w-6 h-1.5 sm:w-7 sm:h-2 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] shadow-lg shadow-[var(--luxury-gold)]/40'
: 'w-1.5 h-1.5 sm:w-2 sm:h-2 bg-gray-300 hover:bg-[var(--luxury-gold)]/50'
}
disabled:cursor-not-allowed
`}

View File

@@ -250,14 +250,14 @@ const RoomFilter: React.FC<RoomFilterProps> = ({ onFilterChange }) => {
return (
<div className="bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a]
rounded-xl border border-[#d4af37]/30
backdrop-blur-xl shadow-2xl shadow-[#d4af37]/10
rounded-xl border border-[var(--luxury-gold)]/30
backdrop-blur-xl shadow-2xl shadow-[var(--luxury-gold)]/10
p-4 sm:p-5 md:p-6"
>
<div className="flex items-center gap-2 sm:gap-3 mb-4 sm:mb-5 md:mb-6">
<div className="p-1.5 sm:p-2 bg-[#d4af37]/10 rounded-lg
border border-[#d4af37]/30">
<svg className="w-4 h-4 sm:w-5 sm:h-5 text-[#d4af37]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<div className="p-1.5 sm:p-2 bg-[var(--luxury-gold)]/10 rounded-lg
border border-[var(--luxury-gold)]/30">
<svg className="w-4 h-4 sm:w-5 sm:h-5 text-[var(--luxury-gold)]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z" />
</svg>
</div>
@@ -282,12 +282,12 @@ const RoomFilter: React.FC<RoomFilterProps> = ({ onFilterChange }) => {
value={filters.type || ''}
onChange={handleInputChange}
className="w-full px-4 py-3.5 bg-[#1a1a1a] border-2
border-[#d4af37]/30 rounded-lg text-white text-base
border-[var(--luxury-gold)]/30 rounded-lg text-white text-base
placeholder-gray-400 focus:ring-2
focus:ring-[#d4af37]/60 focus:border-[#d4af37]
focus:ring-[var(--luxury-gold)]/60 focus:border-[var(--luxury-gold)]
transition-all duration-300 font-normal tracking-wide
appearance-none cursor-pointer
hover:border-[#d4af37]/50"
hover:border-[var(--luxury-gold)]/50"
>
<option value="" className="bg-[#1a1a1a] text-white">All Room Types</option>
<option value="Standard Room" className="bg-[#1a1a1a] text-white">Standard Room</option>
@@ -297,7 +297,7 @@ const RoomFilter: React.FC<RoomFilterProps> = ({ onFilterChange }) => {
<option value="Twin Room" className="bg-[#1a1a1a] text-white">Twin Room</option>
</select>
<div className="absolute right-3 top-1/2 -translate-y-1/2 pointer-events-none">
<svg className="w-5 h-5 text-[#d4af37]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<svg className="w-5 h-5 text-[var(--luxury-gold)]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</div>
@@ -311,7 +311,7 @@ const RoomFilter: React.FC<RoomFilterProps> = ({ onFilterChange }) => {
htmlFor="from"
className="block text-sm font-medium text-gray-200 mb-2 tracking-wide flex items-center gap-2"
>
<Calendar className="w-4 h-4 text-[#d4af37]" />
<Calendar className="w-4 h-4 text-[var(--luxury-gold)]" />
Check-in Date
</label>
<div className="relative">
@@ -331,11 +331,11 @@ const RoomFilter: React.FC<RoomFilterProps> = ({ onFilterChange }) => {
dateFormat="dd/MM/yyyy"
placeholderText="Select check-in"
className="w-full px-4 py-3.5 pl-11 bg-[#1a1a1a] border-2
border-[#d4af37]/30 rounded-lg text-white text-base
border-[var(--luxury-gold)]/30 rounded-lg text-white text-base
placeholder-gray-400 focus:ring-2
focus:ring-[#d4af37]/60 focus:border-[#d4af37]
focus:ring-[var(--luxury-gold)]/60 focus:border-[var(--luxury-gold)]
transition-all duration-300 font-normal tracking-wide
hover:border-[#d4af37]/50"
hover:border-[var(--luxury-gold)]/50"
wrapperClassName="w-full"
/>
{checkInDate && (
@@ -349,13 +349,13 @@ const RoomFilter: React.FC<RoomFilterProps> = ({ onFilterChange }) => {
}
}}
className="absolute right-3 top-1/2 -translate-y-1/2
text-gray-400 hover:text-[#d4af37] transition-colors"
text-gray-400 hover:text-[var(--luxury-gold)] transition-colors"
>
<X className="w-4 h-4" />
</button>
)}
<Calendar className="absolute left-3 top-1/2 -translate-y-1/2
w-5 h-5 text-[#d4af37] pointer-events-none" />
w-5 h-5 text-[var(--luxury-gold)] pointer-events-none" />
</div>
</div>
@@ -364,7 +364,7 @@ const RoomFilter: React.FC<RoomFilterProps> = ({ onFilterChange }) => {
htmlFor="to"
className="block text-sm font-medium text-gray-200 mb-2 tracking-wide flex items-center gap-2"
>
<Calendar className="w-4 h-4 text-[#d4af37]" />
<Calendar className="w-4 h-4 text-[var(--luxury-gold)]" />
Check-out Date
</label>
<div className="relative">
@@ -383,11 +383,11 @@ const RoomFilter: React.FC<RoomFilterProps> = ({ onFilterChange }) => {
dateFormat="dd/MM/yyyy"
placeholderText={checkInDate ? "Select check-out" : "Select check-in first"}
className="w-full px-4 py-3.5 pl-11 bg-[#1a1a1a] border-2
border-[#d4af37]/30 rounded-lg text-white text-base
border-[var(--luxury-gold)]/30 rounded-lg text-white text-base
placeholder-gray-400 focus:ring-2
focus:ring-[#d4af37]/60 focus:border-[#d4af37]
focus:ring-[var(--luxury-gold)]/60 focus:border-[var(--luxury-gold)]
transition-all duration-300 font-normal tracking-wide
hover:border-[#d4af37]/50
hover:border-[var(--luxury-gold)]/50
disabled:opacity-50 disabled:cursor-not-allowed"
wrapperClassName="w-full"
/>
@@ -399,13 +399,13 @@ const RoomFilter: React.FC<RoomFilterProps> = ({ onFilterChange }) => {
setCheckOutDate(null);
}}
className="absolute right-3 top-1/2 -translate-y-1/2
text-gray-400 hover:text-[#d4af37] transition-colors"
text-gray-400 hover:text-[var(--luxury-gold)] transition-colors"
>
<X className="w-4 h-4" />
</button>
)}
<Calendar className="absolute left-3 top-1/2 -translate-y-1/2
w-5 h-5 text-[#d4af37] pointer-events-none" />
w-5 h-5 text-[var(--luxury-gold)] pointer-events-none" />
</div>
{checkInDate && !checkOutDate && (
<p className="mt-1.5 text-xs text-gray-400 font-light">
@@ -418,7 +418,7 @@ const RoomFilter: React.FC<RoomFilterProps> = ({ onFilterChange }) => {
{}
<div>
<label className="block text-sm font-medium text-gray-200 mb-3 tracking-wide flex items-center gap-2">
<DollarSign className="w-4 h-4 text-[#d4af37]" />
<DollarSign className="w-4 h-4 text-[var(--luxury-gold)]" />
Price Range
</label>
<div className="grid grid-cols-2 gap-4">
@@ -432,7 +432,7 @@ const RoomFilter: React.FC<RoomFilterProps> = ({ onFilterChange }) => {
</label>
<div className="relative">
<DollarSign className="absolute left-3 top-1/2 -translate-y-1/2
w-4 h-4 text-[#d4af37] pointer-events-none" />
w-4 h-4 text-[var(--luxury-gold)] pointer-events-none" />
<input
type="text"
id="minPrice"
@@ -447,11 +447,11 @@ const RoomFilter: React.FC<RoomFilterProps> = ({ onFilterChange }) => {
inputMode="numeric"
pattern="[0-9.]*"
className="w-full px-4 py-3.5 pl-10 bg-[#1a1a1a] border-2
border-[#d4af37]/30 rounded-lg text-white text-base
border-[var(--luxury-gold)]/30 rounded-lg text-white text-base
placeholder-gray-400 focus:ring-2
focus:ring-[#d4af37]/60 focus:border-[#d4af37]
focus:ring-[var(--luxury-gold)]/60 focus:border-[var(--luxury-gold)]
transition-all duration-300 font-normal tracking-wide
hover:border-[#d4af37]/50"
hover:border-[var(--luxury-gold)]/50"
/>
</div>
</div>
@@ -465,7 +465,7 @@ const RoomFilter: React.FC<RoomFilterProps> = ({ onFilterChange }) => {
</label>
<div className="relative">
<DollarSign className="absolute left-3 top-1/2 -translate-y-1/2
w-4 h-4 text-[#d4af37] pointer-events-none" />
w-4 h-4 text-[var(--luxury-gold)] pointer-events-none" />
<input
type="text"
id="maxPrice"
@@ -480,11 +480,11 @@ const RoomFilter: React.FC<RoomFilterProps> = ({ onFilterChange }) => {
inputMode="numeric"
pattern="[0-9.]*"
className="w-full px-4 py-3.5 pl-10 bg-[#1a1a1a] border-2
border-[#d4af37]/30 rounded-lg text-white text-base
border-[var(--luxury-gold)]/30 rounded-lg text-white text-base
placeholder-gray-400 focus:ring-2
focus:ring-[#d4af37]/60 focus:border-[#d4af37]
focus:ring-[var(--luxury-gold)]/60 focus:border-[var(--luxury-gold)]
transition-all duration-300 font-normal tracking-wide
hover:border-[#d4af37]/50"
hover:border-[var(--luxury-gold)]/50"
/>
</div>
</div>
@@ -498,12 +498,12 @@ const RoomFilter: React.FC<RoomFilterProps> = ({ onFilterChange }) => {
className="block text-sm font-medium
text-gray-200 mb-2 tracking-wide flex items-center gap-2"
>
<Users className="w-4 h-4 text-[#d4af37]" />
<Users className="w-4 h-4 text-[var(--luxury-gold)]" />
Number of Guests
</label>
<div className="relative">
<Users className="absolute left-3 top-1/2 -translate-y-1/2
w-5 h-5 text-[#d4af37] pointer-events-none" />
w-5 h-5 text-[var(--luxury-gold)] pointer-events-none" />
<input
type="number"
id="capacity"
@@ -514,11 +514,11 @@ const RoomFilter: React.FC<RoomFilterProps> = ({ onFilterChange }) => {
min="1"
max="10"
className="w-full px-4 py-3.5 pl-11 bg-[#1a1a1a] border-2
border-[#d4af37]/30 rounded-lg text-white text-base
border-[var(--luxury-gold)]/30 rounded-lg text-white text-base
placeholder-gray-400 focus:ring-2
focus:ring-[#d4af37]/60 focus:border-[#d4af37]
focus:ring-[var(--luxury-gold)]/60 focus:border-[var(--luxury-gold)]
transition-all duration-300 font-normal tracking-wide
hover:border-[#d4af37]/50
hover:border-[var(--luxury-gold)]/50
[appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none
[&::-webkit-inner-spin-button]:appearance-none"
/>
@@ -532,29 +532,29 @@ const RoomFilter: React.FC<RoomFilterProps> = ({ onFilterChange }) => {
</label>
{availableAmenities.length === 0 ? (
<div className="text-sm text-gray-400 font-light bg-[#1a1a1a]/50
border border-[#d4af37]/20 rounded-lg px-4 py-3">
border border-[var(--luxury-gold)]/20 rounded-lg px-4 py-3">
Loading amenities...
</div>
) : (
<div className="bg-[#1a1a1a]/50 border border-[#d4af37]/20 rounded-lg p-3
<div className="bg-[#1a1a1a]/50 border border-[var(--luxury-gold)]/20 rounded-lg p-3
max-h-48 overflow-y-auto custom-scrollbar space-y-2">
{availableAmenities.map((amenity) => (
<label
key={amenity}
className="flex items-center gap-3 text-sm w-full font-normal tracking-wide
hover:text-[#d4af37] transition-colors cursor-pointer
hover:text-[var(--luxury-gold)] transition-colors cursor-pointer
text-gray-200 group"
>
<input
type="checkbox"
checked={selectedAmenities.includes(amenity)}
onChange={() => toggleAmenity(amenity)}
className="h-5 w-5 accent-[#d4af37] cursor-pointer
border-2 border-[#d4af37]/30 rounded
checked:bg-[#d4af37] checked:border-[#d4af37]
group-hover:border-[#d4af37] transition-all"
className="h-5 w-5 accent-[var(--luxury-gold)] cursor-pointer
border-2 border-[var(--luxury-gold)]/30 rounded
checked:bg-[var(--luxury-gold)] checked:border-[var(--luxury-gold)]
group-hover:border-[var(--luxury-gold)] transition-all"
/>
<span className="flex-1 group-hover:text-[#d4af37] transition-colors">
<span className="flex-1 group-hover:text-[var(--luxury-gold)] transition-colors">
{amenity}
</span>
</label>
@@ -562,7 +562,7 @@ const RoomFilter: React.FC<RoomFilterProps> = ({ onFilterChange }) => {
</div>
)}
{selectedAmenities.length > 0 && (
<p className="mt-2 text-xs text-[#d4af37] font-light">
<p className="mt-2 text-xs text-[var(--luxury-gold)] font-light">
{selectedAmenities.length} amenit{selectedAmenities.length === 1 ? 'y' : 'ies'} selected
</p>
)}
@@ -572,10 +572,10 @@ const RoomFilter: React.FC<RoomFilterProps> = ({ onFilterChange }) => {
<div className="flex flex-col sm:flex-row gap-2 sm:gap-3 pt-2">
<button
type="submit"
className="flex-1 bg-gradient-to-r from-[#d4af37] to-[#c9a227]
className="flex-1 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]
text-[#0f0f0f] py-2.5 sm:py-3 px-4 rounded-sm font-medium tracking-wide text-sm sm:text-base
hover:from-[#f5d76e] hover:to-[#d4af37] active:scale-95
transition-all duration-300 shadow-lg shadow-[#d4af37]/30
hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] active:scale-95
transition-all duration-300 shadow-lg shadow-[var(--luxury-gold)]/30
relative overflow-hidden group touch-manipulation min-h-[44px]"
>
<span className="relative z-10">Apply</span>
@@ -585,8 +585,8 @@ const RoomFilter: React.FC<RoomFilterProps> = ({ onFilterChange }) => {
type="button"
onClick={handleReset}
className="flex-1 bg-[#0a0a0a] backdrop-blur-sm text-gray-300
py-2.5 sm:py-3 px-4 rounded-sm border border-[#d4af37]/30
hover:bg-[#1a1a1a] hover:border-[#d4af37] hover:text-[#d4af37] active:scale-95
py-2.5 sm:py-3 px-4 rounded-sm border border-[var(--luxury-gold)]/30
hover:bg-[#1a1a1a] hover:border-[var(--luxury-gold)] hover:text-[var(--luxury-gold)] active:scale-95
transition-all font-medium tracking-wide text-sm sm:text-base
touch-manipulation min-h-[44px]"
>

View File

@@ -103,15 +103,15 @@ const SearchRoomForm: React.FC<SearchRoomFormProps> = ({
const isOverlay = className.includes('overlay');
return (
<div className={`w-full ${isOverlay ? 'bg-transparent shadow-none border-none p-0' : 'luxury-glass rounded-sm shadow-2xl p-6 border border-[#d4af37]/20'} ${className}`}>
<div className={`w-full ${isOverlay ? 'bg-transparent shadow-none border-none p-0' : 'luxury-glass rounded-sm shadow-2xl p-6 border border-[var(--luxury-gold)]/20'} ${className}`}>
{}
{(!isOverlay || !isMobile) && (
<div className={`flex items-center justify-center gap-1.5 sm:gap-2 md:gap-3 ${isOverlay ? 'mb-1 sm:mb-2 md:mb-3 lg:mb-4 xl:mb-6' : 'mb-6'}`}>
<div className={`${isOverlay ? 'w-0.5 sm:w-0.5 md:w-1' : 'w-1'} ${isOverlay ? 'h-3 sm:h-4 md:h-6 lg:h-8' : 'h-8'} bg-gradient-to-b from-[#d4af37] to-[#c9a227]`}></div>
<div className={`${isOverlay ? 'w-0.5 sm:w-0.5 md:w-1' : 'w-1'} ${isOverlay ? 'h-3 sm:h-4 md:h-6 lg:h-8' : 'h-8'} bg-gradient-to-b from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]`}></div>
<h3 className={`${isOverlay ? 'text-xs sm:text-sm md:text-base lg:text-lg xl:text-xl' : 'text-2xl'} font-serif font-semibold text-gray-900 tracking-tight`}>
{isOverlay && isMobile ? 'Find Rooms' : 'Find Available Rooms'}
</h3>
<div className={`${isOverlay ? 'w-0.5 sm:w-0.5 md:w-1' : 'w-1'} ${isOverlay ? 'h-3 sm:h-4 md:h-6 lg:h-8' : 'h-8'} bg-gradient-to-b from-[#d4af37] to-[#c9a227]`}></div>
<div className={`${isOverlay ? 'w-0.5 sm:w-0.5 md:w-1' : 'w-1'} ${isOverlay ? 'h-3 sm:h-4 md:h-6 lg:h-8' : 'h-8'} bg-gradient-to-b from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]`}></div>
</div>
)}

View File

@@ -212,6 +212,26 @@ export interface UpdateRecaptchaSettingsRequest {
recaptcha_enabled?: boolean;
}
export interface ThemeSettingsResponse {
status: string;
data: {
theme_primary_color: string;
theme_primary_light: string;
theme_primary_dark: string;
theme_primary_accent: string;
updated_at?: string | null;
updated_by?: string | null;
};
message?: string;
}
export interface UpdateThemeSettingsRequest {
theme_primary_color?: string;
theme_primary_light?: string;
theme_primary_dark?: string;
theme_primary_accent?: string;
}
export interface VerifyRecaptchaRequest {
token: string;
}
@@ -438,6 +458,25 @@ const recaptchaService = {
},
};
export default systemSettingsService;
export { recaptchaService };
const themeService = {
getThemeSettings: async (): Promise<ThemeSettingsResponse> => {
const response = await apiClient.get<ThemeSettingsResponse>(
'/api/admin/system-settings/theme'
);
return response.data;
},
updateThemeSettings: async (
settings: UpdateThemeSettingsRequest
): Promise<ThemeSettingsResponse> => {
const response = await apiClient.put<ThemeSettingsResponse>(
'/api/admin/system-settings/theme',
settings
);
return response.data;
},
};
export default systemSettingsService;
export { recaptchaService, themeService };

View File

@@ -42,14 +42,14 @@ const HousekeepingLayout: React.FC = () => {
return (
<div className="min-h-screen bg-gradient-to-br from-gray-50 via-white to-gray-50 overflow-x-hidden">
{/* Luxury Top Navigation Bar */}
<header className="sticky top-0 z-50 bg-white/95 backdrop-blur-xl border-b border-[#d4af37]/20 shadow-sm">
<header className="sticky top-0 z-50 bg-white/95 backdrop-blur-xl border-b border-[var(--luxury-gold)]/20 shadow-sm">
<div className="w-full max-w-7xl mx-auto px-3 sm:px-4 md:px-6 lg:px-8">
<div className="flex items-center justify-between h-14 sm:h-16">
{/* Logo/Brand */}
<div className="flex items-center space-x-2 sm:space-x-3 min-w-0 flex-shrink-0">
<div className="relative flex-shrink-0">
<div className="absolute inset-0 bg-gradient-to-r from-[#d4af37] to-[#c9a227] rounded-lg blur-sm opacity-50"></div>
<div className="relative bg-gradient-to-r from-[#d4af37] to-[#c9a227] p-1.5 sm:p-2 rounded-lg">
<div className="absolute inset-0 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] rounded-lg blur-sm opacity-50"></div>
<div className="relative bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] p-1.5 sm:p-2 rounded-lg">
<Sparkles className="w-4 h-4 sm:w-5 sm:h-5 md:w-6 md:h-6 text-white" />
</div>
</div>
@@ -70,7 +70,7 @@ const HousekeepingLayout: React.FC = () => {
to={item.path}
className={`flex items-center space-x-1 sm:space-x-2 px-2 sm:px-3 py-1.5 sm:py-2 rounded-lg text-xs sm:text-sm font-medium transition-all duration-200 ${
isActive(item.path)
? 'bg-gradient-to-r from-[#d4af37]/10 to-[#c9a227]/10 text-[#d4af37] border border-[#d4af37]/30'
? 'bg-gradient-to-r from-[var(--luxury-gold)]/10 to-[var(--luxury-gold-dark)]/10 text-[var(--luxury-gold)] border border-[var(--luxury-gold)]/30'
: 'text-gray-600 hover:text-gray-900 hover:bg-gray-100'
}`}
>
@@ -87,7 +87,7 @@ const HousekeepingLayout: React.FC = () => {
<InAppNotificationBell />
<div className="hidden lg:flex items-center space-x-2 px-3 py-1.5 rounded-lg bg-gradient-to-r from-gray-50 to-gray-100/50 border border-gray-200/50">
<div className="w-7 h-7 rounded-full bg-gradient-to-br from-[#d4af37] to-[#c9a227] flex items-center justify-center flex-shrink-0">
<div className="w-7 h-7 rounded-full bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] flex items-center justify-center flex-shrink-0">
<User className="w-3.5 h-3.5 text-white" />
</div>
<div className="text-left min-w-0">

View File

@@ -417,7 +417,7 @@ const ProfilePage: React.FC = () => {
{}
<div className="mb-6 sm:mb-8 animate-fade-in">
<div className="flex items-center gap-2 sm:gap-3 mb-2 sm:mb-3">
<div className="h-1 w-12 sm:w-16 md:w-20 bg-gradient-to-r from-[#d4af37] via-amber-400 to-[#d4af37] rounded-full"></div>
<div className="h-1 w-12 sm:w-16 md:w-20 bg-gradient-to-r from-[var(--luxury-gold)] via-amber-400 to-[var(--luxury-gold)] rounded-full"></div>
<h1 className="text-2xl sm:text-3xl lg:text-4xl font-serif font-bold bg-gradient-to-r from-gray-900 via-amber-900/90 to-gray-900 bg-clip-text text-transparent tracking-tight">
Accountant Profile & Settings
</h1>
@@ -428,61 +428,61 @@ const ProfilePage: React.FC = () => {
</div>
{}
<div className="mb-4 sm:mb-6 border-b border-[#d4af37]/20 overflow-x-auto bg-white/50 backdrop-blur-sm rounded-t-lg sm:rounded-t-xl px-4 sm:px-6">
<div className="mb-4 sm:mb-6 border-b border-[var(--luxury-gold)]/20 overflow-x-auto bg-white/50 backdrop-blur-sm rounded-t-lg sm:rounded-t-xl px-4 sm:px-6">
<div className="flex space-x-4 sm:space-x-8 min-w-max">
<button
onClick={() => setActiveTab('profile')}
className={`py-3 sm:py-4 px-2 sm:px-1 border-b-2 font-semibold text-xs sm:text-sm transition-all duration-300 whitespace-nowrap ${
activeTab === 'profile'
? 'border-[#d4af37] text-[#d4af37] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[#d4af37] hover:border-[#d4af37]/30'
? 'border-[var(--luxury-gold)] text-[var(--luxury-gold)] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[var(--luxury-gold)] hover:border-[var(--luxury-gold)]/30'
}`}
>
<User className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'profile' ? 'text-[#d4af37]' : ''}`} />
<User className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'profile' ? 'text-[var(--luxury-gold)]' : ''}`} />
Profile Information
</button>
<button
onClick={() => setActiveTab('password')}
className={`py-3 sm:py-4 px-2 sm:px-1 border-b-2 font-semibold text-xs sm:text-sm transition-all duration-300 whitespace-nowrap ${
activeTab === 'password'
? 'border-[#d4af37] text-[#d4af37] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[#d4af37] hover:border-[#d4af37]/30'
? 'border-[var(--luxury-gold)] text-[var(--luxury-gold)] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[var(--luxury-gold)] hover:border-[var(--luxury-gold)]/30'
}`}
>
<KeyRound className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'password' ? 'text-[#d4af37]' : ''}`} />
<KeyRound className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'password' ? 'text-[var(--luxury-gold)]' : ''}`} />
Change Password
</button>
<button
onClick={() => setActiveTab('mfa')}
className={`py-3 sm:py-4 px-2 sm:px-1 border-b-2 font-semibold text-xs sm:text-sm transition-all duration-300 whitespace-nowrap ${
activeTab === 'mfa'
? 'border-[#d4af37] text-[#d4af37] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[#d4af37] hover:border-[#d4af37]/30'
? 'border-[var(--luxury-gold)] text-[var(--luxury-gold)] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[var(--luxury-gold)] hover:border-[var(--luxury-gold)]/30'
}`}
>
<Shield className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'mfa' ? 'text-[#d4af37]' : ''}`} />
<Shield className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'mfa' ? 'text-[var(--luxury-gold)]' : ''}`} />
Two-Factor Authentication
</button>
<button
onClick={() => setActiveTab('sessions')}
className={`py-3 sm:py-4 px-2 sm:px-1 border-b-2 font-semibold text-xs sm:text-sm transition-all duration-300 whitespace-nowrap ${
activeTab === 'sessions'
? 'border-[#d4af37] text-[#d4af37] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[#d4af37] hover:border-[#d4af37]/30'
? 'border-[var(--luxury-gold)] text-[var(--luxury-gold)] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[var(--luxury-gold)] hover:border-[var(--luxury-gold)]/30'
}`}
>
<Monitor className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'sessions' ? 'text-[#d4af37]' : ''}`} />
<Monitor className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'sessions' ? 'text-[var(--luxury-gold)]' : ''}`} />
Active Sessions
</button>
<button
onClick={() => setActiveTab('gdpr')}
className={`py-3 sm:py-4 px-2 sm:px-1 border-b-2 font-semibold text-xs sm:text-sm transition-all duration-300 whitespace-nowrap ${
activeTab === 'gdpr'
? 'border-[#d4af37] text-[#d4af37] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[#d4af37] hover:border-[#d4af37]/30'
? 'border-[var(--luxury-gold)] text-[var(--luxury-gold)] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[var(--luxury-gold)] hover:border-[var(--luxury-gold)]/30'
}`}
>
<Database className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'gdpr' ? 'text-[#d4af37]' : ''}`} />
<Database className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'gdpr' ? 'text-[var(--luxury-gold)]' : ''}`} />
Data Privacy
</button>
</div>
@@ -490,7 +490,7 @@ const ProfilePage: React.FC = () => {
{}
{activeTab === 'profile' && (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl animate-slide-up">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl animate-slide-up">
<form onSubmit={handleSubmitProfile(onSubmitProfile)} className="space-y-5 sm:space-y-6">
{}
<div className="flex flex-col sm:flex-row items-center sm:items-start gap-4 sm:gap-6 pb-5 sm:pb-6 border-b border-gray-200">
@@ -499,20 +499,20 @@ const ProfilePage: React.FC = () => {
<img
src={avatarPreview || normalizeImageUrl(userInfo?.avatar)}
alt="Profile"
className="w-20 h-20 sm:w-24 sm:h-24 rounded-full object-cover ring-4 ring-[#d4af37]/20 shadow-lg"
className="w-20 h-20 sm:w-24 sm:h-24 rounded-full object-cover ring-4 ring-[var(--luxury-gold)]/20 shadow-lg"
onError={() => {
// If image fails to load, show default avatar
setAvatarError(true);
}}
/>
) : (
<div className="w-20 h-20 sm:w-24 sm:h-24 rounded-full bg-gradient-to-br from-[#d4af37] to-[#c9a227] flex items-center justify-center ring-4 ring-[#d4af37]/20 shadow-lg">
<div className="w-20 h-20 sm:w-24 sm:h-24 rounded-full bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] flex items-center justify-center ring-4 ring-[var(--luxury-gold)]/20 shadow-lg">
<User className="w-10 h-10 sm:w-12 sm:h-12 text-white" />
</div>
)}
<label
htmlFor="avatar-upload"
className="absolute bottom-0 right-0 p-2 bg-gradient-to-br from-[#d4af37] to-[#c9a227] rounded-full cursor-pointer hover:from-[#f5d76e] hover:to-[#d4af37] transition-all duration-300 shadow-lg hover:shadow-xl hover:shadow-[#d4af37]/40 hover:-translate-y-0.5 active:translate-y-0"
className="absolute bottom-0 right-0 p-2 bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] rounded-full cursor-pointer hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] transition-all duration-300 shadow-lg hover:shadow-xl hover:shadow-[var(--luxury-gold)]/40 hover:-translate-y-0.5 active:translate-y-0"
>
<Camera className="w-3.5 h-3.5 sm:w-4 sm:h-4 text-white" />
<input
@@ -528,7 +528,7 @@ const ProfilePage: React.FC = () => {
<div>
<label className="block text-sm sm:text-base font-medium text-gray-700 mb-2">
<User className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[#d4af37]" />
<User className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[var(--luxury-gold)]" />
Full Name
<span className="text-red-500 ml-1">*</span>
</label>
@@ -551,7 +551,7 @@ const ProfilePage: React.FC = () => {
{}
<div>
<label className="block text-sm sm:text-base font-medium text-gray-700 mb-2">
<Mail className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[#d4af37]" />
<Mail className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[var(--luxury-gold)]" />
Email Address
<span className="text-red-500 ml-1">*</span>
</label>
@@ -574,7 +574,7 @@ const ProfilePage: React.FC = () => {
{}
<div>
<label className="block text-sm sm:text-base font-medium text-gray-700 mb-2">
<Phone className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[#d4af37]" />
<Phone className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[var(--luxury-gold)]" />
Phone Number
<span className="text-red-500 ml-1">*</span>
</label>
@@ -611,7 +611,7 @@ const ProfilePage: React.FC = () => {
{}
{activeTab === 'password' && (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl animate-slide-up">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl animate-slide-up">
<form onSubmit={handleSubmitPassword(onSubmitPassword)} className="space-y-5 sm:space-y-6">
{}
<div className="bg-gradient-to-r from-blue-50 to-indigo-50 border border-blue-200/60 rounded-sm p-4 sm:p-5">
@@ -640,7 +640,7 @@ const ProfilePage: React.FC = () => {
{}
<div>
<label className="block text-sm sm:text-base font-medium text-gray-700 mb-2">
<Lock className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[#d4af37]" />
<Lock className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[var(--luxury-gold)]" />
Current Password
<span className="text-red-500 ml-1">*</span>
</label>
@@ -656,7 +656,7 @@ const ProfilePage: React.FC = () => {
<button
type="button"
onClick={() => setShowPassword({ ...showPassword, current: !showPassword.current })}
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[#d4af37] transition-colors"
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[var(--luxury-gold)] transition-colors"
>
{showPassword.current ? (
<EyeOff className="w-4 h-4 sm:w-5 sm:h-5" />
@@ -676,7 +676,7 @@ const ProfilePage: React.FC = () => {
{}
<div>
<label className="block text-sm sm:text-base font-medium text-gray-700 mb-2">
<Lock className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[#d4af37]" />
<Lock className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[var(--luxury-gold)]" />
New Password
<span className="text-red-500 ml-1">*</span>
</label>
@@ -692,7 +692,7 @@ const ProfilePage: React.FC = () => {
<button
type="button"
onClick={() => setShowPassword({ ...showPassword, new: !showPassword.new })}
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[#d4af37] transition-colors"
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[var(--luxury-gold)] transition-colors"
>
{showPassword.new ? (
<EyeOff className="w-4 h-4 sm:w-5 sm:h-5" />
@@ -712,7 +712,7 @@ const ProfilePage: React.FC = () => {
{}
<div>
<label className="block text-sm sm:text-base font-medium text-gray-700 mb-2">
<Lock className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[#d4af37]" />
<Lock className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[var(--luxury-gold)]" />
Confirm New Password
<span className="text-red-500 ml-1">*</span>
</label>
@@ -728,7 +728,7 @@ const ProfilePage: React.FC = () => {
<button
type="button"
onClick={() => setShowPassword({ ...showPassword, confirm: !showPassword.confirm })}
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[#d4af37] transition-colors"
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[var(--luxury-gold)] transition-colors"
>
{showPassword.confirm ? (
<EyeOff className="w-4 h-4 sm:w-5 sm:h-5" />
@@ -762,11 +762,11 @@ const ProfilePage: React.FC = () => {
{}
{activeTab === 'mfa' && (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl animate-slide-up space-y-5 sm:space-y-6">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl animate-slide-up space-y-5 sm:space-y-6">
{}
<div>
<h2 className="text-xl sm:text-2xl font-serif font-semibold text-gray-900 mb-2 flex items-center gap-2">
<Shield className="w-5 h-5 sm:w-6 sm:h-6 text-[#d4af37]" />
<Shield className="w-5 h-5 sm:w-6 sm:h-6 text-[var(--luxury-gold)]" />
Two-Factor Authentication
</h2>
<p className="text-xs sm:text-sm text-gray-600 font-light leading-relaxed">
@@ -838,7 +838,7 @@ const ProfilePage: React.FC = () => {
{}
<div className="bg-white border border-gray-200 rounded-sm p-4 sm:p-5">
<h3 className="text-sm sm:text-base font-semibold text-gray-900 mb-2 flex items-center gap-2">
<RefreshCw className="w-4 h-4 sm:w-5 sm:h-5 text-[#d4af37]" />
<RefreshCw className="w-4 h-4 sm:w-5 sm:h-5 text-[var(--luxury-gold)]" />
Backup Codes
</h3>
<p className="text-xs sm:text-sm text-gray-600 font-light mb-4 leading-relaxed">
@@ -984,7 +984,7 @@ const ProfilePage: React.FC = () => {
{}
<div className="bg-white border border-gray-200 rounded-sm p-4 sm:p-5">
<h3 className="font-semibold text-gray-900 mb-2 text-sm sm:text-base flex items-center gap-2">
<KeyRound className="w-4 h-4 sm:w-5 sm:h-5 text-[#d4af37]" />
<KeyRound className="w-4 h-4 sm:w-5 sm:h-5 text-[var(--luxury-gold)]" />
Step 2: Verify Setup
</h3>
<p className="text-xs sm:text-sm text-gray-600 font-light mb-4 leading-relaxed">
@@ -1110,10 +1110,10 @@ const SessionsTab: React.FC = () => {
};
const getDeviceIcon = (userAgent?: string) => {
if (!userAgent) return <Monitor className="w-5 h-5 text-[#d4af37]" />;
if (!userAgent) return <Monitor className="w-5 h-5 text-[var(--luxury-gold)]" />;
if (userAgent.includes('Mobile')) return <Smartphone className="w-5 h-5 text-blue-500" />;
if (userAgent.includes('Tablet')) return <Tablet className="w-5 h-5 text-purple-500" />;
return <Monitor className="w-5 h-5 text-[#d4af37]" />;
return <Monitor className="w-5 h-5 text-[var(--luxury-gold)]" />;
};
const getDeviceName = (userAgent?: string) => {
@@ -1181,17 +1181,17 @@ const SessionsTab: React.FC = () => {
if (loading) {
return (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl">
<Loading text="Loading sessions..." />
</div>
);
}
return (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl animate-slide-up space-y-5 sm:space-y-6">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl animate-slide-up space-y-5 sm:space-y-6">
<div>
<h2 className="text-xl sm:text-2xl font-serif font-semibold text-gray-900 mb-2 flex items-center gap-2">
<Monitor className="w-5 h-5 sm:w-6 sm:h-6 text-[#d4af37]" />
<Monitor className="w-5 h-5 sm:w-6 sm:h-6 text-[var(--luxury-gold)]" />
Active Sessions
</h2>
<p className="text-xs sm:text-sm text-gray-600 font-light">
@@ -1220,11 +1220,11 @@ const SessionsTab: React.FC = () => {
{sessions.map((session) => (
<div
key={session.id}
className="bg-gradient-to-r from-slate-50 to-white border border-[#d4af37]/20 rounded-sm p-4 sm:p-5 hover:shadow-lg hover:border-[#d4af37]/40 transition-all duration-300"
className="bg-gradient-to-r from-slate-50 to-white border border-[var(--luxury-gold)]/20 rounded-sm p-4 sm:p-5 hover:shadow-lg hover:border-[var(--luxury-gold)]/40 transition-all duration-300"
>
<div className="flex items-start justify-between gap-4">
<div className="flex items-start gap-4 flex-1">
<div className="p-2 sm:p-3 bg-gradient-to-br from-[#d4af37]/10 to-[#c9a227]/10 rounded-sm flex-shrink-0">
<div className="p-2 sm:p-3 bg-gradient-to-br from-[var(--luxury-gold)]/10 to-[var(--luxury-gold-dark)]/10 rounded-sm flex-shrink-0">
{getDeviceIcon(session.user_agent)}
</div>
<div className="flex-1 min-w-0">
@@ -1354,17 +1354,17 @@ const GDPRTab: React.FC = () => {
if (loading) {
return (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl">
<Loading text="Loading privacy data..." />
</div>
);
}
return (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl animate-slide-up space-y-5 sm:space-y-6">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl animate-slide-up space-y-5 sm:space-y-6">
<div>
<h2 className="text-xl sm:text-2xl font-serif font-semibold text-gray-900 mb-2 flex items-center gap-2">
<Database className="w-5 h-5 sm:w-6 sm:h-6 text-[#d4af37]" />
<Database className="w-5 h-5 sm:w-6 sm:h-6 text-[var(--luxury-gold)]" />
Data Privacy & GDPR Rights
</h2>
<p className="text-xs sm:text-sm text-gray-600 font-light">
@@ -1431,14 +1431,14 @@ const GDPRTab: React.FC = () => {
{requests.length > 0 && (
<div className="border-t border-gray-200 pt-5 sm:pt-6">
<h3 className="text-base sm:text-lg font-semibold text-gray-900 mb-4 flex items-center gap-2">
<FileText className="w-5 h-5 text-[#d4af37]" />
<FileText className="w-5 h-5 text-[var(--luxury-gold)]" />
Request History
</h3>
<div className="space-y-3 sm:space-y-4">
{requests.map((request) => (
<div
key={request.id}
className="bg-gradient-to-r from-slate-50 to-white border border-[#d4af37]/20 rounded-sm p-4 sm:p-5 hover:shadow-md hover:border-[#d4af37]/40 transition-all duration-300"
className="bg-gradient-to-r from-slate-50 to-white border border-[var(--luxury-gold)]/20 rounded-sm p-4 sm:p-5 hover:shadow-md hover:border-[var(--luxury-gold)]/40 transition-all duration-300"
>
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 sm:gap-4">
<div className="flex-1 min-w-0">

View File

@@ -1334,10 +1334,10 @@ const AdvancedRoomManagementPage: React.FC = () => {
{/* Room Modal */}
{showRoomModal && (
<div className="fixed inset-0 bg-black/80 backdrop-blur-sm flex items-center justify-center z-[100] p-4">
<div className="bg-gradient-to-br from-[#1a1a1a] via-[#0f0f0f] to-[#1a1a1a] rounded-xl border border-[#d4af37]/30 backdrop-blur-xl shadow-2xl shadow-[#d4af37]/20 p-8 w-full max-w-4xl max-h-[90vh] overflow-y-auto">
<div className="flex justify-between items-center mb-6 pb-6 border-b border-[#d4af37]/20">
<div className="bg-gradient-to-br from-[#1a1a1a] via-[#0f0f0f] to-[#1a1a1a] rounded-xl border border-[var(--luxury-gold)]/30 backdrop-blur-xl shadow-2xl shadow-[var(--luxury-gold)]/20 p-8 w-full max-w-4xl max-h-[90vh] overflow-y-auto">
<div className="flex justify-between items-center mb-6 pb-6 border-b border-[var(--luxury-gold)]/20">
<div>
<h2 className="text-xl sm:text-2xl md:text-2xl font-serif font-semibold bg-gradient-to-r from-white via-[#d4af37] to-white bg-clip-text text-transparent tracking-wide">
<h2 className="text-xl sm:text-2xl md:text-2xl font-serif font-semibold bg-gradient-to-r from-white via-[var(--luxury-gold)] to-white bg-clip-text text-transparent tracking-wide">
{editingRoom ? 'Update Room' : 'Add New Room'}
</h2>
<p className="text-gray-400 text-sm mt-1 font-light">
@@ -1346,16 +1346,16 @@ const AdvancedRoomManagementPage: React.FC = () => {
</div>
<button
onClick={() => setShowRoomModal(false)}
className="p-2 hover:bg-[#d4af37]/10 rounded-lg transition-colors border border-[#d4af37]/20 hover:border-[#d4af37]/40"
className="p-2 hover:bg-[var(--luxury-gold)]/10 rounded-lg transition-colors border border-[var(--luxury-gold)]/20 hover:border-[var(--luxury-gold)]/40"
>
<X className="w-6 h-6 text-[#d4af37] hover:text-white transition-colors" />
<X className="w-6 h-6 text-[var(--luxury-gold)] hover:text-white transition-colors" />
</button>
</div>
<form onSubmit={handleRoomSubmit} className="space-y-6">
<div className="space-y-4">
<h3 className="text-lg font-serif font-semibold text-[#d4af37] mb-4 flex items-center gap-2">
<div className="w-1 h-6 bg-gradient-to-b from-[#d4af37] to-[#c9a227]" />
<h3 className="text-lg font-serif font-semibold text-[var(--luxury-gold)] mb-4 flex items-center gap-2">
<div className="w-1 h-6 bg-gradient-to-b from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]" />
Basic Information
</h3>
@@ -1368,7 +1368,7 @@ const AdvancedRoomManagementPage: React.FC = () => {
type="text"
value={roomFormData.room_number}
onChange={(e) => setRoomFormData({ ...roomFormData, room_number: e.target.value })}
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white placeholder-gray-500 focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37] transition-all duration-300"
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white placeholder-gray-500 focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)] transition-all duration-300"
placeholder="e.g., 1001"
required
/>
@@ -1381,7 +1381,7 @@ const AdvancedRoomManagementPage: React.FC = () => {
type="number"
value={roomFormData.floor}
onChange={(e) => setRoomFormData({ ...roomFormData, floor: parseInt(e.target.value) })}
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white placeholder-gray-500 focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37] transition-all duration-300"
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white placeholder-gray-500 focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)] transition-all duration-300"
required
min="1"
/>
@@ -1405,7 +1405,7 @@ const AdvancedRoomManagementPage: React.FC = () => {
amenities: inheritedAmenities // Inherit amenities from room type
});
}}
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37] transition-all duration-300"
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)] transition-all duration-300"
required
>
{roomTypes.length > 0 ? (
@@ -1430,7 +1430,7 @@ const AdvancedRoomManagementPage: React.FC = () => {
<select
value={roomFormData.status}
onChange={(e) => setRoomFormData({ ...roomFormData, status: e.target.value as 'available' | 'occupied' | 'maintenance' })}
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37] transition-all duration-300"
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)] transition-all duration-300"
required
>
<option value="available" className="bg-[#1a1a1a]">Available</option>
@@ -1439,13 +1439,13 @@ const AdvancedRoomManagementPage: React.FC = () => {
</select>
</div>
<div className="flex items-center gap-3 p-4 bg-[#0a0a0a] rounded-lg border border-[#d4af37]/20">
<div className="flex items-center gap-3 p-4 bg-[#0a0a0a] rounded-lg border border-[var(--luxury-gold)]/20">
<input
type="checkbox"
id="featured"
checked={roomFormData.featured}
onChange={(e) => setRoomFormData({ ...roomFormData, featured: e.target.checked })}
className="w-5 h-5 text-[#d4af37] bg-[#1a1a1a] border-[#d4af37]/30 rounded focus:ring-[#d4af37]/50 focus:ring-2 cursor-pointer transition-all"
className="w-5 h-5 text-[var(--luxury-gold)] bg-[#1a1a1a] border-[var(--luxury-gold)]/30 rounded focus:ring-[var(--luxury-gold)]/50 focus:ring-2 cursor-pointer transition-all"
/>
<label htmlFor="featured" className="text-sm text-gray-300 cursor-pointer font-medium">
Featured Room
@@ -1462,7 +1462,7 @@ const AdvancedRoomManagementPage: React.FC = () => {
min="0"
value={roomFormData.price}
onChange={(e) => setRoomFormData({ ...roomFormData, price: e.target.value })}
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white placeholder-gray-500 focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37] transition-all duration-300"
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white placeholder-gray-500 focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)] transition-all duration-300"
placeholder="e.g., 150.00"
/>
</div>
@@ -1475,7 +1475,7 @@ const AdvancedRoomManagementPage: React.FC = () => {
value={roomFormData.description}
onChange={(e) => setRoomFormData({ ...roomFormData, description: e.target.value })}
rows={4}
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white placeholder-gray-500 focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37] transition-all duration-300 resize-none"
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white placeholder-gray-500 focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)] transition-all duration-300 resize-none"
placeholder="Enter the actual description for this specific room..."
/>
</div>
@@ -1490,7 +1490,7 @@ const AdvancedRoomManagementPage: React.FC = () => {
min="1"
value={roomFormData.capacity}
onChange={(e) => setRoomFormData({ ...roomFormData, capacity: e.target.value })}
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white placeholder-gray-500 focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37] transition-all duration-300"
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white placeholder-gray-500 focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)] transition-all duration-300"
placeholder="e.g., 4"
/>
</div>
@@ -1503,7 +1503,7 @@ const AdvancedRoomManagementPage: React.FC = () => {
type="text"
value={roomFormData.room_size}
onChange={(e) => setRoomFormData({ ...roomFormData, room_size: e.target.value })}
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white placeholder-gray-500 focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37] transition-all duration-300"
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white placeholder-gray-500 focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)] transition-all duration-300"
placeholder="e.g., 1 Room, 50 sqm"
/>
</div>
@@ -1517,19 +1517,19 @@ const AdvancedRoomManagementPage: React.FC = () => {
type="text"
value={roomFormData.view}
onChange={(e) => setRoomFormData({ ...roomFormData, view: e.target.value })}
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white placeholder-gray-500 focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37] transition-all duration-300"
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white placeholder-gray-500 focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)] transition-all duration-300"
placeholder="e.g., City View, Ocean View, Mountain View"
/>
</div>
</div>
<div className="space-y-4">
<h3 className="text-lg font-serif font-semibold text-[#d4af37] mb-4 flex items-center gap-2">
<div className="w-1 h-6 bg-gradient-to-b from-[#d4af37] to-[#c9a227]" />
<h3 className="text-lg font-serif font-semibold text-[var(--luxury-gold)] mb-4 flex items-center gap-2">
<div className="w-1 h-6 bg-gradient-to-b from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]" />
Amenities & Features
</h3>
<div className="border border-[#d4af37]/20 rounded-lg p-4 bg-[#0a0a0a]/50 backdrop-blur-sm">
<div className="border border-[var(--luxury-gold)]/20 rounded-lg p-4 bg-[#0a0a0a]/50 backdrop-blur-sm">
{(() => {
const selectedRoomType = roomTypesList.find(rt => rt.id === roomFormData.room_type_id);
const inheritedAmenities = selectedRoomType ? getAmenitiesArray(selectedRoomType.amenities) : [];
@@ -1549,15 +1549,15 @@ const AdvancedRoomManagementPage: React.FC = () => {
<>
<div className="mb-3">
<p className="text-xs text-gray-400 italic flex items-center gap-2">
<Check className="w-3 h-3 text-[#d4af37]" />
Inherited from room type: <strong className="text-[#d4af37]">{selectedRoomType?.name}</strong>
<Check className="w-3 h-3 text-[var(--luxury-gold)]" />
Inherited from room type: <strong className="text-[var(--luxury-gold)]">{selectedRoomType?.name}</strong>
</p>
</div>
<div className="flex flex-wrap gap-2">
{inheritedAmenities.map((amenity) => (
<span
key={amenity}
className="px-3 py-1.5 bg-gradient-to-r from-[#d4af37]/20 to-[#c9a227]/20 border border-[#d4af37]/30 rounded-lg text-sm text-[#d4af37] font-medium"
className="px-3 py-1.5 bg-gradient-to-r from-[var(--luxury-gold)]/20 to-[var(--luxury-gold-dark)]/20 border border-[var(--luxury-gold)]/30 rounded-lg text-sm text-[var(--luxury-gold)] font-medium"
>
{amenity}
</span>
@@ -1572,17 +1572,17 @@ const AdvancedRoomManagementPage: React.FC = () => {
</div>
</div>
<div className="flex gap-4 pt-4 border-t border-[#d4af37]/20">
<div className="flex gap-4 pt-4 border-t border-[var(--luxury-gold)]/20">
<button
type="button"
onClick={() => setShowRoomModal(false)}
className="flex-1 px-6 py-3 border border-[#d4af37]/30 text-gray-300 rounded-lg hover:bg-[#d4af37]/10 hover:border-[#d4af37] transition-all duration-300 font-medium"
className="flex-1 px-6 py-3 border border-[var(--luxury-gold)]/30 text-gray-300 rounded-lg hover:bg-[var(--luxury-gold)]/10 hover:border-[var(--luxury-gold)] transition-all duration-300 font-medium"
>
Cancel
</button>
<button
type="submit"
className="flex-1 px-6 py-3 bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-[#0f0f0f] rounded-lg hover:from-[#f5d76e] hover:to-[#d4af37] transition-all duration-300 font-semibold shadow-lg shadow-[#d4af37]/30 hover:shadow-xl hover:shadow-[#d4af37]/40"
className="flex-1 px-6 py-3 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-[#0f0f0f] rounded-lg hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] transition-all duration-300 font-semibold shadow-lg shadow-[var(--luxury-gold)]/30 hover:shadow-xl hover:shadow-[var(--luxury-gold)]/40"
>
{editingRoom ? 'Update Room' : 'Add Room'}
</button>
@@ -1590,9 +1590,9 @@ const AdvancedRoomManagementPage: React.FC = () => {
</form>
{editingRoom && (
<div className="mt-8 pt-8 border-t border-[#d4af37]/20">
<h3 className="text-lg font-serif font-semibold text-[#d4af37] mb-6 flex items-center gap-2">
<div className="w-1 h-6 bg-gradient-to-b from-[#d4af37] to-[#c9a227]" />
<div className="mt-8 pt-8 border-t border-[var(--luxury-gold)]/20">
<h3 className="text-lg font-serif font-semibold text-[var(--luxury-gold)] mb-6 flex items-center gap-2">
<div className="w-1 h-6 bg-gradient-to-b from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]" />
<ImageIcon className="w-5 h-5" />
Room Images
</h3>
@@ -1655,8 +1655,8 @@ const AdvancedRoomManagementPage: React.FC = () => {
return (
<div key={index} className="relative group">
<div className="overflow-hidden rounded-lg border border-[#d4af37]/20
hover:border-[#d4af37] transition-all duration-300">
<div className="overflow-hidden rounded-lg border border-[var(--luxury-gold)]/20
hover:border-[var(--luxury-gold)] transition-all duration-300">
<img
src={imageUrl}
alt={`Room Image ${index + 1}`}
@@ -1669,7 +1669,7 @@ const AdvancedRoomManagementPage: React.FC = () => {
</div>
{isRoomImage && (
<>
<div className="absolute top-2 left-2 bg-[#d4af37]/90 backdrop-blur-sm
<div className="absolute top-2 left-2 bg-[var(--luxury-gold)]/90 backdrop-blur-sm
text-[#0f0f0f] px-2 py-1 rounded text-xs font-semibold
opacity-0 group-hover:opacity-100 transition-opacity duration-300">
Room Image
@@ -1692,7 +1692,7 @@ const AdvancedRoomManagementPage: React.FC = () => {
</div>
</div>
) : (
<div className="mb-6 p-8 bg-[#0a0a0a]/50 rounded-lg border border-[#d4af37]/10 text-center">
<div className="mb-6 p-8 bg-[#0a0a0a]/50 rounded-lg border border-[var(--luxury-gold)]/10 text-center">
<ImageIcon className="w-12 h-12 text-gray-600 mx-auto mb-3" />
<p className="text-sm text-gray-400 font-light">
No images uploaded yet. Upload images below to display them here.
@@ -1717,10 +1717,10 @@ const AdvancedRoomManagementPage: React.FC = () => {
className="w-full text-sm text-gray-400
file:mr-4 file:py-3 file:px-6 file:rounded-lg file:border-0
file:text-sm file:font-semibold
file:bg-gradient-to-r file:from-[#d4af37]/20 file:to-[#c9a227]/20
file:text-[#d4af37] file:border file:border-[#d4af37]/30
hover:file:from-[#d4af37]/30 hover:file:to-[#c9a227]/30
hover:file:border-[#d4af37] file:cursor-pointer
file:bg-gradient-to-r file:from-[var(--luxury-gold)]/20 file:to-[var(--luxury-gold-dark)]/20
file:text-[var(--luxury-gold)] file:border file:border-[var(--luxury-gold)]/30
hover:file:from-[var(--luxury-gold)]/30 hover:file:to-[var(--luxury-gold-dark)]/30
hover:file:border-[var(--luxury-gold)] file:cursor-pointer
transition-all duration-300 bg-[#0a0a0a] rounded-lg"
/>
<p className="text-xs text-gray-500 mt-1 italic">
@@ -1742,7 +1742,7 @@ const AdvancedRoomManagementPage: React.FC = () => {
type="button"
onClick={handleUploadImages}
disabled={uploadingImages || selectedFiles.length === 0}
className="px-6 py-2 bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-[#0f0f0f] rounded-lg hover:from-[#f5d76e] hover:to-[#d4af37] transition-all duration-300 font-semibold shadow-lg shadow-[#d4af37]/30 hover:shadow-xl hover:shadow-[#d4af37]/40 disabled:opacity-50 disabled:cursor-not-allowed"
className="px-6 py-2 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-[#0f0f0f] rounded-lg hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] transition-all duration-300 font-semibold shadow-lg shadow-[var(--luxury-gold)]/30 hover:shadow-xl hover:shadow-[var(--luxury-gold)]/40 disabled:opacity-50 disabled:cursor-not-allowed"
>
{uploadingImages ? 'Uploading...' : 'Upload Images'}
</button>
@@ -1752,7 +1752,7 @@ const AdvancedRoomManagementPage: React.FC = () => {
</div>
)}
<div className="mt-8 pt-6 border-t border-[#d4af37]/20 flex justify-end">
<div className="mt-8 pt-6 border-t border-[var(--luxury-gold)]/20 flex justify-end">
<button
type="button"
onClick={() => {

View File

@@ -1,4 +1,5 @@
import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import {
BarChart3,
FileText,
@@ -26,7 +27,8 @@ import {
CreditCard,
Building2,
Target,
Award
Award,
ChevronRight
} from 'lucide-react';
import { toast } from 'react-toastify';
import Loading from '../../shared/components/Loading';
@@ -36,7 +38,6 @@ import Pagination from '../../shared/components/Pagination';
import CurrencyIcon from '../../shared/components/CurrencyIcon';
import { useAsync } from '../../shared/hooks/useAsync';
import reportService, { ReportData } from '../../features/analytics/services/reportService';
import reviewService, { Review } from '../../features/reviews/services/reviewService';
import { auditService, AuditLog, AuditLogFilters } from '../../features/analytics/services/auditService';
import { formatDate } from '../../shared/utils/format';
import { useFormatCurrency } from '../../features/payments/hooks/useFormatCurrency';
@@ -62,10 +63,11 @@ import { SimpleBarChart, SimpleLineChart, SimplePieChart, KPICard } from '../../
import { exportData } from '../../shared/utils/exportUtils';
import CustomReportBuilder from '../../features/analytics/components/CustomReportBuilder';
type AnalyticsTab = 'overview' | 'reports' | 'revenue' | 'operational' | 'guest' | 'financial' | 'audit-logs' | 'reviews';
type AnalyticsTab = 'overview' | 'reports' | 'revenue' | 'operational' | 'guest' | 'financial' | 'audit-logs';
const AnalyticsDashboardPage: React.FC = () => {
const { formatCurrency } = useFormatCurrency();
const navigate = useNavigate();
const [activeTab, setActiveTab] = useState<AnalyticsTab>('overview');
const [showReportBuilder, setShowReportBuilder] = useState(false);
const [analyticsDateRange, setAnalyticsDateRange] = useState({
@@ -96,16 +98,6 @@ const AnalyticsDashboardPage: React.FC = () => {
});
const [reviews, setReviews] = useState<Review[]>([]);
const [reviewsLoading, setReviewsLoading] = useState(true);
const [reviewsFilters, setReviewsFilters] = useState({
status: '',
});
const [reviewsCurrentPage, setReviewsCurrentPage] = useState(1);
const [reviewsTotalPages, setReviewsTotalPages] = useState(1);
const [reviewsTotalItems, setReviewsTotalItems] = useState(0);
const reviewsPerPage = 5;
// Advanced Analytics Data
const { data: comprehensiveData, loading: comprehensiveLoading, execute: fetchComprehensive } = useAsync<ComprehensiveAnalyticsData>(
() => analyticsService.getComprehensiveAnalytics({
@@ -214,8 +206,6 @@ const AnalyticsDashboardPage: React.FC = () => {
useEffect(() => {
if (activeTab === 'audit-logs') {
fetchLogs();
} else if (activeTab === 'reviews') {
fetchReviews();
} else if (activeTab === 'overview') {
fetchComprehensive();
} else if (activeTab === 'revenue') {
@@ -227,17 +217,12 @@ const AnalyticsDashboardPage: React.FC = () => {
} else if (activeTab === 'financial') {
Promise.all([fetchProfitLoss(), fetchPaymentMethods(), fetchRefunds()]);
}
}, [activeTab, auditFilters, currentPage, reviewsFilters, reviewsCurrentPage, analyticsDateRange]);
}, [activeTab, auditFilters, currentPage, analyticsDateRange]);
useEffect(() => {
setAuditFilters(prev => ({ ...prev, page: currentPage }));
}, [currentPage]);
useEffect(() => {
if (activeTab === 'reviews') {
setReviewsCurrentPage(1);
}
}, [reviewsFilters, activeTab]);
const fetchLogs = async () => {
try {
@@ -400,76 +385,6 @@ const AnalyticsDashboardPage: React.FC = () => {
}
};
const fetchReviews = async () => {
try {
setReviewsLoading(true);
const response = await reviewService.getReviews({
...reviewsFilters,
page: reviewsCurrentPage,
limit: reviewsPerPage,
});
setReviews(response.data.reviews);
if (response.data.pagination) {
setReviewsTotalPages(response.data.pagination.totalPages);
setReviewsTotalItems(response.data.pagination.total);
}
} catch (error: any) {
toast.error(error.response?.data?.message || 'Unable to load reviews list');
} finally {
setReviewsLoading(false);
}
};
const handleApproveReview = async (id: number) => {
try {
await reviewService.approveReview(id);
toast.success('Review approved successfully');
fetchReviews();
} catch (error: any) {
toast.error(error.response?.data?.message || 'Unable to approve review');
}
};
const handleRejectReview = async (id: number) => {
if (!window.confirm('Are you sure you want to reject this review?')) return;
try {
await reviewService.rejectReview(id);
toast.success('Review rejected successfully');
fetchReviews();
} catch (error: any) {
toast.error(error.response?.data?.message || 'Unable to reject review');
}
};
const getReviewStatusBadge = (status: string) => {
const badges: Record<string, { bg: string; text: string; label: string; border: string }> = {
pending: { bg: 'bg-gradient-to-r from-amber-50 to-yellow-50', text: 'text-amber-800', label: 'Pending', border: 'border-amber-200' },
approved: { bg: 'bg-gradient-to-r from-emerald-50 to-green-50', text: 'text-emerald-800', label: 'Approved', border: 'border-emerald-200' },
rejected: { bg: 'bg-gradient-to-r from-rose-50 to-red-50', text: 'text-rose-800', label: 'Rejected', border: 'border-rose-200' },
};
const badge = badges[status] || badges.pending;
return (
<span className={`px-3 py-1.5 rounded-full text-xs font-semibold border shadow-sm ${badge.bg} ${badge.text} ${badge.border}`}>
{badge.label}
</span>
);
};
const renderStars = (rating: number) => {
return (
<div className="flex items-center gap-0.5">
{[1, 2, 3, 4, 5].map((star) => (
<Star
key={star}
className={`w-4 h-4 ${star <= rating ? 'text-amber-400 fill-amber-400' : 'text-gray-300'}`}
/>
))}
</div>
);
};
const tabs = [
{ id: 'overview' as AnalyticsTab, label: 'Overview', icon: BarChart3 },
{ id: 'revenue' as AnalyticsTab, label: 'Revenue', icon: DollarSign },
@@ -478,7 +393,6 @@ const AnalyticsDashboardPage: React.FC = () => {
{ id: 'financial' as AnalyticsTab, label: 'Financial', icon: CreditCard },
{ id: 'reports' as AnalyticsTab, label: 'Reports', icon: FileText },
{ id: 'audit-logs' as AnalyticsTab, label: 'Audit Logs', icon: ClipboardList },
{ id: 'reviews' as AnalyticsTab, label: 'Reviews', icon: Star },
];
return (
@@ -668,7 +582,7 @@ const AnalyticsDashboardPage: React.FC = () => {
</div>
{/* Quick Access Cards */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 lg:gap-8">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 lg:gap-8">
<div
onClick={() => setActiveTab('revenue')}
className="group relative bg-white/90 backdrop-blur-xl rounded-2xl shadow-xl border border-green-100/50 p-8 cursor-pointer transition-all duration-300 hover:shadow-2xl hover:scale-105 hover:border-green-300/60 overflow-hidden"
@@ -731,6 +645,34 @@ const AnalyticsDashboardPage: React.FC = () => {
</p>
</div>
</div>
<div
onClick={() => navigate('/admin/reviews')}
className="group relative bg-white/90 backdrop-blur-xl rounded-2xl shadow-xl border border-amber-100/50 p-8 cursor-pointer transition-all duration-300 hover:shadow-2xl hover:scale-105 hover:border-amber-300/60 overflow-hidden"
>
<div className="absolute top-0 right-0 w-32 h-32 bg-gradient-to-br from-amber-400/10 to-transparent rounded-bl-full"></div>
<div className="relative space-y-5">
<div className="flex items-center gap-4">
<div className="p-3.5 rounded-xl bg-gradient-to-br from-amber-500 to-amber-600 shadow-lg">
<Star className="w-6 h-6 text-white" />
</div>
<div>
<h3 className="font-bold text-gray-900 text-xl mb-1">Review Management</h3>
<div className="h-1 w-12 bg-gradient-to-r from-amber-500 to-amber-600 rounded-full"></div>
</div>
</div>
<p className="text-gray-600 text-sm leading-relaxed">
Approve and manage customer reviews and ratings
</p>
<div className="pt-5 border-t border-gray-100">
<div className="flex items-center justify-between text-sm">
<span className="text-gray-500 font-medium">Manage Reviews</span>
<ChevronRight className="w-5 h-5 text-amber-600 group-hover:translate-x-1 transition-transform" />
</div>
</div>
</div>
<div className="absolute inset-0 bg-gradient-to-r from-transparent via-amber-50/30 to-transparent opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none"></div>
</div>
</div>
</>
) : (
@@ -1275,169 +1217,6 @@ const AnalyticsDashboardPage: React.FC = () => {
</div>
)}
{}
{activeTab === 'reviews' && (
<div className="space-y-8">
{}
<div className="bg-white/90 backdrop-blur-xl rounded-2xl shadow-xl border border-gray-200/50 p-8">
<div className="space-y-3">
<div className="flex items-center gap-3">
<div className="p-2.5 rounded-xl bg-gradient-to-br from-amber-500/10 to-yellow-500/10 border border-amber-200/40">
<Star className="w-6 h-6 text-amber-600 fill-amber-600" />
</div>
<h2 className="text-3xl font-extrabold text-gray-900">Review Management</h2>
</div>
<p className="text-gray-600 text-base max-w-2xl leading-relaxed">
Approve and manage customer reviews and ratings
</p>
</div>
</div>
{}
<div className="relative bg-white/90 backdrop-blur-xl rounded-2xl shadow-xl border border-gray-200/50 p-8">
<div className="flex items-center gap-3 mb-6">
<div className="p-2 rounded-xl bg-gradient-to-br from-amber-500/10 to-amber-600/10 border border-amber-200/40">
<Filter className="w-5 h-5 text-amber-600" />
</div>
<h3 className="text-xl font-bold text-gray-900">Filters</h3>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="space-y-2">
<label className="block text-sm font-semibold text-gray-900">Status</label>
<select
value={reviewsFilters.status}
onChange={(e) => setReviewsFilters({ ...reviewsFilters, status: e.target.value })}
className="w-full px-4 py-3 bg-white border-2 border-gray-200 rounded-xl focus:border-amber-400 focus:ring-4 focus:ring-amber-100 transition-all duration-200 text-gray-700 font-medium shadow-sm hover:shadow-md cursor-pointer"
>
<option value="">All statuses</option>
<option value="pending">Pending</option>
<option value="approved">Approved</option>
<option value="rejected">Rejected</option>
</select>
</div>
<div className="flex items-end">
<div className="w-full px-4 py-3 bg-gradient-to-r from-gray-50 to-white border-2 border-gray-200 rounded-xl">
<span className="text-sm font-semibold text-gray-700">
{reviewsTotalItems} review{reviewsTotalItems !== 1 ? 's' : ''}
</span>
</div>
</div>
</div>
</div>
{}
{reviewsLoading && reviews.length === 0 ? (
<Loading fullScreen text="Loading reviews..." />
) : reviews.length === 0 ? (
<div className="relative bg-white/90 backdrop-blur-xl rounded-2xl shadow-xl border border-gray-200/50 p-8">
<EmptyState
title="No Reviews Found"
description="No reviews match your current filters."
/>
</div>
) : (
<>
<div className="relative bg-white/90 backdrop-blur-xl rounded-2xl shadow-xl border border-gray-200/50 overflow-hidden">
<div className="overflow-x-auto">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gradient-to-r from-gray-50 to-gray-100">
<tr>
<th className="px-8 py-5 text-left text-xs font-bold text-gray-700 uppercase tracking-wider border-b border-gray-200">User</th>
<th className="px-8 py-5 text-left text-xs font-bold text-gray-700 uppercase tracking-wider border-b border-gray-200">Room</th>
<th className="px-8 py-5 text-left text-xs font-bold text-gray-700 uppercase tracking-wider border-b border-gray-200">Rating</th>
<th className="px-8 py-5 text-left text-xs font-bold text-gray-700 uppercase tracking-wider border-b border-gray-200">Comment</th>
<th className="px-8 py-5 text-left text-xs font-bold text-gray-700 uppercase tracking-wider border-b border-gray-200">Created Date</th>
<th className="px-8 py-5 text-left text-xs font-bold text-gray-700 uppercase tracking-wider border-b border-gray-200">Status</th>
<th className="px-8 py-5 text-right text-xs font-bold text-gray-700 uppercase tracking-wider border-b border-gray-200">Actions</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{reviews.map((review) => (
<tr key={review.id} className="hover:bg-gray-50 transition-colors">
<td className="px-8 py-5 whitespace-nowrap">
<div className="text-sm font-semibold text-gray-900">{review.user?.name}</div>
{review.user?.email && (
<div className="text-xs text-gray-500">{review.user.email}</div>
)}
</td>
<td className="px-8 py-5 whitespace-nowrap">
<div className="text-sm font-medium text-gray-900">
Room {review.room?.room_number}
</div>
{review.room?.room_type?.name && (
<div className="text-xs text-gray-500">{review.room.room_type.name}</div>
)}
</td>
<td className="px-8 py-5 whitespace-nowrap">
<div className="flex items-center gap-2">
{renderStars(review.rating)}
<span className="text-sm font-semibold text-gray-700">({review.rating})</span>
</div>
</td>
<td className="px-8 py-5">
<div className="text-sm text-gray-900 max-w-xs">{review.comment}</div>
</td>
<td className="px-8 py-5 whitespace-nowrap">
<div className="text-sm text-gray-600">
{new Date(review.created_at).toLocaleDateString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric'
})}
</div>
</td>
<td className="px-8 py-5 whitespace-nowrap">
{getReviewStatusBadge(review.status)}
</td>
<td className="px-8 py-5 whitespace-nowrap text-right text-sm font-medium">
{review.status === 'pending' && (
<div className="flex items-center justify-end gap-3">
<button
onClick={() => handleApproveReview(review.id)}
className="px-4 py-2 bg-gradient-to-r from-emerald-500 to-emerald-600 text-white rounded-lg hover:from-emerald-600 hover:to-emerald-700 transition-all duration-200 shadow-lg hover:shadow-xl font-semibold flex items-center gap-2"
title="Approve"
>
<CheckCircle className="w-4 h-4" />
Approve
</button>
<button
onClick={() => handleRejectReview(review.id)}
className="px-4 py-2 bg-gradient-to-r from-rose-500 to-rose-600 text-white rounded-lg hover:from-rose-600 hover:to-rose-700 transition-all duration-200 shadow-lg hover:shadow-xl font-semibold flex items-center gap-2"
title="Reject"
>
<XCircle className="w-4 h-4" />
Reject
</button>
</div>
)}
{review.status !== 'pending' && (
<span className="text-gray-400 text-xs">No actions available</span>
)}
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
{}
{reviewsTotalPages > 1 && (
<div className="flex justify-center">
<Pagination
currentPage={reviewsCurrentPage}
totalPages={reviewsTotalPages}
onPageChange={setReviewsCurrentPage}
totalItems={reviewsTotalItems}
itemsPerPage={reviewsPerPage}
/>
</div>
)}
</>
)}
</div>
)}
{}
{showDetails && selectedLog && (
<div className="fixed inset-0 bg-black/60 backdrop-blur-sm flex items-center justify-center z-50 p-4">

View File

@@ -1,472 +0,0 @@
import React, { useState, useEffect, useRef } from 'react';
import {
FileText,
Search,
Filter,
Eye,
Activity,
AlertCircle,
CheckCircle,
XCircle,
Info
} from 'lucide-react';
import { toast } from 'react-toastify';
import Loading from '../../shared/components/Loading';
import EmptyState from '../../shared/components/EmptyState';
import Pagination from '../../shared/components/Pagination';
import { auditService, AuditLog, AuditLogFilters } from '../../features/analytics/services/auditService';
import { formatDate } from '../../shared/utils/format';
import { logger } from '../../shared/utils/logger';
const AuditLogsPage: React.FC = () => {
const [logs, setLogs] = useState<AuditLog[]>([]);
const [loading, setLoading] = useState(true);
const [currentPage, setCurrentPage] = useState(1);
const [totalPages, setTotalPages] = useState(1);
const [totalItems, setTotalItems] = useState(0);
const [selectedLog, setSelectedLog] = useState<AuditLog | null>(null);
const [showDetails, setShowDetails] = useState(false);
const itemsPerPage = 20;
const abortControllerRef = useRef<AbortController | null>(null);
const [filters, setFilters] = useState<AuditLogFilters>({
page: 1,
limit: itemsPerPage,
});
useEffect(() => {
// Cancel previous request if exists
if (abortControllerRef.current) {
abortControllerRef.current.abort();
}
// Create new abort controller
abortControllerRef.current = new AbortController();
fetchLogs();
// Cleanup: abort request on unmount
return () => {
if (abortControllerRef.current) {
abortControllerRef.current.abort();
}
};
}, [filters, currentPage]);
useEffect(() => {
setFilters(prev => ({ ...prev, page: currentPage }));
}, [currentPage]);
const fetchLogs = async () => {
try {
setLoading(true);
const response = await auditService.getAuditLogs({
...filters,
page: currentPage,
limit: itemsPerPage,
});
setLogs(response.data.logs);
if (response.data.pagination) {
setTotalPages(response.data.pagination.totalPages);
setTotalItems(response.data.pagination.total);
}
} catch (error: any) {
// Handle AbortError silently
if (error.name === 'AbortError') {
return;
}
// Clear data when API connection fails
setLogs([]);
setTotalPages(1);
setTotalItems(0);
logger.error('Error fetching audit logs', error);
toast.error(error.response?.data?.message || 'Unable to load audit logs');
} finally {
setLoading(false);
}
};
const handleFilterChange = (key: keyof AuditLogFilters, value: any) => {
setFilters(prev => ({ ...prev, [key]: value }));
setCurrentPage(1);
};
const handleSearch = (searchTerm: string) => {
handleFilterChange('search', searchTerm || undefined);
};
const handleViewDetails = (log: AuditLog) => {
setSelectedLog(log);
setShowDetails(true);
};
const getStatusIcon = (status: string) => {
switch (status) {
case 'success':
return <CheckCircle className="w-5 h-5 text-green-500" />;
case 'failed':
return <XCircle className="w-5 h-5 text-red-500" />;
case 'error':
return <AlertCircle className="w-5 h-5 text-orange-500" />;
default:
return <Info className="w-5 h-5 text-gray-500" />;
}
};
const getStatusBadge = (status: string) => {
const baseClasses = "px-2 py-1 rounded-full text-xs font-medium";
switch (status) {
case 'success':
return `${baseClasses} bg-green-100 text-green-800`;
case 'failed':
return `${baseClasses} bg-red-100 text-red-800`;
case 'error':
return `${baseClasses} bg-orange-100 text-orange-800`;
default:
return `${baseClasses} bg-gray-100 text-gray-800`;
}
};
if (loading && logs.length === 0) {
return <Loading fullScreen text="Loading audit logs..." />;
}
return (
<div className="container mx-auto px-4 py-8">
<div className="mb-8">
<h1 className="text-3xl font-bold text-gray-900 mb-2">Audit Logs</h1>
<p className="text-gray-600">View all system activity and actions</p>
</div>
{}
<div className="mb-6 bg-white p-4 rounded-lg shadow-md">
<div className="flex items-center space-x-2 mb-4">
<Filter className="w-5 h-5 text-gray-500" />
<h3 className="text-lg font-semibold text-gray-900">Filters</h3>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Search
</label>
<div className="relative">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" />
<input
type="text"
placeholder="Search actions, types..."
value={filters.search || ''}
onChange={(e) => handleSearch(e.target.value)}
className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-[#d4af37]"
/>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Action
</label>
<input
type="text"
placeholder="Filter by action"
value={filters.action || ''}
onChange={(e) => handleFilterChange('action', e.target.value || undefined)}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-[#d4af37]"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Resource Type
</label>
<input
type="text"
placeholder="Filter by type"
value={filters.resource_type || ''}
onChange={(e) => handleFilterChange('resource_type', e.target.value || undefined)}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-[#d4af37]"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Status
</label>
<select
value={filters.status || ''}
onChange={(e) => handleFilterChange('status', e.target.value || undefined)}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-[#d4af37]"
>
<option value="">All</option>
<option value="success">Success</option>
<option value="failed">Failed</option>
<option value="error">Error</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Start Date
</label>
<input
type="date"
value={filters.start_date || ''}
onChange={(e) => handleFilterChange('start_date', e.target.value || undefined)}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-[#d4af37]"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
End Date
</label>
<input
type="date"
value={filters.end_date || ''}
onChange={(e) => handleFilterChange('end_date', e.target.value || undefined)}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-[#d4af37]"
/>
</div>
</div>
</div>
{}
<div className="grid grid-cols-1 md:grid-cols-4 gap-4 mb-6">
<div className="bg-white p-4 rounded-lg shadow-md">
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-gray-600">Total Logs</p>
<p className="text-2xl font-bold text-gray-900">{totalItems}</p>
</div>
<FileText className="w-8 h-8 text-[#d4af37]" />
</div>
</div>
<div className="bg-white p-4 rounded-lg shadow-md">
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-gray-600">Current Page</p>
<p className="text-2xl font-bold text-gray-900">{currentPage}</p>
</div>
<Activity className="w-8 h-8 text-blue-500" />
</div>
</div>
</div>
{}
{logs.length === 0 ? (
<EmptyState
title="No Audit Logs Found"
description="No audit logs match your current filters."
/>
) : (
<div className="bg-white rounded-lg shadow-md overflow-hidden">
<div className="overflow-x-auto">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
ID
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Action
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Resource
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
User
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Status
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
IP Address
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Date
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Actions
</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{logs.map((log) => (
<tr key={log.id} className="hover:bg-gray-50">
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
#{log.id}
</td>
<td className="px-6 py-4 whitespace-nowrap">
<div className="text-sm font-medium text-gray-900">{log.action}</div>
</td>
<td className="px-6 py-4 whitespace-nowrap">
<div className="text-sm text-gray-900">{log.resource_type}</div>
{log.resource_id && (
<div className="text-xs text-gray-500">ID: {log.resource_id}</div>
)}
</td>
<td className="px-6 py-4 whitespace-nowrap">
{log.user ? (
<div>
<div className="text-sm font-medium text-gray-900">{log.user.full_name}</div>
<div className="text-xs text-gray-500">{log.user.email}</div>
</div>
) : (
<span className="text-sm text-gray-400">System</span>
)}
</td>
<td className="px-6 py-4 whitespace-nowrap">
<div className="flex items-center space-x-2">
{getStatusIcon(log.status)}
<span className={getStatusBadge(log.status)}>
{log.status}
</span>
</div>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{log.ip_address || '-'}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{formatDate(log.created_at)}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium">
<button
onClick={() => handleViewDetails(log)}
className="text-[#d4af37] hover:text-[#c9a227] flex items-center space-x-1"
>
<Eye className="w-4 h-4" />
<span>View</span>
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)}
{}
{totalPages > 1 && (
<div className="mt-6">
<Pagination
currentPage={currentPage}
totalPages={totalPages}
onPageChange={setCurrentPage}
/>
</div>
)}
{}
{showDetails && selectedLog && (
<div className="fixed inset-0 bg-black bg-opacity-50 z-50 overflow-y-auto p-4">
<div className="min-h-full flex items-start justify-center py-8">
<div className="bg-white rounded-lg max-w-3xl w-full my-8 max-h-[calc(100vh-4rem)] overflow-y-auto">
<div className="p-6">
<div className="flex justify-between items-center mb-4">
<h2 className="text-2xl font-bold text-gray-900">Audit Log Details</h2>
<button
onClick={() => setShowDetails(false)}
className="text-gray-400 hover:text-gray-600"
>
<XCircle className="w-6 h-6" />
</button>
</div>
<div className="space-y-4">
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700">ID</label>
<p className="mt-1 text-sm text-gray-900">#{selectedLog.id}</p>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">Status</label>
<div className="mt-1 flex items-center space-x-2">
{getStatusIcon(selectedLog.status)}
<span className={getStatusBadge(selectedLog.status)}>
{selectedLog.status}
</span>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">Action</label>
<p className="mt-1 text-sm text-gray-900">{selectedLog.action}</p>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">Resource Type</label>
<p className="mt-1 text-sm text-gray-900">{selectedLog.resource_type}</p>
</div>
{selectedLog.resource_id && (
<div>
<label className="block text-sm font-medium text-gray-700">Resource ID</label>
<p className="mt-1 text-sm text-gray-900">{selectedLog.resource_id}</p>
</div>
)}
<div>
<label className="block text-sm font-medium text-gray-700">Date</label>
<p className="mt-1 text-sm text-gray-900">{formatDate(selectedLog.created_at)}</p>
</div>
{selectedLog.user && (
<>
<div>
<label className="block text-sm font-medium text-gray-700">User</label>
<p className="mt-1 text-sm text-gray-900">{selectedLog.user.full_name}</p>
<p className="text-xs text-gray-500">{selectedLog.user.email}</p>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">User ID</label>
<p className="mt-1 text-sm text-gray-900">{selectedLog.user_id}</p>
</div>
</>
)}
{selectedLog.ip_address && (
<div>
<label className="block text-sm font-medium text-gray-700">IP Address</label>
<p className="mt-1 text-sm text-gray-900">{selectedLog.ip_address}</p>
</div>
)}
{selectedLog.request_id && (
<div>
<label className="block text-sm font-medium text-gray-700">Request ID</label>
<p className="mt-1 text-sm text-gray-900 font-mono text-xs">{selectedLog.request_id}</p>
</div>
)}
</div>
{selectedLog.user_agent && (
<div>
<label className="block text-sm font-medium text-gray-700">User Agent</label>
<p className="mt-1 text-sm text-gray-900 break-all">{selectedLog.user_agent}</p>
</div>
)}
{selectedLog.error_message && (
<div>
<label className="block text-sm font-medium text-red-700">Error Message</label>
<p className="mt-1 text-sm text-red-900 bg-red-50 p-3 rounded">{selectedLog.error_message}</p>
</div>
)}
{selectedLog.details && (
<div>
<label className="block text-sm font-medium text-gray-700">Details</label>
<pre className="mt-1 text-sm text-gray-900 bg-gray-50 p-3 rounded overflow-x-auto">
{JSON.stringify(selectedLog.details, null, 2)}
</pre>
</div>
)}
</div>
<div className="mt-6 flex justify-end">
<button
onClick={() => setShowDetails(false)}
className="px-4 py-2 bg-gray-200 text-gray-800 rounded-lg hover:bg-gray-300 transition-colors"
>
Close
</button>
</div>
</div>
</div>
</div>
</div>
)}
</div>
);
};
export default AuditLogsPage;

View File

@@ -255,7 +255,7 @@ const BannerManagementPage: React.FC = () => {
resetForm();
setShowModal(true);
}}
className="flex items-center space-x-2 px-4 py-2 bg-[#d4af37] text-white rounded-lg hover:bg-[#c9a227] transition-colors"
className="flex items-center space-x-2 px-4 py-2 bg-[var(--luxury-gold)] text-white rounded-lg hover:bg-[var(--luxury-gold-dark)] transition-colors"
>
<Plus className="w-5 h-5" />
<span>Add Banner</span>
@@ -276,7 +276,7 @@ const BannerManagementPage: React.FC = () => {
placeholder="Search by title..."
value={filters.search}
onChange={(e) => setFilters({ ...filters, search: e.target.value })}
className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-[#d4af37]"
className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-[var(--luxury-gold)]"
/>
</div>
</div>
@@ -287,7 +287,7 @@ const BannerManagementPage: React.FC = () => {
<select
value={filters.position}
onChange={(e) => setFilters({ ...filters, position: e.target.value })}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-[#d4af37]"
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-[var(--luxury-gold)]"
>
<option value="">All Positions</option>
<option value="home">Home</option>
@@ -384,7 +384,7 @@ const BannerManagementPage: React.FC = () => {
<div className="flex space-x-2">
<button
onClick={() => handleEdit(banner)}
className="text-[#d4af37] hover:text-[#c9a227]"
className="text-[var(--luxury-gold)] hover:text-[var(--luxury-gold-dark)]"
>
<Edit className="w-5 h-5" />
</button>

View File

@@ -426,7 +426,7 @@ const BlogManagementPage: React.FC = () => {
type="button"
onClick={() => fileInputRef.current?.click()}
disabled={isUploading}
className="w-full flex items-center justify-center gap-2 px-4 py-2 bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-white rounded-lg hover:from-[#f5d76e] hover:to-[#d4af37] transition-all disabled:opacity-50 disabled:cursor-not-allowed"
className="w-full flex items-center justify-center gap-2 px-4 py-2 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-white rounded-lg hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] transition-all disabled:opacity-50 disabled:cursor-not-allowed"
>
{isUploading ? (
<>
@@ -468,7 +468,7 @@ const BlogManagementPage: React.FC = () => {
</button>
<button
onClick={() => handleOpenModal()}
className="flex items-center gap-2 px-4 py-2 bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-white rounded-lg hover:from-[#f5d76e] hover:to-[#d4af37] transition-all shadow-lg"
className="flex items-center gap-2 px-4 py-2 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-white rounded-lg hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] transition-all shadow-lg"
>
<Plus className="w-5 h-5" />
<span>New Post</span>
@@ -488,7 +488,7 @@ const BlogManagementPage: React.FC = () => {
placeholder="Search posts..."
value={filters.search}
onChange={(e) => setFilters({ ...filters, search: e.target.value })}
className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-transparent"
className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-transparent"
/>
</div>
</div>
@@ -501,7 +501,7 @@ const BlogManagementPage: React.FC = () => {
published: value === 'all' ? undefined : value === 'published',
});
}}
className="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-transparent"
className="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-transparent"
>
<option value="all">All Posts</option>
<option value="published">Published</option>
@@ -561,7 +561,7 @@ const BlogManagementPage: React.FC = () => {
<div className="flex items-center gap-2">
<button
onClick={() => handleOpenModal(post)}
className="text-[#d4af37] hover:text-[#c9a227]"
className="text-[var(--luxury-gold)] hover:text-[var(--luxury-gold-dark)]"
>
<Edit className="w-4 h-4" />
</button>
@@ -646,7 +646,7 @@ const BlogManagementPage: React.FC = () => {
value={formData.slug}
onChange={(e) => setFormData({ ...formData, slug: e.target.value })}
placeholder="Auto-generated from title"
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-transparent bg-gray-50"
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-transparent bg-gray-50"
/>
<p className="mt-1 text-xs text-gray-500">Leave empty to auto-generate, or customize the URL slug</p>
</div>
@@ -657,7 +657,7 @@ const BlogManagementPage: React.FC = () => {
value={formData.excerpt}
onChange={(e) => setFormData({ ...formData, excerpt: e.target.value })}
rows={3}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-transparent"
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-transparent"
/>
</div>
@@ -668,7 +668,7 @@ const BlogManagementPage: React.FC = () => {
value={formData.content}
onChange={(e) => setFormData({ ...formData, content: e.target.value })}
rows={10}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-transparent"
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-transparent"
/>
</div>
@@ -682,7 +682,7 @@ const BlogManagementPage: React.FC = () => {
<button
type="button"
onClick={() => setShowSectionBuilder(!showSectionBuilder)}
className="flex items-center gap-2 px-4 py-2 bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-white rounded-lg hover:from-[#f5d76e] hover:to-[#d4af37] transition-all shadow-lg"
className="flex items-center gap-2 px-4 py-2 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-white rounded-lg hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] transition-all shadow-lg"
>
<Sparkles className="w-4 h-4" />
<span>{showSectionBuilder ? 'Hide' : 'Show'} Section Builder</span>
@@ -707,9 +707,9 @@ const BlogManagementPage: React.FC = () => {
key={type}
type="button"
onClick={() => addSection(type)}
className="flex flex-col items-center gap-2 p-4 bg-gradient-to-br from-gray-50 to-white border-2 border-gray-200 rounded-xl hover:border-[#d4af37] hover:shadow-lg transition-all group"
className="flex flex-col items-center gap-2 p-4 bg-gradient-to-br from-gray-50 to-white border-2 border-gray-200 rounded-xl hover:border-[var(--luxury-gold)] hover:shadow-lg transition-all group"
>
<Icon className="w-6 h-6 text-gray-600 group-hover:text-[#d4af37] transition-colors" />
<Icon className="w-6 h-6 text-gray-600 group-hover:text-[var(--luxury-gold)] transition-colors" />
<span className="text-sm font-medium text-gray-700">{label}</span>
</button>
))}
@@ -726,7 +726,7 @@ const BlogManagementPage: React.FC = () => {
<div className="flex items-center justify-between mb-4">
<div className="flex items-center gap-3">
<GripVertical className="w-5 h-5 text-gray-400" />
<span className="px-3 py-1 bg-[#d4af37]/10 text-[#d4af37] rounded-full text-sm font-semibold uppercase">
<span className="px-3 py-1 bg-[var(--luxury-gold)]/10 text-[var(--luxury-gold)] rounded-full text-sm font-semibold uppercase">
{section.type}
</span>
</div>
@@ -735,7 +735,7 @@ const BlogManagementPage: React.FC = () => {
type="button"
onClick={() => moveSection(index, 'up')}
disabled={index === 0}
className="p-2 text-gray-400 hover:text-[#d4af37] disabled:opacity-30 disabled:cursor-not-allowed"
className="p-2 text-gray-400 hover:text-[var(--luxury-gold)] disabled:opacity-30 disabled:cursor-not-allowed"
>
<MoveUp className="w-4 h-4" />
</button>
@@ -743,7 +743,7 @@ const BlogManagementPage: React.FC = () => {
type="button"
onClick={() => moveSection(index, 'down')}
disabled={index === (formData.sections?.length || 0) - 1}
className="p-2 text-gray-400 hover:text-[#d4af37] disabled:opacity-30 disabled:cursor-not-allowed"
className="p-2 text-gray-400 hover:text-[var(--luxury-gold)] disabled:opacity-30 disabled:cursor-not-allowed"
>
<MoveDown className="w-4 h-4" />
</button>
@@ -767,7 +767,7 @@ const BlogManagementPage: React.FC = () => {
type="text"
value={section.title || ''}
onChange={(e) => updateSection(index, { title: e.target.value })}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37]"
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)]"
placeholder="Hero Title"
/>
</div>
@@ -777,7 +777,7 @@ const BlogManagementPage: React.FC = () => {
value={section.content || ''}
onChange={(e) => updateSection(index, { content: e.target.value })}
rows={3}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37]"
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)]"
placeholder="Hero content"
/>
</div>
@@ -795,7 +795,7 @@ const BlogManagementPage: React.FC = () => {
type="url"
value={section.image || ''}
onChange={(e) => updateSection(index, { image: e.target.value })}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] text-sm"
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] text-sm"
placeholder="https://..."
/>
</div>
@@ -811,7 +811,7 @@ const BlogManagementPage: React.FC = () => {
type="text"
value={section.title || ''}
onChange={(e) => updateSection(index, { title: e.target.value })}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37]"
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)]"
/>
</div>
<div>
@@ -820,7 +820,7 @@ const BlogManagementPage: React.FC = () => {
value={section.content || ''}
onChange={(e) => updateSection(index, { content: e.target.value })}
rows={6}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37]"
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)]"
placeholder="Enter your text content (HTML supported). You can use &lt;img src='URL' /&gt; to add images."
/>
<div className="mt-2">
@@ -847,7 +847,7 @@ const BlogManagementPage: React.FC = () => {
<select
value={section.alignment || 'left'}
onChange={(e) => updateSection(index, { alignment: e.target.value as 'left' | 'center' | 'right' })}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37]"
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)]"
>
<option value="left">Left</option>
<option value="center">Center</option>
@@ -873,7 +873,7 @@ const BlogManagementPage: React.FC = () => {
type="url"
value={section.image || ''}
onChange={(e) => updateSection(index, { image: e.target.value })}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] text-sm"
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] text-sm"
placeholder="https://..."
/>
</div>
@@ -884,7 +884,7 @@ const BlogManagementPage: React.FC = () => {
type="text"
value={section.title || ''}
onChange={(e) => updateSection(index, { title: e.target.value })}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37]"
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)]"
/>
</div>
</>
@@ -915,7 +915,7 @@ const BlogManagementPage: React.FC = () => {
updatedImages[imgIndex] = e.target.value;
updateSection(index, { images: updatedImages });
}}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] text-sm mb-2"
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] text-sm mb-2"
placeholder="Image URL"
/>
<div className="flex gap-2">
@@ -950,7 +950,7 @@ const BlogManagementPage: React.FC = () => {
value={(section.images || []).join('\n')}
onChange={(e) => updateSection(index, { images: e.target.value.split('\n').filter(url => url.trim()) })}
rows={4}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] text-sm"
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] text-sm"
placeholder="https://image1.com/...&#10;https://image2.com/..."
/>
</div>
@@ -965,7 +965,7 @@ const BlogManagementPage: React.FC = () => {
value={section.quote || ''}
onChange={(e) => updateSection(index, { quote: e.target.value })}
rows={4}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37]"
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)]"
placeholder="Enter the quote"
/>
</div>
@@ -975,7 +975,7 @@ const BlogManagementPage: React.FC = () => {
type="text"
value={section.author || ''}
onChange={(e) => updateSection(index, { author: e.target.value })}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37]"
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)]"
/>
</div>
</>
@@ -1012,7 +1012,7 @@ const BlogManagementPage: React.FC = () => {
updateSection(index, { features: updatedFeatures });
}}
placeholder="Feature title"
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] text-sm"
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] text-sm"
/>
<textarea
value={feature.description || ''}
@@ -1023,7 +1023,7 @@ const BlogManagementPage: React.FC = () => {
}}
placeholder="Feature description"
rows={2}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] text-sm"
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] text-sm"
/>
<input
type="text"
@@ -1034,7 +1034,7 @@ const BlogManagementPage: React.FC = () => {
updateSection(index, { features: updatedFeatures });
}}
placeholder="Icon URL (optional)"
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] text-sm"
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] text-sm"
/>
</div>
</div>
@@ -1062,7 +1062,7 @@ const BlogManagementPage: React.FC = () => {
type="text"
value={section.title || ''}
onChange={(e) => updateSection(index, { title: e.target.value })}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37]"
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)]"
/>
</div>
<div>
@@ -1071,7 +1071,7 @@ const BlogManagementPage: React.FC = () => {
value={section.content || ''}
onChange={(e) => updateSection(index, { content: e.target.value })}
rows={3}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37]"
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)]"
/>
</div>
<div className="grid grid-cols-2 gap-4">
@@ -1081,7 +1081,7 @@ const BlogManagementPage: React.FC = () => {
type="text"
value={section.cta_text || ''}
onChange={(e) => updateSection(index, { cta_text: e.target.value })}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37]"
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)]"
/>
</div>
<div>
@@ -1090,7 +1090,7 @@ const BlogManagementPage: React.FC = () => {
type="url"
value={section.cta_link || ''}
onChange={(e) => updateSection(index, { cta_link: e.target.value })}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37]"
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)]"
/>
</div>
</div>
@@ -1104,7 +1104,7 @@ const BlogManagementPage: React.FC = () => {
type="url"
value={section.video_url || ''}
onChange={(e) => updateSection(index, { video_url: e.target.value })}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37]"
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)]"
placeholder="https://youtube.com/watch?v=..."
/>
</div>
@@ -1125,7 +1125,7 @@ const BlogManagementPage: React.FC = () => {
value={formData.featured_image}
onChange={(e) => setFormData({ ...formData, featured_image: e.target.value })}
placeholder="https://images.unsplash.com/..."
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-transparent"
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-transparent"
/>
</div>
@@ -1143,7 +1143,7 @@ const BlogManagementPage: React.FC = () => {
}
}}
placeholder="Add a tag and press Enter"
className="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-transparent"
className="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-transparent"
/>
<button
type="button"
@@ -1157,13 +1157,13 @@ const BlogManagementPage: React.FC = () => {
{formData.tags?.map((tag) => (
<span
key={tag}
className="inline-flex items-center gap-1 px-3 py-1 bg-[#d4af37]/10 text-[#d4af37] rounded-full text-sm"
className="inline-flex items-center gap-1 px-3 py-1 bg-[var(--luxury-gold)]/10 text-[var(--luxury-gold)] rounded-full text-sm"
>
{tag}
<button
type="button"
onClick={() => handleRemoveTag(tag)}
className="hover:text-[#c9a227]"
className="hover:text-[var(--luxury-gold-dark)]"
>
<X className="w-3 h-3" />
</button>
@@ -1179,7 +1179,7 @@ const BlogManagementPage: React.FC = () => {
type="text"
value={formData.meta_title}
onChange={(e) => setFormData({ ...formData, meta_title: e.target.value })}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-transparent"
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-transparent"
/>
</div>
<div>
@@ -1188,7 +1188,7 @@ const BlogManagementPage: React.FC = () => {
type="text"
value={formData.meta_keywords}
onChange={(e) => setFormData({ ...formData, meta_keywords: e.target.value })}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-transparent"
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-transparent"
/>
</div>
</div>
@@ -1199,7 +1199,7 @@ const BlogManagementPage: React.FC = () => {
value={formData.meta_description}
onChange={(e) => setFormData({ ...formData, meta_description: e.target.value })}
rows={3}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-transparent"
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-transparent"
/>
</div>
@@ -1209,7 +1209,7 @@ const BlogManagementPage: React.FC = () => {
type="checkbox"
checked={formData.is_published}
onChange={(e) => setFormData({ ...formData, is_published: e.target.checked })}
className="w-4 h-4 text-[#d4af37] border-gray-300 rounded focus:ring-[#d4af37]"
className="w-4 h-4 text-[var(--luxury-gold)] border-gray-300 rounded focus:ring-[var(--luxury-gold)]"
/>
<span className="text-sm font-medium text-gray-700">Publish</span>
</label>
@@ -1220,7 +1220,7 @@ const BlogManagementPage: React.FC = () => {
type="datetime-local"
value={formData.published_at ? new Date(formData.published_at).toISOString().slice(0, 16) : ''}
onChange={(e) => setFormData({ ...formData, published_at: e.target.value ? new Date(e.target.value).toISOString() : undefined })}
className="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-transparent"
className="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-transparent"
/>
</div>
)}

File diff suppressed because it is too large Load Diff

View File

@@ -162,7 +162,7 @@ const ComplaintManagementPage: React.FC = () => {
<select
value={filters.status || ''}
onChange={(e) => setFilters({ ...filters, status: e.target.value || undefined, page: 1 })}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-transparent"
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-transparent"
>
<option value="">All Statuses</option>
<option value="open">Open</option>
@@ -177,7 +177,7 @@ const ComplaintManagementPage: React.FC = () => {
<select
value={filters.priority || ''}
onChange={(e) => setFilters({ ...filters, priority: e.target.value || undefined, page: 1 })}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-transparent"
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-transparent"
>
<option value="">All Priorities</option>
<option value="low">Low</option>
@@ -191,7 +191,7 @@ const ComplaintManagementPage: React.FC = () => {
<select
value={filters.category || ''}
onChange={(e) => setFilters({ ...filters, category: e.target.value || undefined, page: 1 })}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-transparent"
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-transparent"
>
<option value="">All Categories</option>
<option value="room_quality">Room Quality</option>
@@ -261,7 +261,7 @@ const ComplaintManagementPage: React.FC = () => {
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium">
<button
onClick={() => handleViewDetails(complaint.id)}
className="text-[#d4af37] hover:text-[#c9a227] mr-3"
className="text-[var(--luxury-gold)] hover:text-[var(--luxury-gold-dark)] mr-3"
>
<Eye className="w-5 h-5" />
</button>
@@ -415,7 +415,7 @@ const ResolveComplaintModal: React.FC<{
value={resolution}
onChange={(e) => setResolution(e.target.value)}
rows={4}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-transparent"
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-transparent"
placeholder="Describe how the complaint was resolved..."
/>
</div>
@@ -426,7 +426,7 @@ const ResolveComplaintModal: React.FC<{
<select
value={rating || ''}
onChange={(e) => setRating(e.target.value ? parseInt(e.target.value) : undefined)}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-transparent"
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-transparent"
>
<option value="">Not rated</option>
<option value="1">1 - Very Dissatisfied</option>
@@ -444,7 +444,7 @@ const ResolveComplaintModal: React.FC<{
value={feedback}
onChange={(e) => setFeedback(e.target.value)}
rows={3}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-transparent"
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-transparent"
placeholder="Guest feedback on resolution..."
/>
</div>

View File

@@ -98,7 +98,7 @@ const ComplianceReportingPage: React.FC = () => {
<button
onClick={handleExport}
disabled={generating}
className="flex items-center space-x-2 px-4 py-2 bg-[#d4af37] text-white rounded-lg hover:bg-[#c9a227] transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
className="flex items-center space-x-2 px-4 py-2 bg-[var(--luxury-gold)] text-white rounded-lg hover:bg-[var(--luxury-gold-dark)] transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
>
<Download className="w-5 h-5" />
<span>{generating ? 'Generating...' : 'Export CSV'}</span>
@@ -114,7 +114,7 @@ const ComplianceReportingPage: React.FC = () => {
type="date"
value={dateRange.start_date}
onChange={(e) => setDateRange({ ...dateRange, start_date: e.target.value })}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-transparent"
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-transparent"
/>
</div>
<div>
@@ -123,13 +123,13 @@ const ComplianceReportingPage: React.FC = () => {
type="date"
value={dateRange.end_date}
onChange={(e) => setDateRange({ ...dateRange, end_date: e.target.value })}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-transparent"
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-transparent"
/>
</div>
<div className="flex items-end">
<button
onClick={fetchComplianceData}
className="w-full px-4 py-2 bg-[#d4af37] text-white rounded-lg hover:bg-[#c9a227] transition-colors"
className="w-full px-4 py-2 bg-[var(--luxury-gold)] text-white rounded-lg hover:bg-[var(--luxury-gold-dark)] transition-colors"
>
Refresh Report
</button>

View File

@@ -117,8 +117,8 @@ const CookieSettingsPage: React.FC = () => {
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-6 pb-6 border-b border-gray-200/60">
<div className="space-y-3">
<div className="flex items-center gap-3">
<div className="p-2.5 rounded-lg bg-gradient-to-br from-[#d4af37]/10 to-[#d4af37]/5 border border-[#d4af37]/20 shadow-sm">
<Shield className="w-6 h-6 text-[#d4af37]" />
<div className="p-2.5 rounded-lg bg-gradient-to-br from-[var(--luxury-gold)]/10 to-[var(--luxury-gold)]/5 border border-[var(--luxury-gold)]/20 shadow-sm">
<Shield className="w-6 h-6 text-[var(--luxury-gold)]" />
</div>
<h1 className="enterprise-section-title">Cookie & Privacy Controls</h1>
</div>

View File

@@ -78,8 +78,8 @@ const CurrencySettingsPage: React.FC = () => {
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-6 pb-6 border-b border-gray-200/60">
<div className="space-y-3">
<div className="flex items-center gap-3">
<div className="p-2.5 rounded-lg bg-gradient-to-br from-[#d4af37]/10 to-[#d4af37]/5 border border-[#d4af37]/20 shadow-sm">
<DollarSign className="w-6 h-6 text-[#d4af37]" />
<div className="p-2.5 rounded-lg bg-gradient-to-br from-[var(--luxury-gold)]/10 to-[var(--luxury-gold)]/5 border border-[var(--luxury-gold)]/20 shadow-sm">
<DollarSign className="w-6 h-6 text-[var(--luxury-gold)]" />
</div>
<h1 className="enterprise-section-title">Platform Currency Settings</h1>
</div>

View File

@@ -124,7 +124,7 @@ const FinancialAuditTrailPage: React.FC = () => {
</div>
<button
onClick={handleExport}
className="flex items-center space-x-2 px-4 py-2 bg-[#d4af37] text-white rounded-lg hover:bg-[#c9a227] transition-colors"
className="flex items-center space-x-2 px-4 py-2 bg-[var(--luxury-gold)] text-white rounded-lg hover:bg-[var(--luxury-gold-dark)] transition-colors"
>
<Download className="w-5 h-5" />
<span>Export CSV</span>
@@ -139,7 +139,7 @@ const FinancialAuditTrailPage: React.FC = () => {
<select
value={filters.action_type || ''}
onChange={(e) => setFilters({ ...filters, action_type: e.target.value || undefined, page: 1 })}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-transparent"
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-transparent"
>
<option value="">All Actions</option>
<option value="payment_created">Payment Created</option>
@@ -159,7 +159,7 @@ const FinancialAuditTrailPage: React.FC = () => {
type="number"
value={filters.payment_id || ''}
onChange={(e) => setFilters({ ...filters, payment_id: e.target.value ? parseInt(e.target.value) : undefined, page: 1 })}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-transparent"
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-transparent"
placeholder="Filter by payment ID"
/>
</div>
@@ -169,7 +169,7 @@ const FinancialAuditTrailPage: React.FC = () => {
type="number"
value={filters.booking_id || ''}
onChange={(e) => setFilters({ ...filters, booking_id: e.target.value ? parseInt(e.target.value) : undefined, page: 1 })}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-transparent"
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-transparent"
placeholder="Filter by booking ID"
/>
</div>
@@ -230,7 +230,7 @@ const FinancialAuditTrailPage: React.FC = () => {
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium">
<button
onClick={() => handleViewDetails(record.id)}
className="text-[#d4af37] hover:text-[#c9a227]"
className="text-[var(--luxury-gold)] hover:text-[var(--luxury-gold-dark)]"
>
<Eye className="w-5 h-5" />
</button>

View File

@@ -359,4 +359,3 @@ const InvoiceManagementPage: React.FC = () => {
};
export default InvoiceManagementPage;

View File

@@ -417,7 +417,7 @@ const ProfilePage: React.FC = () => {
{}
<div className="mb-6 sm:mb-8 animate-fade-in">
<div className="flex items-center gap-2 sm:gap-3 mb-2 sm:mb-3">
<div className="h-1 w-12 sm:w-16 md:w-20 bg-gradient-to-r from-[#d4af37] via-amber-400 to-[#d4af37] rounded-full"></div>
<div className="h-1 w-12 sm:w-16 md:w-20 bg-gradient-to-r from-[var(--luxury-gold)] via-amber-400 to-[var(--luxury-gold)] rounded-full"></div>
<h1 className="text-2xl sm:text-3xl lg:text-4xl font-serif font-bold bg-gradient-to-r from-gray-900 via-amber-900/90 to-gray-900 bg-clip-text text-transparent tracking-tight">
Admin Profile & Settings
</h1>
@@ -428,61 +428,61 @@ const ProfilePage: React.FC = () => {
</div>
{}
<div className="mb-4 sm:mb-6 border-b border-[#d4af37]/20 overflow-x-auto bg-white/50 backdrop-blur-sm rounded-t-lg sm:rounded-t-xl px-4 sm:px-6">
<div className="mb-4 sm:mb-6 border-b border-[var(--luxury-gold)]/20 overflow-x-auto bg-white/50 backdrop-blur-sm rounded-t-lg sm:rounded-t-xl px-4 sm:px-6">
<div className="flex space-x-4 sm:space-x-8 min-w-max">
<button
onClick={() => setActiveTab('profile')}
className={`py-3 sm:py-4 px-2 sm:px-1 border-b-2 font-semibold text-xs sm:text-sm transition-all duration-300 whitespace-nowrap ${
activeTab === 'profile'
? 'border-[#d4af37] text-[#d4af37] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[#d4af37] hover:border-[#d4af37]/30'
? 'border-[var(--luxury-gold)] text-[var(--luxury-gold)] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[var(--luxury-gold)] hover:border-[var(--luxury-gold)]/30'
}`}
>
<User className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'profile' ? 'text-[#d4af37]' : ''}`} />
<User className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'profile' ? 'text-[var(--luxury-gold)]' : ''}`} />
Profile Information
</button>
<button
onClick={() => setActiveTab('password')}
className={`py-3 sm:py-4 px-2 sm:px-1 border-b-2 font-semibold text-xs sm:text-sm transition-all duration-300 whitespace-nowrap ${
activeTab === 'password'
? 'border-[#d4af37] text-[#d4af37] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[#d4af37] hover:border-[#d4af37]/30'
? 'border-[var(--luxury-gold)] text-[var(--luxury-gold)] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[var(--luxury-gold)] hover:border-[var(--luxury-gold)]/30'
}`}
>
<KeyRound className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'password' ? 'text-[#d4af37]' : ''}`} />
<KeyRound className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'password' ? 'text-[var(--luxury-gold)]' : ''}`} />
Change Password
</button>
<button
onClick={() => setActiveTab('mfa')}
className={`py-3 sm:py-4 px-2 sm:px-1 border-b-2 font-semibold text-xs sm:text-sm transition-all duration-300 whitespace-nowrap ${
activeTab === 'mfa'
? 'border-[#d4af37] text-[#d4af37] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[#d4af37] hover:border-[#d4af37]/30'
? 'border-[var(--luxury-gold)] text-[var(--luxury-gold)] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[var(--luxury-gold)] hover:border-[var(--luxury-gold)]/30'
}`}
>
<Shield className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'mfa' ? 'text-[#d4af37]' : ''}`} />
<Shield className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'mfa' ? 'text-[var(--luxury-gold)]' : ''}`} />
Two-Factor Authentication
</button>
<button
onClick={() => setActiveTab('sessions')}
className={`py-3 sm:py-4 px-2 sm:px-1 border-b-2 font-semibold text-xs sm:text-sm transition-all duration-300 whitespace-nowrap ${
activeTab === 'sessions'
? 'border-[#d4af37] text-[#d4af37] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[#d4af37] hover:border-[#d4af37]/30'
? 'border-[var(--luxury-gold)] text-[var(--luxury-gold)] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[var(--luxury-gold)] hover:border-[var(--luxury-gold)]/30'
}`}
>
<Monitor className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'sessions' ? 'text-[#d4af37]' : ''}`} />
<Monitor className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'sessions' ? 'text-[var(--luxury-gold)]' : ''}`} />
Active Sessions
</button>
<button
onClick={() => setActiveTab('gdpr')}
className={`py-3 sm:py-4 px-2 sm:px-1 border-b-2 font-semibold text-xs sm:text-sm transition-all duration-300 whitespace-nowrap ${
activeTab === 'gdpr'
? 'border-[#d4af37] text-[#d4af37] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[#d4af37] hover:border-[#d4af37]/30'
? 'border-[var(--luxury-gold)] text-[var(--luxury-gold)] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[var(--luxury-gold)] hover:border-[var(--luxury-gold)]/30'
}`}
>
<Database className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'gdpr' ? 'text-[#d4af37]' : ''}`} />
<Database className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'gdpr' ? 'text-[var(--luxury-gold)]' : ''}`} />
Data Privacy
</button>
</div>
@@ -490,7 +490,7 @@ const ProfilePage: React.FC = () => {
{}
{activeTab === 'profile' && (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl animate-slide-up">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl animate-slide-up">
<form onSubmit={handleSubmitProfile(onSubmitProfile)} className="space-y-5 sm:space-y-6">
{}
<div className="flex flex-col sm:flex-row items-center sm:items-start gap-4 sm:gap-6 pb-5 sm:pb-6 border-b border-gray-200">
@@ -499,20 +499,20 @@ const ProfilePage: React.FC = () => {
<img
src={avatarPreview || normalizeImageUrl(userInfo?.avatar)}
alt="Profile"
className="w-20 h-20 sm:w-24 sm:h-24 rounded-full object-cover ring-4 ring-[#d4af37]/20 shadow-lg"
className="w-20 h-20 sm:w-24 sm:h-24 rounded-full object-cover ring-4 ring-[var(--luxury-gold)]/20 shadow-lg"
onError={() => {
// If image fails to load, show default avatar
setAvatarError(true);
}}
/>
) : (
<div className="w-20 h-20 sm:w-24 sm:h-24 rounded-full bg-gradient-to-br from-[#d4af37] to-[#c9a227] flex items-center justify-center ring-4 ring-[#d4af37]/20 shadow-lg">
<div className="w-20 h-20 sm:w-24 sm:h-24 rounded-full bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] flex items-center justify-center ring-4 ring-[var(--luxury-gold)]/20 shadow-lg">
<User className="w-10 h-10 sm:w-12 sm:h-12 text-white" />
</div>
)}
<label
htmlFor="avatar-upload"
className="absolute bottom-0 right-0 p-2 bg-gradient-to-br from-[#d4af37] to-[#c9a227] rounded-full cursor-pointer hover:from-[#f5d76e] hover:to-[#d4af37] transition-all duration-300 shadow-lg hover:shadow-xl hover:shadow-[#d4af37]/40 hover:-translate-y-0.5 active:translate-y-0"
className="absolute bottom-0 right-0 p-2 bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] rounded-full cursor-pointer hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] transition-all duration-300 shadow-lg hover:shadow-xl hover:shadow-[var(--luxury-gold)]/40 hover:-translate-y-0.5 active:translate-y-0"
>
<Camera className="w-3.5 h-3.5 sm:w-4 sm:h-4 text-white" />
<input
@@ -528,7 +528,7 @@ const ProfilePage: React.FC = () => {
<div>
<label className="block text-sm sm:text-base font-medium text-gray-700 mb-2">
<User className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[#d4af37]" />
<User className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[var(--luxury-gold)]" />
Full Name
<span className="text-red-500 ml-1">*</span>
</label>
@@ -551,7 +551,7 @@ const ProfilePage: React.FC = () => {
{}
<div>
<label className="block text-sm sm:text-base font-medium text-gray-700 mb-2">
<Mail className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[#d4af37]" />
<Mail className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[var(--luxury-gold)]" />
Email Address
<span className="text-red-500 ml-1">*</span>
</label>
@@ -574,7 +574,7 @@ const ProfilePage: React.FC = () => {
{}
<div>
<label className="block text-sm sm:text-base font-medium text-gray-700 mb-2">
<Phone className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[#d4af37]" />
<Phone className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[var(--luxury-gold)]" />
Phone Number
<span className="text-red-500 ml-1">*</span>
</label>
@@ -611,7 +611,7 @@ const ProfilePage: React.FC = () => {
{}
{activeTab === 'password' && (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl animate-slide-up">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl animate-slide-up">
<form onSubmit={handleSubmitPassword(onSubmitPassword)} className="space-y-5 sm:space-y-6">
{}
<div className="bg-gradient-to-r from-blue-50 to-indigo-50 border border-blue-200/60 rounded-sm p-4 sm:p-5">
@@ -640,7 +640,7 @@ const ProfilePage: React.FC = () => {
{}
<div>
<label className="block text-sm sm:text-base font-medium text-gray-700 mb-2">
<Lock className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[#d4af37]" />
<Lock className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[var(--luxury-gold)]" />
Current Password
<span className="text-red-500 ml-1">*</span>
</label>
@@ -656,7 +656,7 @@ const ProfilePage: React.FC = () => {
<button
type="button"
onClick={() => setShowPassword({ ...showPassword, current: !showPassword.current })}
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[#d4af37] transition-colors"
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[var(--luxury-gold)] transition-colors"
>
{showPassword.current ? (
<EyeOff className="w-4 h-4 sm:w-5 sm:h-5" />
@@ -676,7 +676,7 @@ const ProfilePage: React.FC = () => {
{}
<div>
<label className="block text-sm sm:text-base font-medium text-gray-700 mb-2">
<Lock className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[#d4af37]" />
<Lock className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[var(--luxury-gold)]" />
New Password
<span className="text-red-500 ml-1">*</span>
</label>
@@ -692,7 +692,7 @@ const ProfilePage: React.FC = () => {
<button
type="button"
onClick={() => setShowPassword({ ...showPassword, new: !showPassword.new })}
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[#d4af37] transition-colors"
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[var(--luxury-gold)] transition-colors"
>
{showPassword.new ? (
<EyeOff className="w-4 h-4 sm:w-5 sm:h-5" />
@@ -712,7 +712,7 @@ const ProfilePage: React.FC = () => {
{}
<div>
<label className="block text-sm sm:text-base font-medium text-gray-700 mb-2">
<Lock className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[#d4af37]" />
<Lock className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[var(--luxury-gold)]" />
Confirm New Password
<span className="text-red-500 ml-1">*</span>
</label>
@@ -728,7 +728,7 @@ const ProfilePage: React.FC = () => {
<button
type="button"
onClick={() => setShowPassword({ ...showPassword, confirm: !showPassword.confirm })}
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[#d4af37] transition-colors"
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[var(--luxury-gold)] transition-colors"
>
{showPassword.confirm ? (
<EyeOff className="w-4 h-4 sm:w-5 sm:h-5" />
@@ -762,11 +762,11 @@ const ProfilePage: React.FC = () => {
{}
{activeTab === 'mfa' && (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl animate-slide-up space-y-5 sm:space-y-6">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl animate-slide-up space-y-5 sm:space-y-6">
{}
<div>
<h2 className="text-xl sm:text-2xl font-serif font-semibold text-gray-900 mb-2 flex items-center gap-2">
<Shield className="w-5 h-5 sm:w-6 sm:h-6 text-[#d4af37]" />
<Shield className="w-5 h-5 sm:w-6 sm:h-6 text-[var(--luxury-gold)]" />
Two-Factor Authentication
</h2>
<p className="text-xs sm:text-sm text-gray-600 font-light leading-relaxed">
@@ -838,7 +838,7 @@ const ProfilePage: React.FC = () => {
{}
<div className="bg-white border border-gray-200 rounded-sm p-4 sm:p-5">
<h3 className="text-sm sm:text-base font-semibold text-gray-900 mb-2 flex items-center gap-2">
<RefreshCw className="w-4 h-4 sm:w-5 sm:h-5 text-[#d4af37]" />
<RefreshCw className="w-4 h-4 sm:w-5 sm:h-5 text-[var(--luxury-gold)]" />
Backup Codes
</h3>
<p className="text-xs sm:text-sm text-gray-600 font-light mb-4 leading-relaxed">
@@ -984,7 +984,7 @@ const ProfilePage: React.FC = () => {
{}
<div className="bg-white border border-gray-200 rounded-sm p-4 sm:p-5">
<h3 className="font-semibold text-gray-900 mb-2 text-sm sm:text-base flex items-center gap-2">
<KeyRound className="w-4 h-4 sm:w-5 sm:h-5 text-[#d4af37]" />
<KeyRound className="w-4 h-4 sm:w-5 sm:h-5 text-[var(--luxury-gold)]" />
Step 2: Verify Setup
</h3>
<p className="text-xs sm:text-sm text-gray-600 font-light mb-4 leading-relaxed">
@@ -1110,10 +1110,10 @@ const SessionsTab: React.FC = () => {
};
const getDeviceIcon = (userAgent?: string) => {
if (!userAgent) return <Monitor className="w-5 h-5 text-[#d4af37]" />;
if (!userAgent) return <Monitor className="w-5 h-5 text-[var(--luxury-gold)]" />;
if (userAgent.includes('Mobile')) return <Smartphone className="w-5 h-5 text-blue-500" />;
if (userAgent.includes('Tablet')) return <Tablet className="w-5 h-5 text-purple-500" />;
return <Monitor className="w-5 h-5 text-[#d4af37]" />;
return <Monitor className="w-5 h-5 text-[var(--luxury-gold)]" />;
};
const getDeviceName = (userAgent?: string) => {
@@ -1181,17 +1181,17 @@ const SessionsTab: React.FC = () => {
if (loading) {
return (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl">
<Loading text="Loading sessions..." />
</div>
);
}
return (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl animate-slide-up space-y-5 sm:space-y-6">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl animate-slide-up space-y-5 sm:space-y-6">
<div>
<h2 className="text-xl sm:text-2xl font-serif font-semibold text-gray-900 mb-2 flex items-center gap-2">
<Monitor className="w-5 h-5 sm:w-6 sm:h-6 text-[#d4af37]" />
<Monitor className="w-5 h-5 sm:w-6 sm:h-6 text-[var(--luxury-gold)]" />
Active Sessions
</h2>
<p className="text-xs sm:text-sm text-gray-600 font-light">
@@ -1220,11 +1220,11 @@ const SessionsTab: React.FC = () => {
{sessions.map((session) => (
<div
key={session.id}
className="bg-gradient-to-r from-slate-50 to-white border border-[#d4af37]/20 rounded-sm p-4 sm:p-5 hover:shadow-lg hover:border-[#d4af37]/40 transition-all duration-300"
className="bg-gradient-to-r from-slate-50 to-white border border-[var(--luxury-gold)]/20 rounded-sm p-4 sm:p-5 hover:shadow-lg hover:border-[var(--luxury-gold)]/40 transition-all duration-300"
>
<div className="flex items-start justify-between gap-4">
<div className="flex items-start gap-4 flex-1">
<div className="p-2 sm:p-3 bg-gradient-to-br from-[#d4af37]/10 to-[#c9a227]/10 rounded-sm flex-shrink-0">
<div className="p-2 sm:p-3 bg-gradient-to-br from-[var(--luxury-gold)]/10 to-[var(--luxury-gold-dark)]/10 rounded-sm flex-shrink-0">
{getDeviceIcon(session.user_agent)}
</div>
<div className="flex-1 min-w-0">
@@ -1354,17 +1354,17 @@ const GDPRTab: React.FC = () => {
if (loading) {
return (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl">
<Loading text="Loading privacy data..." />
</div>
);
}
return (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl animate-slide-up space-y-5 sm:space-y-6">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl animate-slide-up space-y-5 sm:space-y-6">
<div>
<h2 className="text-xl sm:text-2xl font-serif font-semibold text-gray-900 mb-2 flex items-center gap-2">
<Database className="w-5 h-5 sm:w-6 sm:h-6 text-[#d4af37]" />
<Database className="w-5 h-5 sm:w-6 sm:h-6 text-[var(--luxury-gold)]" />
Data Privacy & GDPR Rights
</h2>
<p className="text-xs sm:text-sm text-gray-600 font-light">
@@ -1431,14 +1431,14 @@ const GDPRTab: React.FC = () => {
{requests.length > 0 && (
<div className="border-t border-gray-200 pt-5 sm:pt-6">
<h3 className="text-base sm:text-lg font-semibold text-gray-900 mb-4 flex items-center gap-2">
<FileText className="w-5 h-5 text-[#d4af37]" />
<FileText className="w-5 h-5 text-[var(--luxury-gold)]" />
Request History
</h3>
<div className="space-y-3 sm:space-y-4">
{requests.map((request) => (
<div
key={request.id}
className="bg-gradient-to-r from-slate-50 to-white border border-[#d4af37]/20 rounded-sm p-4 sm:p-5 hover:shadow-md hover:border-[#d4af37]/40 transition-all duration-300"
className="bg-gradient-to-r from-slate-50 to-white border border-[var(--luxury-gold)]/20 rounded-sm p-4 sm:p-5 hover:shadow-md hover:border-[var(--luxury-gold)]/40 transition-all duration-300"
>
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 sm:gap-4">
<div className="flex-1 min-w-0">

View File

@@ -0,0 +1,859 @@
import React, { useEffect, useState } from 'react';
import {
Tag,
Search,
Plus,
Edit,
Trash2,
Filter,
X,
} from 'lucide-react';
import { toast } from 'react-toastify';
import Loading from '../../shared/components/Loading';
import Pagination from '../../shared/components/Pagination';
import { useFormatCurrency } from '../../features/payments/hooks/useFormatCurrency';
import { useCurrency } from '../../features/payments/contexts/CurrencyContext';
import promotionService, { Promotion } from '../../features/loyalty/services/promotionService';
import { getRoomTypes } from '../../features/rooms/services/roomService';
interface RoomType {
id: number;
name: string;
}
const PromotionsManagementPage: React.FC = () => {
const { formatCurrency } = useFormatCurrency();
const { currency } = useCurrency();
const [promotions, setPromotions] = useState<Promotion[]>([]);
const [promotionsLoading, setPromotionsLoading] = useState(true);
const [showPromotionModal, setShowPromotionModal] = useState(false);
const [editingPromotion, setEditingPromotion] = useState<Promotion | null>(null);
const [promotionFilters, setPromotionFilters] = useState({
search: '',
status: '',
type: '',
});
const [promotionsCurrentPage, setPromotionsCurrentPage] = useState(1);
const [promotionsTotalPages, setPromotionsTotalPages] = useState(1);
const [promotionsTotalItems, setPromotionsTotalItems] = useState(0);
const promotionsPerPage = 5;
const [promotionFormData, setPromotionFormData] = useState({
code: '',
name: '',
description: '',
discount_type: 'percentage' as 'percentage' | 'fixed',
discount_value: 0,
min_booking_amount: 0,
max_discount_amount: 0,
min_stay_days: 0,
max_stay_days: 0,
advance_booking_days: 0,
max_advance_booking_days: 0,
allowed_check_in_days: [] as number[],
allowed_check_out_days: [] as number[],
allowed_room_type_ids: [] as number[],
excluded_room_type_ids: [] as number[],
min_guests: 0,
max_guests: 0,
first_time_customer_only: false,
repeat_customer_only: false,
blackout_dates: [] as string[],
start_date: '',
end_date: '',
usage_limit: 0,
status: 'active' as 'active' | 'inactive' | 'expired',
});
const [roomTypes, setRoomTypes] = useState<RoomType[]>([]);
useEffect(() => {
fetchPromotions();
}, [promotionFilters, promotionsCurrentPage]);
useEffect(() => {
fetchRoomTypes();
}, []);
useEffect(() => {
setPromotionsCurrentPage(1);
}, [promotionFilters]);
const fetchRoomTypes = async () => {
try {
const response = await getRoomTypes();
if (response.success && response.data.room_types) {
setRoomTypes(response.data.room_types);
}
} catch (error: any) {
console.error('Failed to fetch room types:', error);
}
};
const fetchPromotions = async () => {
try {
setPromotionsLoading(true);
const response = await promotionService.getPromotions({
...promotionFilters,
page: promotionsCurrentPage,
limit: promotionsPerPage,
});
setPromotions(response.data.promotions);
if (response.data.pagination) {
setPromotionsTotalPages(response.data.pagination.totalPages);
setPromotionsTotalItems(response.data.pagination.total);
}
} catch (error: any) {
toast.error(error.response?.data?.message || 'Unable to load promotions list');
} finally {
setPromotionsLoading(false);
}
};
const handlePromotionSubmit = async (e: React.FormEvent) => {
e.preventDefault();
try {
const submitData: any = {
...promotionFormData,
min_stay_days: promotionFormData.min_stay_days || undefined,
max_stay_days: promotionFormData.max_stay_days || undefined,
advance_booking_days: promotionFormData.advance_booking_days || undefined,
max_advance_booking_days: promotionFormData.max_advance_booking_days || undefined,
min_guests: promotionFormData.min_guests || undefined,
max_guests: promotionFormData.max_guests || undefined,
allowed_check_in_days: promotionFormData.allowed_check_in_days?.length ? promotionFormData.allowed_check_in_days : undefined,
allowed_check_out_days: promotionFormData.allowed_check_out_days?.length ? promotionFormData.allowed_check_out_days : undefined,
allowed_room_type_ids: promotionFormData.allowed_room_type_ids?.length ? promotionFormData.allowed_room_type_ids : undefined,
excluded_room_type_ids: promotionFormData.excluded_room_type_ids?.length ? promotionFormData.excluded_room_type_ids : undefined,
blackout_dates: promotionFormData.blackout_dates?.length ? promotionFormData.blackout_dates : undefined,
min_booking_amount: promotionFormData.min_booking_amount || undefined,
max_discount_amount: promotionFormData.max_discount_amount || undefined,
usage_limit: promotionFormData.usage_limit || undefined,
};
if (editingPromotion) {
await promotionService.updatePromotion(editingPromotion.id, submitData);
toast.success('Promotion updated successfully');
} else {
await promotionService.createPromotion(submitData);
toast.success('Promotion added successfully');
}
setShowPromotionModal(false);
resetPromotionForm();
fetchPromotions();
} catch (error: any) {
toast.error(error.response?.data?.message || 'An error occurred');
}
};
const handleEditPromotion = (promotion: Promotion) => {
setEditingPromotion(promotion);
setPromotionFormData({
code: promotion.code,
name: promotion.name,
description: promotion.description || '',
discount_type: promotion.discount_type,
discount_value: promotion.discount_value,
min_booking_amount: promotion.min_booking_amount || 0,
max_discount_amount: promotion.max_discount_amount || 0,
min_stay_days: promotion.min_stay_days || 0,
max_stay_days: promotion.max_stay_days || 0,
advance_booking_days: promotion.advance_booking_days || 0,
max_advance_booking_days: promotion.max_advance_booking_days || 0,
allowed_check_in_days: promotion.allowed_check_in_days || [],
allowed_check_out_days: promotion.allowed_check_out_days || [],
allowed_room_type_ids: promotion.allowed_room_type_ids || [],
excluded_room_type_ids: promotion.excluded_room_type_ids || [],
min_guests: promotion.min_guests || 0,
max_guests: promotion.max_guests || 0,
first_time_customer_only: promotion.first_time_customer_only || false,
repeat_customer_only: promotion.repeat_customer_only || false,
blackout_dates: promotion.blackout_dates || [],
start_date: promotion.start_date?.split('T')[0] || '',
end_date: promotion.end_date?.split('T')[0] || '',
usage_limit: promotion.usage_limit || 0,
status: promotion.status,
});
setShowPromotionModal(true);
};
const handleDeletePromotion = async (id: number) => {
if (!window.confirm('Are you sure you want to delete this promotion?')) return;
try {
await promotionService.deletePromotion(id);
toast.success('Promotion deleted successfully');
fetchPromotions();
} catch (error: any) {
toast.error(error.response?.data?.message || 'Unable to delete promotion');
}
};
const resetPromotionForm = () => {
setEditingPromotion(null);
setPromotionFormData({
code: '',
name: '',
description: '',
discount_type: 'percentage',
discount_value: 0,
min_booking_amount: 0,
max_discount_amount: 0,
min_stay_days: 0,
max_stay_days: 0,
advance_booking_days: 0,
max_advance_booking_days: 0,
allowed_check_in_days: [],
allowed_check_out_days: [],
allowed_room_type_ids: [],
excluded_room_type_ids: [],
min_guests: 0,
max_guests: 0,
first_time_customer_only: false,
repeat_customer_only: false,
blackout_dates: [],
start_date: '',
end_date: '',
usage_limit: 0,
status: 'active',
});
};
const getPromotionStatusBadge = (status: string) => {
const badges: Record<string, { bg: string; text: string; label: string; border: string }> = {
active: { bg: 'bg-gradient-to-r from-emerald-50 to-green-50', text: 'text-emerald-800', label: 'Active', border: 'border-emerald-200' },
inactive: { bg: 'bg-gradient-to-r from-slate-50 to-gray-50', text: 'text-slate-700', label: 'Inactive', border: 'border-slate-200' },
expired: { bg: 'bg-gradient-to-r from-rose-50 to-red-50', text: 'text-rose-800', label: 'Expired', border: 'border-rose-200' },
};
const badge = badges[status] || badges.active;
return (
<span className={`px-4 py-1.5 rounded-full text-xs font-semibold border shadow-sm ${badge.bg} ${badge.text} ${badge.border}`}>
{badge.label}
</span>
);
};
return (
<div className="min-h-screen bg-gradient-to-br from-slate-50 via-white to-slate-50 -m-6 p-8">
<div className="space-y-8">
{}
<div className="bg-white/90 backdrop-blur-xl rounded-2xl shadow-xl border border-gray-200/50 p-8">
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-6">
<div className="space-y-3">
<div className="flex items-center gap-3">
<div className="p-2.5 rounded-xl bg-gradient-to-br from-purple-500/10 to-pink-500/10 border border-purple-200/40">
<Tag className="w-6 h-6 text-purple-600" />
</div>
<h2 className="text-3xl font-extrabold text-gray-900">Promotion Management</h2>
</div>
<p className="text-gray-600 text-base max-w-2xl leading-relaxed">
Manage discount codes and promotional campaigns
</p>
</div>
<button
onClick={() => {
resetPromotionForm();
setShowPromotionModal(true);
}}
className="group relative px-8 py-4 bg-gradient-to-r from-purple-500 via-purple-500 to-pink-600 text-white font-semibold rounded-xl shadow-xl shadow-purple-500/30 hover:shadow-2xl hover:shadow-purple-500/40 transition-all duration-300 hover:scale-105 overflow-hidden"
>
<div className="absolute inset-0 bg-gradient-to-r from-transparent via-white/20 to-transparent translate-x-[-100%] group-hover:translate-x-[100%] transition-transform duration-1000"></div>
<div className="relative flex items-center gap-3">
<Plus className="w-5 h-5" />
Add Promotion
</div>
</button>
</div>
</div>
{}
<div className="relative bg-white/90 backdrop-blur-xl rounded-2xl shadow-xl border border-gray-200/50 p-8">
<div className="flex items-center gap-3 mb-6">
<div className="p-2 rounded-xl bg-gradient-to-br from-amber-500/10 to-amber-600/10 border border-amber-200/40">
<Filter className="w-5 h-5 text-amber-600" />
</div>
<h3 className="text-xl font-bold text-gray-900">Filters</h3>
</div>
<div className="grid grid-cols-1 md:grid-cols-4 gap-6">
<div className="relative group">
<Search className="absolute left-4 top-1/2 transform -translate-y-1/2 text-gray-400 w-5 h-5 group-focus-within:text-purple-500 transition-colors" />
<input
type="text"
placeholder="Search by code or name..."
value={promotionFilters.search}
onChange={(e) => setPromotionFilters({ ...promotionFilters, search: e.target.value })}
className="w-full pl-12 pr-4 py-3.5 bg-white border-2 border-gray-200 rounded-xl focus:border-purple-400 focus:ring-4 focus:ring-purple-100 transition-all duration-200 text-gray-700 placeholder-gray-400 font-medium shadow-sm hover:shadow-md"
/>
</div>
<select
value={promotionFilters.type}
onChange={(e) => setPromotionFilters({ ...promotionFilters, type: e.target.value })}
className="px-4 py-3.5 bg-white border-2 border-gray-200 rounded-xl focus:border-purple-400 focus:ring-4 focus:ring-purple-100 transition-all duration-200 text-gray-700 font-medium shadow-sm hover:shadow-md cursor-pointer"
>
<option value="">All Types</option>
<option value="percentage">Percentage</option>
<option value="fixed">Fixed Amount</option>
</select>
<select
value={promotionFilters.status}
onChange={(e) => setPromotionFilters({ ...promotionFilters, status: e.target.value })}
className="px-4 py-3.5 bg-white border-2 border-gray-200 rounded-xl focus:border-purple-400 focus:ring-4 focus:ring-purple-100 transition-all duration-200 text-gray-700 font-medium shadow-sm hover:shadow-md cursor-pointer"
>
<option value="">All Statuses</option>
<option value="active">Active</option>
<option value="inactive">Inactive</option>
</select>
</div>
</div>
{}
{promotionsLoading && promotions.length === 0 ? (
<Loading fullScreen text="Loading promotions..." />
) : (
<div className="relative bg-white/90 backdrop-blur-xl rounded-2xl shadow-xl border border-gray-200/50 overflow-hidden">
<div className="overflow-x-auto">
<table className="w-full">
<thead className="bg-gradient-to-r from-gray-50 to-gray-100">
<tr>
<th className="px-8 py-5 text-left text-xs font-bold text-gray-700 uppercase tracking-wider border-b border-gray-200">Code</th>
<th className="px-8 py-5 text-left text-xs font-bold text-gray-700 uppercase tracking-wider border-b border-gray-200">Program Name</th>
<th className="px-8 py-5 text-left text-xs font-bold text-gray-700 uppercase tracking-wider border-b border-gray-200">Value</th>
<th className="px-8 py-5 text-left text-xs font-bold text-gray-700 uppercase tracking-wider border-b border-gray-200">Period</th>
<th className="px-8 py-5 text-left text-xs font-bold text-gray-700 uppercase tracking-wider border-b border-gray-200">Used</th>
<th className="px-8 py-5 text-left text-xs font-bold text-gray-700 uppercase tracking-wider border-b border-gray-200">Status</th>
<th className="px-8 py-5 text-right text-xs font-bold text-gray-700 uppercase tracking-wider border-b border-gray-200">Actions</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-100">
{promotions.map((promotion) => (
<tr key={promotion.id} className="hover:bg-gray-50 transition-colors">
<td className="px-8 py-5 whitespace-nowrap">
<div className="flex items-center gap-3">
<div className="p-2 bg-gradient-to-br from-purple-100 to-purple-200 rounded-lg">
<Tag className="w-4 h-4 text-purple-600" />
</div>
<span className="text-sm font-mono font-bold bg-gradient-to-r from-purple-600 to-purple-700 bg-clip-text text-transparent">{promotion.code}</span>
</div>
</td>
<td className="px-8 py-5">
<div className="text-sm font-semibold text-gray-900">{promotion.name}</div>
<div className="text-xs text-gray-500 mt-0.5">{promotion.description}</div>
</td>
<td className="px-8 py-5 whitespace-nowrap">
<div className="text-sm font-bold bg-gradient-to-r from-emerald-600 to-emerald-700 bg-clip-text text-transparent">
{promotion.discount_type === 'percentage'
? `${promotion.discount_value}%`
: formatCurrency(promotion.discount_value)}
</div>
</td>
<td className="px-8 py-5 whitespace-nowrap">
<div className="text-xs text-gray-600">
{promotion.start_date ? new Date(promotion.start_date).toLocaleDateString('en-US', { month: 'short', day: 'numeric' }) : 'N/A'}
<span className="text-gray-400 mx-1"></span>
{promotion.end_date ? new Date(promotion.end_date).toLocaleDateString('en-US', { month: 'short', day: 'numeric' }) : 'N/A'}
</div>
</td>
<td className="px-8 py-5 whitespace-nowrap">
<div className="text-sm font-medium text-gray-700">
<span className="text-purple-600 font-semibold">{promotion.used_count || 0}</span>
<span className="text-gray-400 mx-1">/</span>
<span className="text-gray-600">{promotion.usage_limit || '∞'}</span>
</div>
</td>
<td className="px-8 py-5 whitespace-nowrap">
{getPromotionStatusBadge(promotion.status)}
</td>
<td className="px-8 py-5 whitespace-nowrap text-right">
<div className="flex items-center justify-end gap-2">
<button
onClick={() => handleEditPromotion(promotion)}
className="p-2 rounded-lg text-blue-600 hover:text-blue-700 hover:bg-blue-50 transition-all duration-200 shadow-sm hover:shadow-md border border-blue-200 hover:border-blue-300"
title="Edit"
>
<Edit className="w-5 h-5" />
</button>
<button
onClick={() => handleDeletePromotion(promotion.id)}
className="p-2 rounded-lg text-rose-600 hover:text-rose-700 hover:bg-rose-50 transition-all duration-200 shadow-sm hover:shadow-md border border-rose-200 hover:border-rose-300"
title="Delete"
>
<Trash2 className="w-5 h-5" />
</button>
</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
<Pagination
currentPage={promotionsCurrentPage}
totalPages={promotionsTotalPages}
onPageChange={setPromotionsCurrentPage}
totalItems={promotionsTotalItems}
itemsPerPage={promotionsPerPage}
/>
</div>
)}
</div>
{}
{showPromotionModal && (
<div className="fixed inset-0 bg-black/70 backdrop-blur-md z-50 overflow-y-auto p-3 sm:p-4">
<div className="min-h-full flex items-center justify-center py-4">
<div className="bg-white rounded-2xl sm:rounded-3xl shadow-2xl max-w-5xl w-full my-4 flex flex-col border border-gray-200" style={{ maxHeight: 'calc(100vh - 2rem)' }}>
<div className="bg-gradient-to-r from-slate-900 via-slate-800 to-slate-900 px-4 sm:px-6 md:px-8 py-4 sm:py-5 md:py-6 border-b border-slate-700 flex-shrink-0">
<div className="flex justify-between items-center">
<div>
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold text-purple-100 mb-1">
{editingPromotion ? 'Update Promotion' : 'Add New Promotion'}
</h2>
<p className="text-purple-200/80 text-xs sm:text-sm font-light">
{editingPromotion ? 'Modify promotion details' : 'Create a new promotion program'}
</p>
</div>
<button
onClick={() => setShowPromotionModal(false)}
className="w-9 h-9 sm:w-10 sm:h-10 flex items-center justify-center rounded-xl text-purple-100 hover:text-white hover:bg-slate-700/50 transition-all duration-200 border border-slate-600 hover:border-purple-400"
>
<X className="w-5 h-5 sm:w-6 sm:h-6" />
</button>
</div>
</div>
<div className="flex-1 overflow-y-auto min-h-0">
<form onSubmit={handlePromotionSubmit} className="p-4 sm:p-6 md:p-8 space-y-4 sm:space-y-5 md:space-y-6">
<div className="grid grid-cols-2 gap-6">
<div>
<label className="block text-xs font-semibold text-gray-600 uppercase tracking-wider mb-2">
Code <span className="text-red-500">*</span>
</label>
<input
type="text"
value={promotionFormData.code}
onChange={(e) => setPromotionFormData({ ...promotionFormData, code: e.target.value.toUpperCase() })}
className="w-full px-4 py-3 bg-white border-2 border-gray-200 rounded-xl focus:border-purple-400 focus:ring-4 focus:ring-purple-100 transition-all duration-200 text-gray-700 font-medium shadow-sm font-mono"
placeholder="e.g: SUMMER2024"
required
/>
</div>
<div>
<label className="block text-xs font-semibold text-gray-600 uppercase tracking-wider mb-2">
Program Name <span className="text-red-500">*</span>
</label>
<input
type="text"
value={promotionFormData.name}
onChange={(e) => setPromotionFormData({ ...promotionFormData, name: e.target.value })}
className="w-full px-4 py-3 bg-white border-2 border-gray-200 rounded-xl focus:border-purple-400 focus:ring-4 focus:ring-purple-100 transition-all duration-200 text-gray-700 font-medium shadow-sm"
placeholder="e.g: Summer Sale"
required
/>
</div>
</div>
<div>
<label className="block text-xs font-semibold text-gray-600 uppercase tracking-wider mb-2">
Description
</label>
<textarea
value={promotionFormData.description}
onChange={(e) => setPromotionFormData({ ...promotionFormData, description: e.target.value })}
className="w-full px-4 py-3 bg-white border-2 border-gray-200 rounded-xl focus:border-purple-400 focus:ring-4 focus:ring-purple-100 transition-all duration-200 text-gray-700 font-medium shadow-sm"
rows={3}
placeholder="Detailed description of the program..."
/>
</div>
<div className="grid grid-cols-2 gap-6">
<div>
<label className="block text-xs font-semibold text-gray-600 uppercase tracking-wider mb-2">
Discount Type <span className="text-red-500">*</span>
</label>
<select
value={promotionFormData.discount_type}
onChange={(e) => setPromotionFormData({ ...promotionFormData, discount_type: e.target.value as 'percentage' | 'fixed' })}
className="w-full px-4 py-3 bg-white border-2 border-gray-200 rounded-xl focus:border-purple-400 focus:ring-4 focus:ring-purple-100 transition-all duration-200 text-gray-700 font-medium shadow-sm cursor-pointer"
>
<option value="percentage">Percentage (%)</option>
<option value="fixed">Fixed Amount ({currency})</option>
</select>
</div>
<div>
<label className="block text-xs font-semibold text-gray-600 uppercase tracking-wider mb-2">
Discount Value <span className="text-red-500">*</span>
</label>
<input
type="number"
value={promotionFormData.discount_value}
onChange={(e) => setPromotionFormData({ ...promotionFormData, discount_value: parseFloat(e.target.value) })}
className="w-full px-4 py-3 bg-white border-2 border-gray-200 rounded-xl focus:border-purple-400 focus:ring-4 focus:ring-purple-100 transition-all duration-200 text-gray-700 font-medium shadow-sm"
min="0"
max={promotionFormData.discount_type === 'percentage' ? 100 : undefined}
required
/>
</div>
</div>
<div className="grid grid-cols-2 gap-6">
<div>
<label className="block text-xs font-semibold text-gray-600 uppercase tracking-wider mb-2">
Minimum Order Value ({currency})
</label>
<input
type="number"
value={promotionFormData.min_booking_amount}
onChange={(e) => setPromotionFormData({ ...promotionFormData, min_booking_amount: parseFloat(e.target.value) })}
className="w-full px-4 py-3 bg-white border-2 border-gray-200 rounded-xl focus:border-purple-400 focus:ring-4 focus:ring-purple-100 transition-all duration-200 text-gray-700 font-medium shadow-sm"
min="0"
/>
</div>
<div>
<label className="block text-xs font-semibold text-gray-600 uppercase tracking-wider mb-2">
Maximum Discount ({currency})
</label>
<input
type="number"
value={promotionFormData.max_discount_amount}
onChange={(e) => setPromotionFormData({ ...promotionFormData, max_discount_amount: parseFloat(e.target.value) })}
className="w-full px-4 py-3 bg-white border-2 border-gray-200 rounded-xl focus:border-purple-400 focus:ring-4 focus:ring-purple-100 transition-all duration-200 text-gray-700 font-medium shadow-sm"
min="0"
/>
</div>
</div>
{/* Enterprise Booking Conditions Section */}
<div className="border-t-2 border-purple-200 pt-6 mt-6">
<h3 className="text-lg font-bold text-gray-900 mb-4 flex items-center gap-2">
<div className="h-1 w-8 bg-gradient-to-r from-purple-400 to-purple-600 rounded-full"></div>
Enterprise Booking Conditions
</h3>
<p className="text-sm text-gray-600 mb-6">Configure advanced conditions for when this promotion applies</p>
</div>
<div className="grid grid-cols-2 gap-6">
<div>
<label className="block text-xs font-semibold text-gray-600 uppercase tracking-wider mb-2">
Minimum Stay (nights)
</label>
<input
type="number"
value={promotionFormData.min_stay_days || ''}
onChange={(e) => setPromotionFormData({ ...promotionFormData, min_stay_days: parseInt(e.target.value) || 0 })}
className="w-full px-4 py-3 bg-white border-2 border-gray-200 rounded-xl focus:border-purple-400 focus:ring-4 focus:ring-purple-100 transition-all duration-200 text-gray-700 font-medium shadow-sm"
min="0"
placeholder="0 = no minimum"
/>
<p className="text-xs text-gray-500 mt-1">Minimum number of nights required for booking</p>
</div>
<div>
<label className="block text-xs font-semibold text-gray-600 uppercase tracking-wider mb-2">
Advance Booking (days)
</label>
<input
type="number"
value={promotionFormData.advance_booking_days || ''}
onChange={(e) => setPromotionFormData({ ...promotionFormData, advance_booking_days: parseInt(e.target.value) || 0 })}
className="w-full px-4 py-3 bg-white border-2 border-gray-200 rounded-xl focus:border-purple-400 focus:ring-4 focus:ring-purple-100 transition-all duration-200 text-gray-700 font-medium shadow-sm"
min="0"
placeholder="0 = no requirement"
/>
<p className="text-xs text-gray-500 mt-1">Minimum days in advance the booking must be made</p>
</div>
</div>
<div className="grid grid-cols-2 gap-6">
<div>
<label className="block text-xs font-semibold text-gray-600 uppercase tracking-wider mb-2">
Maximum Stay (nights)
</label>
<input
type="number"
value={promotionFormData.max_stay_days || ''}
onChange={(e) => setPromotionFormData({ ...promotionFormData, max_stay_days: parseInt(e.target.value) || 0 })}
className="w-full px-4 py-3 bg-white border-2 border-gray-200 rounded-xl focus:border-purple-400 focus:ring-4 focus:ring-purple-100 transition-all duration-200 text-gray-700 font-medium shadow-sm"
min="0"
placeholder="0 = no maximum"
/>
<p className="text-xs text-gray-500 mt-1">Maximum number of nights allowed for booking</p>
</div>
<div>
<label className="block text-xs font-semibold text-gray-600 uppercase tracking-wider mb-2">
Max Advance Booking (days)
</label>
<input
type="number"
value={promotionFormData.max_advance_booking_days || ''}
onChange={(e) => setPromotionFormData({ ...promotionFormData, max_advance_booking_days: parseInt(e.target.value) || 0 })}
className="w-full px-4 py-3 bg-white border-2 border-gray-200 rounded-xl focus:border-purple-400 focus:ring-4 focus:ring-purple-100 transition-all duration-200 text-gray-700 font-medium shadow-sm"
min="0"
placeholder="0 = no maximum"
/>
<p className="text-xs text-gray-500 mt-1">Maximum days in advance the booking can be made</p>
</div>
</div>
<div className="grid grid-cols-2 gap-6">
<div>
<label className="block text-xs font-semibold text-gray-600 uppercase tracking-wider mb-2">
Allowed Check-in Days
</label>
<div className="grid grid-cols-7 gap-2">
{['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'].map((day, index) => (
<label key={day} className="flex items-center gap-2 cursor-pointer">
<input
type="checkbox"
checked={promotionFormData.allowed_check_in_days?.includes(index) || false}
onChange={(e) => {
const current = promotionFormData.allowed_check_in_days || [];
if (e.target.checked) {
setPromotionFormData({ ...promotionFormData, allowed_check_in_days: [...current, index] });
} else {
setPromotionFormData({ ...promotionFormData, allowed_check_in_days: current.filter(d => d !== index) });
}
}}
className="w-4 h-4 text-purple-600 border-gray-300 rounded focus:ring-purple-500"
/>
<span className="text-xs text-gray-700">{day}</span>
</label>
))}
</div>
<p className="text-xs text-gray-500 mt-1">Leave empty to allow all days</p>
</div>
<div>
<label className="block text-xs font-semibold text-gray-600 uppercase tracking-wider mb-2">
Allowed Check-out Days
</label>
<div className="grid grid-cols-7 gap-2">
{['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'].map((day, index) => (
<label key={day} className="flex items-center gap-2 cursor-pointer">
<input
type="checkbox"
checked={promotionFormData.allowed_check_out_days?.includes(index) || false}
onChange={(e) => {
const current = promotionFormData.allowed_check_out_days || [];
if (e.target.checked) {
setPromotionFormData({ ...promotionFormData, allowed_check_out_days: [...current, index] });
} else {
setPromotionFormData({ ...promotionFormData, allowed_check_out_days: current.filter(d => d !== index) });
}
}}
className="w-4 h-4 text-purple-600 border-gray-300 rounded focus:ring-purple-500"
/>
<span className="text-xs text-gray-700">{day}</span>
</label>
))}
</div>
<p className="text-xs text-gray-500 mt-1">Leave empty to allow all days</p>
</div>
</div>
<div className="grid grid-cols-2 gap-6">
<div>
<label className="block text-xs font-semibold text-gray-600 uppercase tracking-wider mb-2">
Allowed Room Types
</label>
<select
multiple
value={promotionFormData.allowed_room_type_ids?.map(String) || []}
onChange={(e) => {
const selected = Array.from(e.target.selectedOptions, option => parseInt(option.value));
setPromotionFormData({ ...promotionFormData, allowed_room_type_ids: selected });
}}
className="w-full px-4 py-3 bg-white border-2 border-gray-200 rounded-xl focus:border-purple-400 focus:ring-4 focus:ring-purple-100 transition-all duration-200 text-gray-700 font-medium shadow-sm"
size={4}
>
{roomTypes.map(rt => (
<option key={rt.id} value={rt.id}>{rt.name}</option>
))}
</select>
<p className="text-xs text-gray-500 mt-1">Hold Ctrl/Cmd to select multiple. Leave empty to allow all room types.</p>
</div>
<div>
<label className="block text-xs font-semibold text-gray-600 uppercase tracking-wider mb-2">
Excluded Room Types
</label>
<select
multiple
value={promotionFormData.excluded_room_type_ids?.map(String) || []}
onChange={(e) => {
const selected = Array.from(e.target.selectedOptions, option => parseInt(option.value));
setPromotionFormData({ ...promotionFormData, excluded_room_type_ids: selected });
}}
className="w-full px-4 py-3 bg-white border-2 border-gray-200 rounded-xl focus:border-purple-400 focus:ring-4 focus:ring-purple-100 transition-all duration-200 text-gray-700 font-medium shadow-sm"
size={4}
>
{roomTypes.map(rt => (
<option key={rt.id} value={rt.id}>{rt.name}</option>
))}
</select>
<p className="text-xs text-gray-500 mt-1">Hold Ctrl/Cmd to select multiple. These room types cannot use this promotion.</p>
</div>
</div>
<div className="grid grid-cols-2 gap-6">
<div>
<label className="block text-xs font-semibold text-gray-600 uppercase tracking-wider mb-2">
Minimum Guests
</label>
<input
type="number"
value={promotionFormData.min_guests || ''}
onChange={(e) => setPromotionFormData({ ...promotionFormData, min_guests: parseInt(e.target.value) || 0 })}
className="w-full px-4 py-3 bg-white border-2 border-gray-200 rounded-xl focus:border-purple-400 focus:ring-4 focus:ring-purple-100 transition-all duration-200 text-gray-700 font-medium shadow-sm"
min="1"
placeholder="0 = no minimum"
/>
<p className="text-xs text-gray-500 mt-1">Minimum number of guests required</p>
</div>
<div>
<label className="block text-xs font-semibold text-gray-600 uppercase tracking-wider mb-2">
Maximum Guests
</label>
<input
type="number"
value={promotionFormData.max_guests || ''}
onChange={(e) => setPromotionFormData({ ...promotionFormData, max_guests: parseInt(e.target.value) || 0 })}
className="w-full px-4 py-3 bg-white border-2 border-gray-200 rounded-xl focus:border-purple-400 focus:ring-4 focus:ring-purple-100 transition-all duration-200 text-gray-700 font-medium shadow-sm"
min="1"
placeholder="0 = no maximum"
/>
<p className="text-xs text-gray-500 mt-1">Maximum number of guests allowed</p>
</div>
</div>
<div className="grid grid-cols-2 gap-6">
<div>
<label className="flex items-center gap-3 cursor-pointer">
<input
type="checkbox"
checked={promotionFormData.first_time_customer_only || false}
onChange={(e) => setPromotionFormData({ ...promotionFormData, first_time_customer_only: e.target.checked, repeat_customer_only: e.target.checked ? false : promotionFormData.repeat_customer_only })}
className="w-5 h-5 text-purple-600 border-gray-300 rounded focus:ring-purple-500"
/>
<span className="text-sm font-semibold text-gray-700">First-Time Customer Only</span>
</label>
<p className="text-xs text-gray-500 mt-1 ml-8">Only available to first-time customers</p>
</div>
<div>
<label className="flex items-center gap-3 cursor-pointer">
<input
type="checkbox"
checked={promotionFormData.repeat_customer_only || false}
onChange={(e) => setPromotionFormData({ ...promotionFormData, repeat_customer_only: e.target.checked, first_time_customer_only: e.target.checked ? false : promotionFormData.first_time_customer_only })}
className="w-5 h-5 text-purple-600 border-gray-300 rounded focus:ring-purple-500"
/>
<span className="text-sm font-semibold text-gray-700">Repeat Customer Only</span>
</label>
<p className="text-xs text-gray-500 mt-1 ml-8">Only available to returning customers</p>
</div>
</div>
<div>
<label className="block text-xs font-semibold text-gray-600 uppercase tracking-wider mb-2">
Blackout Dates
</label>
<textarea
value={promotionFormData.blackout_dates?.join('\n') || ''}
onChange={(e) => {
const dates = e.target.value.split('\n').filter(d => d.trim()).map(d => d.trim());
setPromotionFormData({ ...promotionFormData, blackout_dates: dates });
}}
className="w-full px-4 py-3 bg-white border-2 border-gray-200 rounded-xl focus:border-purple-400 focus:ring-4 focus:ring-purple-100 transition-all duration-200 text-gray-700 font-medium shadow-sm"
rows={3}
placeholder="Enter dates (one per line) in YYYY-MM-DD format&#10;Example:&#10;2024-12-25&#10;2024-12-31&#10;2025-01-01"
/>
<p className="text-xs text-gray-500 mt-1">Dates when promotion doesn't apply. One date per line (YYYY-MM-DD format).</p>
</div>
{/* Dates & Status Section */}
<div className="border-t-2 border-purple-200 pt-6 mt-6">
<h3 className="text-lg font-bold text-gray-900 mb-4 flex items-center gap-2">
<div className="h-1 w-8 bg-gradient-to-r from-purple-400 to-purple-600 rounded-full"></div>
Promotion Period & Status
</h3>
</div>
<div className="grid grid-cols-2 gap-6">
<div>
<label className="block text-xs font-semibold text-gray-600 uppercase tracking-wider mb-2">
Start Date <span className="text-red-500">*</span>
</label>
<input
type="date"
value={promotionFormData.start_date}
onChange={(e) => setPromotionFormData({ ...promotionFormData, start_date: e.target.value })}
className="w-full px-4 py-3 bg-white border-2 border-gray-200 rounded-xl focus:border-purple-400 focus:ring-4 focus:ring-purple-100 transition-all duration-200 text-gray-700 font-medium shadow-sm"
required
/>
</div>
<div>
<label className="block text-xs font-semibold text-gray-600 uppercase tracking-wider mb-2">
End Date <span className="text-red-500">*</span>
</label>
<input
type="date"
value={promotionFormData.end_date}
onChange={(e) => setPromotionFormData({ ...promotionFormData, end_date: e.target.value })}
className="w-full px-4 py-3 bg-white border-2 border-gray-200 rounded-xl focus:border-purple-400 focus:ring-4 focus:ring-purple-100 transition-all duration-200 text-gray-700 font-medium shadow-sm"
required
/>
</div>
</div>
<div className="grid grid-cols-2 gap-6">
<div>
<label className="block text-xs font-semibold text-gray-600 uppercase tracking-wider mb-2">
Usage Limit (0 = unlimited)
</label>
<input
type="number"
value={promotionFormData.usage_limit}
onChange={(e) => setPromotionFormData({ ...promotionFormData, usage_limit: parseInt(e.target.value) })}
className="w-full px-4 py-3 bg-white border-2 border-gray-200 rounded-xl focus:border-purple-400 focus:ring-4 focus:ring-purple-100 transition-all duration-200 text-gray-700 font-medium shadow-sm"
min="0"
/>
</div>
<div>
<label className="block text-xs font-semibold text-gray-600 uppercase tracking-wider mb-2">
Status
</label>
<select
value={promotionFormData.status}
onChange={(e) => setPromotionFormData({ ...promotionFormData, status: e.target.value as 'active' | 'inactive' })}
className="w-full px-4 py-3 bg-white border-2 border-gray-200 rounded-xl focus:border-purple-400 focus:ring-4 focus:ring-purple-100 transition-all duration-200 text-gray-700 font-medium shadow-sm cursor-pointer"
>
<option value="active">Active</option>
<option value="inactive">Inactive</option>
</select>
</div>
</div>
<div className="sticky bottom-0 bg-white border-t border-gray-200 mt-8 -mx-4 sm:-mx-6 md:-mx-8 px-4 sm:px-6 md:px-8 py-4 flex justify-end gap-3">
<button
type="button"
onClick={() => setShowPromotionModal(false)}
className="px-8 py-3 border-2 border-gray-300 rounded-xl text-gray-700 font-semibold hover:bg-gray-50 transition-all duration-200 shadow-sm hover:shadow-md"
>
Cancel
</button>
<button
type="submit"
className="px-8 py-3 bg-gradient-to-r from-purple-500 to-purple-600 text-white rounded-xl font-semibold hover:from-purple-600 hover:to-purple-700 transition-all duration-200 shadow-lg hover:shadow-xl"
>
{editingPromotion ? 'Update' : 'Create'}
</button>
</div>
</form>
</div>
</div>
</div>
</div>
)}
</div>
);
};
export default PromotionsManagementPage;

View File

@@ -1,4 +1,5 @@
import React, { useState, useEffect, useCallback } from 'react';
import { useNavigate } from 'react-router-dom';
import {
LogIn,
LogOut,
@@ -1293,19 +1294,28 @@ const ReceptionDashboardPage: React.FC = () => {
<div className="p-2.5 rounded-xl bg-gradient-to-br from-blue-500/10 to-indigo-500/10 border border-blue-200/40">
<Calendar className="w-6 h-6 text-blue-600" />
</div>
<h2 className="text-xl sm:text-2xl md:text-2xl font-extrabold text-gray-900">Bookings Management</h2>
<h2 className="text-xl sm:text-2xl md:text-2xl font-extrabold text-gray-900">Reception Bookings</h2>
</div>
<p className="text-gray-600 text-base max-w-2xl leading-relaxed">
Manage and track all hotel bookings with precision
Quick view of bookings relevant to reception operations (confirmed, checked-in, checked-out)
</p>
</div>
<button
onClick={() => setShowCreateBookingModal(true)}
className="flex items-center justify-center gap-2 px-6 py-3 bg-gradient-to-r from-amber-500 to-amber-600 text-white rounded-xl font-semibold hover:from-amber-600 hover:to-amber-700 transition-all duration-200 shadow-lg hover:shadow-xl whitespace-nowrap w-full sm:w-auto"
>
<Plus className="w-5 h-5" />
Create Booking
</button>
<div className="flex gap-3">
<button
onClick={() => navigate('/admin/bookings')}
className="flex items-center justify-center gap-2 px-6 py-3 bg-gradient-to-r from-blue-500 to-blue-600 text-white rounded-xl font-semibold hover:from-blue-600 hover:to-blue-700 transition-all duration-200 shadow-lg hover:shadow-xl whitespace-nowrap w-full sm:w-auto"
>
<Eye className="w-5 h-5" />
View All Bookings
</button>
<button
onClick={() => setShowCreateBookingModal(true)}
className="flex items-center justify-center gap-2 px-6 py-3 bg-gradient-to-r from-amber-500 to-amber-600 text-white rounded-xl font-semibold hover:from-amber-600 hover:to-amber-700 transition-all duration-200 shadow-lg hover:shadow-xl whitespace-nowrap w-full sm:w-auto"
>
<Plus className="w-5 h-5" />
Create Booking
</button>
</div>
</div>
</div>

View File

@@ -1,379 +0,0 @@
import React, { useState } from 'react';
import {
Calendar,
Users,
Hotel,
TrendingUp,
Download,
Filter,
BarChart3,
PieChart
} from 'lucide-react';
import { toast } from 'react-toastify';
import Loading from '../../shared/components/Loading';
import EmptyState from '../../shared/components/EmptyState';
import CurrencyIcon from '../../shared/components/CurrencyIcon';
import { useAsync } from '../../shared/hooks/useAsync';
import reportService, { ReportData } from '../../features/analytics/services/reportService';
import { formatDate } from '../../shared/utils/format';
import { useFormatCurrency } from '../../features/payments/hooks/useFormatCurrency';
const ReportsPage: React.FC = () => {
const { formatCurrency } = useFormatCurrency();
const [dateRange, setDateRange] = useState({
from: '',
to: '',
});
const [reportType, setReportType] = useState<'daily' | 'weekly' | 'monthly' | 'yearly' | ''>('');
const fetchReports = async (): Promise<ReportData> => {
const params: any = {};
if (dateRange.from) params.from = dateRange.from;
if (dateRange.to) params.to = dateRange.to;
if (reportType) params.type = reportType;
const response = await reportService.getReports(params);
return response.data;
};
const {
data: reportData,
loading,
error,
execute: refetchReports
} = useAsync<ReportData>(fetchReports, {
immediate: true,
onError: (error: any) => {
toast.error(error.message || 'Unable to load reports');
}
});
const handleExport = async () => {
try {
const params: any = {};
if (dateRange.from) params.from = dateRange.from;
if (dateRange.to) params.to = dateRange.to;
if (reportType) params.type = reportType;
const blob = await reportService.exportReport(params);
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `report-${new Date().toISOString().split('T')[0]}.csv`;
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
document.body.removeChild(a);
toast.success('Report exported successfully');
} catch (error: any) {
toast.error(error.message || 'Failed to export report');
}
};
const handleFilter = () => {
refetchReports();
};
if (loading && !reportData) {
return <Loading fullScreen text="Loading reports..." />;
}
if (error && !reportData) {
return (
<div className="container mx-auto px-4 py-8">
<EmptyState
title="Unable to Load Reports"
description={error.message || 'Something went wrong. Please try again.'}
action={{
label: 'Retry',
onClick: refetchReports
}}
/>
</div>
);
}
return (
<div className="container mx-auto px-4 py-8">
<div className="mb-8 flex justify-between items-center">
<div>
<h1 className="text-3xl font-bold text-gray-900 mb-2">Reports & Analytics</h1>
<p className="text-gray-600">View comprehensive reports and statistics</p>
</div>
<button
onClick={handleExport}
className="flex items-center space-x-2 px-4 py-2 bg-[#d4af37] text-white rounded-lg hover:bg-[#c9a227] transition-colors"
>
<Download className="w-5 h-5" />
<span>Export CSV</span>
</button>
</div>
{}
<div className="mb-6 bg-white p-4 rounded-lg shadow-md">
<div className="flex items-center space-x-2 mb-4">
<Filter className="w-5 h-5 text-gray-500" />
<h3 className="text-lg font-semibold text-gray-900">Filters</h3>
</div>
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
From Date
</label>
<input
type="date"
value={dateRange.from}
onChange={(e) => setDateRange({ ...dateRange, from: e.target.value })}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-[#d4af37]"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
To Date
</label>
<input
type="date"
value={dateRange.to}
onChange={(e) => setDateRange({ ...dateRange, to: e.target.value })}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-[#d4af37]"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Report Type
</label>
<select
value={reportType}
onChange={(e) => setReportType(e.target.value as any)}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-[#d4af37]"
>
<option value="">All</option>
<option value="daily">Daily</option>
<option value="weekly">Weekly</option>
<option value="monthly">Monthly</option>
<option value="yearly">Yearly</option>
</select>
</div>
<div className="flex items-end">
<button
onClick={handleFilter}
className="w-full px-4 py-2 bg-[#d4af37] text-white rounded-lg hover:bg-[#c9a227] transition-colors"
>
Apply Filters
</button>
</div>
</div>
</div>
{reportData && (
<>
{}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
<div className="bg-white p-6 rounded-lg shadow-md border-l-4 border-blue-500">
<div className="flex items-center justify-between mb-4">
<div className="p-3 bg-blue-100 rounded-lg">
<Calendar className="w-6 h-6 text-blue-600" />
</div>
<TrendingUp className="w-5 h-5 text-green-500" />
</div>
<h3 className="text-gray-500 text-sm font-medium mb-1">
Total Bookings
</h3>
<p className="text-3xl font-bold text-gray-800">
{reportData.total_bookings || 0}
</p>
</div>
<div className="bg-white p-6 rounded-lg shadow-md border-l-4 border-green-500">
<div className="flex items-center justify-between mb-4">
<div className="p-3 bg-green-100 rounded-lg">
<CurrencyIcon className="text-green-600" size={24} />
</div>
<TrendingUp className="w-5 h-5 text-green-500" />
</div>
<h3 className="text-gray-500 text-sm font-medium mb-1">
Total Revenue
</h3>
<p className="text-3xl font-bold text-gray-800">
{formatCurrency(reportData.total_revenue || 0)}
</p>
</div>
<div className="bg-white p-6 rounded-lg shadow-md border-l-4 border-purple-500">
<div className="flex items-center justify-between mb-4">
<div className="p-3 bg-purple-100 rounded-lg">
<Users className="w-6 h-6 text-purple-600" />
</div>
<TrendingUp className="w-5 h-5 text-green-500" />
</div>
<h3 className="text-gray-500 text-sm font-medium mb-1">
Total Customers
</h3>
<p className="text-3xl font-bold text-gray-800">
{reportData.total_customers || 0}
</p>
</div>
<div className="bg-white p-6 rounded-lg shadow-md border-l-4 border-orange-500">
<div className="flex items-center justify-between mb-4">
<div className="p-3 bg-orange-100 rounded-lg">
<Hotel className="w-6 h-6 text-orange-600" />
</div>
</div>
<h3 className="text-gray-500 text-sm font-medium mb-1">
Available Rooms
</h3>
<p className="text-3xl font-bold text-gray-800">
{reportData.available_rooms || 0}
</p>
<p className="text-sm text-gray-500 mt-1">
{reportData.occupied_rooms || 0} occupied
</p>
</div>
</div>
{}
{reportData.bookings_by_status && (
<div className="bg-white p-6 rounded-lg shadow-md mb-8">
<div className="flex items-center space-x-2 mb-6">
<PieChart className="w-5 h-5 text-gray-500" />
<h2 className="text-xl font-bold text-gray-900">Bookings by Status</h2>
</div>
<div className="grid grid-cols-2 md:grid-cols-5 gap-4">
{Object.entries(reportData.bookings_by_status).map(([status, count]) => (
<div key={status} className="text-center p-4 bg-gray-50 rounded-lg">
<p className="text-2xl font-bold text-gray-800">{count}</p>
<p className="text-sm text-gray-600 capitalize mt-1">{status.replace('_', ' ')}</p>
</div>
))}
</div>
</div>
)}
{}
{reportData.revenue_by_date && reportData.revenue_by_date.length > 0 && (
<div className="bg-white p-6 rounded-lg shadow-md mb-8">
<div className="flex items-center space-x-2 mb-6">
<BarChart3 className="w-5 h-5 text-gray-500" />
<h2 className="text-xl font-bold text-gray-900">Revenue by Date</h2>
</div>
<div className="overflow-x-auto">
<table className="w-full">
<thead className="bg-gray-50">
<tr>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Date
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Bookings
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Revenue
</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{reportData.revenue_by_date.map((item, index) => (
<tr key={index} className="hover:bg-gray-50">
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
{formatDate(new Date(item.date), 'short')}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{item.bookings}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
{formatCurrency(item.revenue)}
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)}
{}
{reportData.top_rooms && reportData.top_rooms.length > 0 && (
<div className="bg-white p-6 rounded-lg shadow-md mb-8">
<h2 className="text-xl font-bold text-gray-900 mb-6">Top Performing Rooms</h2>
<div className="overflow-x-auto">
<table className="w-full">
<thead className="bg-gray-50">
<tr>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Room Number
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Bookings
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Revenue
</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{reportData.top_rooms.map((room) => (
<tr key={room.room_id} className="hover:bg-gray-50">
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
{room.room_number}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{room.bookings}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
{formatCurrency(room.revenue)}
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)}
{}
{reportData.service_usage && reportData.service_usage.length > 0 && (
<div className="bg-white p-6 rounded-lg shadow-md">
<h2 className="text-xl font-bold text-gray-900 mb-6">Service Usage</h2>
<div className="overflow-x-auto">
<table className="w-full">
<thead className="bg-gray-50">
<tr>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Service Name
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Usage Count
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Total Revenue
</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{reportData.service_usage.map((service) => (
<tr key={service.service_id} className="hover:bg-gray-50">
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
{service.service_name}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{service.usage_count}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
{formatCurrency(service.total_revenue)}
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)}
</>
)}
</div>
);
};
export default ReportsPage;

View File

@@ -22,7 +22,8 @@ import {
MessageCircle,
Clock,
X,
CheckCircle2
CheckCircle2,
Palette
} from 'lucide-react';
import { toast } from 'react-toastify';
import adminPrivacyService, {
@@ -42,12 +43,13 @@ import systemSettingsService, {
CompanySettingsResponse,
UpdateCompanySettingsRequest,
} from '../../features/system/services/systemSettingsService';
import { themeService, ThemeSettingsResponse, UpdateThemeSettingsRequest } from '../../features/system/services/systemSettingsService';
import { recaptchaService, RecaptchaSettingsAdminResponse, UpdateRecaptchaSettingsRequest } from '../../features/system/services/systemSettingsService';
import { useCurrency } from '../../features/payments/contexts/CurrencyContext';
import Loading from '../../shared/components/Loading';
import { getCurrencySymbol } from '../../shared/utils/format';
type SettingsTab = 'general' | 'cookie' | 'currency' | 'payment' | 'smtp' | 'company' | 'recaptcha';
type SettingsTab = 'general' | 'cookie' | 'currency' | 'payment' | 'smtp' | 'company' | 'recaptcha' | 'theme';
const SettingsPage: React.FC = () => {
const { currency, supportedCurrencies, refreshCurrency } = useCurrency();
@@ -147,6 +149,15 @@ const SettingsPage: React.FC = () => {
});
const [showRecaptchaSecret, setShowRecaptchaSecret] = useState(false);
// Theme settings state
const [themeSettings, setThemeSettings] = useState<ThemeSettingsResponse['data'] | null>(null);
const [themeFormData, setThemeFormData] = useState<UpdateThemeSettingsRequest>({
theme_primary_color: '#d4af37',
theme_primary_light: '#f5d76e',
theme_primary_dark: '#c9a227',
theme_primary_accent: '#e8c547',
});
const [loading, setLoading] = useState(true);
const [saving, setSaving] = useState(false);
@@ -200,6 +211,9 @@ const SettingsPage: React.FC = () => {
if (activeTab === 'recaptcha') {
loadRecaptchaSettings();
}
if (activeTab === 'theme') {
loadThemeSettings();
}
}, [activeTab]);
useEffect(() => {
@@ -781,6 +795,47 @@ const SettingsPage: React.FC = () => {
}
};
const loadThemeSettings = async () => {
try {
const themeRes = await themeService.getThemeSettings();
setThemeSettings(themeRes.data);
setThemeFormData({
theme_primary_color: themeRes.data.theme_primary_color || '#d4af37',
theme_primary_light: themeRes.data.theme_primary_light || '#f5d76e',
theme_primary_dark: themeRes.data.theme_primary_dark || '#c9a227',
theme_primary_accent: themeRes.data.theme_primary_accent || '#e8c547',
});
} catch (error: any) {
toast.error(
error.response?.data?.detail ||
error.response?.data?.message ||
'Failed to load theme settings'
);
}
};
const handleSaveTheme = async () => {
try {
setSaving(true);
await themeService.updateThemeSettings(themeFormData);
toast.success('Theme settings updated successfully');
await loadThemeSettings();
// Trigger theme refresh in the app
if (typeof window !== 'undefined') {
window.dispatchEvent(new CustomEvent('refreshTheme'));
}
} catch (error: any) {
toast.error(
error.response?.data?.detail ||
error.response?.data?.message ||
'Failed to save theme settings'
);
} finally {
setSaving(false);
}
};
if (loading) {
return <Loading fullScreen={false} text="Loading settings..." />;
}
@@ -792,6 +847,7 @@ const SettingsPage: React.FC = () => {
{ id: 'payment' as SettingsTab, label: 'Payment', icon: CreditCard },
{ id: 'smtp' as SettingsTab, label: 'Email Server', icon: Mail },
{ id: 'company' as SettingsTab, label: 'Company Info', icon: Building2 },
{ id: 'theme' as SettingsTab, label: 'Theme Colors', icon: Palette },
{ id: 'recaptcha' as SettingsTab, label: 'reCAPTCHA', icon: Shield },
];
@@ -2909,6 +2965,192 @@ const SettingsPage: React.FC = () => {
</div>
</div>
)}
{activeTab === 'theme' && (
<div className="space-y-8">
<div className="flex items-center justify-between">
<div>
<h2 className="text-2xl font-bold text-gray-900 flex items-center gap-3">
<Palette className="w-6 h-6 text-amber-600" />
Theme Colors
</h2>
<p className="text-gray-600 mt-2">
Customize the primary color scheme of your frontend pages
</p>
</div>
</div>
<div className="bg-white rounded-xl shadow-lg border border-gray-200 p-8">
<div className="space-y-6">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="space-y-2">
<label className="flex items-center gap-2 text-sm font-bold text-gray-900 tracking-wide">
<Palette className="w-4 h-4 text-gray-600" />
Primary Color
</label>
<div className="flex gap-3">
<input
type="color"
value={themeFormData.theme_primary_color || '#d4af37'}
onChange={(e) =>
setThemeFormData({
...themeFormData,
theme_primary_color: e.target.value,
})
}
className="w-20 h-12 rounded-lg border-2 border-gray-300 cursor-pointer"
/>
<input
type="text"
value={themeFormData.theme_primary_color || '#d4af37'}
onChange={(e) =>
setThemeFormData({
...themeFormData,
theme_primary_color: e.target.value,
})
}
placeholder="#d4af37"
className="flex-1 px-4 py-3.5 bg-white border border-gray-300 rounded-xl shadow-sm focus:ring-2 focus:ring-amber-500/50 focus:border-amber-500 transition-all duration-200 text-sm font-mono"
/>
</div>
<p className="text-xs text-gray-500">
Main brand color used for buttons, links, and highlights
</p>
</div>
<div className="space-y-2">
<label className="flex items-center gap-2 text-sm font-bold text-gray-900 tracking-wide">
<Palette className="w-4 h-4 text-gray-600" />
Primary Light
</label>
<div className="flex gap-3">
<input
type="color"
value={themeFormData.theme_primary_light || '#f5d76e'}
onChange={(e) =>
setThemeFormData({
...themeFormData,
theme_primary_light: e.target.value,
})
}
className="w-20 h-12 rounded-lg border-2 border-gray-300 cursor-pointer"
/>
<input
type="text"
value={themeFormData.theme_primary_light || '#f5d76e'}
onChange={(e) =>
setThemeFormData({
...themeFormData,
theme_primary_light: e.target.value,
})
}
placeholder="#f5d76e"
className="flex-1 px-4 py-3.5 bg-white border border-gray-300 rounded-xl shadow-sm focus:ring-2 focus:ring-amber-500/50 focus:border-amber-500 transition-all duration-200 text-sm font-mono"
/>
</div>
<p className="text-xs text-gray-500">
Lighter variant for hover states and gradients
</p>
</div>
<div className="space-y-2">
<label className="flex items-center gap-2 text-sm font-bold text-gray-900 tracking-wide">
<Palette className="w-4 h-4 text-gray-600" />
Primary Dark
</label>
<div className="flex gap-3">
<input
type="color"
value={themeFormData.theme_primary_dark || '#c9a227'}
onChange={(e) =>
setThemeFormData({
...themeFormData,
theme_primary_dark: e.target.value,
})
}
className="w-20 h-12 rounded-lg border-2 border-gray-300 cursor-pointer"
/>
<input
type="text"
value={themeFormData.theme_primary_dark || '#c9a227'}
onChange={(e) =>
setThemeFormData({
...themeFormData,
theme_primary_dark: e.target.value,
})
}
placeholder="#c9a227"
className="flex-1 px-4 py-3.5 bg-white border border-gray-300 rounded-xl shadow-sm focus:ring-2 focus:ring-amber-500/50 focus:border-amber-500 transition-all duration-200 text-sm font-mono"
/>
</div>
<p className="text-xs text-gray-500">
Darker variant for borders and shadows
</p>
</div>
<div className="space-y-2">
<label className="flex items-center gap-2 text-sm font-bold text-gray-900 tracking-wide">
<Palette className="w-4 h-4 text-gray-600" />
Primary Accent
</label>
<div className="flex gap-3">
<input
type="color"
value={themeFormData.theme_primary_accent || '#e8c547'}
onChange={(e) =>
setThemeFormData({
...themeFormData,
theme_primary_accent: e.target.value,
})
}
className="w-20 h-12 rounded-lg border-2 border-gray-300 cursor-pointer"
/>
<input
type="text"
value={themeFormData.theme_primary_accent || '#e8c547'}
onChange={(e) =>
setThemeFormData({
...themeFormData,
theme_primary_accent: e.target.value,
})
}
placeholder="#e8c547"
className="flex-1 px-4 py-3.5 bg-white border border-gray-300 rounded-xl shadow-sm focus:ring-2 focus:ring-amber-500/50 focus:border-amber-500 transition-all duration-200 text-sm font-mono"
/>
</div>
<p className="text-xs text-gray-500">
Accent color for special highlights and effects
</p>
</div>
</div>
<div className="bg-blue-50 border border-blue-200 rounded-lg p-4">
<div className="flex items-start gap-3">
<Info className="w-5 h-5 text-blue-600 flex-shrink-0 mt-0.5" />
<div className="text-sm text-blue-800">
<p className="font-semibold mb-1">About Theme Colors</p>
<p className="text-xs">
Changes to theme colors will be applied immediately across all frontend pages.
Use hex color codes (e.g., #d4af37) for best results. The colors will replace the default gold/yellow theme throughout the application.
</p>
</div>
</div>
</div>
<div className="flex justify-end pt-4 border-t border-gray-200">
<button
onClick={handleSaveTheme}
disabled={saving}
className="flex items-center gap-2 px-6 py-3 bg-gradient-to-r from-amber-500 to-amber-600 text-white rounded-xl font-semibold hover:from-amber-600 hover:to-amber-700 transition-all duration-200 shadow-lg hover:shadow-xl disabled:opacity-50 disabled:cursor-not-allowed"
>
<Save className="w-5 h-5" />
{saving ? 'Saving...' : 'Save Theme Settings'}
</button>
</div>
</div>
</div>
</div>
)}
</div>
</div>
);

View File

@@ -92,7 +92,7 @@ const BoricaReturnPage: React.FC = () => {
<div className="bg-gradient-to-br from-gray-900/40 to-gray-800/20
border border-gray-700/50 rounded-xl p-6 sm:p-10 w-full max-w-2xl mx-auto text-center
backdrop-blur-xl shadow-2xl shadow-black/20">
<Loader2 className="w-12 h-12 sm:w-16 sm:h-16 animate-spin text-[#d4af37] mx-auto mb-4" />
<Loader2 className="w-12 h-12 sm:w-16 sm:h-16 animate-spin text-[var(--luxury-gold)] mx-auto mb-4" />
<h1 className="text-xl sm:text-2xl font-serif font-semibold text-white mb-2">
Processing Payment...
</h1>
@@ -124,11 +124,11 @@ const BoricaReturnPage: React.FC = () => {
</p>
<button
onClick={() => navigate(`/bookings/${bookingId}`)}
className="bg-gradient-to-r from-[#d4af37] to-[#c9a227]
className="bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]
text-[#0f0f0f] px-6 py-2 sm:px-8 sm:py-3 rounded-sm
hover:from-[#f5d76e] hover:to-[#d4af37]
hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)]
transition-all duration-300 font-medium tracking-wide
shadow-lg shadow-[#d4af37]/30 text-sm sm:text-base w-full sm:w-auto"
shadow-lg shadow-[var(--luxury-gold)]/30 text-sm sm:text-base w-full sm:w-auto"
>
View Booking
</button>
@@ -165,11 +165,11 @@ const BoricaReturnPage: React.FC = () => {
</button>
<button
onClick={() => navigate('/')}
className="bg-gradient-to-r from-[#d4af37] to-[#c9a227]
className="bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]
text-[#0f0f0f] px-6 py-2 sm:px-8 sm:py-3 rounded-sm
hover:from-[#f5d76e] hover:to-[#d4af37]
hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)]
transition-all duration-300 font-medium tracking-wide
shadow-lg shadow-[#d4af37]/30 text-sm sm:text-base w-full sm:w-auto"
shadow-lg shadow-[var(--luxury-gold)]/30 text-sm sm:text-base w-full sm:w-auto"
>
Go Home
</button>

View File

@@ -130,7 +130,7 @@ const ComplaintPage: React.FC = () => {
</div>
<button
onClick={() => setShowCreateModal(true)}
className="flex items-center space-x-2 px-4 py-2 bg-[#d4af37] text-white rounded-lg hover:bg-[#c9a227] transition-colors"
className="flex items-center space-x-2 px-4 py-2 bg-[var(--luxury-gold)] text-white rounded-lg hover:bg-[var(--luxury-gold-dark)] transition-colors"
>
<Plus className="w-5 h-5" />
<span>Submit Complaint</span>
@@ -180,7 +180,7 @@ const ComplaintPage: React.FC = () => {
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium">
<button
onClick={() => handleViewDetails(complaint.id)}
className="text-[#d4af37] hover:text-[#c9a227]"
className="text-[var(--luxury-gold)] hover:text-[var(--luxury-gold-dark)]"
>
<Eye className="w-5 h-5" />
</button>
@@ -277,7 +277,7 @@ const CreateComplaintModal: React.FC<{
<select
value={formData.booking_id}
onChange={(e) => setFormData({ ...formData, booking_id: e.target.value })}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-transparent"
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-transparent"
>
<option value="">Select a booking</option>
{bookings.map((booking) => (
@@ -295,7 +295,7 @@ const CreateComplaintModal: React.FC<{
value={formData.category}
onChange={(e) => setFormData({ ...formData, category: e.target.value })}
required
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-transparent"
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-transparent"
>
<option value="">Select category</option>
<option value="room_quality">Room Quality</option>
@@ -315,7 +315,7 @@ const CreateComplaintModal: React.FC<{
<select
value={formData.priority}
onChange={(e) => setFormData({ ...formData, priority: e.target.value })}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-transparent"
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-transparent"
>
<option value="low">Low</option>
<option value="medium">Medium</option>
@@ -332,7 +332,7 @@ const CreateComplaintModal: React.FC<{
value={formData.title}
onChange={(e) => setFormData({ ...formData, title: e.target.value })}
required
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-transparent"
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-transparent"
placeholder="Brief description of the issue"
/>
</div>
@@ -345,7 +345,7 @@ const CreateComplaintModal: React.FC<{
onChange={(e) => setFormData({ ...formData, description: e.target.value })}
required
rows={6}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#d4af37] focus:border-transparent"
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-transparent"
placeholder="Please provide detailed information about your complaint..."
/>
</div>
@@ -361,7 +361,7 @@ const CreateComplaintModal: React.FC<{
<button
type="submit"
disabled={submitting}
className="px-4 py-2 bg-[#d4af37] text-white rounded-lg hover:bg-[#c9a227] disabled:opacity-50 disabled:cursor-not-allowed"
className="px-4 py-2 bg-[var(--luxury-gold)] text-white rounded-lg hover:bg-[var(--luxury-gold-dark)] disabled:opacity-50 disabled:cursor-not-allowed"
>
{submitting ? 'Submitting...' : 'Submit Complaint'}
</button>

View File

@@ -231,11 +231,11 @@ const FullPaymentPage: React.FC = () => {
<Link
to="/bookings"
className="inline-flex items-center gap-2
bg-gradient-to-r from-[#d4af37] to-[#c9a227]
bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]
text-[#0f0f0f] px-6 py-3 rounded-sm
hover:from-[#f5d76e] hover:to-[#d4af37]
hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)]
transition-all duration-300 font-medium
tracking-wide shadow-lg shadow-[#d4af37]/30"
tracking-wide shadow-lg shadow-[var(--luxury-gold)]/30"
>
<ArrowLeft className="w-4 h-4" />
Back to booking list
@@ -270,7 +270,7 @@ const FullPaymentPage: React.FC = () => {
<Link
to={`/bookings/${bookingId}`}
className="inline-flex items-center gap-2
text-[#d4af37]/80 hover:text-[#d4af37]
text-[var(--luxury-gold)]/80 hover:text-[var(--luxury-gold)]
mb-6 transition-all duration-300
group font-light tracking-wide"
>
@@ -307,19 +307,19 @@ const FullPaymentPage: React.FC = () => {
{}
{!isPaymentCompleted && (
<div
className="bg-gradient-to-br from-[#d4af37]/10 to-[#c9a227]/5
border-2 border-[#d4af37]/30 rounded-xl p-6 mb-6
backdrop-blur-xl shadow-2xl shadow-[#d4af37]/10"
className="bg-gradient-to-br from-[var(--luxury-gold)]/10 to-[var(--luxury-gold-dark)]/5
border-2 border-[var(--luxury-gold)]/30 rounded-xl p-6 mb-6
backdrop-blur-xl shadow-2xl shadow-[var(--luxury-gold)]/10"
>
<div className="flex items-center gap-4">
<div
className="w-16 h-16 bg-[#d4af37]/20 rounded-full
flex items-center justify-center border border-[#d4af37]/30"
className="w-16 h-16 bg-[var(--luxury-gold)]/20 rounded-full
flex items-center justify-center border border-[var(--luxury-gold)]/30"
>
<CreditCard className="w-10 h-10 text-[#d4af37]" />
<CreditCard className="w-10 h-10 text-[var(--luxury-gold)]" />
</div>
<div className="flex-1">
<h1 className="text-2xl font-serif font-bold text-[#d4af37] mb-1 tracking-wide">
<h1 className="text-2xl font-serif font-bold text-[var(--luxury-gold)] mb-1 tracking-wide">
Complete Payment
</h1>
<p className="text-gray-300 font-light tracking-wide">
@@ -336,11 +336,11 @@ const FullPaymentPage: React.FC = () => {
{}
<div
className="bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a]
rounded-xl border border-[#d4af37]/20
backdrop-blur-xl shadow-2xl shadow-[#d4af37]/5 p-6"
rounded-xl border border-[var(--luxury-gold)]/20
backdrop-blur-xl shadow-2xl shadow-[var(--luxury-gold)]/5 p-6"
>
<h2 className="text-xl font-serif font-semibold text-[#d4af37] mb-4 flex items-center gap-2">
<div className="w-1 h-6 bg-gradient-to-b from-[#d4af37] to-[#c9a227]" />
<h2 className="text-xl font-serif font-semibold text-[var(--luxury-gold)] mb-4 flex items-center gap-2">
<div className="w-1 h-6 bg-gradient-to-b from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]" />
Payment Information
</h2>
@@ -353,8 +353,8 @@ const FullPaymentPage: React.FC = () => {
</div>
<div
className="flex justify-between border-t border-[#d4af37]/20 pt-3
text-[#d4af37]"
className="flex justify-between border-t border-[var(--luxury-gold)]/20 pt-3
text-[var(--luxury-gold)]"
>
<span className="font-medium">
Amount to Pay
@@ -386,11 +386,11 @@ const FullPaymentPage: React.FC = () => {
{!isPaymentCompleted && booking && stripePayment && (
<div
className="bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a]
rounded-xl border border-[#d4af37]/20
backdrop-blur-xl shadow-2xl shadow-[#d4af37]/5 p-6"
rounded-xl border border-[var(--luxury-gold)]/20
backdrop-blur-xl shadow-2xl shadow-[var(--luxury-gold)]/5 p-6"
>
<h2 className="text-xl font-serif font-semibold text-[#d4af37] mb-4 flex items-center gap-2">
<div className="w-1 h-6 bg-gradient-to-b from-[#d4af37] to-[#c9a227]" />
<h2 className="text-xl font-serif font-semibold text-[var(--luxury-gold)] mb-4 flex items-center gap-2">
<div className="w-1 h-6 bg-gradient-to-b from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]" />
<CreditCard className="w-5 h-5" />
Card Payment
</h2>
@@ -406,11 +406,11 @@ const FullPaymentPage: React.FC = () => {
</p>
<button
onClick={() => navigate(`/bookings/${booking.id}`)}
className="bg-gradient-to-r from-[#d4af37] to-[#c9a227]
className="bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]
text-[#0f0f0f] px-6 py-3 rounded-sm
hover:from-[#f5d76e] hover:to-[#d4af37]
hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)]
transition-all duration-300 font-medium
tracking-wide shadow-lg shadow-[#d4af37]/30"
tracking-wide shadow-lg shadow-[var(--luxury-gold)]/30"
>
View Booking
</button>
@@ -440,12 +440,12 @@ const FullPaymentPage: React.FC = () => {
<div className="lg:col-span-1">
<div
className="bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a]
rounded-xl border border-[#d4af37]/20
backdrop-blur-xl shadow-2xl shadow-[#d4af37]/5 p-6
rounded-xl border border-[var(--luxury-gold)]/20
backdrop-blur-xl shadow-2xl shadow-[var(--luxury-gold)]/5 p-6
sticky top-6"
>
<h3 className="text-lg font-serif font-semibold text-[#d4af37] mb-4 flex items-center gap-2">
<div className="w-1 h-5 bg-gradient-to-b from-[#d4af37] to-[#c9a227]" />
<h3 className="text-lg font-serif font-semibold text-[var(--luxury-gold)] mb-4 flex items-center gap-2">
<div className="w-1 h-5 bg-gradient-to-b from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]" />
Booking Summary
</h3>
@@ -476,9 +476,9 @@ const FullPaymentPage: React.FC = () => {
</p>
</div>
<div className="pt-3 border-t border-[#d4af37]/20">
<div className="pt-3 border-t border-[var(--luxury-gold)]/20">
<span className="text-gray-400 font-light">Total Amount</span>
<p className="text-xl font-bold text-[#d4af37]">
<p className="text-xl font-bold text-[var(--luxury-gold)]">
{formatPrice(booking.total_price)}
</p>
</div>
@@ -486,7 +486,7 @@ const FullPaymentPage: React.FC = () => {
{/* PCI DSS Compliance Trust Badge */}
{!isPaymentCompleted && (
<div className="mt-6 pt-6 border-t border-[#d4af37]/20">
<div className="mt-6 pt-6 border-t border-[var(--luxury-gold)]/20">
<div className="bg-gradient-to-r from-blue-900/20 to-indigo-900/20 border border-blue-500/30 rounded-lg p-4">
<div className="flex items-start gap-3">
<div className="flex-shrink-0">

View File

@@ -195,7 +195,7 @@ const GuestRequestsPage: React.FC = () => {
}
setShowCreateModal(true);
}}
className="flex items-center space-x-2 px-6 py-3 bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-white rounded-lg hover:from-[#f5d76e] hover:to-[#d4af37] transition-all duration-300 shadow-lg hover:shadow-xl font-medium"
className="flex items-center space-x-2 px-6 py-3 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-white rounded-lg hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] transition-all duration-300 shadow-lg hover:shadow-xl font-medium"
>
<Plus className="w-5 h-5" />
<span>New Request</span>
@@ -209,7 +209,7 @@ const GuestRequestsPage: React.FC = () => {
<select
value={filterStatus}
onChange={(e) => setFilterStatus(e.target.value)}
className="border border-gray-300 rounded-lg px-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[#d4af37]"
className="border border-gray-300 rounded-lg px-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[var(--luxury-gold)]"
>
<option value="">All Statuses</option>
<option value="pending">Pending</option>
@@ -344,7 +344,7 @@ const GuestRequestsPage: React.FC = () => {
});
setSelectedBooking(booking);
}}
className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[#d4af37]"
className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[var(--luxury-gold)]"
required
>
<option value="">Select Booking</option>
@@ -363,7 +363,7 @@ const GuestRequestsPage: React.FC = () => {
<select
value={requestForm.request_type}
onChange={(e) => setRequestForm({ ...requestForm, request_type: e.target.value })}
className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[#d4af37]"
className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[var(--luxury-gold)]"
required
>
{requestTypes.map((type) => (
@@ -383,7 +383,7 @@ const GuestRequestsPage: React.FC = () => {
value={requestForm.title}
onChange={(e) => setRequestForm({ ...requestForm, title: e.target.value })}
placeholder="Brief description of your request"
className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[#d4af37]"
className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[var(--luxury-gold)]"
required
/>
</div>
@@ -397,7 +397,7 @@ const GuestRequestsPage: React.FC = () => {
onChange={(e) => setRequestForm({ ...requestForm, description: e.target.value })}
placeholder="Additional details about your request"
rows={4}
className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[#d4af37]"
className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[var(--luxury-gold)]"
/>
</div>
@@ -408,7 +408,7 @@ const GuestRequestsPage: React.FC = () => {
<select
value={requestForm.priority}
onChange={(e) => setRequestForm({ ...requestForm, priority: e.target.value })}
className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[#d4af37]"
className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[var(--luxury-gold)]"
>
<option value="low">Low</option>
<option value="normal">Normal</option>
@@ -426,7 +426,7 @@ const GuestRequestsPage: React.FC = () => {
onChange={(e) => setRequestForm({ ...requestForm, guest_notes: e.target.value })}
placeholder="Any special instructions or preferences"
rows={3}
className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[#d4af37]"
className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[var(--luxury-gold)]"
/>
</div>
@@ -439,7 +439,7 @@ const GuestRequestsPage: React.FC = () => {
</button>
<button
onClick={handleCreateRequest}
className="px-4 py-2 text-sm text-white bg-gradient-to-r from-[#d4af37] to-[#c9a227] rounded-lg hover:from-[#f5d76e] hover:to-[#d4af37] transition-colors font-medium"
className="px-4 py-2 text-sm text-white bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] rounded-lg hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] transition-colors font-medium"
>
Submit Request
</button>

View File

@@ -91,11 +91,11 @@ const PayPalCancelPage: React.FC = () => {
{bookingId && (
<button
onClick={() => navigate(`/bookings/${bookingId}`)}
className="flex-1 bg-gradient-to-r from-[#d4af37] to-[#c9a227]
className="flex-1 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]
text-[#0f0f0f] px-4 py-2 sm:px-6 sm:py-3 rounded-sm
hover:from-[#f5d76e] hover:to-[#d4af37]
hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)]
transition-all duration-300 font-medium tracking-wide
shadow-lg shadow-[#d4af37]/30 flex items-center justify-center gap-2
shadow-lg shadow-[var(--luxury-gold)]/30 flex items-center justify-center gap-2
disabled:opacity-50 disabled:cursor-not-allowed text-sm sm:text-base"
disabled={cancelling}
>
@@ -107,7 +107,7 @@ const PayPalCancelPage: React.FC = () => {
onClick={() => navigate('/bookings')}
className="flex-1 bg-gradient-to-br from-gray-800/40 to-gray-700/20
border border-gray-600/30 text-gray-300 px-4 py-2 sm:px-6 sm:py-3 rounded-sm
hover:border-[#d4af37]/50 hover:text-[#d4af37]
hover:border-[var(--luxury-gold)]/50 hover:text-[var(--luxury-gold)]
transition-all duration-300 font-light tracking-wide
backdrop-blur-sm text-sm sm:text-base"
>

View File

@@ -82,10 +82,10 @@ const PayPalReturnPage: React.FC = () => {
<div className="min-h-screen bg-gradient-to-b from-[#0f0f0f] via-[#1a1a1a] to-[#0f0f0f]
flex items-center justify-center py-8 sm:py-12 px-4 sm:px-6 lg:px-8">
<div className="text-center w-full max-w-2xl mx-auto">
<div className="w-16 h-16 sm:w-20 sm:h-20 bg-gradient-to-br from-[#d4af37]/20 to-[#f5d76e]/20
<div className="w-16 h-16 sm:w-20 sm:h-20 bg-gradient-to-br from-[var(--luxury-gold)]/20 to-[var(--luxury-gold-light)]/20
rounded-full flex items-center justify-center mx-auto mb-4 sm:mb-6
border border-[#d4af37]/30 shadow-lg shadow-[#d4af37]/20">
<Loader2 className="w-10 h-10 sm:w-12 sm:h-12 text-[#d4af37] animate-spin" />
border border-[var(--luxury-gold)]/30 shadow-lg shadow-[var(--luxury-gold)]/20">
<Loader2 className="w-10 h-10 sm:w-12 sm:h-12 text-[var(--luxury-gold)] animate-spin" />
</div>
<p className="text-gray-300/80 font-light text-base sm:text-lg tracking-wide">
Processing your payment...
@@ -115,11 +115,11 @@ const PayPalReturnPage: React.FC = () => {
</p>
<button
onClick={() => navigate(`/bookings/${bookingId}`)}
className="bg-gradient-to-r from-[#d4af37] to-[#c9a227]
className="bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]
text-[#0f0f0f] px-6 py-2 sm:px-8 sm:py-3 rounded-sm
hover:from-[#f5d76e] hover:to-[#d4af37]
hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)]
transition-all duration-300 font-medium tracking-wide
shadow-lg shadow-[#d4af37]/30 text-sm sm:text-base w-full sm:w-auto"
shadow-lg shadow-[var(--luxury-gold)]/30 text-sm sm:text-base w-full sm:w-auto"
>
View Booking
</button>
@@ -149,11 +149,11 @@ const PayPalReturnPage: React.FC = () => {
{bookingId && (
<button
onClick={() => navigate(`/bookings/${bookingId}`)}
className="flex-1 bg-gradient-to-r from-[#d4af37] to-[#c9a227]
className="flex-1 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]
text-[#0f0f0f] px-4 py-2 sm:px-6 sm:py-3 rounded-sm
hover:from-[#f5d76e] hover:to-[#d4af37]
hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)]
transition-all duration-300 font-medium tracking-wide
shadow-lg shadow-[#d4af37]/30 text-sm sm:text-base"
shadow-lg shadow-[var(--luxury-gold)]/30 text-sm sm:text-base"
>
View Booking
</button>
@@ -162,7 +162,7 @@ const PayPalReturnPage: React.FC = () => {
onClick={() => navigate('/bookings')}
className="flex-1 bg-gradient-to-br from-gray-800/40 to-gray-700/20
border border-gray-600/30 text-gray-300 px-4 py-2 sm:px-6 sm:py-3 rounded-sm
hover:border-[#d4af37]/50 hover:text-[#d4af37]
hover:border-[var(--luxury-gold)]/50 hover:text-[var(--luxury-gold)]
transition-all duration-300 font-light tracking-wide
backdrop-blur-sm text-sm sm:text-base"
>

View File

@@ -417,7 +417,7 @@ const ProfilePage: React.FC = () => {
{}
<div className="mb-6 sm:mb-8 animate-fade-in">
<div className="flex items-center gap-2 sm:gap-3 mb-2 sm:mb-3">
<div className="h-1 w-12 sm:w-16 md:w-20 bg-gradient-to-r from-[#d4af37] via-amber-400 to-[#d4af37] rounded-full"></div>
<div className="h-1 w-12 sm:w-16 md:w-20 bg-gradient-to-r from-[var(--luxury-gold)] via-amber-400 to-[var(--luxury-gold)] rounded-full"></div>
<h1 className="text-2xl sm:text-3xl lg:text-4xl font-serif font-bold bg-gradient-to-r from-gray-900 via-amber-900/90 to-gray-900 bg-clip-text text-transparent tracking-tight">
Profile & Settings
</h1>
@@ -428,61 +428,61 @@ const ProfilePage: React.FC = () => {
</div>
{}
<div className="mb-4 sm:mb-6 border-b border-[#d4af37]/20 overflow-x-auto bg-white/50 backdrop-blur-sm rounded-t-lg sm:rounded-t-xl px-4 sm:px-6">
<div className="mb-4 sm:mb-6 border-b border-[var(--luxury-gold)]/20 overflow-x-auto bg-white/50 backdrop-blur-sm rounded-t-lg sm:rounded-t-xl px-4 sm:px-6">
<div className="flex space-x-4 sm:space-x-8 min-w-max">
<button
onClick={() => setActiveTab('profile')}
className={`py-3 sm:py-4 px-2 sm:px-1 border-b-2 font-semibold text-xs sm:text-sm transition-all duration-300 whitespace-nowrap ${
activeTab === 'profile'
? 'border-[#d4af37] text-[#d4af37] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[#d4af37] hover:border-[#d4af37]/30'
? 'border-[var(--luxury-gold)] text-[var(--luxury-gold)] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[var(--luxury-gold)] hover:border-[var(--luxury-gold)]/30'
}`}
>
<User className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'profile' ? 'text-[#d4af37]' : ''}`} />
<User className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'profile' ? 'text-[var(--luxury-gold)]' : ''}`} />
Profile Information
</button>
<button
onClick={() => setActiveTab('password')}
className={`py-3 sm:py-4 px-2 sm:px-1 border-b-2 font-semibold text-xs sm:text-sm transition-all duration-300 whitespace-nowrap ${
activeTab === 'password'
? 'border-[#d4af37] text-[#d4af37] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[#d4af37] hover:border-[#d4af37]/30'
? 'border-[var(--luxury-gold)] text-[var(--luxury-gold)] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[var(--luxury-gold)] hover:border-[var(--luxury-gold)]/30'
}`}
>
<KeyRound className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'password' ? 'text-[#d4af37]' : ''}`} />
<KeyRound className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'password' ? 'text-[var(--luxury-gold)]' : ''}`} />
Change Password
</button>
<button
onClick={() => setActiveTab('mfa')}
className={`py-3 sm:py-4 px-2 sm:px-1 border-b-2 font-semibold text-xs sm:text-sm transition-all duration-300 whitespace-nowrap ${
activeTab === 'mfa'
? 'border-[#d4af37] text-[#d4af37] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[#d4af37] hover:border-[#d4af37]/30'
? 'border-[var(--luxury-gold)] text-[var(--luxury-gold)] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[var(--luxury-gold)] hover:border-[var(--luxury-gold)]/30'
}`}
>
<Shield className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'mfa' ? 'text-[#d4af37]' : ''}`} />
<Shield className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'mfa' ? 'text-[var(--luxury-gold)]' : ''}`} />
Two-Factor Authentication
</button>
<button
onClick={() => setActiveTab('sessions')}
className={`py-3 sm:py-4 px-2 sm:px-1 border-b-2 font-semibold text-xs sm:text-sm transition-all duration-300 whitespace-nowrap ${
activeTab === 'sessions'
? 'border-[#d4af37] text-[#d4af37] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[#d4af37] hover:border-[#d4af37]/30'
? 'border-[var(--luxury-gold)] text-[var(--luxury-gold)] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[var(--luxury-gold)] hover:border-[var(--luxury-gold)]/30'
}`}
>
<Monitor className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'sessions' ? 'text-[#d4af37]' : ''}`} />
<Monitor className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'sessions' ? 'text-[var(--luxury-gold)]' : ''}`} />
Active Sessions
</button>
<button
onClick={() => setActiveTab('gdpr')}
className={`py-3 sm:py-4 px-2 sm:px-1 border-b-2 font-semibold text-xs sm:text-sm transition-all duration-300 whitespace-nowrap ${
activeTab === 'gdpr'
? 'border-[#d4af37] text-[#d4af37] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[#d4af37] hover:border-[#d4af37]/30'
? 'border-[var(--luxury-gold)] text-[var(--luxury-gold)] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[var(--luxury-gold)] hover:border-[var(--luxury-gold)]/30'
}`}
>
<Database className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'gdpr' ? 'text-[#d4af37]' : ''}`} />
<Database className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'gdpr' ? 'text-[var(--luxury-gold)]' : ''}`} />
Data Privacy
</button>
</div>
@@ -490,7 +490,7 @@ const ProfilePage: React.FC = () => {
{}
{activeTab === 'profile' && (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl animate-slide-up">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl animate-slide-up">
<form onSubmit={handleSubmitProfile(onSubmitProfile)} className="space-y-5 sm:space-y-6">
{}
<div className="flex flex-col sm:flex-row items-center sm:items-start gap-4 sm:gap-6 pb-5 sm:pb-6 border-b border-gray-200">
@@ -499,20 +499,20 @@ const ProfilePage: React.FC = () => {
<img
src={avatarPreview || normalizeImageUrl(userInfo?.avatar)}
alt="Profile"
className="w-20 h-20 sm:w-24 sm:h-24 rounded-full object-cover ring-4 ring-[#d4af37]/20 shadow-lg"
className="w-20 h-20 sm:w-24 sm:h-24 rounded-full object-cover ring-4 ring-[var(--luxury-gold)]/20 shadow-lg"
onError={() => {
// If image fails to load, show default avatar
setAvatarError(true);
}}
/>
) : (
<div className="w-20 h-20 sm:w-24 sm:h-24 rounded-full bg-gradient-to-br from-[#d4af37] to-[#c9a227] flex items-center justify-center ring-4 ring-[#d4af37]/20 shadow-lg">
<div className="w-20 h-20 sm:w-24 sm:h-24 rounded-full bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] flex items-center justify-center ring-4 ring-[var(--luxury-gold)]/20 shadow-lg">
<User className="w-10 h-10 sm:w-12 sm:h-12 text-white" />
</div>
)}
<label
htmlFor="avatar-upload"
className="absolute bottom-0 right-0 p-2 bg-gradient-to-br from-[#d4af37] to-[#c9a227] rounded-full cursor-pointer hover:from-[#f5d76e] hover:to-[#d4af37] transition-all duration-300 shadow-lg hover:shadow-xl hover:shadow-[#d4af37]/40 hover:-translate-y-0.5 active:translate-y-0"
className="absolute bottom-0 right-0 p-2 bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] rounded-full cursor-pointer hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] transition-all duration-300 shadow-lg hover:shadow-xl hover:shadow-[var(--luxury-gold)]/40 hover:-translate-y-0.5 active:translate-y-0"
>
<Camera className="w-3.5 h-3.5 sm:w-4 sm:h-4 text-white" />
<input
@@ -528,7 +528,7 @@ const ProfilePage: React.FC = () => {
<div>
<label className="block text-sm sm:text-base font-medium text-gray-700 mb-2">
<User className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[#d4af37]" />
<User className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[var(--luxury-gold)]" />
Full Name
<span className="text-red-500 ml-1">*</span>
</label>
@@ -551,7 +551,7 @@ const ProfilePage: React.FC = () => {
{}
<div>
<label className="block text-sm sm:text-base font-medium text-gray-700 mb-2">
<Mail className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[#d4af37]" />
<Mail className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[var(--luxury-gold)]" />
Email Address
<span className="text-red-500 ml-1">*</span>
</label>
@@ -574,7 +574,7 @@ const ProfilePage: React.FC = () => {
{}
<div>
<label className="block text-sm sm:text-base font-medium text-gray-700 mb-2">
<Phone className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[#d4af37]" />
<Phone className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[var(--luxury-gold)]" />
Phone Number
<span className="text-red-500 ml-1">*</span>
</label>
@@ -611,7 +611,7 @@ const ProfilePage: React.FC = () => {
{}
{activeTab === 'password' && (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl animate-slide-up">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl animate-slide-up">
<form onSubmit={handleSubmitPassword(onSubmitPassword)} className="space-y-5 sm:space-y-6">
{}
<div className="bg-gradient-to-r from-blue-50 to-indigo-50 border border-blue-200/60 rounded-sm p-4 sm:p-5">
@@ -640,7 +640,7 @@ const ProfilePage: React.FC = () => {
{}
<div>
<label className="block text-sm sm:text-base font-medium text-gray-700 mb-2">
<Lock className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[#d4af37]" />
<Lock className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[var(--luxury-gold)]" />
Current Password
<span className="text-red-500 ml-1">*</span>
</label>
@@ -656,7 +656,7 @@ const ProfilePage: React.FC = () => {
<button
type="button"
onClick={() => setShowPassword({ ...showPassword, current: !showPassword.current })}
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[#d4af37] transition-colors"
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[var(--luxury-gold)] transition-colors"
>
{showPassword.current ? (
<EyeOff className="w-4 h-4 sm:w-5 sm:h-5" />
@@ -676,7 +676,7 @@ const ProfilePage: React.FC = () => {
{}
<div>
<label className="block text-sm sm:text-base font-medium text-gray-700 mb-2">
<Lock className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[#d4af37]" />
<Lock className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[var(--luxury-gold)]" />
New Password
<span className="text-red-500 ml-1">*</span>
</label>
@@ -692,7 +692,7 @@ const ProfilePage: React.FC = () => {
<button
type="button"
onClick={() => setShowPassword({ ...showPassword, new: !showPassword.new })}
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[#d4af37] transition-colors"
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[var(--luxury-gold)] transition-colors"
>
{showPassword.new ? (
<EyeOff className="w-4 h-4 sm:w-5 sm:h-5" />
@@ -712,7 +712,7 @@ const ProfilePage: React.FC = () => {
{}
<div>
<label className="block text-sm sm:text-base font-medium text-gray-700 mb-2">
<Lock className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[#d4af37]" />
<Lock className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[var(--luxury-gold)]" />
Confirm New Password
<span className="text-red-500 ml-1">*</span>
</label>
@@ -728,7 +728,7 @@ const ProfilePage: React.FC = () => {
<button
type="button"
onClick={() => setShowPassword({ ...showPassword, confirm: !showPassword.confirm })}
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[#d4af37] transition-colors"
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[var(--luxury-gold)] transition-colors"
>
{showPassword.confirm ? (
<EyeOff className="w-4 h-4 sm:w-5 sm:h-5" />
@@ -762,11 +762,11 @@ const ProfilePage: React.FC = () => {
{}
{activeTab === 'mfa' && (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl animate-slide-up space-y-5 sm:space-y-6">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl animate-slide-up space-y-5 sm:space-y-6">
{}
<div>
<h2 className="text-xl sm:text-2xl font-serif font-semibold text-gray-900 mb-2 flex items-center gap-2">
<Shield className="w-5 h-5 sm:w-6 sm:h-6 text-[#d4af37]" />
<Shield className="w-5 h-5 sm:w-6 sm:h-6 text-[var(--luxury-gold)]" />
Two-Factor Authentication
</h2>
<p className="text-xs sm:text-sm text-gray-600 font-light leading-relaxed">
@@ -838,7 +838,7 @@ const ProfilePage: React.FC = () => {
{}
<div className="bg-white border border-gray-200 rounded-sm p-4 sm:p-5">
<h3 className="text-sm sm:text-base font-semibold text-gray-900 mb-2 flex items-center gap-2">
<RefreshCw className="w-4 h-4 sm:w-5 sm:h-5 text-[#d4af37]" />
<RefreshCw className="w-4 h-4 sm:w-5 sm:h-5 text-[var(--luxury-gold)]" />
Backup Codes
</h3>
<p className="text-xs sm:text-sm text-gray-600 font-light mb-4 leading-relaxed">
@@ -984,7 +984,7 @@ const ProfilePage: React.FC = () => {
{}
<div className="bg-white border border-gray-200 rounded-sm p-4 sm:p-5">
<h3 className="font-semibold text-gray-900 mb-2 text-sm sm:text-base flex items-center gap-2">
<KeyRound className="w-4 h-4 sm:w-5 sm:h-5 text-[#d4af37]" />
<KeyRound className="w-4 h-4 sm:w-5 sm:h-5 text-[var(--luxury-gold)]" />
Step 2: Verify Setup
</h3>
<p className="text-xs sm:text-sm text-gray-600 font-light mb-4 leading-relaxed">
@@ -1110,10 +1110,10 @@ const SessionsTab: React.FC = () => {
};
const getDeviceIcon = (userAgent?: string) => {
if (!userAgent) return <Monitor className="w-5 h-5 text-[#d4af37]" />;
if (!userAgent) return <Monitor className="w-5 h-5 text-[var(--luxury-gold)]" />;
if (userAgent.includes('Mobile')) return <Smartphone className="w-5 h-5 text-blue-500" />;
if (userAgent.includes('Tablet')) return <Tablet className="w-5 h-5 text-purple-500" />;
return <Monitor className="w-5 h-5 text-[#d4af37]" />;
return <Monitor className="w-5 h-5 text-[var(--luxury-gold)]" />;
};
const getDeviceName = (userAgent?: string) => {
@@ -1181,17 +1181,17 @@ const SessionsTab: React.FC = () => {
if (loading) {
return (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl">
<Loading text="Loading sessions..." />
</div>
);
}
return (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl animate-slide-up space-y-5 sm:space-y-6">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl animate-slide-up space-y-5 sm:space-y-6">
<div>
<h2 className="text-xl sm:text-2xl font-serif font-semibold text-gray-900 mb-2 flex items-center gap-2">
<Monitor className="w-5 h-5 sm:w-6 sm:h-6 text-[#d4af37]" />
<Monitor className="w-5 h-5 sm:w-6 sm:h-6 text-[var(--luxury-gold)]" />
Active Sessions
</h2>
<p className="text-xs sm:text-sm text-gray-600 font-light">
@@ -1220,11 +1220,11 @@ const SessionsTab: React.FC = () => {
{sessions.map((session) => (
<div
key={session.id}
className="bg-gradient-to-r from-slate-50 to-white border border-[#d4af37]/20 rounded-sm p-4 sm:p-5 hover:shadow-lg hover:border-[#d4af37]/40 transition-all duration-300"
className="bg-gradient-to-r from-slate-50 to-white border border-[var(--luxury-gold)]/20 rounded-sm p-4 sm:p-5 hover:shadow-lg hover:border-[var(--luxury-gold)]/40 transition-all duration-300"
>
<div className="flex items-start justify-between gap-4">
<div className="flex items-start gap-4 flex-1">
<div className="p-2 sm:p-3 bg-gradient-to-br from-[#d4af37]/10 to-[#c9a227]/10 rounded-sm flex-shrink-0">
<div className="p-2 sm:p-3 bg-gradient-to-br from-[var(--luxury-gold)]/10 to-[var(--luxury-gold-dark)]/10 rounded-sm flex-shrink-0">
{getDeviceIcon(session.user_agent)}
</div>
<div className="flex-1 min-w-0">
@@ -1354,17 +1354,17 @@ const GDPRTab: React.FC = () => {
if (loading) {
return (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl">
<Loading text="Loading privacy data..." />
</div>
);
}
return (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl animate-slide-up space-y-5 sm:space-y-6">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl animate-slide-up space-y-5 sm:space-y-6">
<div>
<h2 className="text-xl sm:text-2xl font-serif font-semibold text-gray-900 mb-2 flex items-center gap-2">
<Database className="w-5 h-5 sm:w-6 sm:h-6 text-[#d4af37]" />
<Database className="w-5 h-5 sm:w-6 sm:h-6 text-[var(--luxury-gold)]" />
Data Privacy & GDPR Rights
</h2>
<p className="text-xs sm:text-sm text-gray-600 font-light">
@@ -1431,14 +1431,14 @@ const GDPRTab: React.FC = () => {
{requests.length > 0 && (
<div className="border-t border-gray-200 pt-5 sm:pt-6">
<h3 className="text-base sm:text-lg font-semibold text-gray-900 mb-4 flex items-center gap-2">
<FileText className="w-5 h-5 text-[#d4af37]" />
<FileText className="w-5 h-5 text-[var(--luxury-gold)]" />
Request History
</h3>
<div className="space-y-3 sm:space-y-4">
{requests.map((request) => (
<div
key={request.id}
className="bg-gradient-to-r from-slate-50 to-white border border-[#d4af37]/20 rounded-sm p-4 sm:p-5 hover:shadow-md hover:border-[#d4af37]/40 transition-all duration-300"
className="bg-gradient-to-r from-slate-50 to-white border border-[var(--luxury-gold)]/20 rounded-sm p-4 sm:p-5 hover:shadow-md hover:border-[var(--luxury-gold)]/40 transition-all duration-300"
>
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 sm:gap-4">
<div className="flex-1 min-w-0">

View File

@@ -184,9 +184,9 @@ const RoomDetailPage: React.FC = () => {
>
<div className="w-full px-2 sm:px-4 md:px-6 lg:px-8 py-8 sm:py-12">
<div className="animate-pulse space-y-6">
<div className="h-[600px] bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-xl border border-[#d4af37]/20" />
<div className="h-12 bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-lg w-1/3 border border-[#d4af37]/10" />
<div className="h-6 bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-lg w-2/3 border border-[#d4af37]/10" />
<div className="h-[600px] bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-xl border border-[var(--luxury-gold)]/20" />
<div className="h-12 bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-lg w-1/3 border border-[var(--luxury-gold)]/10" />
<div className="h-6 bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] rounded-lg w-2/3 border border-[var(--luxury-gold)]/10" />
</div>
</div>
</div>
@@ -217,10 +217,10 @@ const RoomDetailPage: React.FC = () => {
<button
onClick={() => navigate('/rooms')}
className="inline-flex items-center gap-2 bg-gradient-to-r
from-[#d4af37] to-[#c9a227] text-[#0f0f0f]
px-6 py-3 rounded-sm hover:from-[#f5d76e]
hover:to-[#d4af37] transition-all duration-300
font-medium tracking-wide shadow-lg shadow-[#d4af37]/30"
from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-[#0f0f0f]
px-6 py-3 rounded-sm hover:from-[var(--luxury-gold-light)]
hover:to-[var(--luxury-gold)] transition-all duration-300
font-medium tracking-wide shadow-lg shadow-[var(--luxury-gold)]/30"
>
<ArrowLeft className="w-5 h-5" />
Back to Room List
@@ -251,7 +251,7 @@ const RoomDetailPage: React.FC = () => {
<Link
to="/rooms"
className="inline-flex items-center gap-1
text-[#d4af37]/80 hover:text-[#d4af37]
text-[var(--luxury-gold)]/80 hover:text-[var(--luxury-gold)]
mb-3 transition-all duration-300
group font-light tracking-wide text-xs sm:text-sm"
>
@@ -281,10 +281,10 @@ const RoomDetailPage: React.FC = () => {
<div className="flex items-center gap-1.5 mb-2">
{room.featured && (
<div className="flex items-center gap-1
bg-gradient-to-r from-[#d4af37] to-[#c9a227]
bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]
text-[#0f0f0f] px-2 py-0.5 rounded-sm
text-[10px] sm:text-xs font-medium tracking-wide
shadow-sm shadow-[#d4af37]/30"
shadow-sm shadow-[var(--luxury-gold)]/30"
>
<Sparkles className="w-2.5 h-2.5" />
Featured
@@ -315,7 +315,7 @@ const RoomDetailPage: React.FC = () => {
</p>
)}
{room.status === 'occupied' && nextAvailableDate && (
<p className="text-[9px] sm:text-[10px] text-[#d4af37] font-light leading-tight">
<p className="text-[9px] sm:text-[10px] text-[var(--luxury-gold)] font-light leading-tight">
Available from {nextAvailableDate.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}
</p>
)}
@@ -324,7 +324,7 @@ const RoomDetailPage: React.FC = () => {
<h1 className="text-xl sm:text-2xl lg:text-3xl font-serif font-semibold
text-white mb-2 tracking-tight leading-tight
bg-gradient-to-r from-white via-[#d4af37] to-white
bg-gradient-to-r from-white via-[var(--luxury-gold)] to-white
bg-clip-text text-transparent"
>
{roomType?.name}
@@ -336,12 +336,12 @@ const RoomDetailPage: React.FC = () => {
<div className="grid grid-cols-1 md:grid-cols-3 gap-2 sm:gap-3 mb-3">
<div className="flex items-center gap-2
p-2 bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a]
rounded-lg border border-[#d4af37]/20
hover:border-[#d4af37]/40 transition-all duration-300"
rounded-lg border border-[var(--luxury-gold)]/20
hover:border-[var(--luxury-gold)]/40 transition-all duration-300"
>
<div className="p-1 bg-[#d4af37]/10 rounded-lg
border border-[#d4af37]/30">
<MapPin className="w-3.5 h-3.5 text-[#d4af37]" />
<div className="p-1 bg-[var(--luxury-gold)]/10 rounded-lg
border border-[var(--luxury-gold)]/30">
<MapPin className="w-3.5 h-3.5 text-[var(--luxury-gold)]" />
</div>
<div>
<p className="text-[10px] sm:text-xs text-gray-400 font-light tracking-wide mb-0.5">
@@ -355,11 +355,11 @@ const RoomDetailPage: React.FC = () => {
<div className="flex items-center gap-2
p-2 bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a]
rounded-lg border border-[#d4af37]/20"
rounded-lg border border-[var(--luxury-gold)]/20"
>
<div className="p-1 bg-[#d4af37]/10 rounded-lg
border border-[#d4af37]/30">
<Users className="w-3.5 h-3.5 text-[#d4af37]" />
<div className="p-1 bg-[var(--luxury-gold)]/10 rounded-lg
border border-[var(--luxury-gold)]/30">
<Users className="w-3.5 h-3.5 text-[var(--luxury-gold)]" />
</div>
<div>
<p className="text-[10px] sm:text-xs text-gray-400 font-light tracking-wide mb-0.5">
@@ -374,12 +374,12 @@ const RoomDetailPage: React.FC = () => {
{room.average_rating != null && (
<div className="flex items-center gap-2
p-2 bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a]
rounded-lg border border-[#d4af37]/20
hover:border-[#d4af37]/40 transition-all duration-300"
rounded-lg border border-[var(--luxury-gold)]/20
hover:border-[var(--luxury-gold)]/40 transition-all duration-300"
>
<div className="p-1 bg-[#d4af37]/10 rounded-lg
border border-[#d4af37]/30">
<Star className="w-3.5 h-3.5 text-[#d4af37] fill-[#d4af37]" />
<div className="p-1 bg-[var(--luxury-gold)]/10 rounded-lg
border border-[var(--luxury-gold)]/30">
<Star className="w-3.5 h-3.5 text-[var(--luxury-gold)] fill-[var(--luxury-gold)]" />
</div>
<div>
<p className="text-[10px] sm:text-xs text-gray-400 font-light tracking-wide mb-0.5">
@@ -402,13 +402,13 @@ const RoomDetailPage: React.FC = () => {
{}
{(room?.description || roomType?.description) && (
<div className="p-3 sm:p-4 bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a]
rounded-lg border border-[#d4af37]/20
backdrop-blur-xl shadow-lg shadow-[#d4af37]/5"
rounded-lg border border-[var(--luxury-gold)]/20
backdrop-blur-xl shadow-lg shadow-[var(--luxury-gold)]/5"
>
<div className="flex items-center gap-2 mb-2">
<div className="p-1 bg-[#d4af37]/10 rounded-lg
border border-[#d4af37]/30">
<Award className="w-3.5 h-3.5 text-[#d4af37]" />
<div className="p-1 bg-[var(--luxury-gold)]/10 rounded-lg
border border-[var(--luxury-gold)]/30">
<Award className="w-3.5 h-3.5 text-[var(--luxury-gold)]" />
</div>
<h2 className="text-sm sm:text-base font-serif font-semibold
text-white tracking-wide"
@@ -426,13 +426,13 @@ const RoomDetailPage: React.FC = () => {
{}
<div className="p-3 sm:p-4 bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a]
rounded-lg border border-[#d4af37]/20
backdrop-blur-xl shadow-lg shadow-[#d4af37]/5"
rounded-lg border border-[var(--luxury-gold)]/20
backdrop-blur-xl shadow-lg shadow-[var(--luxury-gold)]/5"
>
<div className="flex items-center gap-2 mb-2">
<div className="p-1 bg-[#d4af37]/10 rounded-lg
border border-[#d4af37]/30">
<Sparkles className="w-3.5 h-3.5 text-[#d4af37]" />
<div className="p-1 bg-[var(--luxury-gold)]/10 rounded-lg
border border-[var(--luxury-gold)]/30">
<Sparkles className="w-3.5 h-3.5 text-[var(--luxury-gold)]" />
</div>
<h2 className="text-sm sm:text-base font-serif font-semibold
text-white tracking-wide"
@@ -447,10 +447,10 @@ const RoomDetailPage: React.FC = () => {
: (roomType?.amenities || [])
}
/>
<div className="mt-6 pt-6 border-t border-[#d4af37]/20">
<div className="mt-6 pt-6 border-t border-[var(--luxury-gold)]/20">
<Link
to="/services"
className="inline-flex items-center gap-2 px-4 py-2 bg-gradient-to-r from-[#d4af37]/20 to-[#c9a227]/10 hover:from-[#d4af37]/30 hover:to-[#d4af37]/20 text-[#d4af37] rounded-lg font-medium transition-all duration-300 border border-[#d4af37]/30 hover:border-[#d4af37]/50"
className="inline-flex items-center gap-2 px-4 py-2 bg-gradient-to-r from-[var(--luxury-gold)]/20 to-[var(--luxury-gold-dark)]/10 hover:from-[var(--luxury-gold)]/30 hover:to-[var(--luxury-gold)]/20 text-[var(--luxury-gold)] rounded-lg font-medium transition-all duration-300 border border-[var(--luxury-gold)]/30 hover:border-[var(--luxury-gold)]/50"
>
<Award className="w-4 h-4" />
<span className="text-sm">View All Services</span>
@@ -462,20 +462,20 @@ const RoomDetailPage: React.FC = () => {
{}
<aside className="lg:col-span-4">
<div className="bg-gradient-to-br from-[#1a1a1a] via-[#0f0f0f] to-[#1a1a1a]
rounded-lg border border-[#d4af37]/30
backdrop-blur-xl shadow-lg shadow-[#d4af37]/20
rounded-lg border border-[var(--luxury-gold)]/30
backdrop-blur-xl shadow-lg shadow-[var(--luxury-gold)]/20
p-3 sm:p-4 sticky top-4"
>
{}
<div className="mb-4 pb-4 border-b border-[#d4af37]/20">
<div className="mb-4 pb-4 border-b border-[var(--luxury-gold)]/20">
<p className="text-[10px] sm:text-xs text-gray-400 font-light tracking-wide mb-1">
Starting from
</p>
<div className="flex items-baseline gap-1.5">
<CurrencyIcon className="text-[#d4af37]" size={16} />
<CurrencyIcon className="text-[var(--luxury-gold)]" size={16} />
<div>
<div className="text-2xl sm:text-3xl font-serif font-semibold
bg-gradient-to-r from-[#d4af37] to-[#f5d76e]
bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-light)]
bg-clip-text text-transparent tracking-tight"
>
{formattedPrice}
@@ -510,7 +510,7 @@ const RoomDetailPage: React.FC = () => {
tracking-wide relative overflow-hidden group text-xs sm:text-sm
${
room.status === 'available'
? 'bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-[#0f0f0f] hover:from-[#f5d76e] hover:to-[#d4af37] shadow-sm shadow-[#d4af37]/30 hover:shadow-[#d4af37]/50'
? 'bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-[#0f0f0f] hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] shadow-sm shadow-[var(--luxury-gold)]/30 hover:shadow-[var(--luxury-gold)]/50'
: 'bg-gray-800 text-gray-500 cursor-not-allowed border border-gray-700'
}`}
>
@@ -525,12 +525,12 @@ const RoomDetailPage: React.FC = () => {
</div>
{room.status === 'available' && (
<div className="flex items-start gap-2 p-2 bg-[#d4af37]/5
rounded-lg border border-[#d4af37]/20 mb-3"
<div className="flex items-start gap-2 p-2 bg-[var(--luxury-gold)]/5
rounded-lg border border-[var(--luxury-gold)]/20 mb-3"
>
<Shield className="w-3.5 h-3.5 text-[#d4af37] mt-0.5 flex-shrink-0" />
<Shield className="w-3.5 h-3.5 text-[var(--luxury-gold)] mt-0.5 flex-shrink-0" />
<p className="text-[10px] sm:text-xs text-gray-300 font-light tracking-wide leading-relaxed">
<strong className="text-[#d4af37]">20% deposit required</strong> to secure your booking. Pay the remaining balance on arrival at the hotel.
<strong className="text-[var(--luxury-gold)]">20% deposit required</strong> to secure your booking. Pay the remaining balance on arrival at the hotel.
</p>
</div>
)}
@@ -540,27 +540,27 @@ const RoomDetailPage: React.FC = () => {
{}
<div className="space-y-2">
<div className="flex items-center justify-between
py-1.5 border-b border-[#d4af37]/10"
py-1.5 border-b border-[var(--luxury-gold)]/10"
>
<span className="text-[10px] sm:text-xs text-gray-400 font-light tracking-wide">Room Type</span>
<strong className="text-xs sm:text-sm text-white font-light">{roomType?.name}</strong>
</div>
<div className="flex items-center justify-between
py-1.5 border-b border-[#d4af37]/10"
py-1.5 border-b border-[var(--luxury-gold)]/10"
>
<span className="text-[10px] sm:text-xs text-gray-400 font-light tracking-wide">Max Guests</span>
<span className="text-xs sm:text-sm text-white font-light">{(room?.capacity || roomType?.capacity || 0)} guests</span>
</div>
{room?.room_size && (
<div className="flex items-center justify-between
py-1.5 border-b border-[#d4af37]/10"
py-1.5 border-b border-[var(--luxury-gold)]/10"
>
<span className="text-[10px] sm:text-xs text-gray-400 font-light tracking-wide">Room Size</span>
<span className="text-xs sm:text-sm text-white font-light">{room.room_size}</span>
</div>
)}
{room?.view && (
<div className={`flex items-center justify-between ${room?.room_size ? 'py-1.5 border-b border-[#d4af37]/10' : 'py-1.5'}`}>
<div className={`flex items-center justify-between ${room?.room_size ? 'py-1.5 border-b border-[var(--luxury-gold)]/10' : 'py-1.5'}`}>
<span className="text-[10px] sm:text-xs text-gray-400 font-light tracking-wide">View</span>
<span className="text-xs sm:text-sm text-white font-light">{room.view}</span>
</div>
@@ -572,8 +572,8 @@ const RoomDetailPage: React.FC = () => {
{}
<div className="mb-4 p-3 sm:p-4 bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a]
rounded-lg border border-[#d4af37]/20
backdrop-blur-xl shadow-lg shadow-[#d4af37]/5"
rounded-lg border border-[var(--luxury-gold)]/20
backdrop-blur-xl shadow-lg shadow-[var(--luxury-gold)]/5"
>
<ReviewSection roomId={room.id} />
</div>

View File

@@ -150,17 +150,17 @@ const RoomListPage: React.FC = () => {
{}
{/* Promotion Banner */}
{showPromotionBanner && activePromotion && (
<div className="w-full bg-gradient-to-r from-[#d4af37]/20 via-[#f5d76e]/15 to-[#d4af37]/20 border-b border-[#d4af37]/30">
<div className="w-full bg-gradient-to-r from-[var(--luxury-gold)]/20 via-[var(--luxury-gold-light)]/15 to-[var(--luxury-gold)]/20 border-b border-[var(--luxury-gold)]/30">
<div className="w-full max-w-[1920px] mx-auto px-3 sm:px-4 md:px-6 lg:px-8 xl:px-12 2xl:px-16 3xl:px-20 py-4">
<div className="flex items-center justify-between gap-4 bg-gradient-to-r from-[#1a1a1a] to-[#0f0f0f] border border-[#d4af37]/40 rounded-lg p-4 backdrop-blur-xl shadow-lg">
<div className="flex items-center justify-between gap-4 bg-gradient-to-r from-[#1a1a1a] to-[#0f0f0f] border border-[var(--luxury-gold)]/40 rounded-lg p-4 backdrop-blur-xl shadow-lg">
<div className="flex items-center gap-3 flex-1">
<div className="p-2 bg-[#d4af37]/20 rounded-lg border border-[#d4af37]/40">
<Tag className="w-5 h-5 text-[#d4af37]" />
<div className="p-2 bg-[var(--luxury-gold)]/20 rounded-lg border border-[var(--luxury-gold)]/40">
<Tag className="w-5 h-5 text-[var(--luxury-gold)]" />
</div>
<div className="flex-1">
<div className="flex items-center gap-2 mb-1">
<CheckCircle className="w-4 h-4 text-green-400" />
<span className="text-sm font-semibold text-[#d4af37]">
<span className="text-sm font-semibold text-[var(--luxury-gold)]">
Active Promotion: {activePromotion.code || activePromotion.title}
</span>
</div>
@@ -176,7 +176,7 @@ const RoomListPage: React.FC = () => {
</div>
<button
onClick={handleDismissPromotion}
className="p-2 hover:bg-[#d4af37]/10 rounded-lg transition-colors"
className="p-2 hover:bg-[var(--luxury-gold)]/10 rounded-lg transition-colors"
aria-label="Dismiss promotion"
>
<X className="w-5 h-5 text-gray-400 hover:text-white" />
@@ -186,19 +186,19 @@ const RoomListPage: React.FC = () => {
</div>
)}
<div className="w-full bg-gradient-to-br from-[#1a1a1a] via-[#0f0f0f] to-[#1a1a1a] border-b border-[#d4af37]/10 pt-6 sm:pt-7 md:pt-8">
<div className="w-full bg-gradient-to-br from-[#1a1a1a] via-[#0f0f0f] to-[#1a1a1a] border-b border-[var(--luxury-gold)]/10 pt-6 sm:pt-7 md:pt-8">
<div className="w-full max-w-[1920px] mx-auto px-3 sm:px-4 md:px-6 lg:px-8 xl:px-12 2xl:px-16 3xl:px-20 py-6 sm:py-7 md:py-8 lg:py-10">
{}
<Link
to="/"
className="inline-flex items-center gap-2
bg-gradient-to-r from-[#d4af37] to-[#c9a227]
text-[#0f0f0f] hover:from-[#f5d76e] hover:to-[#d4af37]
bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]
text-[#0f0f0f] hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)]
active:scale-95
mb-4 sm:mb-5 md:mb-6 transition-all duration-300
group font-medium tracking-wide text-sm
px-4 py-2 rounded-sm
shadow-lg shadow-[#d4af37]/30 hover:shadow-xl hover:shadow-[#d4af37]/40
shadow-lg shadow-[var(--luxury-gold)]/30 hover:shadow-xl hover:shadow-[var(--luxury-gold)]/40
touch-manipulation"
>
<ArrowLeft className="w-4 h-4 sm:w-4 sm:h-4 group-hover:-translate-x-1 transition-transform" />
@@ -208,13 +208,13 @@ const RoomListPage: React.FC = () => {
{}
<div className="text-center max-w-3xl mx-auto px-2">
<div className="inline-flex items-center justify-center gap-2 mb-3 sm:mb-4">
<div className="p-2 sm:p-2.5 bg-[#d4af37]/10 rounded-lg border border-[#d4af37]/30 backdrop-blur-sm">
<Hotel className="w-5 h-5 sm:w-5 sm:h-5 text-[#d4af37]" />
<div className="p-2 sm:p-2.5 bg-[var(--luxury-gold)]/10 rounded-lg border border-[var(--luxury-gold)]/30 backdrop-blur-sm">
<Hotel className="w-5 h-5 sm:w-5 sm:h-5 text-[var(--luxury-gold)]" />
</div>
</div>
<h1 className="text-2xl xs:text-3xl sm:text-4xl md:text-5xl font-serif font-semibold
text-white mb-2 sm:mb-3 tracking-tight leading-tight px-2
bg-gradient-to-r from-white via-[#d4af37] to-white
bg-gradient-to-r from-white via-[var(--luxury-gold)] to-white
bg-clip-text text-transparent"
>
Our Rooms & Suites
@@ -236,24 +236,24 @@ const RoomListPage: React.FC = () => {
<button
onClick={() => setIsFilterOpen(!isFilterOpen)}
className="w-full bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a]
border border-[#d4af37]/30 rounded-xl p-4
backdrop-blur-xl shadow-lg shadow-[#d4af37]/10
border border-[var(--luxury-gold)]/30 rounded-xl p-4
backdrop-blur-xl shadow-lg shadow-[var(--luxury-gold)]/10
flex items-center justify-between gap-3
hover:border-[#d4af37]/50 hover:shadow-xl hover:shadow-[#d4af37]/20
hover:border-[var(--luxury-gold)]/50 hover:shadow-xl hover:shadow-[var(--luxury-gold)]/20
transition-all duration-300 touch-manipulation"
>
<div className="flex items-center gap-3">
<div className="p-2 bg-[#d4af37]/10 rounded-lg border border-[#d4af37]/30">
<Filter className="w-5 h-5 text-[#d4af37]" />
<div className="p-2 bg-[var(--luxury-gold)]/10 rounded-lg border border-[var(--luxury-gold)]/30">
<Filter className="w-5 h-5 text-[var(--luxury-gold)]" />
</div>
<span className="text-white font-medium tracking-wide text-base">
Filters
</span>
</div>
{isFilterOpen ? (
<ChevronUp className="w-5 h-5 text-[#d4af37]" />
<ChevronUp className="w-5 h-5 text-[var(--luxury-gold)]" />
) : (
<ChevronDown className="w-5 h-5 text-[#d4af37]" />
<ChevronDown className="w-5 h-5 text-[var(--luxury-gold)]" />
)}
</button>
</div>
@@ -308,10 +308,10 @@ const RoomListPage: React.FC = () => {
<p className="text-red-300 font-light text-sm sm:text-base md:text-lg mb-4 sm:mb-5 md:mb-6 tracking-wide px-2">{error}</p>
<button
onClick={() => window.location.reload()}
className="px-5 sm:px-6 md:px-8 py-2.5 sm:py-3 bg-gradient-to-r from-[#d4af37] to-[#c9a227]
className="px-5 sm:px-6 md:px-8 py-2.5 sm:py-3 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]
text-[#0f0f0f] rounded-sm font-medium tracking-wide text-sm sm:text-base
hover:from-[#f5d76e] hover:to-[#d4af37] active:scale-95
transition-all duration-300 shadow-lg shadow-[#d4af37]/30
hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] active:scale-95
transition-all duration-300 shadow-lg shadow-[var(--luxury-gold)]/30
touch-manipulation min-h-[44px]"
>
Try Again
@@ -321,13 +321,13 @@ const RoomListPage: React.FC = () => {
{!loading && !error && rooms.length === 0 && (
<div className="bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a]
border border-[#d4af37]/20 rounded-xl p-8 sm:p-10 md:p-12 lg:p-16 text-center
backdrop-blur-xl shadow-2xl shadow-[#d4af37]/5"
border border-[var(--luxury-gold)]/20 rounded-xl p-8 sm:p-10 md:p-12 lg:p-16 text-center
backdrop-blur-xl shadow-2xl shadow-[var(--luxury-gold)]/5"
>
<div className="inline-flex items-center justify-center w-16 h-16 sm:w-20 sm:h-20 md:w-24 md:h-24
bg-[#d4af37]/10 rounded-2xl mb-4 sm:mb-5 md:mb-6 lg:mb-8 border border-[#d4af37]/30"
bg-[var(--luxury-gold)]/10 rounded-2xl mb-4 sm:mb-5 md:mb-6 lg:mb-8 border border-[var(--luxury-gold)]/30"
>
<Hotel className="w-8 h-8 sm:w-10 sm:h-10 md:w-12 md:h-12 text-[#d4af37]" />
<Hotel className="w-8 h-8 sm:w-10 sm:h-10 md:w-12 md:h-12 text-[var(--luxury-gold)]" />
</div>
<h3 className="text-lg sm:text-xl md:text-2xl font-serif font-semibold
text-white mb-3 sm:mb-4 tracking-wide px-2"
@@ -339,10 +339,10 @@ const RoomListPage: React.FC = () => {
</p>
<button
onClick={() => window.location.href = '/rooms'}
className="px-5 sm:px-6 md:px-8 py-2.5 sm:py-3 bg-gradient-to-r from-[#d4af37] to-[#c9a227]
className="px-5 sm:px-6 md:px-8 py-2.5 sm:py-3 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]
text-[#0f0f0f] rounded-sm font-medium tracking-wide text-sm sm:text-base
hover:from-[#f5d76e] hover:to-[#d4af37] active:scale-95
transition-all duration-300 shadow-lg shadow-[#d4af37]/30
hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] active:scale-95
transition-all duration-300 shadow-lg shadow-[var(--luxury-gold)]/30
touch-manipulation min-h-[44px]"
>
Clear Filters
@@ -355,8 +355,8 @@ const RoomListPage: React.FC = () => {
{}
<div className="mb-3 sm:mb-4 md:mb-5 flex flex-col sm:flex-row items-start sm:items-center justify-between gap-2 sm:gap-3">
<p className="text-gray-400 font-light tracking-wide text-xs sm:text-sm md:text-base">
Showing <span className="text-[#d4af37] font-medium">{rooms.length}</span> of{' '}
<span className="text-[#d4af37] font-medium">{pagination.total}</span> rooms
Showing <span className="text-[var(--luxury-gold)] font-medium">{rooms.length}</span> of{' '}
<span className="text-[var(--luxury-gold)] font-medium">{pagination.total}</span> rooms
</p>
</div>
@@ -370,7 +370,7 @@ const RoomListPage: React.FC = () => {
</div>
{pagination.totalPages > 1 && (
<div className="mt-4 sm:mt-5 md:mt-6 pt-3 sm:pt-4 border-t border-[#d4af37]/20">
<div className="mt-4 sm:mt-5 md:mt-6 pt-3 sm:pt-4 border-t border-[var(--luxury-gold)]/20">
<Pagination
currentPage={pagination.page}
totalPages={pagination.totalPages}

View File

@@ -94,9 +94,9 @@ const TaskDetailModal: React.FC<TaskModalProps> = ({
/>
{/* Luxury Modal with enhanced styling - Compact */}
<div className="relative w-full max-w-3xl mx-auto my-2 sm:my-3 md:my-4 bg-white rounded-xl sm:rounded-2xl shadow-2xl overflow-hidden animate-scale-in border border-[#d4af37]/20 flex flex-col" style={{ maxHeight: 'calc(100vh - 1rem)' }}>
<div className="relative w-full max-w-3xl mx-auto my-2 sm:my-3 md:my-4 bg-white rounded-xl sm:rounded-2xl shadow-2xl overflow-hidden animate-scale-in border border-[var(--luxury-gold)]/20 flex flex-col" style={{ maxHeight: 'calc(100vh - 1rem)' }}>
{/* Luxury Header with enhanced gradient and effects - Compact */}
<div className="relative bg-gradient-to-r from-[#d4af37] via-[#c9a227] via-[#d4af37] to-[#c9a227] p-3 sm:p-4 md:p-5 overflow-hidden flex-shrink-0">
<div className="relative bg-gradient-to-r from-[var(--luxury-gold)] via-[var(--luxury-gold-dark)] via-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] p-3 sm:p-4 md:p-5 overflow-hidden flex-shrink-0">
{/* Animated background pattern */}
<div className="absolute inset-0 opacity-10">
<div className="absolute inset-0" style={{
@@ -147,9 +147,9 @@ const TaskDetailModal: React.FC<TaskModalProps> = ({
>
{/* Task Info with luxury cards - Compact */}
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
<div className="group relative flex items-center space-x-2.5 sm:space-x-3 p-3 sm:p-3.5 bg-gradient-to-br from-gray-50 via-white to-gray-50 rounded-lg sm:rounded-xl border border-gray-200/50 hover:border-[#d4af37]/30 transition-all duration-300 hover:shadow-md overflow-hidden">
<div className="absolute inset-0 bg-gradient-to-br from-[#d4af37]/5 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
<div className="relative w-9 h-9 sm:w-10 sm:h-10 rounded-lg bg-gradient-to-br from-[#d4af37] to-[#c9a227] flex items-center justify-center flex-shrink-0 shadow-md group-hover:scale-105 transition-transform duration-300">
<div className="group relative flex items-center space-x-2.5 sm:space-x-3 p-3 sm:p-3.5 bg-gradient-to-br from-gray-50 via-white to-gray-50 rounded-lg sm:rounded-xl border border-gray-200/50 hover:border-[var(--luxury-gold)]/30 transition-all duration-300 hover:shadow-md overflow-hidden">
<div className="absolute inset-0 bg-gradient-to-br from-[var(--luxury-gold)]/5 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
<div className="relative w-9 h-9 sm:w-10 sm:h-10 rounded-lg bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] flex items-center justify-center flex-shrink-0 shadow-md group-hover:scale-105 transition-transform duration-300">
<Calendar className="w-4 h-4 sm:w-5 sm:h-5 text-white drop-shadow-md" />
</div>
<div className="relative min-w-0 flex-1">
@@ -192,16 +192,16 @@ const TaskDetailModal: React.FC<TaskModalProps> = ({
<div className="space-y-2">
<div className="flex items-center justify-between gap-3">
<h3 className="text-sm sm:text-base font-bold text-gray-900 flex items-center space-x-2 min-w-0">
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-[#d4af37] to-[#c9a227] flex items-center justify-center shadow-md">
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] flex items-center justify-center shadow-md">
<TrendingUp className="w-4 h-4 sm:w-5 sm:h-5 text-white" />
</div>
<span className="truncate">Task Progress</span>
</h3>
<span className="text-xl sm:text-2xl font-bold bg-gradient-to-r from-[#d4af37] to-[#c9a227] bg-clip-text text-transparent flex-shrink-0">{progress}%</span>
<span className="text-xl sm:text-2xl font-bold bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] bg-clip-text text-transparent flex-shrink-0">{progress}%</span>
</div>
<div className="relative w-full h-3 sm:h-3.5 bg-gray-200/50 rounded-full overflow-hidden shadow-inner border border-gray-300/30">
<div
className="absolute inset-y-0 left-0 bg-gradient-to-r from-[#d4af37] via-[#c9a227] to-[#d4af37] rounded-full transition-all duration-700 ease-out shadow-md"
className="absolute inset-y-0 left-0 bg-gradient-to-r from-[var(--luxury-gold)] via-[var(--luxury-gold-dark)] to-[var(--luxury-gold)] rounded-full transition-all duration-700 ease-out shadow-md"
style={{ width: `${progress}%` }}
>
<div className="absolute inset-0 bg-gradient-to-r from-transparent via-white/30 to-transparent animate-shimmer"></div>
@@ -217,7 +217,7 @@ const TaskDetailModal: React.FC<TaskModalProps> = ({
{task.checklist_items && task.checklist_items.length > 0 && (
<div className="space-y-2.5">
<h3 className="text-sm sm:text-base font-bold text-gray-900 flex items-center space-x-2">
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-[#d4af37] to-[#c9a227] flex items-center justify-center shadow-md">
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] flex items-center justify-center shadow-md">
<Award className="w-4 h-4 sm:w-5 sm:h-5 text-white" />
</div>
<span>Checklist Items</span>
@@ -229,11 +229,11 @@ const TaskDetailModal: React.FC<TaskModalProps> = ({
className={`group relative flex items-start space-x-2.5 sm:space-x-3 p-2.5 sm:p-3 rounded-lg sm:rounded-xl border transition-all duration-300 cursor-pointer overflow-hidden ${
item.completed
? 'bg-gradient-to-br from-green-50 via-emerald-50/50 to-green-50 border-green-300/50 hover:border-green-400/70'
: 'bg-white border-gray-200/50 hover:border-[#d4af37]/50 hover:shadow-md hover:bg-gradient-to-br hover:from-[#d4af37]/5 hover:to-transparent'
: 'bg-white border-gray-200/50 hover:border-[var(--luxury-gold)]/50 hover:shadow-md hover:bg-gradient-to-br hover:from-[var(--luxury-gold)]/5 hover:to-transparent'
}`}
>
{!item.completed && (
<div className="absolute inset-0 bg-gradient-to-r from-[#d4af37]/0 via-[#d4af37]/5 to-[#d4af37]/0 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
<div className="absolute inset-0 bg-gradient-to-r from-[var(--luxury-gold)]/0 via-[var(--luxury-gold)]/5 to-[var(--luxury-gold)]/0 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
)}
<input
type="checkbox"
@@ -243,7 +243,7 @@ const TaskDetailModal: React.FC<TaskModalProps> = ({
onUpdateChecklist(task, index, e.target.checked);
}}
disabled={isUpdating || task.status === 'completed'}
className="relative mt-0.5 h-4 w-4 sm:h-5 sm:w-5 text-[#d4af37] focus:ring-2 focus:ring-[#d4af37] focus:ring-offset-1 border-2 border-gray-300 rounded-md disabled:opacity-50 disabled:cursor-not-allowed flex-shrink-0 transition-all duration-200 checked:bg-[#d4af37] checked:border-[#d4af37]"
className="relative mt-0.5 h-4 w-4 sm:h-5 sm:w-5 text-[var(--luxury-gold)] focus:ring-2 focus:ring-[var(--luxury-gold)] focus:ring-offset-1 border-2 border-gray-300 rounded-md disabled:opacity-50 disabled:cursor-not-allowed flex-shrink-0 transition-all duration-200 checked:bg-[var(--luxury-gold)] checked:border-[var(--luxury-gold)]"
/>
<div className="relative flex-1 min-w-0">
<span
@@ -284,7 +284,7 @@ const TaskDetailModal: React.FC<TaskModalProps> = ({
<div className="space-y-2.5">
<div className="flex items-center justify-between">
<h3 className="text-sm sm:text-base font-bold text-gray-900 flex items-center space-x-2">
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-[#d4af37] to-[#c9a227] flex items-center justify-center shadow-md">
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] flex items-center justify-center shadow-md">
<Camera className="w-4 h-4 sm:w-5 sm:h-5 text-white" />
</div>
<span>Photos</span>
@@ -329,7 +329,7 @@ const TaskDetailModal: React.FC<TaskModalProps> = ({
<img
src={fullUrl}
alt={`Task photo ${index + 1}`}
className="w-full h-24 sm:h-32 object-cover rounded-lg border border-gray-200 hover:border-[#d4af37] transition-all duration-200 cursor-pointer"
className="w-full h-24 sm:h-32 object-cover rounded-lg border border-gray-200 hover:border-[var(--luxury-gold)] transition-all duration-200 cursor-pointer"
onClick={() => window.open(fullUrl, '_blank')}
/>
{task.id && task.status !== 'completed' && (
@@ -358,7 +358,7 @@ const TaskDetailModal: React.FC<TaskModalProps> = ({
)}
{uploadingPhoto && (
<div className="text-center py-2">
<RefreshCw className="w-4 h-4 animate-spin text-[#d4af37] mx-auto" />
<RefreshCw className="w-4 h-4 animate-spin text-[var(--luxury-gold)] mx-auto" />
<p className="text-xs text-gray-500 mt-1">Uploading photo...</p>
</div>
)}
@@ -367,7 +367,7 @@ const TaskDetailModal: React.FC<TaskModalProps> = ({
{/* Luxury Footer Actions - Sticky and Compact */}
<div className="relative p-3 sm:p-4 bg-gradient-to-br from-gray-50 via-white to-gray-50 border-t border-gray-200/50 flex flex-col sm:flex-row items-stretch sm:items-center justify-between gap-2 sm:gap-3 flex-shrink-0 shadow-lg">
<div className="absolute inset-0 bg-gradient-to-r from-[#d4af37]/5 via-transparent to-[#d4af37]/5 opacity-50"></div>
<div className="absolute inset-0 bg-gradient-to-r from-[var(--luxury-gold)]/5 via-transparent to-[var(--luxury-gold)]/5 opacity-50"></div>
<div className="flex items-center gap-2">
{task.id && task.status !== 'completed' && (
<button
@@ -1344,12 +1344,12 @@ const HousekeepingDashboardPage: React.FC = () => {
Enterprise Dashboard
</h1>
<p className="text-xs sm:text-sm md:text-base text-gray-600 font-light truncate">
Welcome back, <span className="font-semibold text-[#d4af37]">{userInfo?.name || userInfo?.email || 'Housekeeping Staff'}</span>
Welcome back, <span className="font-semibold text-[var(--luxury-gold)]">{userInfo?.name || userInfo?.email || 'Housekeeping Staff'}</span>
</p>
</div>
<button
onClick={() => activeTab === 'tasks' ? fetchTasks() : fetchInspections()}
className="w-full sm:w-auto flex items-center justify-center space-x-2 px-4 sm:px-6 py-2 sm:py-3 bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-white rounded-lg hover:from-[#f5d76e] hover:to-[#d4af37] transition-all duration-300 shadow-lg hover:shadow-xl hover:-translate-y-0.5 text-sm sm:text-base font-medium flex-shrink-0"
className="w-full sm:w-auto flex items-center justify-center space-x-2 px-4 sm:px-6 py-2 sm:py-3 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-white rounded-lg hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] transition-all duration-300 shadow-lg hover:shadow-xl hover:-translate-y-0.5 text-sm sm:text-base font-medium flex-shrink-0"
>
<RefreshCw className="w-4 h-4 sm:w-5 sm:h-5" />
<span>Refresh</span>
@@ -1365,7 +1365,7 @@ const HousekeepingDashboardPage: React.FC = () => {
onClick={() => setActiveTab('tasks')}
className={`flex-1 px-4 sm:px-6 py-2.5 sm:py-3 rounded-lg sm:rounded-xl font-semibold text-sm sm:text-base transition-all duration-300 ${
activeTab === 'tasks'
? 'bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-white shadow-lg'
? 'bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-white shadow-lg'
: 'bg-white text-gray-700 hover:bg-gray-100'
}`}
>
@@ -1378,7 +1378,7 @@ const HousekeepingDashboardPage: React.FC = () => {
onClick={() => setActiveTab('inspections')}
className={`flex-1 px-4 sm:px-6 py-2.5 sm:py-3 rounded-lg sm:rounded-xl font-semibold text-sm sm:text-base transition-all duration-300 ${
activeTab === 'inspections'
? 'bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-white shadow-lg'
? 'bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-white shadow-lg'
: 'bg-white text-gray-700 hover:bg-gray-100'
}`}
>
@@ -1422,7 +1422,7 @@ const HousekeepingDashboardPage: React.FC = () => {
type="date"
value={filters.date}
onChange={(e) => setFilters({ ...filters, date: e.target.value })}
className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[#d4af37]"
className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[var(--luxury-gold)]"
/>
</div>
<div className="flex-1 min-w-0">
@@ -1430,7 +1430,7 @@ const HousekeepingDashboardPage: React.FC = () => {
<select
value={filters.status}
onChange={(e) => setFilters({ ...filters, status: e.target.value })}
className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[#d4af37]"
className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[var(--luxury-gold)]"
>
<option value="">All Statuses</option>
<option value="pending">Pending</option>
@@ -1444,7 +1444,7 @@ const HousekeepingDashboardPage: React.FC = () => {
<select
value={filters.task_type}
onChange={(e) => setFilters({ ...filters, task_type: e.target.value })}
className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[#d4af37]"
className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[var(--luxury-gold)]"
>
<option value="">All Types</option>
<option value="checkout">Checkout</option>
@@ -1472,7 +1472,7 @@ const HousekeepingDashboardPage: React.FC = () => {
<div className="enterprise-card p-4 sm:p-5 md:p-6">
<div className="flex items-center justify-between mb-4 sm:mb-5">
<h2 className="text-lg sm:text-xl md:text-2xl font-serif font-bold text-gray-900 flex items-center gap-2 sm:gap-3">
<Target className="w-5 h-5 sm:w-6 sm:h-6 text-[#d4af37]" />
<Target className="w-5 h-5 sm:w-6 sm:h-6 text-[var(--luxury-gold)]" />
<span>Your Performance Today</span>
</h2>
</div>
@@ -1511,9 +1511,9 @@ const HousekeepingDashboardPage: React.FC = () => {
</p>
<p className="text-[9px] sm:text-xs text-gray-500 mt-1">vs estimated</p>
</div>
<div className="p-3 sm:p-4 bg-gradient-to-br from-[#d4af37]/10 to-[#c9a227]/10 rounded-lg sm:rounded-xl border border-[#d4af37]/20">
<div className="p-3 sm:p-4 bg-gradient-to-br from-[var(--luxury-gold)]/10 to-[var(--luxury-gold-dark)]/10 rounded-lg sm:rounded-xl border border-[var(--luxury-gold)]/20">
<div className="flex items-center gap-2 mb-2">
<Award className="w-4 h-4 sm:w-5 sm:h-5 text-[#d4af37]" />
<Award className="w-4 h-4 sm:w-5 sm:h-5 text-[var(--luxury-gold)]" />
<p className="text-[10px] sm:text-xs text-gray-600 font-medium">Quality</p>
</div>
<p className="text-xl sm:text-2xl font-bold text-gray-900">
@@ -1580,13 +1580,13 @@ const HousekeepingDashboardPage: React.FC = () => {
</div>
<div className="enterprise-card p-4 sm:p-5 md:p-6 relative overflow-hidden group hover:scale-105 transition-transform duration-300">
<div className="absolute top-0 right-0 w-24 h-24 sm:w-32 sm:h-32 bg-gradient-to-br from-[#d4af37]/20 to-[#c9a227]/20 rounded-full blur-2xl"></div>
<div className="absolute top-0 right-0 w-24 h-24 sm:w-32 sm:h-32 bg-gradient-to-br from-[var(--luxury-gold)]/20 to-[var(--luxury-gold-dark)]/20 rounded-full blur-2xl"></div>
<div className="relative">
<div className="flex items-center justify-between mb-3 sm:mb-4">
<div className="w-10 h-10 sm:w-12 sm:h-12 rounded-xl bg-gradient-to-br from-[#d4af37] to-[#c9a227] flex items-center justify-center shadow-lg flex-shrink-0">
<div className="w-10 h-10 sm:w-12 sm:h-12 rounded-xl bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] flex items-center justify-center shadow-lg flex-shrink-0">
<Sparkles className="w-5 h-5 sm:w-6 sm:h-6 text-white" />
</div>
<span className="text-[10px] sm:text-xs font-semibold text-[#c9a227] bg-[#d4af37]/10 px-2 sm:px-3 py-0.5 sm:py-1 rounded-full whitespace-nowrap">TOTAL</span>
<span className="text-[10px] sm:text-xs font-semibold text-[var(--luxury-gold-dark)] bg-[var(--luxury-gold)]/10 px-2 sm:px-3 py-0.5 sm:py-1 rounded-full whitespace-nowrap">TOTAL</span>
</div>
<p className="text-xs sm:text-sm font-medium text-gray-600 mb-1">Total Today</p>
<p className="text-2xl sm:text-3xl font-bold text-gray-900">{stats.total}</p>
@@ -1600,7 +1600,7 @@ const HousekeepingDashboardPage: React.FC = () => {
<div className="space-y-4 sm:space-y-5">
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 sm:gap-4">
<h2 className="text-xl sm:text-2xl font-serif font-bold text-gray-900 flex items-center gap-2">
<Eye className="w-5 h-5 sm:w-6 sm:h-6 text-[#d4af37]" />
<Eye className="w-5 h-5 sm:w-6 sm:h-6 text-[var(--luxury-gold)]" />
<span>Room Inspections</span>
</h2>
<button
@@ -1609,7 +1609,7 @@ const HousekeepingDashboardPage: React.FC = () => {
await fetchRoomsForInspection();
setShowCreateInspectionModal(true);
}}
className="w-full sm:w-auto flex items-center justify-center space-x-2 px-4 sm:px-6 py-2 sm:py-3 bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-white rounded-lg hover:from-[#f5d76e] hover:to-[#d4af37] transition-all duration-300 shadow-lg hover:shadow-xl text-sm sm:text-base font-medium"
className="w-full sm:w-auto flex items-center justify-center space-x-2 px-4 sm:px-6 py-2 sm:py-3 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-white rounded-lg hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] transition-all duration-300 shadow-lg hover:shadow-xl text-sm sm:text-base font-medium"
>
<Plus className="w-4 h-4 sm:w-5 sm:h-5" />
<span>New Inspection</span>
@@ -1620,8 +1620,8 @@ const HousekeepingDashboardPage: React.FC = () => {
<Loading />
) : inspections.length === 0 ? (
<div className="enterprise-card p-8 sm:p-12 text-center">
<div className="w-16 h-16 sm:w-20 sm:h-20 rounded-full bg-gradient-to-br from-[#d4af37]/20 to-[#c9a227]/20 flex items-center justify-center mx-auto mb-3 sm:mb-4">
<Eye className="w-8 h-8 sm:w-10 sm:h-10 text-[#d4af37]" />
<div className="w-16 h-16 sm:w-20 sm:h-20 rounded-full bg-gradient-to-br from-[var(--luxury-gold)]/20 to-[var(--luxury-gold-dark)]/20 flex items-center justify-center mx-auto mb-3 sm:mb-4">
<Eye className="w-8 h-8 sm:w-10 sm:h-10 text-[var(--luxury-gold)]" />
</div>
<h3 className="text-lg sm:text-xl font-semibold text-gray-900 mb-2">No inspections found</h3>
<p className="text-sm sm:text-base text-gray-500">You don't have any inspections assigned yet.</p>
@@ -1640,7 +1640,7 @@ const HousekeepingDashboardPage: React.FC = () => {
<div className="flex items-start justify-between mb-3 sm:mb-4 gap-3">
<div className="flex-1 min-w-0">
<div className="flex items-center space-x-2 sm:space-x-3 mb-2">
<div className="w-8 h-8 sm:w-10 sm:h-10 rounded-lg bg-gradient-to-br from-[#d4af37] to-[#c9a227] flex items-center justify-center shadow-lg flex-shrink-0">
<div className="w-8 h-8 sm:w-10 sm:h-10 rounded-lg bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] flex items-center justify-center shadow-lg flex-shrink-0">
<MapPin className="w-4 h-4 sm:w-5 sm:h-5 text-white" />
</div>
<div className="min-w-0 flex-1">
@@ -1664,7 +1664,7 @@ const HousekeepingDashboardPage: React.FC = () => {
<div className="flex items-center space-x-4 text-xs sm:text-sm text-gray-600 mb-3 sm:mb-4">
<div className="flex items-center space-x-1.5">
<Calendar className="w-3.5 h-3.5 sm:w-4 sm:h-4 text-[#d4af37] flex-shrink-0" />
<Calendar className="w-3.5 h-3.5 sm:w-4 sm:h-4 text-[var(--luxury-gold)] flex-shrink-0" />
<span className="text-[10px] sm:text-xs truncate">{formatDate(inspection.scheduled_at)}</span>
</div>
</div>
@@ -1673,11 +1673,11 @@ const HousekeepingDashboardPage: React.FC = () => {
<div className="mb-3 sm:mb-4">
<div className="flex items-center justify-between mb-1.5 sm:mb-2">
<span className="text-[10px] sm:text-xs font-medium text-gray-600">Quality Score</span>
<span className="text-xs sm:text-sm font-bold text-[#d4af37]">{inspection.overall_score.toFixed(1)}/5.0</span>
<span className="text-xs sm:text-sm font-bold text-[var(--luxury-gold)]">{inspection.overall_score.toFixed(1)}/5.0</span>
</div>
<div className="relative w-full h-1.5 sm:h-2 bg-gray-200 rounded-full overflow-hidden">
<div
className="absolute inset-y-0 left-0 bg-gradient-to-r from-[#d4af37] to-[#c9a227] rounded-full transition-all duration-500"
className="absolute inset-y-0 left-0 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] rounded-full transition-all duration-500"
style={{ width: `${(inspection.overall_score / 5) * 100}%` }}
/>
</div>
@@ -1709,7 +1709,7 @@ const HousekeepingDashboardPage: React.FC = () => {
<div className="space-y-4 sm:space-y-5">
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-2 sm:gap-4">
<h2 className="text-xl sm:text-2xl font-serif font-bold text-gray-900 flex items-center gap-2">
<Building2 className="w-5 h-5 sm:w-6 sm:h-6 text-[#d4af37]" />
<Building2 className="w-5 h-5 sm:w-6 sm:h-6 text-[var(--luxury-gold)]" />
<span>Today's Tasks by Floor</span>
</h2>
<span className="text-xs sm:text-sm text-gray-500">{tasks.length} task{tasks.length !== 1 ? 's' : ''} across {tasksByFloor.length} floor{tasksByFloor.length !== 1 ? 's' : ''}</span>
@@ -1717,8 +1717,8 @@ const HousekeepingDashboardPage: React.FC = () => {
{tasks.length === 0 ? (
<div className="enterprise-card p-8 sm:p-12 text-center">
<div className="w-16 h-16 sm:w-20 sm:h-20 rounded-full bg-gradient-to-br from-[#d4af37]/20 to-[#c9a227]/20 flex items-center justify-center mx-auto mb-3 sm:mb-4">
<Sparkles className="w-8 h-8 sm:w-10 sm:h-10 text-[#d4af37]" />
<div className="w-16 h-16 sm:w-20 sm:h-20 rounded-full bg-gradient-to-br from-[var(--luxury-gold)]/20 to-[var(--luxury-gold-dark)]/20 flex items-center justify-center mx-auto mb-3 sm:mb-4">
<Sparkles className="w-8 h-8 sm:w-10 sm:h-10 text-[var(--luxury-gold)]" />
</div>
<h3 className="text-lg sm:text-xl font-semibold text-gray-900 mb-2">No tasks assigned</h3>
<p className="text-sm sm:text-base text-gray-500">You don't have any housekeeping tasks assigned for today.</p>
@@ -1743,16 +1743,16 @@ const HousekeepingDashboardPage: React.FC = () => {
onClick={() => setSelectedFloor(floor)}
className={`relative px-4 sm:px-6 py-2.5 sm:py-3 rounded-lg sm:rounded-xl font-semibold text-sm sm:text-base transition-all duration-300 flex items-center gap-2 sm:gap-3 whitespace-nowrap flex-shrink-0 ${
isActive
? 'bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-white shadow-lg scale-105'
: 'bg-white text-gray-700 hover:bg-gray-100 border border-gray-200/50 hover:border-[#d4af37]/30'
? 'bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-white shadow-lg scale-105'
: 'bg-white text-gray-700 hover:bg-gray-100 border border-gray-200/50 hover:border-[var(--luxury-gold)]/30'
}`}
>
<Building2 className={`w-4 h-4 sm:w-5 sm:h-5 ${isActive ? 'text-white' : 'text-[#d4af37]'}`} />
<Building2 className={`w-4 h-4 sm:w-5 sm:h-5 ${isActive ? 'text-white' : 'text-[var(--luxury-gold)]'}`} />
<span className="font-bold">{getFloorDisplayName(floor)}</span>
<span className={`px-2 py-0.5 rounded-full text-[10px] sm:text-xs font-bold ${
isActive
? 'bg-white/20 text-white'
: 'bg-[#d4af37]/10 text-[#c9a227]'
: 'bg-[var(--luxury-gold)]/10 text-[var(--luxury-gold-dark)]'
}`}>
{floorStats.total}
</span>
@@ -1779,10 +1779,10 @@ const HousekeepingDashboardPage: React.FC = () => {
{selectedFloor !== null && (
<div className="space-y-4 sm:space-y-5">
{/* Floor Header with Stats */}
<div className="enterprise-card p-4 sm:p-5 bg-gradient-to-r from-[#d4af37]/10 via-[#c9a227]/5 to-[#d4af37]/10 border border-[#d4af37]/20 rounded-xl sm:rounded-2xl">
<div className="enterprise-card p-4 sm:p-5 bg-gradient-to-r from-[var(--luxury-gold)]/10 via-[var(--luxury-gold-dark)]/5 to-[var(--luxury-gold)]/10 border border-[var(--luxury-gold)]/20 rounded-xl sm:rounded-2xl">
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 sm:gap-4">
<div className="flex items-center gap-3 sm:gap-4">
<div className="w-10 h-10 sm:w-12 sm:h-12 rounded-xl bg-gradient-to-br from-[#d4af37] to-[#c9a227] flex items-center justify-center shadow-lg">
<div className="w-10 h-10 sm:w-12 sm:h-12 rounded-xl bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] flex items-center justify-center shadow-lg">
<Building2 className="w-5 h-5 sm:w-6 sm:h-6 text-white" />
</div>
<div>
@@ -1820,8 +1820,8 @@ const HousekeepingDashboardPage: React.FC = () => {
{/* Tasks Grid */}
{currentFloorTasks.length === 0 ? (
<div className="enterprise-card p-8 sm:p-12 text-center">
<div className="w-16 h-16 sm:w-20 sm:h-20 rounded-full bg-gradient-to-br from-[#d4af37]/20 to-[#c9a227]/20 flex items-center justify-center mx-auto mb-3 sm:mb-4">
<Sparkles className="w-8 h-8 sm:w-10 sm:h-10 text-[#d4af37]" />
<div className="w-16 h-16 sm:w-20 sm:h-20 rounded-full bg-gradient-to-br from-[var(--luxury-gold)]/20 to-[var(--luxury-gold-dark)]/20 flex items-center justify-center mx-auto mb-3 sm:mb-4">
<Sparkles className="w-8 h-8 sm:w-10 sm:h-10 text-[var(--luxury-gold)]" />
</div>
<h3 className="text-lg sm:text-xl font-semibold text-gray-900 mb-2">No tasks on this floor</h3>
<p className="text-sm sm:text-base text-gray-500">No housekeeping tasks assigned for {getFloorDisplayName(selectedFloor).toLowerCase()}.</p>
@@ -1845,7 +1845,7 @@ const HousekeepingDashboardPage: React.FC = () => {
<div className="flex items-start justify-between mb-3 sm:mb-4 gap-3">
<div className="flex-1 min-w-0">
<div className="flex items-center space-x-2 sm:space-x-3 mb-2">
<div className="w-8 h-8 sm:w-10 sm:h-10 rounded-lg bg-gradient-to-br from-[#d4af37] to-[#c9a227] flex items-center justify-center shadow-lg flex-shrink-0">
<div className="w-8 h-8 sm:w-10 sm:h-10 rounded-lg bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] flex items-center justify-center shadow-lg flex-shrink-0">
<MapPin className="w-4 h-4 sm:w-5 sm:h-5 text-white" />
</div>
<div className="min-w-0 flex-1">
@@ -1863,7 +1863,7 @@ const HousekeepingDashboardPage: React.FC = () => {
<div className="flex items-center space-x-4 text-xs sm:text-sm text-gray-600 mb-3 sm:mb-4">
<div className="flex items-center space-x-1.5">
<Calendar className="w-3.5 h-3.5 sm:w-4 sm:h-4 text-[#d4af37] flex-shrink-0" />
<Calendar className="w-3.5 h-3.5 sm:w-4 sm:h-4 text-[var(--luxury-gold)] flex-shrink-0" />
<span className="text-[10px] sm:text-xs truncate">{formatDate(task.scheduled_time)}</span>
</div>
</div>
@@ -1872,7 +1872,7 @@ const HousekeepingDashboardPage: React.FC = () => {
<div className="mb-3 sm:mb-4">
<div className="flex items-center justify-between mb-1.5 sm:mb-2">
<span className="text-[10px] sm:text-xs font-medium text-gray-600">Progress</span>
<span className="text-xs sm:text-sm font-bold text-[#d4af37]">{progress}%</span>
<span className="text-xs sm:text-sm font-bold text-[var(--luxury-gold)]">{progress}%</span>
</div>
<div className="relative w-full h-1.5 sm:h-2 bg-gray-200 rounded-full overflow-hidden">
<div
@@ -1961,7 +1961,7 @@ const HousekeepingDashboardPage: React.FC = () => {
<div className="p-6 border-b border-gray-200">
<div className="flex items-center justify-between">
<h2 className="text-xl font-bold text-gray-900 flex items-center gap-2">
<FileCheck className="w-5 h-5 text-[#d4af37]" />
<FileCheck className="w-5 h-5 text-[var(--luxury-gold)]" />
Create Room Inspection
</h2>
<button
@@ -1983,7 +1983,7 @@ const HousekeepingDashboardPage: React.FC = () => {
<select
value={inspectionForm.room_id}
onChange={(e) => setInspectionForm({ ...inspectionForm, room_id: e.target.value })}
className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[#d4af37]"
className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[var(--luxury-gold)]"
required
>
<option value="">Select Room</option>
@@ -2007,7 +2007,7 @@ const HousekeepingDashboardPage: React.FC = () => {
checklist_items: defaultInspectionChecklist[type] || [],
});
}}
className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[#d4af37]"
className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[var(--luxury-gold)]"
>
<option value="pre_checkin">Pre Check-in</option>
<option value="post_checkout">Post Checkout</option>
@@ -2025,7 +2025,7 @@ const HousekeepingDashboardPage: React.FC = () => {
</button>
<button
onClick={handleCreateInspection}
className="px-4 py-2 text-sm text-white bg-gradient-to-r from-[#d4af37] to-[#c9a227] rounded-lg hover:from-[#f5d76e] hover:to-[#d4af37] transition-colors font-medium"
className="px-4 py-2 text-sm text-white bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] rounded-lg hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] transition-colors font-medium"
>
Create Inspection
</button>
@@ -2039,7 +2039,7 @@ const HousekeepingDashboardPage: React.FC = () => {
{isInspectionModalOpen && selectedInspection && (
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/50 backdrop-blur-sm">
<div className="bg-white rounded-xl shadow-2xl max-w-3xl w-full max-h-[90vh] overflow-y-auto">
<div className="p-6 border-b border-gray-200 bg-gradient-to-r from-[#d4af37] to-[#c9a227]">
<div className="p-6 border-b border-gray-200 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]">
<div className="flex items-center justify-between">
<h2 className="text-xl font-bold text-white flex items-center gap-2">
<FileCheck className="w-5 h-5" />
@@ -2107,7 +2107,7 @@ const HousekeepingDashboardPage: React.FC = () => {
{selectedInspection.overall_score && (
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">Overall Score</label>
<p className="text-2xl font-bold text-[#d4af37]">{selectedInspection.overall_score.toFixed(1)} / 5.0</p>
<p className="text-2xl font-bold text-[var(--luxury-gold)]">{selectedInspection.overall_score.toFixed(1)} / 5.0</p>
</div>
)}
</div>

View File

@@ -379,7 +379,7 @@ const HousekeepingProfilePage: React.FC = () => {
{/* Header */}
<div className="mb-6 sm:mb-8 animate-fade-in">
<div className="flex items-center gap-2 sm:gap-3 mb-2 sm:mb-3">
<div className="h-1 w-12 sm:w-16 md:w-20 bg-gradient-to-r from-[#d4af37] via-amber-400 to-[#d4af37] rounded-full"></div>
<div className="h-1 w-12 sm:w-16 md:w-20 bg-gradient-to-r from-[var(--luxury-gold)] via-amber-400 to-[var(--luxury-gold)] rounded-full"></div>
<h1 className="text-2xl sm:text-3xl lg:text-4xl font-serif font-bold bg-gradient-to-r from-gray-900 via-amber-900/90 to-gray-900 bg-clip-text text-transparent tracking-tight">
Housekeeping Profile
</h1>
@@ -390,50 +390,50 @@ const HousekeepingProfilePage: React.FC = () => {
</div>
{/* Tabs */}
<div className="mb-4 sm:mb-6 border-b border-[#d4af37]/20 overflow-x-auto bg-white/50 backdrop-blur-sm rounded-t-lg sm:rounded-t-xl px-4 sm:px-6">
<div className="mb-4 sm:mb-6 border-b border-[var(--luxury-gold)]/20 overflow-x-auto bg-white/50 backdrop-blur-sm rounded-t-lg sm:rounded-t-xl px-4 sm:px-6">
<div className="flex space-x-4 sm:space-x-8 min-w-max">
<button
onClick={() => setActiveTab('profile')}
className={`py-3 sm:py-4 px-2 sm:px-1 border-b-2 font-semibold text-xs sm:text-sm transition-all duration-300 whitespace-nowrap ${
activeTab === 'profile'
? 'border-[#d4af37] text-[#d4af37] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[#d4af37] hover:border-[#d4af37]/30'
? 'border-[var(--luxury-gold)] text-[var(--luxury-gold)] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[var(--luxury-gold)] hover:border-[var(--luxury-gold)]/30'
}`}
>
<User className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'profile' ? 'text-[#d4af37]' : ''}`} />
<User className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'profile' ? 'text-[var(--luxury-gold)]' : ''}`} />
Profile
</button>
<button
onClick={() => setActiveTab('password')}
className={`py-3 sm:py-4 px-2 sm:px-1 border-b-2 font-semibold text-xs sm:text-sm transition-all duration-300 whitespace-nowrap ${
activeTab === 'password'
? 'border-[#d4af37] text-[#d4af37] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[#d4af37] hover:border-[#d4af37]/30'
? 'border-[var(--luxury-gold)] text-[var(--luxury-gold)] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[var(--luxury-gold)] hover:border-[var(--luxury-gold)]/30'
}`}
>
<KeyRound className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'password' ? 'text-[#d4af37]' : ''}`} />
<KeyRound className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'password' ? 'text-[var(--luxury-gold)]' : ''}`} />
Password
</button>
<button
onClick={() => setActiveTab('mfa')}
className={`py-3 sm:py-4 px-2 sm:px-1 border-b-2 font-semibold text-xs sm:text-sm transition-all duration-300 whitespace-nowrap ${
activeTab === 'mfa'
? 'border-[#d4af37] text-[#d4af37] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[#d4af37] hover:border-[#d4af37]/30'
? 'border-[var(--luxury-gold)] text-[var(--luxury-gold)] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[var(--luxury-gold)] hover:border-[var(--luxury-gold)]/30'
}`}
>
<Shield className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'mfa' ? 'text-[#d4af37]' : ''}`} />
<Shield className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'mfa' ? 'text-[var(--luxury-gold)]' : ''}`} />
Two-Factor Auth
</button>
<button
onClick={() => setActiveTab('sessions')}
className={`py-3 sm:py-4 px-2 sm:px-1 border-b-2 font-semibold text-xs sm:text-sm transition-all duration-300 whitespace-nowrap ${
activeTab === 'sessions'
? 'border-[#d4af37] text-[#d4af37] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[#d4af37] hover:border-[#d4af37]/30'
? 'border-[var(--luxury-gold)] text-[var(--luxury-gold)] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[var(--luxury-gold)] hover:border-[var(--luxury-gold)]/30'
}`}
>
<Monitor className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'sessions' ? 'text-[#d4af37]' : ''}`} />
<Monitor className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'sessions' ? 'text-[var(--luxury-gold)]' : ''}`} />
Sessions
</button>
</div>
@@ -441,7 +441,7 @@ const HousekeepingProfilePage: React.FC = () => {
{/* Profile Tab */}
{activeTab === 'profile' && (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl animate-slide-up">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl animate-slide-up">
<form onSubmit={handleSubmitProfile(onSubmitProfile)} className="space-y-5 sm:space-y-6">
{/* Avatar Section */}
<div className="flex flex-col sm:flex-row items-center sm:items-start gap-4 sm:gap-6 pb-5 sm:pb-6 border-b border-gray-200">
@@ -450,17 +450,17 @@ const HousekeepingProfilePage: React.FC = () => {
<img
src={avatarPreview || normalizeImageUrl(userInfo?.avatar)}
alt="Profile"
className="w-20 h-20 sm:w-24 sm:h-24 rounded-full object-cover ring-4 ring-[#d4af37]/20 shadow-lg"
className="w-20 h-20 sm:w-24 sm:h-24 rounded-full object-cover ring-4 ring-[var(--luxury-gold)]/20 shadow-lg"
onError={() => setAvatarError(true)}
/>
) : (
<div className="w-20 h-20 sm:w-24 sm:h-24 rounded-full bg-gradient-to-br from-[#d4af37] to-[#c9a227] flex items-center justify-center ring-4 ring-[#d4af37]/20 shadow-lg">
<div className="w-20 h-20 sm:w-24 sm:h-24 rounded-full bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] flex items-center justify-center ring-4 ring-[var(--luxury-gold)]/20 shadow-lg">
<User className="w-10 h-10 sm:w-12 sm:h-12 text-white" />
</div>
)}
<label
htmlFor="avatar-upload"
className="absolute bottom-0 right-0 p-2 bg-gradient-to-br from-[#d4af37] to-[#c9a227] rounded-full cursor-pointer hover:from-[#f5d76e] hover:to-[#d4af37] transition-all duration-300 shadow-lg"
className="absolute bottom-0 right-0 p-2 bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] rounded-full cursor-pointer hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] transition-all duration-300 shadow-lg"
>
<Camera className="w-3.5 h-3.5 sm:w-4 sm:h-4 text-white" />
<input
@@ -477,7 +477,7 @@ const HousekeepingProfilePage: React.FC = () => {
{/* Name Field */}
<div>
<label className="block text-sm sm:text-base font-medium text-gray-700 mb-2">
<User className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[#d4af37]" />
<User className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[var(--luxury-gold)]" />
Full Name <span className="text-red-500">*</span>
</label>
<input
@@ -499,7 +499,7 @@ const HousekeepingProfilePage: React.FC = () => {
{/* Email Field */}
<div>
<label className="block text-sm sm:text-base font-medium text-gray-700 mb-2">
<Mail className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[#d4af37]" />
<Mail className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[var(--luxury-gold)]" />
Email Address <span className="text-red-500">*</span>
</label>
<input
@@ -521,7 +521,7 @@ const HousekeepingProfilePage: React.FC = () => {
{/* Phone Field */}
<div>
<label className="block text-sm sm:text-base font-medium text-gray-700 mb-2">
<Phone className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[#d4af37]" />
<Phone className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[var(--luxury-gold)]" />
Phone Number <span className="text-red-500">*</span>
</label>
<input
@@ -556,7 +556,7 @@ const HousekeepingProfilePage: React.FC = () => {
{/* Password Tab */}
{activeTab === 'password' && (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl animate-slide-up">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl animate-slide-up">
<form onSubmit={handleSubmitPassword(onSubmitPassword)} className="space-y-5 sm:space-y-6">
{/* Password Requirements */}
<div className="bg-gradient-to-r from-blue-50 to-indigo-50 border border-blue-200/60 rounded-sm p-4 sm:p-5">
@@ -579,7 +579,7 @@ const HousekeepingProfilePage: React.FC = () => {
{/* Current Password */}
<div>
<label className="block text-sm sm:text-base font-medium text-gray-700 mb-2">
<Lock className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[#d4af37]" />
<Lock className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[var(--luxury-gold)]" />
Current Password <span className="text-red-500">*</span>
</label>
<div className="relative">
@@ -594,7 +594,7 @@ const HousekeepingProfilePage: React.FC = () => {
<button
type="button"
onClick={() => setShowPassword({ ...showPassword, current: !showPassword.current })}
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[#d4af37] transition-colors"
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[var(--luxury-gold)] transition-colors"
>
{showPassword.current ? <EyeOff className="w-4 h-4 sm:w-5 sm:h-5" /> : <Eye className="w-4 h-4 sm:w-5 sm:h-5" />}
</button>
@@ -610,7 +610,7 @@ const HousekeepingProfilePage: React.FC = () => {
{/* New Password */}
<div>
<label className="block text-sm sm:text-base font-medium text-gray-700 mb-2">
<Lock className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[#d4af37]" />
<Lock className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[var(--luxury-gold)]" />
New Password <span className="text-red-500">*</span>
</label>
<div className="relative">
@@ -625,7 +625,7 @@ const HousekeepingProfilePage: React.FC = () => {
<button
type="button"
onClick={() => setShowPassword({ ...showPassword, new: !showPassword.new })}
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[#d4af37] transition-colors"
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[var(--luxury-gold)] transition-colors"
>
{showPassword.new ? <EyeOff className="w-4 h-4 sm:w-5 sm:h-5" /> : <Eye className="w-4 h-4 sm:w-5 sm:h-5" />}
</button>
@@ -641,7 +641,7 @@ const HousekeepingProfilePage: React.FC = () => {
{/* Confirm Password */}
<div>
<label className="block text-sm sm:text-base font-medium text-gray-700 mb-2">
<Lock className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[#d4af37]" />
<Lock className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[var(--luxury-gold)]" />
Confirm Password <span className="text-red-500">*</span>
</label>
<div className="relative">
@@ -656,7 +656,7 @@ const HousekeepingProfilePage: React.FC = () => {
<button
type="button"
onClick={() => setShowPassword({ ...showPassword, confirm: !showPassword.confirm })}
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[#d4af37] transition-colors"
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[var(--luxury-gold)] transition-colors"
>
{showPassword.confirm ? <EyeOff className="w-4 h-4 sm:w-5 sm:h-5" /> : <Eye className="w-4 h-4 sm:w-5 sm:h-5" />}
</button>
@@ -742,10 +742,10 @@ const MFATab: React.FC<MFATabProps> = ({
setLoading,
}) => {
return (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl animate-slide-up space-y-5 sm:space-y-6">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl animate-slide-up space-y-5 sm:space-y-6">
<div>
<h2 className="text-xl sm:text-2xl font-serif font-semibold text-gray-900 mb-2 flex items-center gap-2">
<Shield className="w-5 h-5 sm:w-6 sm:h-6 text-[#d4af37]" />
<Shield className="w-5 h-5 sm:w-6 sm:h-6 text-[var(--luxury-gold)]" />
Two-Factor Authentication
</h2>
<p className="text-xs sm:text-sm text-gray-600 font-light">
@@ -894,7 +894,7 @@ const MFATab: React.FC<MFATabProps> = ({
<div className="bg-white border border-gray-200 rounded-sm p-4">
<h3 className="font-semibold text-gray-900 mb-2 flex items-center gap-2">
<KeyRound className="w-4 h-4 text-[#d4af37]" />
<KeyRound className="w-4 h-4 text-[var(--luxury-gold)]" />
Step 2: Verify Setup
</h3>
<p className="text-sm text-gray-600 mb-4">Enter the 6-digit code from your authenticator app.</p>
@@ -992,10 +992,10 @@ const SessionsTab: React.FC = () => {
};
const getDeviceIcon = (userAgent?: string) => {
if (!userAgent) return <Monitor className="w-5 h-5 text-[#d4af37]" />;
if (!userAgent) return <Monitor className="w-5 h-5 text-[var(--luxury-gold)]" />;
if (userAgent.includes('Mobile')) return <Smartphone className="w-5 h-5 text-blue-500" />;
if (userAgent.includes('Tablet')) return <Tablet className="w-5 h-5 text-purple-500" />;
return <Monitor className="w-5 h-5 text-[#d4af37]" />;
return <Monitor className="w-5 h-5 text-[var(--luxury-gold)]" />;
};
const getDeviceName = (userAgent?: string) => {
@@ -1053,17 +1053,17 @@ const SessionsTab: React.FC = () => {
if (loading) {
return (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl">
<Loading text="Loading sessions..." />
</div>
);
}
return (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl animate-slide-up space-y-5 sm:space-y-6">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl animate-slide-up space-y-5 sm:space-y-6">
<div>
<h2 className="text-xl sm:text-2xl font-serif font-semibold text-gray-900 mb-2 flex items-center gap-2">
<Monitor className="w-5 h-5 sm:w-6 sm:h-6 text-[#d4af37]" />
<Monitor className="w-5 h-5 sm:w-6 sm:h-6 text-[var(--luxury-gold)]" />
Active Sessions
</h2>
<p className="text-xs sm:text-sm text-gray-600 font-light">
@@ -1092,11 +1092,11 @@ const SessionsTab: React.FC = () => {
{sessions.map((session) => (
<div
key={session.id}
className="bg-gradient-to-r from-slate-50 to-white border border-[#d4af37]/20 rounded-sm p-4 sm:p-5 hover:shadow-lg transition-all"
className="bg-gradient-to-r from-slate-50 to-white border border-[var(--luxury-gold)]/20 rounded-sm p-4 sm:p-5 hover:shadow-lg transition-all"
>
<div className="flex items-start justify-between gap-4">
<div className="flex items-start gap-4 flex-1">
<div className="p-2 sm:p-3 bg-gradient-to-br from-[#d4af37]/10 to-[#c9a227]/10 rounded-sm flex-shrink-0">
<div className="p-2 sm:p-3 bg-gradient-to-br from-[var(--luxury-gold)]/10 to-[var(--luxury-gold-dark)]/10 rounded-sm flex-shrink-0">
{getDeviceIcon(session.user_agent)}
</div>
<div className="flex-1 min-w-0">

View File

@@ -75,7 +75,7 @@ const HousekeepingShiftViewPage: React.FC = () => {
<div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4 animate-fade-in">
<div>
<div className="flex items-center gap-3 mb-2">
<div className="h-1 w-16 bg-gradient-to-r from-[#d4af37] to-[#c9a227] rounded-full"></div>
<div className="h-1 w-16 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] rounded-full"></div>
<h1 className="text-4xl font-bold bg-gradient-to-r from-slate-900 via-slate-800 to-slate-900 bg-clip-text text-transparent tracking-tight">
My Shifts
</h1>
@@ -86,7 +86,7 @@ const HousekeepingShiftViewPage: React.FC = () => {
type="date"
value={selectedDate.toISOString().split('T')[0]}
onChange={(e) => setSelectedDate(new Date(e.target.value))}
className="px-4 py-2 border-2 border-slate-200 rounded-xl focus:border-[#d4af37] focus:ring-4 focus:ring-yellow-100"
className="px-4 py-2 border-2 border-slate-200 rounded-xl focus:border-[var(--luxury-gold)] focus:ring-4 focus:ring-yellow-100"
/>
</div>
@@ -96,9 +96,9 @@ const HousekeepingShiftViewPage: React.FC = () => {
<div className="flex items-center justify-between">
<div>
<p className="text-slate-600 text-sm font-medium">Upcoming Shifts</p>
<p className="text-3xl font-bold text-[#d4af37] mt-2">{getUpcomingShifts()}</p>
<p className="text-3xl font-bold text-[var(--luxury-gold)] mt-2">{getUpcomingShifts()}</p>
</div>
<Calendar className="w-12 h-12 text-[#d4af37]" />
<Calendar className="w-12 h-12 text-[var(--luxury-gold)]" />
</div>
</div>
<div className="bg-white/80 backdrop-blur-sm rounded-xl shadow-lg border border-slate-200/60 p-6">
@@ -169,7 +169,7 @@ const HousekeepingShiftViewPage: React.FC = () => {
<select
value={shift.status}
onChange={(e) => handleStatusUpdate(shift.id, e.target.value)}
className="px-4 py-2 border-2 border-slate-200 rounded-xl focus:border-[#d4af37] cursor-pointer"
className="px-4 py-2 border-2 border-slate-200 rounded-xl focus:border-[var(--luxury-gold)] cursor-pointer"
>
<option value="scheduled">Scheduled</option>
<option value="in_progress">Start Shift</option>

View File

@@ -363,7 +363,7 @@ const ChatManagementPage: React.FC = () => {
<div className="flex items-center justify-between">
<div>
<div className="flex items-center gap-3 mb-2">
<div className="h-1 w-16 bg-gradient-to-r from-[#d4af37] to-[#c9a227] rounded-full"></div>
<div className="h-1 w-16 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] rounded-full"></div>
<h1 className="text-3xl font-serif font-bold bg-gradient-to-r from-slate-900 via-slate-800 to-slate-900 bg-clip-text text-transparent tracking-tight">
Chat Management
</h1>
@@ -372,7 +372,7 @@ const ChatManagementPage: React.FC = () => {
</div>
<button
onClick={fetchChats}
className="px-6 py-2.5 bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-slate-900 rounded-lg font-semibold hover:from-[#c9a227] hover:to-[#d4af37] transition-all duration-300 shadow-lg shadow-[#d4af37]/30 hover:shadow-xl hover:shadow-[#d4af37]/40 flex items-center gap-2"
className="px-6 py-2.5 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-slate-900 rounded-lg font-semibold hover:from-[var(--luxury-gold-dark)] hover:to-[var(--luxury-gold)] transition-all duration-300 shadow-lg shadow-[var(--luxury-gold)]/30 hover:shadow-xl hover:shadow-[var(--luxury-gold)]/40 flex items-center gap-2"
>
<RefreshCw className="w-4 h-4" />
Refresh
@@ -381,9 +381,9 @@ const ChatManagementPage: React.FC = () => {
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6 h-[calc(100vh-200px)]">
{}
<div className="luxury-glass rounded-xl shadow-2xl border border-[#d4af37]/20 overflow-hidden flex flex-col">
<div className="p-4 border-b border-[#d4af37]/20 bg-gradient-to-r from-[#d4af37]/10 via-[#c9a227]/10 to-[#d4af37]/10 relative">
<div className="absolute top-0 left-0 right-0 h-0.5 bg-gradient-to-r from-transparent via-[#d4af37] to-transparent"></div>
<div className="luxury-glass rounded-xl shadow-2xl border border-[var(--luxury-gold)]/20 overflow-hidden flex flex-col">
<div className="p-4 border-b border-[var(--luxury-gold)]/20 bg-gradient-to-r from-[var(--luxury-gold)]/10 via-[var(--luxury-gold-dark)]/10 to-[var(--luxury-gold)]/10 relative">
<div className="absolute top-0 left-0 right-0 h-0.5 bg-gradient-to-r from-transparent via-[var(--luxury-gold)] to-transparent"></div>
<h2 className="font-serif font-semibold text-slate-900 tracking-wide">Chats ({chats.length})</h2>
</div>
<div className="flex-1 overflow-y-auto">
@@ -398,9 +398,9 @@ const ChatManagementPage: React.FC = () => {
<div
key={chat.id}
onClick={() => setSelectedChat(chat)}
className={`p-4 cursor-pointer hover:bg-gradient-to-r hover:from-[#d4af37]/5 hover:to-[#c9a227]/5 transition-all duration-300 ${
className={`p-4 cursor-pointer hover:bg-gradient-to-r hover:from-[var(--luxury-gold)]/5 hover:to-[var(--luxury-gold-dark)]/5 transition-all duration-300 ${
selectedChat?.id === chat.id
? 'bg-gradient-to-r from-[#d4af37]/10 to-[#c9a227]/10 border-l-4 border-[#d4af37] shadow-sm'
? 'bg-gradient-to-r from-[var(--luxury-gold)]/10 to-[var(--luxury-gold-dark)]/10 border-l-4 border-[var(--luxury-gold)] shadow-sm'
: 'border-l-4 border-transparent'
}`}
>
@@ -425,7 +425,7 @@ const ChatManagementPage: React.FC = () => {
e.stopPropagation();
handleAcceptChat(chat.id);
}}
className="mt-2 w-full px-3 py-1.5 bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-slate-900 text-sm font-semibold rounded-lg hover:from-[#c9a227] hover:to-[#d4af37] transition-all duration-300 shadow-md shadow-[#d4af37]/30 hover:shadow-lg"
className="mt-2 w-full px-3 py-1.5 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-slate-900 text-sm font-semibold rounded-lg hover:from-[var(--luxury-gold-dark)] hover:to-[var(--luxury-gold)] transition-all duration-300 shadow-md shadow-[var(--luxury-gold)]/30 hover:shadow-lg"
>
Accept Chat
</button>
@@ -438,11 +438,11 @@ const ChatManagementPage: React.FC = () => {
</div>
{}
<div className="lg:col-span-2 luxury-glass rounded-xl shadow-2xl border border-[#d4af37]/20 overflow-hidden flex flex-col">
<div className="lg:col-span-2 luxury-glass rounded-xl shadow-2xl border border-[var(--luxury-gold)]/20 overflow-hidden flex flex-col">
{selectedChat ? (
<>
<div className="p-4 border-b border-[#d4af37]/20 bg-gradient-to-r from-[#d4af37]/10 via-[#c9a227]/10 to-[#d4af37]/10 flex items-center justify-between relative">
<div className="absolute top-0 left-0 right-0 h-0.5 bg-gradient-to-r from-transparent via-[#d4af37] to-transparent"></div>
<div className="p-4 border-b border-[var(--luxury-gold)]/20 bg-gradient-to-r from-[var(--luxury-gold)]/10 via-[var(--luxury-gold-dark)]/10 to-[var(--luxury-gold)]/10 flex items-center justify-between relative">
<div className="absolute top-0 left-0 right-0 h-0.5 bg-gradient-to-r from-transparent via-[var(--luxury-gold)] to-transparent"></div>
<div>
<h2 className="font-serif font-semibold text-slate-900 tracking-wide">
{selectedChat.visitor_name || 'Guest'}
@@ -451,7 +451,7 @@ const ChatManagementPage: React.FC = () => {
<p className="text-sm text-slate-600 font-light">{selectedChat.visitor_email}</p>
)}
{selectedChat.staff_name && (
<p className="text-xs text-[#d4af37] mt-1 font-medium">
<p className="text-xs text-[var(--luxury-gold)] mt-1 font-medium">
Accepted by: {selectedChat.staff_name}
</p>
)}
@@ -489,12 +489,12 @@ const ChatManagementPage: React.FC = () => {
<div
className={`max-w-[80%] rounded-xl p-4 shadow-lg ${
message.sender_type === 'staff'
? 'bg-gradient-to-br from-[#d4af37] to-[#c9a227] text-slate-900 border border-[#d4af37]/30'
? 'bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-slate-900 border border-[var(--luxury-gold)]/30'
: 'bg-white text-slate-800 border border-slate-200/60 shadow-sm'
}`}
>
{message.sender_type === 'visitor' && (
<div className="text-xs font-semibold mb-1.5 text-[#d4af37] tracking-wide">
<div className="text-xs font-semibold mb-1.5 text-[var(--luxury-gold)] tracking-wide">
{message.sender_name || 'Visitor'}
</div>
)}
@@ -521,7 +521,7 @@ const ChatManagementPage: React.FC = () => {
</div>
{selectedChat.status !== 'closed' && (
<div className="p-4 border-t border-[#d4af37]/20 bg-white/90 backdrop-blur-sm">
<div className="p-4 border-t border-[var(--luxury-gold)]/20 bg-white/90 backdrop-blur-sm">
<div className="flex gap-3">
<input
type="text"
@@ -529,13 +529,13 @@ const ChatManagementPage: React.FC = () => {
onChange={(e) => setNewMessage(e.target.value)}
onKeyPress={handleKeyPress}
placeholder="Type your message..."
className="flex-1 px-4 py-3 border-2 border-slate-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-[#d4af37]/30 focus:border-[#d4af37] transition-all duration-200 font-light"
className="flex-1 px-4 py-3 border-2 border-slate-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-[var(--luxury-gold)]/30 focus:border-[var(--luxury-gold)] transition-all duration-200 font-light"
disabled={selectedChat.status === 'pending'}
/>
<button
onClick={handleSendMessage}
disabled={!newMessage.trim() || selectedChat.status === 'pending'}
className="bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-slate-900 px-5 py-3 rounded-xl hover:from-[#c9a227] hover:to-[#d4af37] disabled:bg-gray-300 disabled:text-gray-500 disabled:cursor-not-allowed transition-all duration-300 flex items-center gap-2 font-semibold shadow-lg shadow-[#d4af37]/30 hover:shadow-xl disabled:shadow-none"
className="bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-slate-900 px-5 py-3 rounded-xl hover:from-[var(--luxury-gold-dark)] hover:to-[var(--luxury-gold)] disabled:bg-gray-300 disabled:text-gray-500 disabled:cursor-not-allowed transition-all duration-300 flex items-center gap-2 font-semibold shadow-lg shadow-[var(--luxury-gold)]/30 hover:shadow-xl disabled:shadow-none"
>
<Send className="w-4 h-4" />
</button>

View File

@@ -417,7 +417,7 @@ const ProfilePage: React.FC = () => {
{}
<div className="mb-6 sm:mb-8 animate-fade-in">
<div className="flex items-center gap-2 sm:gap-3 mb-2 sm:mb-3">
<div className="h-1 w-12 sm:w-16 md:w-20 bg-gradient-to-r from-[#d4af37] via-amber-400 to-[#d4af37] rounded-full"></div>
<div className="h-1 w-12 sm:w-16 md:w-20 bg-gradient-to-r from-[var(--luxury-gold)] via-amber-400 to-[var(--luxury-gold)] rounded-full"></div>
<h1 className="text-2xl sm:text-3xl lg:text-4xl font-serif font-bold bg-gradient-to-r from-gray-900 via-amber-900/90 to-gray-900 bg-clip-text text-transparent tracking-tight">
Staff Profile & Settings
</h1>
@@ -428,61 +428,61 @@ const ProfilePage: React.FC = () => {
</div>
{}
<div className="mb-4 sm:mb-6 border-b border-[#d4af37]/20 overflow-x-auto bg-white/50 backdrop-blur-sm rounded-t-lg sm:rounded-t-xl px-4 sm:px-6">
<div className="mb-4 sm:mb-6 border-b border-[var(--luxury-gold)]/20 overflow-x-auto bg-white/50 backdrop-blur-sm rounded-t-lg sm:rounded-t-xl px-4 sm:px-6">
<div className="flex space-x-4 sm:space-x-8 min-w-max">
<button
onClick={() => setActiveTab('profile')}
className={`py-3 sm:py-4 px-2 sm:px-1 border-b-2 font-semibold text-xs sm:text-sm transition-all duration-300 whitespace-nowrap ${
activeTab === 'profile'
? 'border-[#d4af37] text-[#d4af37] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[#d4af37] hover:border-[#d4af37]/30'
? 'border-[var(--luxury-gold)] text-[var(--luxury-gold)] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[var(--luxury-gold)] hover:border-[var(--luxury-gold)]/30'
}`}
>
<User className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'profile' ? 'text-[#d4af37]' : ''}`} />
<User className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'profile' ? 'text-[var(--luxury-gold)]' : ''}`} />
Profile Information
</button>
<button
onClick={() => setActiveTab('password')}
className={`py-3 sm:py-4 px-2 sm:px-1 border-b-2 font-semibold text-xs sm:text-sm transition-all duration-300 whitespace-nowrap ${
activeTab === 'password'
? 'border-[#d4af37] text-[#d4af37] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[#d4af37] hover:border-[#d4af37]/30'
? 'border-[var(--luxury-gold)] text-[var(--luxury-gold)] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[var(--luxury-gold)] hover:border-[var(--luxury-gold)]/30'
}`}
>
<KeyRound className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'password' ? 'text-[#d4af37]' : ''}`} />
<KeyRound className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'password' ? 'text-[var(--luxury-gold)]' : ''}`} />
Change Password
</button>
<button
onClick={() => setActiveTab('mfa')}
className={`py-3 sm:py-4 px-2 sm:px-1 border-b-2 font-semibold text-xs sm:text-sm transition-all duration-300 whitespace-nowrap ${
activeTab === 'mfa'
? 'border-[#d4af37] text-[#d4af37] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[#d4af37] hover:border-[#d4af37]/30'
? 'border-[var(--luxury-gold)] text-[var(--luxury-gold)] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[var(--luxury-gold)] hover:border-[var(--luxury-gold)]/30'
}`}
>
<Shield className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'mfa' ? 'text-[#d4af37]' : ''}`} />
<Shield className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'mfa' ? 'text-[var(--luxury-gold)]' : ''}`} />
Two-Factor Authentication
</button>
<button
onClick={() => setActiveTab('sessions')}
className={`py-3 sm:py-4 px-2 sm:px-1 border-b-2 font-semibold text-xs sm:text-sm transition-all duration-300 whitespace-nowrap ${
activeTab === 'sessions'
? 'border-[#d4af37] text-[#d4af37] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[#d4af37] hover:border-[#d4af37]/30'
? 'border-[var(--luxury-gold)] text-[var(--luxury-gold)] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[var(--luxury-gold)] hover:border-[var(--luxury-gold)]/30'
}`}
>
<Monitor className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'sessions' ? 'text-[#d4af37]' : ''}`} />
<Monitor className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'sessions' ? 'text-[var(--luxury-gold)]' : ''}`} />
Active Sessions
</button>
<button
onClick={() => setActiveTab('gdpr')}
className={`py-3 sm:py-4 px-2 sm:px-1 border-b-2 font-semibold text-xs sm:text-sm transition-all duration-300 whitespace-nowrap ${
activeTab === 'gdpr'
? 'border-[#d4af37] text-[#d4af37] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[#d4af37] hover:border-[#d4af37]/30'
? 'border-[var(--luxury-gold)] text-[var(--luxury-gold)] shadow-sm'
: 'border-transparent text-gray-500 hover:text-[var(--luxury-gold)] hover:border-[var(--luxury-gold)]/30'
}`}
>
<Database className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'gdpr' ? 'text-[#d4af37]' : ''}`} />
<Database className={`w-4 h-4 sm:w-5 sm:h-5 inline mr-2 ${activeTab === 'gdpr' ? 'text-[var(--luxury-gold)]' : ''}`} />
Data Privacy
</button>
</div>
@@ -490,7 +490,7 @@ const ProfilePage: React.FC = () => {
{}
{activeTab === 'profile' && (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl animate-slide-up">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl animate-slide-up">
<form onSubmit={handleSubmitProfile(onSubmitProfile)} className="space-y-5 sm:space-y-6">
{}
<div className="flex flex-col sm:flex-row items-center sm:items-start gap-4 sm:gap-6 pb-5 sm:pb-6 border-b border-gray-200">
@@ -499,20 +499,20 @@ const ProfilePage: React.FC = () => {
<img
src={avatarPreview || normalizeImageUrl(userInfo?.avatar)}
alt="Profile"
className="w-20 h-20 sm:w-24 sm:h-24 rounded-full object-cover ring-4 ring-[#d4af37]/20 shadow-lg"
className="w-20 h-20 sm:w-24 sm:h-24 rounded-full object-cover ring-4 ring-[var(--luxury-gold)]/20 shadow-lg"
onError={() => {
// If image fails to load, show default avatar
setAvatarError(true);
}}
/>
) : (
<div className="w-20 h-20 sm:w-24 sm:h-24 rounded-full bg-gradient-to-br from-[#d4af37] to-[#c9a227] flex items-center justify-center ring-4 ring-[#d4af37]/20 shadow-lg">
<div className="w-20 h-20 sm:w-24 sm:h-24 rounded-full bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] flex items-center justify-center ring-4 ring-[var(--luxury-gold)]/20 shadow-lg">
<User className="w-10 h-10 sm:w-12 sm:h-12 text-white" />
</div>
)}
<label
htmlFor="avatar-upload"
className="absolute bottom-0 right-0 p-2 bg-gradient-to-br from-[#d4af37] to-[#c9a227] rounded-full cursor-pointer hover:from-[#f5d76e] hover:to-[#d4af37] transition-all duration-300 shadow-lg hover:shadow-xl hover:shadow-[#d4af37]/40 hover:-translate-y-0.5 active:translate-y-0"
className="absolute bottom-0 right-0 p-2 bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] rounded-full cursor-pointer hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] transition-all duration-300 shadow-lg hover:shadow-xl hover:shadow-[var(--luxury-gold)]/40 hover:-translate-y-0.5 active:translate-y-0"
>
<Camera className="w-3.5 h-3.5 sm:w-4 sm:h-4 text-white" />
<input
@@ -528,7 +528,7 @@ const ProfilePage: React.FC = () => {
<div>
<label className="block text-sm sm:text-base font-medium text-gray-700 mb-2">
<User className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[#d4af37]" />
<User className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[var(--luxury-gold)]" />
Full Name
<span className="text-red-500 ml-1">*</span>
</label>
@@ -551,7 +551,7 @@ const ProfilePage: React.FC = () => {
{}
<div>
<label className="block text-sm sm:text-base font-medium text-gray-700 mb-2">
<Mail className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[#d4af37]" />
<Mail className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[var(--luxury-gold)]" />
Email Address
<span className="text-red-500 ml-1">*</span>
</label>
@@ -574,7 +574,7 @@ const ProfilePage: React.FC = () => {
{}
<div>
<label className="block text-sm sm:text-base font-medium text-gray-700 mb-2">
<Phone className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[#d4af37]" />
<Phone className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[var(--luxury-gold)]" />
Phone Number
<span className="text-red-500 ml-1">*</span>
</label>
@@ -611,7 +611,7 @@ const ProfilePage: React.FC = () => {
{}
{activeTab === 'password' && (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl animate-slide-up">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl animate-slide-up">
<form onSubmit={handleSubmitPassword(onSubmitPassword)} className="space-y-5 sm:space-y-6">
{}
<div className="bg-gradient-to-r from-blue-50 to-indigo-50 border border-blue-200/60 rounded-sm p-4 sm:p-5">
@@ -640,7 +640,7 @@ const ProfilePage: React.FC = () => {
{}
<div>
<label className="block text-sm sm:text-base font-medium text-gray-700 mb-2">
<Lock className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[#d4af37]" />
<Lock className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[var(--luxury-gold)]" />
Current Password
<span className="text-red-500 ml-1">*</span>
</label>
@@ -656,7 +656,7 @@ const ProfilePage: React.FC = () => {
<button
type="button"
onClick={() => setShowPassword({ ...showPassword, current: !showPassword.current })}
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[#d4af37] transition-colors"
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[var(--luxury-gold)] transition-colors"
>
{showPassword.current ? (
<EyeOff className="w-4 h-4 sm:w-5 sm:h-5" />
@@ -676,7 +676,7 @@ const ProfilePage: React.FC = () => {
{}
<div>
<label className="block text-sm sm:text-base font-medium text-gray-700 mb-2">
<Lock className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[#d4af37]" />
<Lock className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[var(--luxury-gold)]" />
New Password
<span className="text-red-500 ml-1">*</span>
</label>
@@ -692,7 +692,7 @@ const ProfilePage: React.FC = () => {
<button
type="button"
onClick={() => setShowPassword({ ...showPassword, new: !showPassword.new })}
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[#d4af37] transition-colors"
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[var(--luxury-gold)] transition-colors"
>
{showPassword.new ? (
<EyeOff className="w-4 h-4 sm:w-5 sm:h-5" />
@@ -712,7 +712,7 @@ const ProfilePage: React.FC = () => {
{}
<div>
<label className="block text-sm sm:text-base font-medium text-gray-700 mb-2">
<Lock className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[#d4af37]" />
<Lock className="w-4 h-4 sm:w-5 sm:h-5 inline mr-2 text-[var(--luxury-gold)]" />
Confirm New Password
<span className="text-red-500 ml-1">*</span>
</label>
@@ -728,7 +728,7 @@ const ProfilePage: React.FC = () => {
<button
type="button"
onClick={() => setShowPassword({ ...showPassword, confirm: !showPassword.confirm })}
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[#d4af37] transition-colors"
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-[var(--luxury-gold)] transition-colors"
>
{showPassword.confirm ? (
<EyeOff className="w-4 h-4 sm:w-5 sm:h-5" />
@@ -762,11 +762,11 @@ const ProfilePage: React.FC = () => {
{}
{activeTab === 'mfa' && (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl animate-slide-up space-y-5 sm:space-y-6">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl animate-slide-up space-y-5 sm:space-y-6">
{}
<div>
<h2 className="text-xl sm:text-2xl font-serif font-semibold text-gray-900 mb-2 flex items-center gap-2">
<Shield className="w-5 h-5 sm:w-6 sm:h-6 text-[#d4af37]" />
<Shield className="w-5 h-5 sm:w-6 sm:h-6 text-[var(--luxury-gold)]" />
Two-Factor Authentication
</h2>
<p className="text-xs sm:text-sm text-gray-600 font-light leading-relaxed">
@@ -838,7 +838,7 @@ const ProfilePage: React.FC = () => {
{}
<div className="bg-white border border-gray-200 rounded-sm p-4 sm:p-5">
<h3 className="text-sm sm:text-base font-semibold text-gray-900 mb-2 flex items-center gap-2">
<RefreshCw className="w-4 h-4 sm:w-5 sm:h-5 text-[#d4af37]" />
<RefreshCw className="w-4 h-4 sm:w-5 sm:h-5 text-[var(--luxury-gold)]" />
Backup Codes
</h3>
<p className="text-xs sm:text-sm text-gray-600 font-light mb-4 leading-relaxed">
@@ -984,7 +984,7 @@ const ProfilePage: React.FC = () => {
{}
<div className="bg-white border border-gray-200 rounded-sm p-4 sm:p-5">
<h3 className="font-semibold text-gray-900 mb-2 text-sm sm:text-base flex items-center gap-2">
<KeyRound className="w-4 h-4 sm:w-5 sm:h-5 text-[#d4af37]" />
<KeyRound className="w-4 h-4 sm:w-5 sm:h-5 text-[var(--luxury-gold)]" />
Step 2: Verify Setup
</h3>
<p className="text-xs sm:text-sm text-gray-600 font-light mb-4 leading-relaxed">
@@ -1110,10 +1110,10 @@ const SessionsTab: React.FC = () => {
};
const getDeviceIcon = (userAgent?: string) => {
if (!userAgent) return <Monitor className="w-5 h-5 text-[#d4af37]" />;
if (!userAgent) return <Monitor className="w-5 h-5 text-[var(--luxury-gold)]" />;
if (userAgent.includes('Mobile')) return <Smartphone className="w-5 h-5 text-blue-500" />;
if (userAgent.includes('Tablet')) return <Tablet className="w-5 h-5 text-purple-500" />;
return <Monitor className="w-5 h-5 text-[#d4af37]" />;
return <Monitor className="w-5 h-5 text-[var(--luxury-gold)]" />;
};
const getDeviceName = (userAgent?: string) => {
@@ -1181,17 +1181,17 @@ const SessionsTab: React.FC = () => {
if (loading) {
return (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl">
<Loading text="Loading sessions..." />
</div>
);
}
return (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl animate-slide-up space-y-5 sm:space-y-6">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl animate-slide-up space-y-5 sm:space-y-6">
<div>
<h2 className="text-xl sm:text-2xl font-serif font-semibold text-gray-900 mb-2 flex items-center gap-2">
<Monitor className="w-5 h-5 sm:w-6 sm:h-6 text-[#d4af37]" />
<Monitor className="w-5 h-5 sm:w-6 sm:h-6 text-[var(--luxury-gold)]" />
Active Sessions
</h2>
<p className="text-xs sm:text-sm text-gray-600 font-light">
@@ -1220,11 +1220,11 @@ const SessionsTab: React.FC = () => {
{sessions.map((session) => (
<div
key={session.id}
className="bg-gradient-to-r from-slate-50 to-white border border-[#d4af37]/20 rounded-sm p-4 sm:p-5 hover:shadow-lg hover:border-[#d4af37]/40 transition-all duration-300"
className="bg-gradient-to-r from-slate-50 to-white border border-[var(--luxury-gold)]/20 rounded-sm p-4 sm:p-5 hover:shadow-lg hover:border-[var(--luxury-gold)]/40 transition-all duration-300"
>
<div className="flex items-start justify-between gap-4">
<div className="flex items-start gap-4 flex-1">
<div className="p-2 sm:p-3 bg-gradient-to-br from-[#d4af37]/10 to-[#c9a227]/10 rounded-sm flex-shrink-0">
<div className="p-2 sm:p-3 bg-gradient-to-br from-[var(--luxury-gold)]/10 to-[var(--luxury-gold-dark)]/10 rounded-sm flex-shrink-0">
{getDeviceIcon(session.user_agent)}
</div>
<div className="flex-1 min-w-0">
@@ -1354,17 +1354,17 @@ const GDPRTab: React.FC = () => {
if (loading) {
return (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl">
<Loading text="Loading privacy data..." />
</div>
);
}
return (
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[#d4af37]/20 shadow-2xl animate-slide-up space-y-5 sm:space-y-6">
<div className="luxury-glass rounded-sm p-4 sm:p-6 lg:p-8 border border-[var(--luxury-gold)]/20 shadow-2xl animate-slide-up space-y-5 sm:space-y-6">
<div>
<h2 className="text-xl sm:text-2xl font-serif font-semibold text-gray-900 mb-2 flex items-center gap-2">
<Database className="w-5 h-5 sm:w-6 sm:h-6 text-[#d4af37]" />
<Database className="w-5 h-5 sm:w-6 sm:h-6 text-[var(--luxury-gold)]" />
Data Privacy & GDPR Rights
</h2>
<p className="text-xs sm:text-sm text-gray-600 font-light">
@@ -1431,14 +1431,14 @@ const GDPRTab: React.FC = () => {
{requests.length > 0 && (
<div className="border-t border-gray-200 pt-5 sm:pt-6">
<h3 className="text-base sm:text-lg font-semibold text-gray-900 mb-4 flex items-center gap-2">
<FileText className="w-5 h-5 text-[#d4af37]" />
<FileText className="w-5 h-5 text-[var(--luxury-gold)]" />
Request History
</h3>
<div className="space-y-3 sm:space-y-4">
{requests.map((request) => (
<div
key={request.id}
className="bg-gradient-to-r from-slate-50 to-white border border-[#d4af37]/20 rounded-sm p-4 sm:p-5 hover:shadow-md hover:border-[#d4af37]/40 transition-all duration-300"
className="bg-gradient-to-r from-slate-50 to-white border border-[var(--luxury-gold)]/20 rounded-sm p-4 sm:p-5 hover:shadow-md hover:border-[var(--luxury-gold)]/40 transition-all duration-300"
>
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 sm:gap-4">
<div className="flex-1 min-w-0">

View File

@@ -2992,10 +2992,10 @@ const ReceptionDashboardPage: React.FC = () => {
{}
{showRoomModal && (
<div className="fixed inset-0 bg-black/80 backdrop-blur-sm flex items-center justify-center z-50 p-4">
<div className="bg-gradient-to-br from-[#1a1a1a] via-[#0f0f0f] to-[#1a1a1a] rounded-xl border border-[#d4af37]/30 backdrop-blur-xl shadow-2xl shadow-[#d4af37]/20 p-8 w-full max-w-4xl max-h-[90vh] overflow-y-auto">
<div className="flex justify-between items-center mb-6 pb-6 border-b border-[#d4af37]/20">
<div className="bg-gradient-to-br from-[#1a1a1a] via-[#0f0f0f] to-[#1a1a1a] rounded-xl border border-[var(--luxury-gold)]/30 backdrop-blur-xl shadow-2xl shadow-[var(--luxury-gold)]/20 p-8 w-full max-w-4xl max-h-[90vh] overflow-y-auto">
<div className="flex justify-between items-center mb-6 pb-6 border-b border-[var(--luxury-gold)]/20">
<div>
<h2 className="text-3xl font-serif font-semibold bg-gradient-to-r from-white via-[#d4af37] to-white bg-clip-text text-transparent tracking-wide">
<h2 className="text-3xl font-serif font-semibold bg-gradient-to-r from-white via-[var(--luxury-gold)] to-white bg-clip-text text-transparent tracking-wide">
{editingRoom ? 'Update Room' : 'Add New Room'}
</h2>
<p className="text-gray-400 text-sm mt-1 font-light">
@@ -3004,17 +3004,17 @@ const ReceptionDashboardPage: React.FC = () => {
</div>
<button
onClick={() => setShowRoomModal(false)}
className="p-2 hover:bg-[#d4af37]/10 rounded-lg transition-colors border border-[#d4af37]/20 hover:border-[#d4af37]/40"
className="p-2 hover:bg-[var(--luxury-gold)]/10 rounded-lg transition-colors border border-[var(--luxury-gold)]/20 hover:border-[var(--luxury-gold)]/40"
>
<X className="w-6 h-6 text-[#d4af37] hover:text-white transition-colors" />
<X className="w-6 h-6 text-[var(--luxury-gold)] hover:text-white transition-colors" />
</button>
</div>
<form onSubmit={handleRoomSubmit} className="space-y-6">
{}
<div className="space-y-4">
<h3 className="text-lg font-serif font-semibold text-[#d4af37] mb-4 flex items-center gap-2">
<div className="w-1 h-6 bg-gradient-to-b from-[#d4af37] to-[#c9a227]" />
<h3 className="text-lg font-serif font-semibold text-[var(--luxury-gold)] mb-4 flex items-center gap-2">
<div className="w-1 h-6 bg-gradient-to-b from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]" />
Basic Information
</h3>
@@ -3027,7 +3027,7 @@ const ReceptionDashboardPage: React.FC = () => {
type="text"
value={roomFormData.room_number}
onChange={(e) => setRoomFormData({ ...roomFormData, room_number: e.target.value })}
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white placeholder-gray-500 focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37] transition-all duration-300"
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white placeholder-gray-500 focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)] transition-all duration-300"
placeholder="e.g., 1001"
required
/>
@@ -3040,7 +3040,7 @@ const ReceptionDashboardPage: React.FC = () => {
type="number"
value={roomFormData.floor}
onChange={(e) => setRoomFormData({ ...roomFormData, floor: parseInt(e.target.value) })}
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white placeholder-gray-500 focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37] transition-all duration-300"
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white placeholder-gray-500 focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)] transition-all duration-300"
required
min="1"
/>
@@ -3054,7 +3054,7 @@ const ReceptionDashboardPage: React.FC = () => {
<select
value={roomFormData.room_type_id}
onChange={(e) => setRoomFormData({ ...roomFormData, room_type_id: parseInt(e.target.value) })}
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37] transition-all duration-300"
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)] transition-all duration-300"
required
>
{roomTypes.length > 0 ? (
@@ -3076,7 +3076,7 @@ const ReceptionDashboardPage: React.FC = () => {
<select
value={roomFormData.status}
onChange={(e) => setRoomFormData({ ...roomFormData, status: e.target.value as any })}
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37] transition-all duration-300"
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)] transition-all duration-300"
required
>
<option value="available" className="bg-[#1a1a1a]">Available</option>
@@ -3085,13 +3085,13 @@ const ReceptionDashboardPage: React.FC = () => {
</select>
</div>
<div className="flex items-center gap-3 p-4 bg-[#0a0a0a] rounded-lg border border-[#d4af37]/20">
<div className="flex items-center gap-3 p-4 bg-[#0a0a0a] rounded-lg border border-[var(--luxury-gold)]/20">
<input
type="checkbox"
id="featured"
checked={roomFormData.featured}
onChange={(e) => setRoomFormData({ ...roomFormData, featured: e.target.checked })}
className="w-5 h-5 text-[#d4af37] bg-[#1a1a1a] border-[#d4af37]/30 rounded focus:ring-[#d4af37]/50 focus:ring-2 cursor-pointer transition-all"
className="w-5 h-5 text-[var(--luxury-gold)] bg-[#1a1a1a] border-[var(--luxury-gold)]/30 rounded focus:ring-[var(--luxury-gold)]/50 focus:ring-2 cursor-pointer transition-all"
/>
<label htmlFor="featured" className="text-sm text-gray-300 cursor-pointer font-medium">
Featured Room
@@ -3108,7 +3108,7 @@ const ReceptionDashboardPage: React.FC = () => {
min="0"
value={roomFormData.price}
onChange={(e) => setRoomFormData({ ...roomFormData, price: e.target.value })}
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white placeholder-gray-500 focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37] transition-all duration-300"
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white placeholder-gray-500 focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)] transition-all duration-300"
placeholder="e.g., 150.00"
/>
</div>
@@ -3121,7 +3121,7 @@ const ReceptionDashboardPage: React.FC = () => {
value={roomFormData.description}
onChange={(e) => setRoomFormData({ ...roomFormData, description: e.target.value })}
rows={4}
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white placeholder-gray-500 focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37] transition-all duration-300 resize-none"
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white placeholder-gray-500 focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)] transition-all duration-300 resize-none"
placeholder="Enter the actual description for this specific room..."
/>
</div>
@@ -3136,7 +3136,7 @@ const ReceptionDashboardPage: React.FC = () => {
min="1"
value={roomFormData.capacity}
onChange={(e) => setRoomFormData({ ...roomFormData, capacity: e.target.value })}
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white placeholder-gray-500 focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37] transition-all duration-300"
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white placeholder-gray-500 focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)] transition-all duration-300"
placeholder="e.g., 4"
/>
</div>
@@ -3149,7 +3149,7 @@ const ReceptionDashboardPage: React.FC = () => {
type="text"
value={roomFormData.room_size}
onChange={(e) => setRoomFormData({ ...roomFormData, room_size: e.target.value })}
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white placeholder-gray-500 focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37] transition-all duration-300"
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white placeholder-gray-500 focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)] transition-all duration-300"
placeholder="e.g., 1 Room, 50 sqm"
/>
</div>
@@ -3163,7 +3163,7 @@ const ReceptionDashboardPage: React.FC = () => {
type="text"
value={roomFormData.view}
onChange={(e) => setRoomFormData({ ...roomFormData, view: e.target.value })}
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[#d4af37]/20 rounded-lg text-white placeholder-gray-500 focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37] transition-all duration-300"
className="w-full px-4 py-3 bg-[#0a0a0a] border border-[var(--luxury-gold)]/20 rounded-lg text-white placeholder-gray-500 focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)] transition-all duration-300"
placeholder="e.g., City View, Ocean View, Mountain View"
/>
</div>
@@ -3171,12 +3171,12 @@ const ReceptionDashboardPage: React.FC = () => {
{}
<div className="space-y-4">
<h3 className="text-lg font-serif font-semibold text-[#d4af37] mb-4 flex items-center gap-2">
<div className="w-1 h-6 bg-gradient-to-b from-[#d4af37] to-[#c9a227]" />
<h3 className="text-lg font-serif font-semibold text-[var(--luxury-gold)] mb-4 flex items-center gap-2">
<div className="w-1 h-6 bg-gradient-to-b from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]" />
Amenities & Features
</h3>
<div className="border border-[#d4af37]/20 rounded-lg p-4 max-h-80 overflow-y-auto bg-[#0a0a0a]/50 backdrop-blur-sm">
<div className="border border-[var(--luxury-gold)]/20 rounded-lg p-4 max-h-80 overflow-y-auto bg-[#0a0a0a]/50 backdrop-blur-sm">
{availableAmenities.length === 0 ? (
<p className="text-sm text-gray-400 text-center py-4">Loading amenities...</p>
) : (
@@ -3188,8 +3188,8 @@ const ReceptionDashboardPage: React.FC = () => {
key={amenity}
className={`flex items-center gap-3 p-3 rounded-lg cursor-pointer transition-all duration-300 ${
isSelected
? 'bg-gradient-to-r from-[#d4af37]/20 to-[#c9a227]/20 border-2 border-[#d4af37] shadow-lg shadow-[#d4af37]/20'
: 'bg-[#1a1a1a]/50 border-2 border-[#333] hover:border-[#d4af37]/30 hover:bg-[#1a1a1a]'
? 'bg-gradient-to-r from-[var(--luxury-gold)]/20 to-[var(--luxury-gold-dark)]/20 border-2 border-[var(--luxury-gold)] shadow-lg shadow-[var(--luxury-gold)]/20'
: 'bg-[#1a1a1a]/50 border-2 border-[#333] hover:border-[var(--luxury-gold)]/30 hover:bg-[#1a1a1a]'
}`}
>
<input
@@ -3200,14 +3200,14 @@ const ReceptionDashboardPage: React.FC = () => {
/>
<div className={`w-5 h-5 rounded border-2 flex items-center justify-center transition-all duration-300 ${
isSelected
? 'bg-[#d4af37] border-[#d4af37] shadow-lg shadow-[#d4af37]/30'
? 'bg-[var(--luxury-gold)] border-[var(--luxury-gold)] shadow-lg shadow-[var(--luxury-gold)]/30'
: 'border-gray-600 bg-transparent'
}`}>
{isSelected && <Check className="w-3 h-3 text-[#0f0f0f] font-bold" />}
</div>
<span className={`text-sm flex-1 transition-colors ${
isSelected
? 'font-semibold text-[#d4af37]'
? 'font-semibold text-[var(--luxury-gold)]'
: 'text-gray-400 hover:text-gray-300'
}`}>
{amenity}
@@ -3226,17 +3226,17 @@ const ReceptionDashboardPage: React.FC = () => {
</div>
{}
<div className="flex gap-4 pt-4 border-t border-[#d4af37]/20">
<div className="flex gap-4 pt-4 border-t border-[var(--luxury-gold)]/20">
<button
type="button"
onClick={() => setShowRoomModal(false)}
className="flex-1 px-6 py-3 border border-[#d4af37]/30 text-gray-300 rounded-lg hover:bg-[#d4af37]/10 hover:border-[#d4af37] transition-all duration-300 font-medium"
className="flex-1 px-6 py-3 border border-[var(--luxury-gold)]/30 text-gray-300 rounded-lg hover:bg-[var(--luxury-gold)]/10 hover:border-[var(--luxury-gold)] transition-all duration-300 font-medium"
>
Cancel
</button>
<button
type="submit"
className="flex-1 px-6 py-3 bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-[#0f0f0f] rounded-lg hover:from-[#f5d76e] hover:to-[#d4af37] transition-all duration-300 font-semibold shadow-lg shadow-[#d4af37]/30 hover:shadow-xl hover:shadow-[#d4af37]/40"
className="flex-1 px-6 py-3 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-[#0f0f0f] rounded-lg hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] transition-all duration-300 font-semibold shadow-lg shadow-[var(--luxury-gold)]/30 hover:shadow-xl hover:shadow-[var(--luxury-gold)]/40"
>
{editingRoom ? 'Update Room' : 'Add Room'}
</button>
@@ -3245,9 +3245,9 @@ const ReceptionDashboardPage: React.FC = () => {
{}
{editingRoom && (
<div className="mt-8 pt-8 border-t border-[#d4af37]/20">
<h3 className="text-lg font-serif font-semibold text-[#d4af37] mb-6 flex items-center gap-2">
<div className="w-1 h-6 bg-gradient-to-b from-[#d4af37] to-[#c9a227]" />
<div className="mt-8 pt-8 border-t border-[var(--luxury-gold)]/20">
<h3 className="text-lg font-serif font-semibold text-[var(--luxury-gold)] mb-6 flex items-center gap-2">
<div className="w-1 h-6 bg-gradient-to-b from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]" />
<ImageIcon className="w-5 h-5" />
Room Images
</h3>
@@ -3316,8 +3316,8 @@ const ReceptionDashboardPage: React.FC = () => {
return (
<div key={index} className="relative group">
<div className="overflow-hidden rounded-lg border border-[#d4af37]/20
hover:border-[#d4af37] transition-all duration-300">
<div className="overflow-hidden rounded-lg border border-[var(--luxury-gold)]/20
hover:border-[var(--luxury-gold)] transition-all duration-300">
<img
src={imageUrl}
alt={`Room Image ${index + 1}`}
@@ -3331,7 +3331,7 @@ const ReceptionDashboardPage: React.FC = () => {
</div>
{isRoomImage && (
<>
<div className="absolute top-2 left-2 bg-[#d4af37]/90 backdrop-blur-sm
<div className="absolute top-2 left-2 bg-[var(--luxury-gold)]/90 backdrop-blur-sm
text-[#0f0f0f] px-2 py-1 rounded text-xs font-semibold
opacity-0 group-hover:opacity-100 transition-opacity duration-300">
Room Image
@@ -3354,7 +3354,7 @@ const ReceptionDashboardPage: React.FC = () => {
</div>
</div>
) : (
<div className="mb-6 p-8 bg-[#0a0a0a]/50 rounded-lg border border-[#d4af37]/10 text-center">
<div className="mb-6 p-8 bg-[#0a0a0a]/50 rounded-lg border border-[var(--luxury-gold)]/10 text-center">
<ImageIcon className="w-12 h-12 text-gray-600 mx-auto mb-3" />
<p className="text-sm text-gray-400 font-light">
No images uploaded yet. Upload images below to display them here.
@@ -3380,10 +3380,10 @@ const ReceptionDashboardPage: React.FC = () => {
className="w-full text-sm text-gray-400
file:mr-4 file:py-3 file:px-6 file:rounded-lg file:border-0
file:text-sm file:font-semibold
file:bg-gradient-to-r file:from-[#d4af37]/20 file:to-[#c9a227]/20
file:text-[#d4af37] file:border file:border-[#d4af37]/30
hover:file:from-[#d4af37]/30 hover:file:to-[#c9a227]/30
hover:file:border-[#d4af37] file:cursor-pointer
file:bg-gradient-to-r file:from-[var(--luxury-gold)]/20 file:to-[var(--luxury-gold-dark)]/20
file:text-[var(--luxury-gold)] file:border file:border-[var(--luxury-gold)]/30
hover:file:from-[var(--luxury-gold)]/30 hover:file:to-[var(--luxury-gold-dark)]/30
hover:file:border-[var(--luxury-gold)] file:cursor-pointer
transition-all duration-300 bg-[#0a0a0a] rounded-lg"
/>
</div>
@@ -3397,7 +3397,7 @@ const ReceptionDashboardPage: React.FC = () => {
type="button"
onClick={handleUploadImages}
disabled={uploadingImages}
className="px-6 py-2 bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-[#0f0f0f] rounded-lg hover:from-[#f5d76e] hover:to-[#d4af37] transition-all duration-300 font-semibold shadow-lg shadow-[#d4af37]/30 hover:shadow-xl hover:shadow-[#d4af37]/40 disabled:opacity-50 disabled:cursor-not-allowed"
className="px-6 py-2 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-[#0f0f0f] rounded-lg hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] transition-all duration-300 font-semibold shadow-lg shadow-[var(--luxury-gold)]/30 hover:shadow-xl hover:shadow-[var(--luxury-gold)]/40 disabled:opacity-50 disabled:cursor-not-allowed"
>
{uploadingImages ? 'Uploading...' : 'Upload Images'}
</button>
@@ -3407,7 +3407,7 @@ const ReceptionDashboardPage: React.FC = () => {
</div>
)}
<div className="mt-8 pt-6 border-t border-[#d4af37]/20 flex justify-end">
<div className="mt-8 pt-6 border-t border-[var(--luxury-gold)]/20 flex justify-end">
<button
type="button"
onClick={() => {

View File

@@ -11,7 +11,7 @@ const AdminDashboardPage = lazy(() => import('../pages/admin/DashboardPage'));
const UserManagementPage = lazy(() => import('../pages/admin/UserManagementPage'));
const GuestProfilePage = lazy(() => import('../pages/admin/GuestProfilePage'));
const GroupBookingManagementPage = lazy(() => import('../pages/admin/GroupBookingManagementPage'));
const BusinessDashboardPage = lazy(() => import('../pages/admin/BusinessDashboardPage'));
const PromotionsManagementPage = lazy(() => import('../pages/admin/PromotionsManagementPage'));
const ReceptionDashboardPage = lazy(() => import('../pages/admin/ReceptionDashboardPage'));
const AdvancedRoomManagementPage = lazy(() => import('../pages/admin/AdvancedRoomManagementPage'));
const PageContentDashboardPage = lazy(() => import('../pages/admin/PageContentDashboard'));
@@ -39,7 +39,7 @@ const adminRoutes: RouteObject[] = [
{ path: 'users', element: <UserManagementPage /> },
{ path: 'guest-profiles', element: <GuestProfilePage /> },
{ path: 'group-bookings', element: <GroupBookingManagementPage /> },
{ path: 'business', element: <BusinessDashboardPage /> },
{ path: 'promotions', element: <PromotionsManagementPage /> },
{ path: 'reception', element: <ReceptionDashboardPage /> },
{ path: 'advanced-rooms', element: <AdvancedRoomManagementPage /> },
{ path: 'page-content', element: <PageContentDashboardPage /> },

View File

@@ -57,11 +57,11 @@ const ConfirmationDialog: React.FC<ConfirmationDialogProps> = ({
{}
<div className="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
<div className="relative transform overflow-hidden rounded-sm bg-gradient-to-b from-white to-gray-50 text-left shadow-2xl border border-[#d4af37]/20 transition-all sm:my-8 sm:w-full sm:max-w-lg animate-fade-in">
<div className="relative transform overflow-hidden rounded-sm bg-gradient-to-b from-white to-gray-50 text-left shadow-2xl border border-[var(--luxury-gold)]/20 transition-all sm:my-8 sm:w-full sm:max-w-lg animate-fade-in">
{}
<button
onClick={onClose}
className="absolute right-4 top-4 text-gray-400 hover:text-[#d4af37] focus:outline-none focus:ring-2 focus:ring-[#d4af37]/50 rounded-sm p-1 transition-colors"
className="absolute right-4 top-4 text-gray-400 hover:text-[var(--luxury-gold)] focus:outline-none focus:ring-2 focus:ring-[var(--luxury-gold)]/50 rounded-sm p-1 transition-colors"
aria-label="Close"
>
<X className="w-5 h-5" />
@@ -74,8 +74,8 @@ const ConfirmationDialog: React.FC<ConfirmationDialogProps> = ({
variant === 'danger'
? 'bg-red-100 border-2 border-red-200'
: variant === 'warning'
? 'bg-[#d4af37]/20 border-2 border-[#d4af37]/40'
: 'bg-[#d4af37]/20 border-2 border-[#d4af37]/40'
? 'bg-[var(--luxury-gold)]/20 border-2 border-[var(--luxury-gold)]/40'
: 'bg-[var(--luxury-gold)]/20 border-2 border-[var(--luxury-gold)]/40'
} sm:mx-0 sm:h-10 sm:w-10`}
>
<AlertTriangle
@@ -83,8 +83,8 @@ const ConfirmationDialog: React.FC<ConfirmationDialogProps> = ({
variant === 'danger'
? 'text-red-600'
: variant === 'warning'
? 'text-[#d4af37]'
: 'text-[#d4af37]'
? 'text-[var(--luxury-gold)]'
: 'text-[var(--luxury-gold)]'
}`}
aria-hidden="true"
/>
@@ -111,8 +111,8 @@ const ConfirmationDialog: React.FC<ConfirmationDialogProps> = ({
variant === 'danger'
? 'bg-red-600 hover:bg-red-700 focus:ring-red-500'
: variant === 'warning'
? 'bg-gradient-to-r from-[#d4af37] to-[#c9a227] hover:from-[#f5d76e] hover:to-[#d4af37] focus:ring-[#d4af37]'
: 'btn-luxury-primary focus:ring-[#d4af37]'
? 'bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] focus:ring-[var(--luxury-gold)]'
: 'btn-luxury-primary focus:ring-[var(--luxury-gold)]'
}`}
>
{isLoading ? (
@@ -147,7 +147,7 @@ const ConfirmationDialog: React.FC<ConfirmationDialogProps> = ({
type="button"
onClick={onClose}
disabled={isLoading}
className="mt-3 inline-flex w-full justify-center rounded-sm bg-white/80 backdrop-blur-sm px-4 py-2.5 text-sm font-medium tracking-wide text-gray-700 shadow-sm border border-gray-300 hover:bg-white hover:border-[#d4af37]/30 hover:text-[#d4af37] sm:mt-0 sm:w-auto disabled:opacity-50 disabled:cursor-not-allowed transition-all"
className="mt-3 inline-flex w-full justify-center rounded-sm bg-white/80 backdrop-blur-sm px-4 py-2.5 text-sm font-medium tracking-wide text-gray-700 shadow-sm border border-gray-300 hover:bg-white hover:border-[var(--luxury-gold)]/30 hover:text-[var(--luxury-gold)] sm:mt-0 sm:w-auto disabled:opacity-50 disabled:cursor-not-allowed transition-all"
>
{cancelText}
</button>

View File

@@ -60,10 +60,10 @@ const CookieConsentBanner: React.FC = () => {
};
return (
<div className="pointer-events-none fixed inset-x-0 bottom-0 z-40 flex justify-center px-4 pb-4 sm:px-6 sm:pb-6">
<div className="pointer-events-none fixed inset-x-0 bottom-0 z-[9998] flex justify-center px-4 pb-4 sm:px-6 sm:pb-6">
<div className="pointer-events-auto relative w-full max-w-4xl overflow-hidden rounded-2xl bg-gradient-to-r from-black/85 via-zinc-900/90 to-black/85 p-[1px] shadow-[0_24px_60px_rgba(0,0,0,0.8)]">
{}
<div className="absolute inset-0 rounded-2xl border border-[#d4af37]/40" />
<div className="absolute inset-0 rounded-2xl border border-[var(--luxury-gold)]/40" />
{}
<div className="pointer-events-none absolute -inset-8 bg-[radial-gradient(circle_at_top,_rgba(212,175,55,0.18),_transparent_55%),radial-gradient(circle_at_bottom,_rgba(0,0,0,0.8),_transparent_60%)] opacity-80" />
@@ -71,8 +71,8 @@ const CookieConsentBanner: React.FC = () => {
<div className="relative flex flex-col gap-4 bg-gradient-to-br from-zinc-950/80 via-zinc-900/90 to-black/90 px-4 py-4 sm:px-6 sm:py-5 lg:px-8 lg:py-6 sm:flex-row sm:items-start sm:justify-between">
{}
<div className="space-y-3 sm:max-w-xl">
<div className="inline-flex items-center gap-2 rounded-full bg-black/60 px-3 py-1 text-[11px] font-medium uppercase tracking-[0.16em] text-[#d4af37]/90 ring-1 ring-[#d4af37]/30">
<span className="h-1.5 w-1.5 rounded-full bg-[#d4af37]" />
<div className="inline-flex items-center gap-2 rounded-full bg-black/60 px-3 py-1 text-[11px] font-medium uppercase tracking-[0.16em] text-[var(--luxury-gold)]/90 ring-1 ring-[var(--luxury-gold)]/30">
<span className="h-1.5 w-1.5 rounded-full bg-[var(--luxury-gold)]" />
Privacy Suite
</div>
@@ -90,14 +90,14 @@ const CookieConsentBanner: React.FC = () => {
<div className="flex flex-wrap items-center gap-3">
<button
type="button"
className="text-[11px] font-semibold uppercase tracking-[0.16em] text-[#d4af37] underline underline-offset-4 hover:text-[#f6e7b4]"
className="text-[11px] font-semibold uppercase tracking-[0.16em] text-[var(--luxury-gold)] underline underline-offset-4 hover:text-[#f6e7b4]"
onClick={() => setShowDetails((prev) => !prev)}
>
{showDetails ? 'Hide detailed preferences' : 'Fine-tune preferences'}
</button>
<Link
to="/gdpr"
className="text-[11px] font-semibold uppercase tracking-[0.16em] text-[#d4af37] underline underline-offset-4 hover:text-[#f6e7b4]"
className="text-[11px] font-semibold uppercase tracking-[0.16em] text-[var(--luxury-gold)] underline underline-offset-4 hover:text-[#f6e7b4]"
>
Data Privacy (GDPR)
</Link>
@@ -107,7 +107,7 @@ const CookieConsentBanner: React.FC = () => {
<div className="mt-1.5 space-y-3 rounded-xl bg-black/40 p-3 ring-1 ring-zinc-800/80 backdrop-blur-md sm:p-4">
<div className="flex flex-col gap-2 text-xs text-zinc-200 sm:text-[13px]">
<div className="flex items-start gap-3">
<div className="mt-0.5 h-4 w-4 rounded border border-[#d4af37]/50 bg-[#d4af37]/20" />
<div className="mt-0.5 h-4 w-4 rounded border border-[var(--luxury-gold)]/50 bg-[var(--luxury-gold)]/20" />
<div>
<p className="font-semibold text-zinc-50">Strictly necessary</p>
<p className="text-[11px] text-zinc-400">
@@ -121,7 +121,7 @@ const CookieConsentBanner: React.FC = () => {
<input
id="cookie-analytics"
type="checkbox"
className="mt-0.5 h-4 w-4 rounded border-zinc-500 bg-black/40 text-[#d4af37] focus:ring-[#d4af37]"
className="mt-0.5 h-4 w-4 rounded border-zinc-500 bg-black/40 text-[var(--luxury-gold)] focus:ring-[var(--luxury-gold)]"
checked={analyticsChecked}
onChange={(e) => setAnalyticsChecked(e.target.checked)}
/>
@@ -138,7 +138,7 @@ const CookieConsentBanner: React.FC = () => {
<input
id="cookie-marketing"
type="checkbox"
className="mt-0.5 h-4 w-4 rounded border-zinc-500 bg-black/40 text-[#d4af37] focus:ring-[#d4af37]"
className="mt-0.5 h-4 w-4 rounded border-zinc-500 bg-black/40 text-[var(--luxury-gold)] focus:ring-[var(--luxury-gold)]"
checked={marketingChecked}
onChange={(e) => setMarketingChecked(e.target.checked)}
/>
@@ -155,7 +155,7 @@ const CookieConsentBanner: React.FC = () => {
<input
id="cookie-preferences"
type="checkbox"
className="mt-0.5 h-4 w-4 rounded border-zinc-500 bg-black/40 text-[#d4af37] focus:ring-[#d4af37]"
className="mt-0.5 h-4 w-4 rounded border-zinc-500 bg-black/40 text-[var(--luxury-gold)] focus:ring-[var(--luxury-gold)]"
checked={preferencesChecked}
onChange={(e) => setPreferencesChecked(e.target.checked)}
/>
@@ -176,7 +176,7 @@ const CookieConsentBanner: React.FC = () => {
<div className="mt-2 flex flex-col gap-2 sm:mt-0 sm:w-56">
<button
type="button"
className="inline-flex w-full items-center justify-center rounded-full bg-gradient-to-r from-[#d4af37] via-[#f2cf74] to-[#d4af37] px-4 py-2.5 text-xs font-semibold uppercase tracking-[0.16em] text-black shadow-[0_10px_30px_rgba(0,0,0,0.6)] transition hover:from-[#f8e4a6] hover:via-[#ffe6a3] hover:to-[#f2cf74] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#d4af37]/70"
className="inline-flex w-full items-center justify-center rounded-full bg-gradient-to-r from-[var(--luxury-gold)] via-[#f2cf74] to-[var(--luxury-gold)] px-4 py-2.5 text-xs font-semibold uppercase tracking-[0.16em] text-black shadow-[0_10px_30px_rgba(0,0,0,0.6)] transition hover:from-[#f8e4a6] hover:via-[#ffe6a3] hover:to-[#f2cf74] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--luxury-gold)]/70"
onClick={handleAcceptAll}
>
Accept all & continue
@@ -191,7 +191,7 @@ const CookieConsentBanner: React.FC = () => {
{showDetails && (
<button
type="button"
className="inline-flex w-full items-center justify-center rounded-full border border-zinc-700 bg-zinc-900/80 px-4 py-2.5 text-xs font-semibold uppercase tracking-[0.16em] text-zinc-100 shadow-[0_8px_22px_rgba(0,0,0,0.6)] transition hover:border-[#d4af37]/60 hover:text-[#f5e9c6] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#d4af37]/70"
className="inline-flex w-full items-center justify-center rounded-full border border-zinc-700 bg-zinc-900/80 px-4 py-2.5 text-xs font-semibold uppercase tracking-[0.16em] text-zinc-100 shadow-[0_8px_22px_rgba(0,0,0,0.6)] transition hover:border-[var(--luxury-gold)]/60 hover:text-[#f5e9c6] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--luxury-gold)]/70"
onClick={handleSaveSelection}
>
Save my selection

View File

@@ -9,7 +9,7 @@ const CookiePreferencesLink: React.FC = () => {
<button
type="button"
onClick={handleClick}
className="hover:text-[#d4af37] transition-colors cursor-pointer font-light tracking-wide text-gray-700"
className="hover:text-[var(--luxury-gold)] transition-colors cursor-pointer font-light tracking-wide text-gray-700"
>
Cookie Preferences
</button>

View File

@@ -79,10 +79,10 @@ const CookiePreferencesModal: React.FC = () => {
};
return (
<div className="fixed inset-0 z-50 overflow-y-auto" aria-labelledby="modal-title" role="dialog" aria-modal="true">
<div className="fixed inset-0 z-[10000] overflow-y-auto" aria-labelledby="modal-title" role="dialog" aria-modal="true">
{/* Backdrop */}
<div
className="fixed inset-0 bg-black/70 backdrop-blur-sm transition-opacity"
className="fixed inset-0 bg-black/70 backdrop-blur-sm transition-opacity z-[10000]"
onClick={() => setIsOpen(false)}
aria-hidden="true"
/>
@@ -91,7 +91,7 @@ const CookiePreferencesModal: React.FC = () => {
<div className="flex min-h-full items-center justify-center p-4 text-center sm:p-0">
<div
ref={modalRef}
className="relative transform overflow-hidden rounded-2xl bg-gradient-to-br from-zinc-950/95 via-zinc-900/95 to-black/95 text-left shadow-2xl border border-[#d4af37]/30 transition-all sm:my-8 sm:w-full sm:max-w-2xl"
className="relative transform overflow-hidden rounded-2xl bg-gradient-to-br from-zinc-950/95 via-zinc-900/95 to-black/95 text-left shadow-2xl border border-[var(--luxury-gold)]/30 transition-all sm:my-8 sm:w-full sm:max-w-2xl"
>
{/* Close button */}
<button
@@ -105,8 +105,8 @@ const CookiePreferencesModal: React.FC = () => {
<div className="px-6 py-6 sm:px-8 sm:py-8">
{/* Header */}
<div className="mb-6">
<div className="inline-flex items-center gap-2 rounded-full bg-black/60 px-3 py-1 text-[11px] font-medium uppercase tracking-[0.16em] text-[#d4af37]/90 ring-1 ring-[#d4af37]/30 mb-4">
<span className="h-1.5 w-1.5 rounded-full bg-[#d4af37]" />
<div className="inline-flex items-center gap-2 rounded-full bg-black/60 px-3 py-1 text-[11px] font-medium uppercase tracking-[0.16em] text-[var(--luxury-gold)]/90 ring-1 ring-[var(--luxury-gold)]/30 mb-4">
<span className="h-1.5 w-1.5 rounded-full bg-[var(--luxury-gold)]" />
Privacy Suite
</div>
<h2 className="text-2xl font-elegant font-bold text-white mb-2">
@@ -121,8 +121,8 @@ const CookiePreferencesModal: React.FC = () => {
<div className="space-y-4 mb-6">
<div className="rounded-xl bg-black/40 p-4 ring-1 ring-zinc-800/80 backdrop-blur-md">
<div className="flex items-start gap-3">
<div className="mt-0.5 h-5 w-5 rounded border border-[#d4af37]/50 bg-[#d4af37]/20 flex items-center justify-center">
<span className="text-[#d4af37] text-xs"></span>
<div className="mt-0.5 h-5 w-5 rounded border border-[var(--luxury-gold)]/50 bg-[var(--luxury-gold)]/20 flex items-center justify-center">
<span className="text-[var(--luxury-gold)] text-xs"></span>
</div>
<div className="flex-1">
<p className="font-semibold text-zinc-50 mb-1">Strictly necessary</p>
@@ -138,7 +138,7 @@ const CookiePreferencesModal: React.FC = () => {
<input
id="cookie-analytics-modal"
type="checkbox"
className="mt-0.5 h-5 w-5 rounded border-zinc-500 bg-black/40 text-[#d4af37] focus:ring-[#d4af37] cursor-pointer"
className="mt-0.5 h-5 w-5 rounded border-zinc-500 bg-black/40 text-[var(--luxury-gold)] focus:ring-[var(--luxury-gold)] cursor-pointer"
checked={analyticsChecked}
onChange={(e) => setAnalyticsChecked(e.target.checked)}
/>
@@ -156,7 +156,7 @@ const CookiePreferencesModal: React.FC = () => {
<input
id="cookie-marketing-modal"
type="checkbox"
className="mt-0.5 h-5 w-5 rounded border-zinc-500 bg-black/40 text-[#d4af37] focus:ring-[#d4af37] cursor-pointer"
className="mt-0.5 h-5 w-5 rounded border-zinc-500 bg-black/40 text-[var(--luxury-gold)] focus:ring-[var(--luxury-gold)] cursor-pointer"
checked={marketingChecked}
onChange={(e) => setMarketingChecked(e.target.checked)}
/>
@@ -174,7 +174,7 @@ const CookiePreferencesModal: React.FC = () => {
<input
id="cookie-preferences-modal"
type="checkbox"
className="mt-0.5 h-5 w-5 rounded border-zinc-500 bg-black/40 text-[#d4af37] focus:ring-[#d4af37] cursor-pointer"
className="mt-0.5 h-5 w-5 rounded border-zinc-500 bg-black/40 text-[var(--luxury-gold)] focus:ring-[var(--luxury-gold)] cursor-pointer"
checked={preferencesChecked}
onChange={(e) => setPreferencesChecked(e.target.checked)}
/>
@@ -193,7 +193,7 @@ const CookiePreferencesModal: React.FC = () => {
<button
type="button"
onClick={handleAcceptAll}
className="flex-1 inline-flex items-center justify-center rounded-full bg-gradient-to-r from-[#d4af37] via-[#f2cf74] to-[#d4af37] px-6 py-3 text-sm font-semibold uppercase tracking-[0.16em] text-black shadow-lg transition hover:from-[#f8e4a6] hover:via-[#ffe6a3] hover:to-[#f2cf74] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#d4af37]/70"
className="flex-1 inline-flex items-center justify-center rounded-full bg-gradient-to-r from-[var(--luxury-gold)] via-[#f2cf74] to-[var(--luxury-gold)] px-6 py-3 text-sm font-semibold uppercase tracking-[0.16em] text-black shadow-lg transition hover:from-[#f8e4a6] hover:via-[#ffe6a3] hover:to-[#f2cf74] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--luxury-gold)]/70"
>
Accept all
</button>
@@ -207,7 +207,7 @@ const CookiePreferencesModal: React.FC = () => {
<button
type="button"
onClick={handleSaveSelection}
className="flex-1 inline-flex items-center justify-center rounded-full border border-[#d4af37]/60 bg-zinc-900/80 px-6 py-3 text-sm font-semibold uppercase tracking-[0.16em] text-[#d4af37] shadow-lg transition hover:border-[#d4af37] hover:bg-zinc-800/80 hover:text-[#f5e9c6] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#d4af37]/70"
className="flex-1 inline-flex items-center justify-center rounded-full border border-[var(--luxury-gold)]/60 bg-zinc-900/80 px-6 py-3 text-sm font-semibold uppercase tracking-[0.16em] text-[var(--luxury-gold)] shadow-lg transition hover:border-[var(--luxury-gold)] hover:bg-zinc-800/80 hover:text-[#f5e9c6] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--luxury-gold)]/70"
>
Save selection
</button>

View File

@@ -83,7 +83,7 @@ const CurrencySelector: React.FC<CurrencySelectorProps> = ({
<select
value={currency}
onChange={handleChange}
className="appearance-none bg-white border border-gray-300 rounded-lg px-4 py-2 pr-8 text-sm font-medium text-gray-900 focus:outline-none focus:ring-2 focus:ring-[#d4af37] focus:border-[#d4af37] transition-colors cursor-pointer"
className="appearance-none bg-white border border-gray-300 rounded-lg px-4 py-2 pr-8 text-sm font-medium text-gray-900 focus:outline-none focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-[var(--luxury-gold)] transition-colors cursor-pointer"
>
{supportedCurrencies.map((curr) => (
<option key={curr} value={curr}>
@@ -110,7 +110,7 @@ const CurrencySelector: React.FC<CurrencySelectorProps> = ({
<select
value={currency}
onChange={handleChange}
className="px-3 py-1.5 border border-gray-300 rounded-md text-sm font-medium text-gray-900 bg-white focus:outline-none focus:ring-2 focus:ring-[#d4af37] focus:border-[#d4af37] transition-colors cursor-pointer"
className="px-3 py-1.5 border border-gray-300 rounded-md text-sm font-medium text-gray-900 bg-white focus:outline-none focus:ring-2 focus:ring-[var(--luxury-gold)] focus:border-[var(--luxury-gold)] transition-colors cursor-pointer"
>
{supportedCurrencies.map((curr) => (
<option key={curr} value={curr}>

View File

@@ -194,7 +194,7 @@ const Footer: React.FC = () => {
return (
<footer className="relative bg-gradient-to-b from-[#0f0f0f] via-[#1a1a1a] to-black text-gray-300 overflow-hidden">
{/* Top Gold Accent Line */}
<div className="absolute top-0 left-0 right-0 h-[2px] bg-gradient-to-r from-transparent via-[#d4af37] to-transparent shadow-lg shadow-[#d4af37]/50"></div>
<div className="absolute top-0 left-0 right-0 h-[2px] bg-gradient-to-r from-transparent via-[var(--luxury-gold)] to-transparent shadow-lg shadow-[var(--luxury-gold)]/50"></div>
{/* Decorative Pattern Overlay */}
<div className="absolute inset-0 opacity-[0.03]" style={{
@@ -212,7 +212,7 @@ const Footer: React.FC = () => {
<div className="flex items-center space-x-4 mb-6 sm:mb-8">
{logoUrl ? (
<div className="relative group">
<div className="absolute inset-0 bg-gradient-to-r from-[#d4af37]/20 to-transparent rounded-lg blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div className="absolute inset-0 bg-gradient-to-r from-[var(--luxury-gold)]/20 to-transparent rounded-lg blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<img
src={logoUrl}
alt={settings.company_name}
@@ -221,17 +221,17 @@ const Footer: React.FC = () => {
</div>
) : (
<div className="relative group">
<div className="p-3 bg-gradient-to-br from-[#d4af37]/10 to-[#c9a227]/5 rounded-lg border border-[#d4af37]/20 backdrop-blur-sm">
<Hotel className="w-8 h-8 sm:w-10 sm:h-10 text-[#d4af37] relative z-10 drop-shadow-lg" />
<div className="p-3 bg-gradient-to-br from-[var(--luxury-gold)]/10 to-[var(--luxury-gold-dark)]/5 rounded-lg border border-[var(--luxury-gold)]/20 backdrop-blur-sm">
<Hotel className="w-8 h-8 sm:w-10 sm:h-10 text-[var(--luxury-gold)] relative z-10 drop-shadow-lg" />
</div>
<div className="absolute inset-0 bg-[#d4af37]/20 blur-2xl opacity-50 group-hover:opacity-75 transition-opacity duration-500"></div>
<div className="absolute inset-0 bg-[var(--luxury-gold)]/20 blur-2xl opacity-50 group-hover:opacity-75 transition-opacity duration-500"></div>
</div>
)}
<div>
<h2 className="text-2xl sm:text-3xl font-display font-semibold text-white tracking-tight mb-1">
{settings.company_name || pageContent?.title || 'Luxury Hotel'}
</h2>
<p className="text-xs sm:text-sm text-[#d4af37] font-light tracking-[3px] sm:tracking-[4px] uppercase">
<p className="text-xs sm:text-sm text-[var(--luxury-gold)] font-light tracking-[3px] sm:tracking-[4px] uppercase">
{settings.company_tagline || 'Excellence Redefined'}
</p>
</div>
@@ -249,10 +249,10 @@ const Footer: React.FC = () => {
return (
<div
key={index}
className="group flex items-center space-x-2 px-3 py-2 bg-gradient-to-r from-[#d4af37]/5 to-transparent border border-[#d4af37]/10 rounded-lg hover:border-[#d4af37]/30 hover:from-[#d4af37]/10 transition-all duration-300"
className="group flex items-center space-x-2 px-3 py-2 bg-gradient-to-r from-[var(--luxury-gold)]/5 to-transparent border border-[var(--luxury-gold)]/10 rounded-lg hover:border-[var(--luxury-gold)]/30 hover:from-[var(--luxury-gold)]/10 transition-all duration-300"
>
<BadgeIcon className="w-4 h-4 sm:w-5 sm:h-5 text-[#d4af37] group-hover:scale-110 transition-transform duration-300" />
<span className="text-xs sm:text-sm font-medium tracking-wide text-gray-300 group-hover:text-[#d4af37] transition-colors">{badge.text}</span>
<BadgeIcon className="w-4 h-4 sm:w-5 sm:h-5 text-[var(--luxury-gold)] group-hover:scale-110 transition-transform duration-300" />
<span className="text-xs sm:text-sm font-medium tracking-wide text-gray-300 group-hover:text-[var(--luxury-gold)] transition-colors">{badge.text}</span>
</div>
);
})}
@@ -266,11 +266,11 @@ const Footer: React.FC = () => {
href={pageContent.social_links.facebook}
target="_blank"
rel="noopener noreferrer"
className="group relative w-12 h-12 sm:w-14 sm:h-14 flex items-center justify-center rounded-lg bg-gradient-to-br from-gray-800/60 to-gray-900/60 backdrop-blur-sm border border-gray-700/50 hover:border-[#d4af37]/60 transition-all duration-300 hover:bg-gradient-to-br hover:from-[#d4af37]/10 hover:to-[#c9a227]/10 hover:shadow-lg hover:shadow-[#d4af37]/20 hover:-translate-y-0.5"
className="group relative w-12 h-12 sm:w-14 sm:h-14 flex items-center justify-center rounded-lg bg-gradient-to-br from-gray-800/60 to-gray-900/60 backdrop-blur-sm border border-gray-700/50 hover:border-[var(--luxury-gold)]/60 transition-all duration-300 hover:bg-gradient-to-br hover:from-[var(--luxury-gold)]/10 hover:to-[var(--luxury-gold-dark)]/10 hover:shadow-lg hover:shadow-[var(--luxury-gold)]/20 hover:-translate-y-0.5"
aria-label="Facebook"
>
<Facebook className="w-5 h-5 sm:w-6 sm:h-6 text-gray-400 group-hover:text-[#d4af37] transition-all duration-300 group-hover:scale-110" />
<div className="absolute inset-0 rounded-lg bg-[#d4af37]/0 group-hover:bg-[#d4af37]/10 blur-xl transition-all duration-500"></div>
<Facebook className="w-5 h-5 sm:w-6 sm:h-6 text-gray-400 group-hover:text-[var(--luxury-gold)] transition-all duration-300 group-hover:scale-110" />
<div className="absolute inset-0 rounded-lg bg-[var(--luxury-gold)]/0 group-hover:bg-[var(--luxury-gold)]/10 blur-xl transition-all duration-500"></div>
</a>
)}
{pageContent?.social_links?.twitter && (
@@ -278,11 +278,11 @@ const Footer: React.FC = () => {
href={pageContent.social_links.twitter}
target="_blank"
rel="noopener noreferrer"
className="group relative w-12 h-12 sm:w-14 sm:h-14 flex items-center justify-center rounded-lg bg-gradient-to-br from-gray-800/60 to-gray-900/60 backdrop-blur-sm border border-gray-700/50 hover:border-[#d4af37]/60 transition-all duration-300 hover:bg-gradient-to-br hover:from-[#d4af37]/10 hover:to-[#c9a227]/10 hover:shadow-lg hover:shadow-[#d4af37]/20 hover:-translate-y-0.5"
className="group relative w-12 h-12 sm:w-14 sm:h-14 flex items-center justify-center rounded-lg bg-gradient-to-br from-gray-800/60 to-gray-900/60 backdrop-blur-sm border border-gray-700/50 hover:border-[var(--luxury-gold)]/60 transition-all duration-300 hover:bg-gradient-to-br hover:from-[var(--luxury-gold)]/10 hover:to-[var(--luxury-gold-dark)]/10 hover:shadow-lg hover:shadow-[var(--luxury-gold)]/20 hover:-translate-y-0.5"
aria-label="Twitter"
>
<Twitter className="w-5 h-5 sm:w-6 sm:h-6 text-gray-400 group-hover:text-[#d4af37] transition-all duration-300 group-hover:scale-110" />
<div className="absolute inset-0 rounded-lg bg-[#d4af37]/0 group-hover:bg-[#d4af37]/10 blur-xl transition-all duration-500"></div>
<Twitter className="w-5 h-5 sm:w-6 sm:h-6 text-gray-400 group-hover:text-[var(--luxury-gold)] transition-all duration-300 group-hover:scale-110" />
<div className="absolute inset-0 rounded-lg bg-[var(--luxury-gold)]/0 group-hover:bg-[var(--luxury-gold)]/10 blur-xl transition-all duration-500"></div>
</a>
)}
{pageContent?.social_links?.instagram && (
@@ -290,11 +290,11 @@ const Footer: React.FC = () => {
href={pageContent.social_links.instagram}
target="_blank"
rel="noopener noreferrer"
className="group relative w-12 h-12 sm:w-14 sm:h-14 flex items-center justify-center rounded-lg bg-gradient-to-br from-gray-800/60 to-gray-900/60 backdrop-blur-sm border border-gray-700/50 hover:border-[#d4af37]/60 transition-all duration-300 hover:bg-gradient-to-br hover:from-[#d4af37]/10 hover:to-[#c9a227]/10 hover:shadow-lg hover:shadow-[#d4af37]/20 hover:-translate-y-0.5"
className="group relative w-12 h-12 sm:w-14 sm:h-14 flex items-center justify-center rounded-lg bg-gradient-to-br from-gray-800/60 to-gray-900/60 backdrop-blur-sm border border-gray-700/50 hover:border-[var(--luxury-gold)]/60 transition-all duration-300 hover:bg-gradient-to-br hover:from-[var(--luxury-gold)]/10 hover:to-[var(--luxury-gold-dark)]/10 hover:shadow-lg hover:shadow-[var(--luxury-gold)]/20 hover:-translate-y-0.5"
aria-label="Instagram"
>
<Instagram className="w-5 h-5 sm:w-6 sm:h-6 text-gray-400 group-hover:text-[#d4af37] transition-all duration-300 group-hover:scale-110" />
<div className="absolute inset-0 rounded-lg bg-[#d4af37]/0 group-hover:bg-[#d4af37]/10 blur-xl transition-all duration-500"></div>
<Instagram className="w-5 h-5 sm:w-6 sm:h-6 text-gray-400 group-hover:text-[var(--luxury-gold)] transition-all duration-300 group-hover:scale-110" />
<div className="absolute inset-0 rounded-lg bg-[var(--luxury-gold)]/0 group-hover:bg-[var(--luxury-gold)]/10 blur-xl transition-all duration-500"></div>
</a>
)}
{pageContent?.social_links?.linkedin && (
@@ -302,11 +302,11 @@ const Footer: React.FC = () => {
href={pageContent.social_links.linkedin}
target="_blank"
rel="noopener noreferrer"
className="group relative w-12 h-12 sm:w-14 sm:h-14 flex items-center justify-center rounded-lg bg-gradient-to-br from-gray-800/60 to-gray-900/60 backdrop-blur-sm border border-gray-700/50 hover:border-[#d4af37]/60 transition-all duration-300 hover:bg-gradient-to-br hover:from-[#d4af37]/10 hover:to-[#c9a227]/10 hover:shadow-lg hover:shadow-[#d4af37]/20 hover:-translate-y-0.5"
className="group relative w-12 h-12 sm:w-14 sm:h-14 flex items-center justify-center rounded-lg bg-gradient-to-br from-gray-800/60 to-gray-900/60 backdrop-blur-sm border border-gray-700/50 hover:border-[var(--luxury-gold)]/60 transition-all duration-300 hover:bg-gradient-to-br hover:from-[var(--luxury-gold)]/10 hover:to-[var(--luxury-gold-dark)]/10 hover:shadow-lg hover:shadow-[var(--luxury-gold)]/20 hover:-translate-y-0.5"
aria-label="LinkedIn"
>
<Linkedin className="w-5 h-5 sm:w-6 sm:h-6 text-gray-400 group-hover:text-[#d4af37] transition-all duration-300 group-hover:scale-110" />
<div className="absolute inset-0 rounded-lg bg-[#d4af37]/0 group-hover:bg-[#d4af37]/10 blur-xl transition-all duration-500"></div>
<Linkedin className="w-5 h-5 sm:w-6 sm:h-6 text-gray-400 group-hover:text-[var(--luxury-gold)] transition-all duration-300 group-hover:scale-110" />
<div className="absolute inset-0 rounded-lg bg-[var(--luxury-gold)]/0 group-hover:bg-[var(--luxury-gold)]/10 blur-xl transition-all duration-500"></div>
</a>
)}
{pageContent?.social_links?.youtube && (
@@ -314,11 +314,11 @@ const Footer: React.FC = () => {
href={pageContent.social_links.youtube}
target="_blank"
rel="noopener noreferrer"
className="group relative w-12 h-12 sm:w-14 sm:h-14 flex items-center justify-center rounded-lg bg-gradient-to-br from-gray-800/60 to-gray-900/60 backdrop-blur-sm border border-gray-700/50 hover:border-[#d4af37]/60 transition-all duration-300 hover:bg-gradient-to-br hover:from-[#d4af37]/10 hover:to-[#c9a227]/10 hover:shadow-lg hover:shadow-[#d4af37]/20 hover:-translate-y-0.5"
className="group relative w-12 h-12 sm:w-14 sm:h-14 flex items-center justify-center rounded-lg bg-gradient-to-br from-gray-800/60 to-gray-900/60 backdrop-blur-sm border border-gray-700/50 hover:border-[var(--luxury-gold)]/60 transition-all duration-300 hover:bg-gradient-to-br hover:from-[var(--luxury-gold)]/10 hover:to-[var(--luxury-gold-dark)]/10 hover:shadow-lg hover:shadow-[var(--luxury-gold)]/20 hover:-translate-y-0.5"
aria-label="YouTube"
>
<Youtube className="w-5 h-5 sm:w-6 sm:h-6 text-gray-400 group-hover:text-[#d4af37] transition-all duration-300 group-hover:scale-110" />
<div className="absolute inset-0 rounded-lg bg-[#d4af37]/0 group-hover:bg-[#d4af37]/10 blur-xl transition-all duration-500"></div>
<Youtube className="w-5 h-5 sm:w-6 sm:h-6 text-gray-400 group-hover:text-[var(--luxury-gold)] transition-all duration-300 group-hover:scale-110" />
<div className="absolute inset-0 rounded-lg bg-[var(--luxury-gold)]/0 group-hover:bg-[var(--luxury-gold)]/10 blur-xl transition-all duration-500"></div>
</a>
)}
</div>
@@ -329,16 +329,16 @@ const Footer: React.FC = () => {
<div className="lg:col-span-2">
<h3 className="text-white font-elegant font-semibold text-lg sm:text-xl mb-4 sm:mb-6 relative inline-block tracking-wide">
<span className="relative z-10">Quick Links</span>
<span className="absolute bottom-0 left-0 w-full h-[2px] bg-gradient-to-r from-[#d4af37] via-[#d4af37]/50 to-transparent"></span>
<span className="absolute bottom-0 left-0 w-full h-[2px] bg-gradient-to-r from-[var(--luxury-gold)] via-[var(--luxury-gold)]/50 to-transparent"></span>
</h3>
<ul className="space-y-3 sm:space-y-4">
{quickLinks.map((link) => (
<li key={link.url}>
<Link
to={link.url}
className="group flex items-center text-sm sm:text-base text-gray-400 hover:text-[#d4af37] transition-all duration-300 relative font-light tracking-wide"
className="group flex items-center text-sm sm:text-base text-gray-400 hover:text-[var(--luxury-gold)] transition-all duration-300 relative font-light tracking-wide"
>
<span className="absolute left-0 w-0 h-[2px] bg-gradient-to-r from-[#d4af37] to-[#c9a227] group-hover:w-8 transition-all duration-300 rounded-full"></span>
<span className="absolute left-0 w-0 h-[2px] bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] group-hover:w-8 transition-all duration-300 rounded-full"></span>
<span className="ml-10 group-hover:translate-x-2 transition-transform duration-300 group-hover:font-medium">{link.label}</span>
</Link>
</li>
@@ -352,16 +352,16 @@ const Footer: React.FC = () => {
<div className="lg:col-span-2">
<h3 className="text-white font-elegant font-semibold text-lg sm:text-xl mb-4 sm:mb-6 relative inline-block tracking-wide">
<span className="relative z-10">Guest Services</span>
<span className="absolute bottom-0 left-0 w-full h-[2px] bg-gradient-to-r from-[#d4af37] via-[#d4af37]/50 to-transparent"></span>
<span className="absolute bottom-0 left-0 w-full h-[2px] bg-gradient-to-r from-[var(--luxury-gold)] via-[var(--luxury-gold)]/50 to-transparent"></span>
</h3>
<ul className="space-y-3 sm:space-y-4">
{supportLinks.map((link) => (
<li key={link.url}>
<Link
to={link.url}
className="group flex items-center text-sm sm:text-base text-gray-400 hover:text-[#d4af37] transition-all duration-300 relative font-light tracking-wide"
className="group flex items-center text-sm sm:text-base text-gray-400 hover:text-[var(--luxury-gold)] transition-all duration-300 relative font-light tracking-wide"
>
<span className="absolute left-0 w-0 h-[2px] bg-gradient-to-r from-[#d4af37] to-[#c9a227] group-hover:w-8 transition-all duration-300 rounded-full"></span>
<span className="absolute left-0 w-0 h-[2px] bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] group-hover:w-8 transition-all duration-300 rounded-full"></span>
<span className="ml-10 group-hover:translate-x-2 transition-transform duration-300 group-hover:font-medium">{link.label}</span>
</Link>
</li>
@@ -374,7 +374,7 @@ const Footer: React.FC = () => {
<div className="lg:col-span-2">
<h3 className="text-white font-elegant font-semibold text-lg sm:text-xl mb-6 sm:mb-8 relative inline-block tracking-wide">
<span className="relative z-10">{homePageContent?.newsletter_section_title || 'Newsletter'}</span>
<span className="absolute bottom-0 left-0 w-full h-[2px] bg-gradient-to-r from-[#d4af37] via-[#d4af37]/50 to-transparent"></span>
<span className="absolute bottom-0 left-0 w-full h-[2px] bg-gradient-to-r from-[var(--luxury-gold)] via-[var(--luxury-gold)]/50 to-transparent"></span>
</h3>
{homePageContent?.newsletter_section_subtitle && (
<p className="text-sm text-gray-400 mb-4 font-light leading-relaxed">
@@ -416,14 +416,14 @@ const Footer: React.FC = () => {
value={newsletterEmail}
onChange={(e) => setNewsletterEmail(e.target.value)}
placeholder={homePageContent?.newsletter_placeholder || 'Enter your email'}
className="w-full px-4 py-2.5 rounded-lg border border-gray-700 bg-gray-800/50 text-white placeholder-gray-400 focus:border-[#d4af37] focus:ring-2 focus:ring-[#d4af37]/20 transition-all disabled:opacity-50 disabled:cursor-not-allowed text-sm"
className="w-full px-4 py-2.5 rounded-lg border border-gray-700 bg-gray-800/50 text-white placeholder-gray-400 focus:border-[var(--luxury-gold)] focus:ring-2 focus:ring-[var(--luxury-gold)]/20 transition-all disabled:opacity-50 disabled:cursor-not-allowed text-sm"
required
disabled={newsletterSubmitting}
/>
<button
type="submit"
disabled={newsletterSubmitting || !newsletterEmail}
className="w-full px-4 py-2.5 bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-[#0f0f0f] rounded-lg font-semibold hover:from-[#f5d76e] hover:to-[#d4af37] transition-all duration-300 shadow-lg shadow-[#d4af37]/30 hover:shadow-xl hover:shadow-[#d4af37]/40 disabled:opacity-50 disabled:cursor-not-allowed text-sm"
className="w-full px-4 py-2.5 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-[#0f0f0f] rounded-lg font-semibold hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] transition-all duration-300 shadow-lg shadow-[var(--luxury-gold)]/30 hover:shadow-xl hover:shadow-[var(--luxury-gold)]/40 disabled:opacity-50 disabled:cursor-not-allowed text-sm"
>
{newsletterSubmitting ? 'Subscribing...' : (homePageContent?.newsletter_button_text || 'Subscribe')}
</button>
@@ -443,17 +443,17 @@ const Footer: React.FC = () => {
<div className="lg:col-span-2">
<h3 className="text-white font-elegant font-semibold text-lg sm:text-xl mb-4 sm:mb-6 relative inline-block tracking-wide">
<span className="relative z-10">Contact</span>
<span className="absolute bottom-0 left-0 w-full h-[2px] bg-gradient-to-r from-[#d4af37] via-[#d4af37]/50 to-transparent"></span>
<span className="absolute bottom-0 left-0 w-full h-[2px] bg-gradient-to-r from-[var(--luxury-gold)] via-[var(--luxury-gold)]/50 to-transparent"></span>
</h3>
{(displayAddress || displayPhone || displayEmail) && (
<ul className="space-y-5 sm:space-y-6">
{displayAddress && (
<li className="flex items-start space-x-4 group">
<div className="relative mt-1 flex-shrink-0">
<div className="p-2 bg-gradient-to-br from-[#d4af37]/10 to-[#c9a227]/5 rounded-lg border border-[#d4af37]/20 group-hover:border-[#d4af37]/40 transition-all duration-300">
<MapPin className="w-4 h-4 sm:w-5 sm:h-5 text-[#d4af37] transition-all duration-300 group-hover:scale-110" />
<div className="p-2 bg-gradient-to-br from-[var(--luxury-gold)]/10 to-[var(--luxury-gold-dark)]/5 rounded-lg border border-[var(--luxury-gold)]/20 group-hover:border-[var(--luxury-gold)]/40 transition-all duration-300">
<MapPin className="w-4 h-4 sm:w-5 sm:h-5 text-[var(--luxury-gold)] transition-all duration-300 group-hover:scale-110" />
</div>
<div className="absolute inset-0 bg-[#d4af37]/20 blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div className="absolute inset-0 bg-[var(--luxury-gold)]/20 blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
</div>
<span className="text-sm sm:text-base text-gray-400 group-hover:text-gray-300 transition-colors leading-relaxed font-light pt-1">
{displayAddress
@@ -469,12 +469,12 @@ const Footer: React.FC = () => {
{displayPhone && (
<li className="flex items-center space-x-4 group">
<div className="relative flex-shrink-0">
<div className="p-2 bg-gradient-to-br from-[#d4af37]/10 to-[#c9a227]/5 rounded-lg border border-[#d4af37]/20 group-hover:border-[#d4af37]/40 transition-all duration-300">
<Phone className="w-4 h-4 sm:w-5 sm:h-5 text-[#d4af37] transition-all duration-300 group-hover:scale-110" />
<div className="p-2 bg-gradient-to-br from-[var(--luxury-gold)]/10 to-[var(--luxury-gold-dark)]/5 rounded-lg border border-[var(--luxury-gold)]/20 group-hover:border-[var(--luxury-gold)]/40 transition-all duration-300">
<Phone className="w-4 h-4 sm:w-5 sm:h-5 text-[var(--luxury-gold)] transition-all duration-300 group-hover:scale-110" />
</div>
<div className="absolute inset-0 bg-[#d4af37]/20 blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div className="absolute inset-0 bg-[var(--luxury-gold)]/20 blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
</div>
<a href={phoneHref} className="text-sm sm:text-base text-gray-400 group-hover:text-[#d4af37] transition-colors font-light tracking-wide">
<a href={phoneHref} className="text-sm sm:text-base text-gray-400 group-hover:text-[var(--luxury-gold)] transition-colors font-light tracking-wide">
{displayPhone}
</a>
</li>
@@ -482,12 +482,12 @@ const Footer: React.FC = () => {
{displayEmail && (
<li className="flex items-center space-x-4 group">
<div className="relative flex-shrink-0">
<div className="p-2 bg-gradient-to-br from-[#d4af37]/10 to-[#c9a227]/5 rounded-lg border border-[#d4af37]/20 group-hover:border-[#d4af37]/40 transition-all duration-300">
<Mail className="w-4 h-4 sm:w-5 sm:h-5 text-[#d4af37] transition-all duration-300 group-hover:scale-110" />
<div className="p-2 bg-gradient-to-br from-[var(--luxury-gold)]/10 to-[var(--luxury-gold-dark)]/5 rounded-lg border border-[var(--luxury-gold)]/20 group-hover:border-[var(--luxury-gold)]/40 transition-all duration-300">
<Mail className="w-4 h-4 sm:w-5 sm:h-5 text-[var(--luxury-gold)] transition-all duration-300 group-hover:scale-110" />
</div>
<div className="absolute inset-0 bg-[#d4af37]/20 blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div className="absolute inset-0 bg-[var(--luxury-gold)]/20 blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
</div>
<a href={`mailto:${displayEmail}`} className="text-sm sm:text-base text-gray-400 group-hover:text-[#d4af37] transition-colors font-light tracking-wide break-all">
<a href={`mailto:${displayEmail}`} className="text-sm sm:text-base text-gray-400 group-hover:text-[var(--luxury-gold)] transition-colors font-light tracking-wide break-all">
{displayEmail}
</a>
</li>
@@ -499,7 +499,7 @@ const Footer: React.FC = () => {
<div className="mt-8 sm:mt-10 pt-6 sm:pt-8 border-t border-gray-800/50">
<div className="flex items-center space-x-1 mb-3">
{[...Array(5)].map((_, i) => (
<Star key={i} className="w-4 h-4 sm:w-5 sm:h-5 fill-[#d4af37] text-[#d4af37] drop-shadow-lg" />
<Star key={i} className="w-4 h-4 sm:w-5 sm:h-5 fill-[var(--luxury-gold)] text-[var(--luxury-gold)] drop-shadow-lg" />
))}
</div>
<p className="text-xs sm:text-sm text-gray-500 font-light tracking-wide">Rated 5.0 by 10,000+ guests</p>
@@ -514,7 +514,7 @@ const Footer: React.FC = () => {
</div>
<div className="relative flex justify-center">
<div className="bg-gradient-to-b from-[#0f0f0f] to-[#1a1a1a] px-6">
<div className="w-24 sm:w-32 h-[2px] bg-gradient-to-r from-transparent via-[#d4af37]/50 to-transparent shadow-lg shadow-[#d4af37]/30"></div>
<div className="w-24 sm:w-32 h-[2px] bg-gradient-to-r from-transparent via-[var(--luxury-gold)]/50 to-transparent shadow-lg shadow-[var(--luxury-gold)]/30"></div>
</div>
</div>
</div>
@@ -530,11 +530,11 @@ const Footer: React.FC = () => {
})()}
</div>
<div className="flex items-center space-x-4 sm:space-x-6 text-xs sm:text-sm text-gray-600">
<Link to="/privacy" className="hover:text-[#d4af37] transition-colors cursor-pointer font-light tracking-wide">Privacy</Link>
<Link to="/privacy" className="hover:text-[var(--luxury-gold)] transition-colors cursor-pointer font-light tracking-wide">Privacy</Link>
<span className="text-gray-700"></span>
<Link to="/terms" className="hover:text-[#d4af37] transition-colors cursor-pointer font-light tracking-wide">Terms</Link>
<Link to="/terms" className="hover:text-[var(--luxury-gold)] transition-colors cursor-pointer font-light tracking-wide">Terms</Link>
<span className="text-gray-700"></span>
<Link to="/refunds" className="hover:text-[#d4af37] transition-colors cursor-pointer font-light tracking-wide">Refunds</Link>
<Link to="/refunds" className="hover:text-[var(--luxury-gold)] transition-colors cursor-pointer font-light tracking-wide">Refunds</Link>
<span className="text-gray-700"></span>
<CookiePreferencesLink />
</div>
@@ -542,7 +542,7 @@ const Footer: React.FC = () => {
</div>
{/* Bottom Gold Accent Line */}
<div className="absolute bottom-0 left-0 right-0 h-[2px] bg-gradient-to-r from-transparent via-[#d4af37] to-transparent shadow-lg shadow-[#d4af37]/50"></div>
<div className="absolute bottom-0 left-0 right-0 h-[2px] bg-gradient-to-r from-transparent via-[var(--luxury-gold)] to-transparent shadow-lg shadow-[var(--luxury-gold)]/50"></div>
{/* Chat Widget */}
<ChatWidget />

View File

@@ -1,5 +1,5 @@
import React, { useState, useRef } from 'react';
import { Link } from 'react-router-dom';
import React, { useState, useRef, useEffect } from 'react';
import { Link, useLocation } from 'react-router-dom';
import {
Hotel,
User,
@@ -41,6 +41,7 @@ const Header: React.FC<HeaderProps> = ({
}) => {
const { settings } = useCompanySettings();
const { openModal } = useAuthModal();
const location = useLocation();
const displayPhone = settings.company_phone || '+1 (234) 567-890';
@@ -55,6 +56,23 @@ const Header: React.FC<HeaderProps> = ({
const [isUserMenuOpen, setIsUserMenuOpen] = useState(false);
const userMenuRef = useRef<HTMLDivElement>(null);
// Track previous pathname to detect actual navigation
const prevPathnameRef = useRef(location.pathname);
// Close menu when navigation happens
useEffect(() => {
const prevPathname = prevPathnameRef.current;
const currentPathname = location.pathname;
// Only close menu if it's an actual navigation (pathname changed)
if (prevPathname !== currentPathname && isMobileMenuOpen) {
setIsMobileMenuOpen(false);
}
// Update ref for next comparison
prevPathnameRef.current = currentPathname;
}, [location.pathname, isMobileMenuOpen]);
useClickOutside(userMenuRef, () => {
if (isUserMenuOpen) {
@@ -84,32 +102,42 @@ const Header: React.FC<HeaderProps> = ({
{!isAuthenticated ? (
<>
<button
onClick={() => {
setIsMobileMenuOpen(false);
onClick={(e) => {
e.stopPropagation();
setTimeout(() => setIsMobileMenuOpen(false), 100);
openModal('login');
}}
onTouchStart={(e) => {
e.stopPropagation();
}}
className="flex items-center
space-x-2 px-4 py-3 text-white/90
hover:bg-[#d4af37]/10 hover:text-[#d4af37]
rounded-sm transition-all duration-300
space-x-2 px-4 py-3.5 text-white/95
hover:bg-[rgba(var(--luxury-gold-rgb),0.15)] hover:text-[var(--luxury-gold)]
rounded-md transition-all duration-300
border-l-2 border-transparent
hover:border-[#d4af37] font-light tracking-wide w-full text-left"
hover:border-[var(--luxury-gold)] font-light tracking-wider text-sm w-full text-left group relative mx-2 cursor-pointer"
style={{ touchAction: 'manipulation' }}
>
<LogIn className="w-4 h-4" />
<span>Login</span>
</button>
<button
onClick={() => {
setIsMobileMenuOpen(false);
onClick={(e) => {
e.stopPropagation();
setTimeout(() => setIsMobileMenuOpen(false), 100);
openModal('register');
}}
onTouchStart={(e) => {
e.stopPropagation();
}}
className="flex items-center
space-x-2 px-4 py-3 bg-gradient-to-r
from-[#d4af37] to-[#c9a227] text-[#0f0f0f]
rounded-sm hover:from-[#f5d76e]
hover:to-[#d4af37] transition-all
duration-300 font-medium tracking-wide
mt-2 w-full text-left"
space-x-2 px-4 py-3.5 bg-gradient-to-r
from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-[#0f0f0f]
rounded-md hover:from-[var(--luxury-gold-light)]
hover:to-[var(--luxury-gold)] transition-all
duration-300 font-medium tracking-wider text-sm
mt-2 w-full text-left mx-2 cursor-pointer"
style={{ touchAction: 'manipulation' }}
>
<UserPlus className="w-4 h-4" />
<span>Register</span>
@@ -118,21 +146,26 @@ const Header: React.FC<HeaderProps> = ({
) : (
<>
<div className="px-4 py-2 text-sm
text-[#d4af37]/70 font-light tracking-wide"
text-text-[rgba(var(--luxury-gold-rgb),0.7)] font-light tracking-wide"
>
Hello, {userInfo?.name}
</div>
<Link
to="/profile"
onClick={() =>
setIsMobileMenuOpen(false)
}
onClick={(e) => {
e.stopPropagation();
setTimeout(() => setIsMobileMenuOpen(false), 100);
}}
onTouchStart={(e) => {
e.stopPropagation();
}}
className="flex items-center
space-x-2 px-4 py-3 text-white/90
hover:bg-[#d4af37]/10 hover:text-[#d4af37]
rounded-sm transition-all duration-300
space-x-2 px-4 py-3.5 text-white/95
hover:bg-[rgba(var(--luxury-gold-rgb),0.15)] hover:text-[var(--luxury-gold)]
rounded-md transition-all duration-300
border-l-2 border-transparent
hover:border-[#d4af37] font-light tracking-wide"
hover:border-[var(--luxury-gold)] font-light tracking-wider text-sm group relative mx-2"
style={{ touchAction: 'manipulation' }}
>
<User className="w-4 h-4" />
<span>Profile</span>
@@ -141,120 +174,160 @@ const Header: React.FC<HeaderProps> = ({
<>
<Link
to="/dashboard"
onClick={() =>
setIsMobileMenuOpen(false)
}
onClick={(e) => {
e.stopPropagation();
setTimeout(() => setIsMobileMenuOpen(false), 100);
}}
onTouchStart={(e) => {
e.stopPropagation();
}}
className="flex items-center
space-x-2 px-4 py-3 text-white/90
hover:bg-[#d4af37]/10 hover:text-[#d4af37]
hover:bg-[rgba(var(--luxury-gold-rgb),0.1)] hover:text-[var(--luxury-gold)]
rounded-sm transition-all duration-300
border-l-2 border-transparent
hover:border-[#d4af37] font-light tracking-wide"
hover:border-[var(--luxury-gold)] font-light tracking-wide"
style={{ touchAction: 'manipulation' }}
>
<Calendar className="w-4 h-4" />
<span>Dashboard</span>
</Link>
<Link
to="/favorites"
onClick={() =>
setIsMobileMenuOpen(false)
}
onClick={(e) => {
e.stopPropagation();
setTimeout(() => setIsMobileMenuOpen(false), 100);
}}
onTouchStart={(e) => {
e.stopPropagation();
}}
className="flex items-center
space-x-2 px-4 py-3 text-white/90
hover:bg-[#d4af37]/10 hover:text-[#d4af37]
hover:bg-[rgba(var(--luxury-gold-rgb),0.1)] hover:text-[var(--luxury-gold)]
rounded-sm transition-all duration-300
border-l-2 border-transparent
hover:border-[#d4af37] font-light tracking-wide"
hover:border-[var(--luxury-gold)] font-light tracking-wide"
style={{ touchAction: 'manipulation' }}
>
<Heart className="w-4 h-4" />
<span>Favorites</span>
</Link>
<Link
to="/bookings"
onClick={() =>
setIsMobileMenuOpen(false)
}
onClick={(e) => {
e.stopPropagation();
setTimeout(() => setIsMobileMenuOpen(false), 100);
}}
onTouchStart={(e) => {
e.stopPropagation();
}}
className="flex items-center
space-x-2 px-4 py-3 text-white/90
hover:bg-[#d4af37]/10 hover:text-[#d4af37]
hover:bg-[rgba(var(--luxury-gold-rgb),0.1)] hover:text-[var(--luxury-gold)]
rounded-sm transition-all duration-300
border-l-2 border-transparent
hover:border-[#d4af37] font-light tracking-wide"
hover:border-[var(--luxury-gold)] font-light tracking-wide"
style={{ touchAction: 'manipulation' }}
>
<Calendar className="w-4 h-4" />
<span>My Bookings</span>
</Link>
<Link
to="/loyalty"
onClick={() =>
setIsMobileMenuOpen(false)
}
onClick={(e) => {
e.stopPropagation();
setTimeout(() => setIsMobileMenuOpen(false), 100);
}}
onTouchStart={(e) => {
e.stopPropagation();
}}
className="flex items-center
space-x-2 px-4 py-3 text-white/90
hover:bg-[#d4af37]/10 hover:text-[#d4af37]
hover:bg-[rgba(var(--luxury-gold-rgb),0.1)] hover:text-[var(--luxury-gold)]
rounded-sm transition-all duration-300
border-l-2 border-transparent
hover:border-[#d4af37] font-light tracking-wide"
hover:border-[var(--luxury-gold)] font-light tracking-wide"
style={{ touchAction: 'manipulation' }}
>
<Star className="w-4 h-4" />
<span>Loyalty Program</span>
</Link>
<Link
to="/group-bookings"
onClick={() =>
setIsMobileMenuOpen(false)
}
onClick={(e) => {
e.stopPropagation();
setTimeout(() => setIsMobileMenuOpen(false), 100);
}}
onTouchStart={(e) => {
e.stopPropagation();
}}
className="flex items-center
space-x-2 px-4 py-3 text-white/90
hover:bg-[#d4af37]/10 hover:text-[#d4af37]
hover:bg-[rgba(var(--luxury-gold-rgb),0.1)] hover:text-[var(--luxury-gold)]
rounded-sm transition-all duration-300
border-l-2 border-transparent
hover:border-[#d4af37] font-light tracking-wide"
hover:border-[var(--luxury-gold)] font-light tracking-wide"
style={{ touchAction: 'manipulation' }}
>
<Users className="w-4 h-4" />
<span>Group Bookings</span>
</Link>
<Link
to="/complaints"
onClick={() =>
setIsMobileMenuOpen(false)
}
onClick={(e) => {
e.stopPropagation();
setTimeout(() => setIsMobileMenuOpen(false), 100);
}}
onTouchStart={(e) => {
e.stopPropagation();
}}
className="flex items-center
space-x-2 px-4 py-3 text-white/90
hover:bg-[#d4af37]/10 hover:text-[#d4af37]
hover:bg-[rgba(var(--luxury-gold-rgb),0.1)] hover:text-[var(--luxury-gold)]
rounded-sm transition-all duration-300
border-l-2 border-transparent
hover:border-[#d4af37] font-light tracking-wide"
hover:border-[var(--luxury-gold)] font-light tracking-wide"
style={{ touchAction: 'manipulation' }}
>
<AlertCircle className="w-4 h-4" />
<span>Complaints</span>
</Link>
<Link
to="/guest-requests"
onClick={() =>
setIsMobileMenuOpen(false)
}
onClick={(e) => {
e.stopPropagation();
setTimeout(() => setIsMobileMenuOpen(false), 100);
}}
onTouchStart={(e) => {
e.stopPropagation();
}}
className="flex items-center
space-x-2 px-4 py-3 text-white/90
hover:bg-[#d4af37]/10 hover:text-[#d4af37]
hover:bg-[rgba(var(--luxury-gold-rgb),0.1)] hover:text-[var(--luxury-gold)]
rounded-sm transition-all duration-300
border-l-2 border-transparent
hover:border-[#d4af37] font-light tracking-wide"
hover:border-[var(--luxury-gold)] font-light tracking-wide"
style={{ touchAction: 'manipulation' }}
>
<Bell className="w-4 h-4" />
<span>Guest Requests</span>
</Link>
<Link
to="/gdpr"
onClick={() =>
setIsMobileMenuOpen(false)
}
onClick={(e) => {
e.stopPropagation();
setTimeout(() => setIsMobileMenuOpen(false), 100);
}}
onTouchStart={(e) => {
e.stopPropagation();
}}
className="flex items-center
space-x-2 px-4 py-3 text-white/90
hover:bg-[#d4af37]/10 hover:text-[#d4af37]
hover:bg-[rgba(var(--luxury-gold-rgb),0.1)] hover:text-[var(--luxury-gold)]
rounded-sm transition-all duration-300
border-l-2 border-transparent
hover:border-[#d4af37] font-light tracking-wide"
hover:border-[var(--luxury-gold)] font-light tracking-wide"
style={{ touchAction: 'manipulation' }}
>
<Shield className="w-4 h-4" />
<span>Privacy & Data</span>
@@ -264,15 +337,20 @@ const Header: React.FC<HeaderProps> = ({
{userInfo?.role === 'admin' && (
<Link
to="/admin"
onClick={() =>
setIsMobileMenuOpen(false)
}
onClick={(e) => {
e.stopPropagation();
setTimeout(() => setIsMobileMenuOpen(false), 100);
}}
onTouchStart={(e) => {
e.stopPropagation();
}}
className="flex items-center
space-x-2 px-4 py-3 text-white/90
hover:bg-[#d4af37]/10 hover:text-[#d4af37]
hover:bg-[rgba(var(--luxury-gold-rgb),0.1)] hover:text-[var(--luxury-gold)]
rounded-sm transition-all duration-300
border-l-2 border-transparent
hover:border-[#d4af37] font-light tracking-wide"
hover:border-[var(--luxury-gold)] font-light tracking-wide"
style={{ touchAction: 'manipulation' }}
>
<User className="w-4 h-4" />
<span>Admin</span>
@@ -281,15 +359,20 @@ const Header: React.FC<HeaderProps> = ({
{userInfo?.role === 'staff' && (
<Link
to="/staff"
onClick={() =>
setIsMobileMenuOpen(false)
}
onClick={(e) => {
e.stopPropagation();
setTimeout(() => setIsMobileMenuOpen(false), 100);
}}
onTouchStart={(e) => {
e.stopPropagation();
}}
className="flex items-center
space-x-2 px-4 py-3 text-white/90
hover:bg-[#d4af37]/10 hover:text-[#d4af37]
hover:bg-[rgba(var(--luxury-gold-rgb),0.1)] hover:text-[var(--luxury-gold)]
rounded-sm transition-all duration-300
border-l-2 border-transparent
hover:border-[#d4af37] font-light tracking-wide"
hover:border-[var(--luxury-gold)] font-light tracking-wide"
style={{ touchAction: 'manipulation' }}
>
<User className="w-4 h-4" />
<span>Staff Dashboard</span>
@@ -298,15 +381,20 @@ const Header: React.FC<HeaderProps> = ({
{userInfo?.role === 'accountant' && (
<Link
to="/accountant"
onClick={() =>
setIsMobileMenuOpen(false)
}
onClick={(e) => {
e.stopPropagation();
setTimeout(() => setIsMobileMenuOpen(false), 100);
}}
onTouchStart={(e) => {
e.stopPropagation();
}}
className="flex items-center
space-x-2 px-4 py-3 text-white/90
hover:bg-[#d4af37]/10 hover:text-[#d4af37]
hover:bg-[rgba(var(--luxury-gold-rgb),0.1)] hover:text-[var(--luxury-gold)]
rounded-sm transition-all duration-300
border-l-2 border-transparent
hover:border-[#d4af37] font-light tracking-wide"
hover:border-[var(--luxury-gold)] font-light tracking-wide"
style={{ touchAction: 'manipulation' }}
>
<User className="w-4 h-4" />
<span>Accountant Dashboard</span>
@@ -315,30 +403,38 @@ const Header: React.FC<HeaderProps> = ({
{userInfo?.role === 'housekeeping' && (
<Link
to="/housekeeping"
onClick={() =>
setIsMobileMenuOpen(false)
}
onClick={(e) => {
e.stopPropagation();
setTimeout(() => setIsMobileMenuOpen(false), 100);
}}
onTouchStart={(e) => {
e.stopPropagation();
}}
className="flex items-center
space-x-2 px-4 py-3 text-white/90
hover:bg-[#d4af37]/10 hover:text-[#d4af37]
hover:bg-[rgba(var(--luxury-gold-rgb),0.1)] hover:text-[var(--luxury-gold)]
rounded-sm transition-all duration-300
border-l-2 border-transparent
hover:border-[#d4af37] font-light tracking-wide"
hover:border-[var(--luxury-gold)] font-light tracking-wide"
style={{ touchAction: 'manipulation' }}
>
<User className="w-4 h-4" />
<span>Housekeeping Dashboard</span>
</Link>
)}
<div className="border-t border-[#d4af37]/20 my-2"></div>
<div className="border-t border-[rgba(var(--luxury-gold-rgb),0.2)] my-2"></div>
<button
onClick={handleLogout}
onClick={(e) => {
e.stopPropagation();
handleLogout();
}}
className="w-full flex items-center
space-x-2 px-4 py-3 text-red-400/90
hover:bg-red-500/10 hover:text-red-400
rounded-sm transition-all duration-300
border-l-2 border-transparent
hover:border-red-500/50 text-left
font-light tracking-wide"
font-light tracking-wide cursor-pointer"
>
<LogOut className="w-4 h-4" />
<span>Logout</span>
@@ -349,18 +445,20 @@ const Header: React.FC<HeaderProps> = ({
);
return (
<header className="bg-gradient-to-b from-[#1a1a1a] to-[#0f0f0f] sticky top-0 z-50 border-b border-[#d4af37]/20 shadow-2xl">
<div className="hidden lg:block bg-[#0a0a0a]/50 border-b border-[#d4af37]/10">
<header
className="bg-gradient-to-b from-[#0f0f0f] via-[#1a1a1a] to-[#0f0f0f] sticky top-0 z-50 border-b border-[rgba(var(--luxury-gold-rgb),0.15)] shadow-[0_8px_32px_rgba(0,0,0,0.4)] backdrop-blur-sm"
>
<div className="hidden lg:block bg-[#0a0a0a]/50 border-b border-[rgba(var(--luxury-gold-rgb),0.1)]">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-2">
<div className="flex items-center justify-end space-x-6 text-sm">
{displayPhone && (
<a href={`tel:${displayPhone.replace(/\s+/g, '').replace(/[()]/g, '')}`} className="flex items-center space-x-2 text-[#d4af37] hover:text-[#f5d76e] transition-colors duration-300 font-light">
<a href={`tel:${displayPhone.replace(/\s+/g, '').replace(/[()]/g, '')}`} className="flex items-center space-x-2 text-[var(--luxury-gold)] hover:text-[var(--luxury-gold-light)] transition-colors duration-300 font-light">
<Phone className="w-3.5 h-3.5" />
<span className="tracking-wide">{displayPhone}</span>
</a>
)}
{displayEmail && (
<a href={`mailto:${displayEmail}`} className="flex items-center space-x-2 text-[#d4af37] hover:text-[#f5d76e] transition-colors duration-300 font-light">
<a href={`mailto:${displayEmail}`} className="flex items-center space-x-2 text-[var(--luxury-gold)] hover:text-[var(--luxury-gold-light)] transition-colors duration-300 font-light">
<Mail className="w-3.5 h-3.5" />
<span className="tracking-wide">{displayEmail}</span>
</a>
@@ -369,96 +467,120 @@ const Header: React.FC<HeaderProps> = ({
</div>
</div>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
<div className="flex items-center justify-between">
<Link
to="/"
className="flex items-center space-x-3
group transition-all duration-300 hover:opacity-90"
>
{logoUrl ? (
<div className="relative">
<img
src={logoUrl}
alt={settings.company_name}
className="h-10 w-auto object-contain drop-shadow-lg"
/>
<div className="w-full py-3 sm:py-4 md:py-5">
<div className="flex items-center justify-between relative w-full">
{/* Logo - Left - Always visible on all screens, flush with left edge */}
<div className="flex items-center flex-shrink-0 pl-2 sm:pl-4 md:pl-6 lg:pl-8 max-w-[50%] sm:max-w-none">
<Link
to="/"
className="flex items-center space-x-1.5 sm:space-x-2 md:space-x-3
group transition-all duration-300 hover:opacity-90 z-10"
>
{logoUrl ? (
<div className="relative flex-shrink-0">
<div className="absolute inset-0 bg-gradient-to-br from-[var(--luxury-gold)]/20 to-transparent rounded-lg blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<img
src={logoUrl}
alt={settings.company_name}
className="h-8 w-8 sm:h-10 sm:w-10 md:h-12 md:w-auto object-contain drop-shadow-[0_4px_12px_rgba(var(--luxury-gold-rgb),0.3)] relative z-10 transition-transform duration-300 group-hover:scale-105"
/>
</div>
) : (
<div className="relative flex-shrink-0">
<div className="absolute inset-0 bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-light)] rounded-full blur-xl opacity-30 group-hover:opacity-50 transition-opacity duration-500"></div>
<Hotel className="relative w-8 h-8 sm:w-10 sm:h-10 md:w-12 md:h-12 text-[var(--luxury-gold)] drop-shadow-[0_4px_12px_rgba(var(--luxury-gold-rgb),0.4)] transition-transform duration-300 group-hover:scale-110" />
</div>
)}
<div className="flex flex-col min-w-0">
<span className="text-sm sm:text-base md:text-lg lg:text-xl xl:text-2xl font-display font-semibold text-white tracking-tight leading-tight bg-gradient-to-r from-white to-white/90 bg-clip-text truncate">
{settings.company_name}
</span>
<span className="text-[8px] sm:text-[9px] md:text-[10px] text-[var(--luxury-gold)] tracking-[0.25em] uppercase font-light hidden sm:block">
{settings.company_tagline || 'Excellence Redefined'}
</span>
</div>
) : (
<div className="relative">
<div className="absolute inset-0 bg-gradient-to-br from-[#d4af37] to-[#f5d76e] rounded-full blur-md opacity-30 group-hover:opacity-50 transition-opacity duration-300"></div>
<Hotel className="relative w-10 h-10 text-[#d4af37] drop-shadow-lg" />
</div>
)}
<div className="flex flex-col">
<span className="text-2xl font-display font-semibold text-white tracking-tight leading-tight">
{settings.company_name}
</span>
<span className="text-[10px] text-[#d4af37] tracking-[0.2em] uppercase font-light">
{settings.company_tagline || 'Excellence Redefined'}
</span>
</div>
</Link>
</Link>
</div>
<Navbar
isMobileMenuOpen={isMobileMenuOpen}
onMobileMenuToggle={toggleMobileMenu}
onLinkClick={() => setIsMobileMenuOpen(false)}
mobileMenuContent={mobileMenuContent}
/>
{/* Navigation Links - Center */}
<div className="absolute left-1/2 transform -translate-x-1/2 hidden md:block z-20">
<Navbar
isMobileMenuOpen={isMobileMenuOpen}
onMobileMenuToggle={toggleMobileMenu}
onLinkClick={() => setIsMobileMenuOpen(false)}
mobileMenuContent={mobileMenuContent}
/>
</div>
{/* Mobile Menu Button - Right (for smaller screens) */}
<div className="flex items-center justify-end md:hidden z-20 pr-2 sm:pr-4">
<Navbar
isMobileMenuOpen={isMobileMenuOpen}
onMobileMenuToggle={toggleMobileMenu}
onLinkClick={() => setIsMobileMenuOpen(false)}
mobileMenuContent={mobileMenuContent}
/>
</div>
{/* Login/Register - Right */}
<div className="hidden md:flex items-center
space-x-3"
justify-end space-x-4 z-10 flex-shrink-0 pr-4 sm:pr-6 lg:pr-8"
>
{!isAuthenticated ? (
<>
<button
onClick={() => openModal('login')}
className="flex items-center space-x-2
px-5 py-2 text-white/90
hover:text-[#d4af37] transition-all duration-300
font-light tracking-wide relative group"
px-6 py-2.5 text-white/95
hover:text-[var(--luxury-gold)] transition-all duration-300
font-light tracking-wider relative group overflow-hidden"
>
<LogIn className="w-4 h-4 relative z-10" />
<span className="relative z-10">Login</span>
<span className="absolute inset-0 border border-[#d4af37]/30 rounded-sm opacity-0 group-hover:opacity-100 transition-opacity duration-300"></span>
<span className="absolute inset-0 border border-[rgba(var(--luxury-gold-rgb),0.2)] rounded-md opacity-0 group-hover:opacity-100 transition-all duration-300 group-hover:border-[rgba(var(--luxury-gold-rgb),0.5)]"></span>
<span className="absolute inset-0 bg-gradient-to-r from-[rgba(var(--luxury-gold-rgb),0.05)] to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300"></span>
<LogIn className="w-4 h-4 relative z-10 transition-transform duration-300 group-hover:scale-110" />
<span className="relative z-10 text-sm">Login</span>
</button>
<button
onClick={() => openModal('register')}
className="flex items-center space-x-2
px-6 py-2.5 bg-gradient-to-r from-[#d4af37] to-[#c9a227]
text-[#0f0f0f] rounded-sm hover:from-[#f5d76e]
hover:to-[#d4af37] transition-all duration-300
font-medium tracking-wide shadow-lg shadow-[#d4af37]/20
hover:shadow-[#d4af37]/30 relative overflow-hidden group"
px-7 py-2.5 bg-gradient-to-r from-[var(--luxury-gold)] via-[var(--luxury-gold-light)] to-[var(--luxury-gold)]
text-[#0f0f0f] rounded-md hover:from-[var(--luxury-gold-light)]
hover:via-[var(--luxury-gold)] hover:to-[var(--luxury-gold-dark)] transition-all duration-500
font-medium tracking-wider shadow-[0_4px_20px_rgba(var(--luxury-gold-rgb),0.3)]
hover:shadow-[0_6px_30px_rgba(var(--luxury-gold-rgb),0.5)] relative overflow-hidden group
transform hover:scale-105 transition-transform duration-300"
>
<span className="absolute inset-0 bg-gradient-to-r from-white/0 via-white/20 to-white/0 translate-x-[-100%] group-hover:translate-x-[100%] transition-transform duration-700"></span>
<UserPlus className="w-4 h-4 relative z-10" />
<span className="relative z-10">Register</span>
<span className="absolute inset-0 bg-gradient-to-r from-white/0 via-white/30 to-white/0 translate-x-[-100%] group-hover:translate-x-[100%] transition-transform duration-1000"></span>
<UserPlus className="w-4 h-4 relative z-10 transition-transform duration-300 group-hover:rotate-12" />
<span className="relative z-10 text-sm">Register</span>
</button>
</>
) : (
<div className="flex items-center gap-3">
<div className="flex items-center gap-3 justify-end w-full">
{isAuthenticated && <InAppNotificationBell />}
<div className="relative" ref={userMenuRef}>
<button
onClick={toggleUserMenu}
className="flex items-center space-x-3
px-3 py-2 rounded-sm hover:bg-white/10
px-4 py-2.5 rounded-md hover:bg-[rgba(var(--luxury-gold-rgb),0.1)]
transition-all duration-300 border border-transparent
hover:border-[#d4af37]/30"
hover:border-[rgba(var(--luxury-gold-rgb),0.3)] group"
>
{userInfo?.avatar ? (
<img
src={normalizeImageUrl(userInfo.avatar)}
alt={userInfo.name}
className="w-9 h-9 rounded-full
object-cover ring-2 ring-[#d4af37]/50"
className="w-10 h-10 rounded-full
object-cover ring-2 ring-[var(--luxury-gold)]/50
transition-all duration-300 group-hover:ring-[var(--luxury-gold)]/80
group-hover:scale-105 shadow-lg"
/>
) : (
<div className="w-9 h-9 bg-gradient-to-br from-[#d4af37] to-[#c9a227]
<div className="w-10 h-10 bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)]
rounded-full flex items-center
justify-center ring-2 ring-[#d4af37]/50 shadow-lg"
justify-center ring-2 ring-[var(--luxury-gold)]/50 shadow-lg
transition-all duration-300 group-hover:ring-[var(--luxury-gold)]/80
group-hover:scale-105"
>
<span className="text-[#0f0f0f]
font-semibold text-sm"
@@ -468,28 +590,29 @@ const Header: React.FC<HeaderProps> = ({
</span>
</div>
)}
<span className="font-light text-white/90 tracking-wide">
<span className="font-light text-white/95 tracking-wider text-sm">
{userInfo?.name}
</span>
</button>
{isUserMenuOpen && (
<div className="absolute right-0 mt-2
w-52 bg-gradient-to-b from-[#1a1a1a] to-[#0f0f0f]
rounded-sm shadow-2xl py-2 border border-[#d4af37]/20
z-50 backdrop-blur-xl animate-fade-in"
<div className="absolute right-0 mt-3
w-56 bg-gradient-to-b from-[#0f0f0f] via-[#1a1a1a] to-[#0f0f0f]
rounded-lg shadow-[0_8px_32px_rgba(0,0,0,0.6)] py-3 border border-[rgba(var(--luxury-gold-rgb),0.2)]
z-[9999] backdrop-blur-xl animate-fade-in"
>
<Link
to="/profile"
onClick={() => setIsUserMenuOpen(false)}
className="flex items-center space-x-3
px-4 py-2.5 text-white/90
hover:bg-[#d4af37]/10 hover:text-[#d4af37]
px-5 py-3 text-white/95
hover:bg-[rgba(var(--luxury-gold-rgb),0.1)] hover:text-[var(--luxury-gold)]
transition-all duration-300 border-l-2 border-transparent
hover:border-[#d4af37]"
hover:border-[var(--luxury-gold)] rounded-md group relative"
>
<User className="w-4 h-4" />
<span className="font-light tracking-wide">Profile</span>
<span className="absolute left-0 top-0 bottom-0 w-0 bg-gradient-to-r from-[rgba(var(--luxury-gold-rgb),0.1)] to-transparent group-hover:w-full transition-all duration-300 rounded-md"></span>
<User className="w-4 h-4 relative z-10 transition-transform duration-300 group-hover:scale-110" />
<span className="font-light tracking-wider text-sm relative z-10">Profile</span>
</Link>
{userInfo?.role !== 'admin' && userInfo?.role !== 'staff' && userInfo?.role !== 'accountant' && userInfo?.role !== 'housekeeping' && (
<>
@@ -497,97 +620,105 @@ const Header: React.FC<HeaderProps> = ({
to="/dashboard"
onClick={() => setIsUserMenuOpen(false)}
className="flex items-center space-x-3
px-4 py-2.5 text-white/90
hover:bg-[#d4af37]/10 hover:text-[#d4af37]
px-5 py-3 text-white/95
hover:bg-[rgba(var(--luxury-gold-rgb),0.1)] hover:text-[var(--luxury-gold)]
transition-all duration-300 border-l-2 border-transparent
hover:border-[#d4af37]"
hover:border-[var(--luxury-gold)] rounded-md group relative"
>
<Calendar className="w-4 h-4" />
<span className="font-light tracking-wide">Dashboard</span>
<span className="absolute left-0 top-0 bottom-0 w-0 bg-gradient-to-r from-[rgba(var(--luxury-gold-rgb),0.1)] to-transparent group-hover:w-full transition-all duration-300 rounded-md"></span>
<Calendar className="w-4 h-4 relative z-10 transition-transform duration-300 group-hover:scale-110" />
<span className="font-light tracking-wider text-sm relative z-10">Dashboard</span>
</Link>
<Link
to="/favorites"
onClick={() => setIsUserMenuOpen(false)}
className="flex items-center space-x-3
px-4 py-2.5 text-white/90
hover:bg-[#d4af37]/10 hover:text-[#d4af37]
px-5 py-3 text-white/95
hover:bg-[rgba(var(--luxury-gold-rgb),0.1)] hover:text-[var(--luxury-gold)]
transition-all duration-300 border-l-2 border-transparent
hover:border-[#d4af37]"
hover:border-[var(--luxury-gold)] rounded-md group relative"
>
<Heart className="w-4 h-4" />
<span className="font-light tracking-wide">Favorites</span>
<span className="absolute left-0 top-0 bottom-0 w-0 bg-gradient-to-r from-[rgba(var(--luxury-gold-rgb),0.1)] to-transparent group-hover:w-full transition-all duration-300 rounded-md"></span>
<Heart className="w-4 h-4 relative z-10 transition-transform duration-300 group-hover:scale-110" />
<span className="font-light tracking-wider text-sm relative z-10">Favorites</span>
</Link>
<Link
to="/bookings"
onClick={() => setIsUserMenuOpen(false)}
className="flex items-center space-x-3
px-4 py-2.5 text-white/90
hover:bg-[#d4af37]/10 hover:text-[#d4af37]
px-5 py-3 text-white/95
hover:bg-[rgba(var(--luxury-gold-rgb),0.1)] hover:text-[var(--luxury-gold)]
transition-all duration-300 border-l-2 border-transparent
hover:border-[#d4af37]"
hover:border-[var(--luxury-gold)] rounded-md group relative"
>
<Calendar className="w-4 h-4" />
<span className="font-light tracking-wide">My Bookings</span>
<span className="absolute left-0 top-0 bottom-0 w-0 bg-gradient-to-r from-[rgba(var(--luxury-gold-rgb),0.1)] to-transparent group-hover:w-full transition-all duration-300 rounded-md"></span>
<Calendar className="w-4 h-4 relative z-10 transition-transform duration-300 group-hover:scale-110" />
<span className="font-light tracking-wider text-sm relative z-10">My Bookings</span>
</Link>
<Link
to="/loyalty"
onClick={() => setIsUserMenuOpen(false)}
className="flex items-center space-x-3
px-4 py-2.5 text-white/90
hover:bg-[#d4af37]/10 hover:text-[#d4af37]
px-5 py-3 text-white/95
hover:bg-[rgba(var(--luxury-gold-rgb),0.1)] hover:text-[var(--luxury-gold)]
transition-all duration-300 border-l-2 border-transparent
hover:border-[#d4af37]"
hover:border-[var(--luxury-gold)] rounded-md group relative"
>
<Star className="w-4 h-4" />
<span className="font-light tracking-wide">Loyalty Program</span>
<span className="absolute left-0 top-0 bottom-0 w-0 bg-gradient-to-r from-[rgba(var(--luxury-gold-rgb),0.1)] to-transparent group-hover:w-full transition-all duration-300 rounded-md"></span>
<Star className="w-4 h-4 relative z-10 transition-transform duration-300 group-hover:scale-110" />
<span className="font-light tracking-wider text-sm relative z-10">Loyalty Program</span>
</Link>
<Link
to="/group-bookings"
onClick={() => setIsUserMenuOpen(false)}
className="flex items-center space-x-3
px-4 py-2.5 text-white/90
hover:bg-[#d4af37]/10 hover:text-[#d4af37]
px-5 py-3 text-white/95
hover:bg-[rgba(var(--luxury-gold-rgb),0.1)] hover:text-[var(--luxury-gold)]
transition-all duration-300 border-l-2 border-transparent
hover:border-[#d4af37]"
hover:border-[var(--luxury-gold)] rounded-md group relative"
>
<Users className="w-4 h-4" />
<span className="font-light tracking-wide">Group Bookings</span>
<span className="absolute left-0 top-0 bottom-0 w-0 bg-gradient-to-r from-[rgba(var(--luxury-gold-rgb),0.1)] to-transparent group-hover:w-full transition-all duration-300 rounded-md"></span>
<Users className="w-4 h-4 relative z-10 transition-transform duration-300 group-hover:scale-110" />
<span className="font-light tracking-wider text-sm relative z-10">Group Bookings</span>
</Link>
<Link
to="/complaints"
onClick={() => setIsUserMenuOpen(false)}
className="flex items-center space-x-3
px-4 py-2.5 text-white/90
hover:bg-[#d4af37]/10 hover:text-[#d4af37]
px-5 py-3 text-white/95
hover:bg-[rgba(var(--luxury-gold-rgb),0.1)] hover:text-[var(--luxury-gold)]
transition-all duration-300 border-l-2 border-transparent
hover:border-[#d4af37]"
hover:border-[var(--luxury-gold)] rounded-md group relative"
>
<AlertCircle className="w-4 h-4" />
<span className="font-light tracking-wide">Complaints</span>
<span className="absolute left-0 top-0 bottom-0 w-0 bg-gradient-to-r from-[rgba(var(--luxury-gold-rgb),0.1)] to-transparent group-hover:w-full transition-all duration-300 rounded-md"></span>
<AlertCircle className="w-4 h-4 relative z-10 transition-transform duration-300 group-hover:scale-110" />
<span className="font-light tracking-wider text-sm relative z-10">Complaints</span>
</Link>
<Link
to="/guest-requests"
onClick={() => setIsUserMenuOpen(false)}
className="flex items-center space-x-3
px-4 py-2.5 text-white/90
hover:bg-[#d4af37]/10 hover:text-[#d4af37]
px-5 py-3 text-white/95
hover:bg-[rgba(var(--luxury-gold-rgb),0.1)] hover:text-[var(--luxury-gold)]
transition-all duration-300 border-l-2 border-transparent
hover:border-[#d4af37]"
hover:border-[var(--luxury-gold)] rounded-md group relative"
>
<Bell className="w-4 h-4" />
<span className="font-light tracking-wide">Guest Requests</span>
<span className="absolute left-0 top-0 bottom-0 w-0 bg-gradient-to-r from-[rgba(var(--luxury-gold-rgb),0.1)] to-transparent group-hover:w-full transition-all duration-300 rounded-md"></span>
<Bell className="w-4 h-4 relative z-10 transition-transform duration-300 group-hover:scale-110" />
<span className="font-light tracking-wider text-sm relative z-10">Guest Requests</span>
</Link>
<Link
to="/gdpr"
onClick={() => setIsUserMenuOpen(false)}
className="flex items-center space-x-3
px-4 py-2.5 text-white/90
hover:bg-[#d4af37]/10 hover:text-[#d4af37]
px-5 py-3 text-white/95
hover:bg-[rgba(var(--luxury-gold-rgb),0.1)] hover:text-[var(--luxury-gold)]
transition-all duration-300 border-l-2 border-transparent
hover:border-[#d4af37]"
hover:border-[var(--luxury-gold)] rounded-md group relative"
>
<Shield className="w-4 h-4" />
<span className="font-light tracking-wide">Privacy & Data</span>
<span className="absolute left-0 top-0 bottom-0 w-0 bg-gradient-to-r from-[rgba(var(--luxury-gold-rgb),0.1)] to-transparent group-hover:w-full transition-all duration-300 rounded-md"></span>
<Shield className="w-4 h-4 relative z-10 transition-transform duration-300 group-hover:scale-110" />
<span className="font-light tracking-wider text-sm relative z-10">Privacy & Data</span>
</Link>
</>
)}
@@ -598,13 +729,14 @@ const Header: React.FC<HeaderProps> = ({
setIsUserMenuOpen(false)
}
className="flex items-center
space-x-3 px-4 py-2.5 text-white/90
hover:bg-[#d4af37]/10 hover:text-[#d4af37]
space-x-3 px-5 py-3 text-white/95
hover:bg-[rgba(var(--luxury-gold-rgb),0.1)] hover:text-[var(--luxury-gold)]
transition-all duration-300 border-l-2 border-transparent
hover:border-[#d4af37]"
hover:border-[var(--luxury-gold)] rounded-md group relative"
>
<User className="w-4 h-4" />
<span className="font-light tracking-wide">Admin</span>
<span className="absolute left-0 top-0 bottom-0 w-0 bg-gradient-to-r from-[rgba(var(--luxury-gold-rgb),0.1)] to-transparent group-hover:w-full transition-all duration-300 rounded-md"></span>
<User className="w-4 h-4 relative z-10 transition-transform duration-300 group-hover:scale-110" />
<span className="font-light tracking-wider text-sm relative z-10">Admin</span>
</Link>
)}
{userInfo?.role === 'staff' && (
@@ -614,13 +746,14 @@ const Header: React.FC<HeaderProps> = ({
setIsUserMenuOpen(false)
}
className="flex items-center
space-x-3 px-4 py-2.5 text-white/90
hover:bg-[#d4af37]/10 hover:text-[#d4af37]
space-x-3 px-5 py-3 text-white/95
hover:bg-[rgba(var(--luxury-gold-rgb),0.1)] hover:text-[var(--luxury-gold)]
transition-all duration-300 border-l-2 border-transparent
hover:border-[#d4af37]"
hover:border-[var(--luxury-gold)] rounded-md group relative"
>
<User className="w-4 h-4" />
<span className="font-light tracking-wide">Staff Dashboard</span>
<span className="absolute left-0 top-0 bottom-0 w-0 bg-gradient-to-r from-[rgba(var(--luxury-gold-rgb),0.1)] to-transparent group-hover:w-full transition-all duration-300 rounded-md"></span>
<User className="w-4 h-4 relative z-10 transition-transform duration-300 group-hover:scale-110" />
<span className="font-light tracking-wider text-sm relative z-10">Staff Dashboard</span>
</Link>
)}
{userInfo?.role === 'accountant' && (
@@ -630,13 +763,14 @@ const Header: React.FC<HeaderProps> = ({
setIsUserMenuOpen(false)
}
className="flex items-center
space-x-3 px-4 py-2.5 text-white/90
hover:bg-[#d4af37]/10 hover:text-[#d4af37]
space-x-3 px-5 py-3 text-white/95
hover:bg-[rgba(var(--luxury-gold-rgb),0.1)] hover:text-[var(--luxury-gold)]
transition-all duration-300 border-l-2 border-transparent
hover:border-[#d4af37]"
hover:border-[var(--luxury-gold)] rounded-md group relative"
>
<User className="w-4 h-4" />
<span className="font-light tracking-wide">Accountant Dashboard</span>
<span className="absolute left-0 top-0 bottom-0 w-0 bg-gradient-to-r from-[rgba(var(--luxury-gold-rgb),0.1)] to-transparent group-hover:w-full transition-all duration-300 rounded-md"></span>
<User className="w-4 h-4 relative z-10 transition-transform duration-300 group-hover:scale-110" />
<span className="font-light tracking-wider text-sm relative z-10">Accountant Dashboard</span>
</Link>
)}
{userInfo?.role === 'housekeeping' && (
@@ -646,26 +780,28 @@ const Header: React.FC<HeaderProps> = ({
setIsUserMenuOpen(false)
}
className="flex items-center
space-x-3 px-4 py-2.5 text-white/90
hover:bg-[#d4af37]/10 hover:text-[#d4af37]
space-x-3 px-5 py-3 text-white/95
hover:bg-[rgba(var(--luxury-gold-rgb),0.1)] hover:text-[var(--luxury-gold)]
transition-all duration-300 border-l-2 border-transparent
hover:border-[#d4af37]"
hover:border-[var(--luxury-gold)] rounded-md group relative"
>
<User className="w-4 h-4" />
<span className="font-light tracking-wide">Housekeeping Dashboard</span>
<span className="absolute left-0 top-0 bottom-0 w-0 bg-gradient-to-r from-[rgba(var(--luxury-gold-rgb),0.1)] to-transparent group-hover:w-full transition-all duration-300 rounded-md"></span>
<User className="w-4 h-4 relative z-10 transition-transform duration-300 group-hover:scale-110" />
<span className="font-light tracking-wider text-sm relative z-10">Housekeeping Dashboard</span>
</Link>
)}
<div className="border-t border-[#d4af37]/20 my-1"></div>
<div className="border-t border-[rgba(var(--luxury-gold-rgb),0.2)] my-2"></div>
<button
onClick={handleLogout}
className="w-full flex items-center
space-x-3 px-4 py-2.5 text-red-400/90
space-x-3 px-5 py-3 text-red-400/95
hover:bg-red-500/10 hover:text-red-400
transition-all duration-300 border-l-2 border-transparent
hover:border-red-500/50 text-left"
hover:border-red-500/50 text-left rounded-md group relative"
>
<LogOut className="w-4 h-4" />
<span className="font-light tracking-wide">Logout</span>
<span className="absolute left-0 top-0 bottom-0 w-0 bg-gradient-to-r from-red-500/10 to-transparent group-hover:w-full transition-all duration-300 rounded-md"></span>
<LogOut className="w-4 h-4 relative z-10 transition-transform duration-300 group-hover:scale-110" />
<span className="font-light tracking-wider text-sm relative z-10">Logout</span>
</button>
</div>
)}

View File

@@ -1,7 +1,7 @@
import React, { useRef } from 'react';
import { createPortal } from 'react-dom';
import { Link } from 'react-router-dom';
import { Menu, X } from 'lucide-react';
import { useClickOutside } from '../hooks/useClickOutside';
interface NavbarProps {
isMobileMenuOpen: boolean;
@@ -28,12 +28,50 @@ const Navbar: React.FC<NavbarProps> = ({
mobileMenuContent
}) => {
const mobileMenuContainerRef = useRef<HTMLDivElement>(null);
const mobileMenuDropdownRef = useRef<HTMLDivElement>(null);
useClickOutside(mobileMenuContainerRef, () => {
if (isMobileMenuOpen) {
// Handle click outside for the portal-rendered dropdown
// Note: We don't use useClickOutside here because the dropdown is rendered via portal
React.useEffect(() => {
if (!isMobileMenuOpen) return;
const handleClickOutside = (event: MouseEvent | TouchEvent) => {
const target = event.target as Node;
const targetElement = target as Element;
// Check if click is on a link - if so, don't close (let navigation happen)
const linkElement = targetElement.closest('a');
if (linkElement && mobileMenuDropdownRef.current?.contains(linkElement)) {
return; // Let the link handle navigation
}
// Check if click is inside the dropdown menu
if (mobileMenuDropdownRef.current?.contains(target)) {
return; // Don't close if clicking inside menu
}
// Check if click is on the menu button
if (mobileMenuContainerRef.current?.contains(target)) {
return; // Don't close if clicking the menu button
}
// Close menu if clicking outside
onMobileMenuToggle();
}
});
};
// Use a delay to avoid interfering with link clicks
// This ensures link navigation happens before the handler is active
const timeoutId = setTimeout(() => {
document.addEventListener('mousedown', handleClickOutside);
document.addEventListener('touchstart', handleClickOutside);
}, 300);
return () => {
clearTimeout(timeoutId);
document.removeEventListener('mousedown', handleClickOutside);
document.removeEventListener('touchstart', handleClickOutside);
};
}, [isMobileMenuOpen, onMobileMenuToggle]);
const handleLinkClick = () => {
if (onLinkClick) {
@@ -51,10 +89,10 @@ const Navbar: React.FC<NavbarProps> = ({
to={link.to}
onClick={handleLinkClick}
className="px-4 py-3 text-white/90
hover:bg-[#d4af37]/10 hover:text-[#d4af37]
hover:bg-[var(--luxury-gold)]/10 hover:text-[var(--luxury-gold)]
rounded-sm transition-all duration-300
border-l-2 border-transparent
hover:border-[#d4af37] font-light tracking-wide"
hover:border-[var(--luxury-gold)] font-light tracking-wide"
>
{link.label}
</Link>
@@ -66,17 +104,24 @@ const Navbar: React.FC<NavbarProps> = ({
return (
<div className="relative" ref={mobileMenuContainerRef}>
{/* Desktop Navigation */}
<nav className="hidden md:flex items-center space-x-1">
<nav className="hidden md:flex items-center space-x-2">
{navLinks.map((link) => (
<Link
key={link.to}
to={link.to}
className="text-white/90 hover:text-[#d4af37]
transition-all duration-300 font-light px-4 py-2
relative group tracking-wide"
className="text-white/95 hover:text-[var(--luxury-gold)]
transition-all duration-300 font-light px-5 py-2.5
relative group tracking-wider text-sm uppercase"
>
<span className="relative z-10">{link.label}</span>
<span className="absolute inset-0 bg-gradient-to-r from-[#d4af37]/0 via-[#d4af37]/10 to-[#d4af37]/0 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></span>
<span className="relative z-10 transition-all duration-300 group-hover:tracking-widest">
{link.label}
</span>
{/* Underline effect */}
<span className="absolute bottom-0 left-0 w-0 h-[1px] bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-light)] group-hover:w-full transition-all duration-500"></span>
{/* Background glow on hover */}
<span className="absolute inset-0 bg-gradient-to-r from-[rgba(var(--luxury-gold-rgb),0.05)] via-[rgba(var(--luxury-gold-rgb),0.1)] to-[rgba(var(--luxury-gold-rgb),0.05)] opacity-0 group-hover:opacity-100 transition-opacity duration-300 rounded-sm"></span>
{/* Subtle border on hover */}
<span className="absolute inset-0 border border-[rgba(var(--luxury-gold-rgb),0.1)] rounded-sm opacity-0 group-hover:opacity-100 transition-opacity duration-300"></span>
</Link>
))}
</nav>
@@ -84,49 +129,138 @@ const Navbar: React.FC<NavbarProps> = ({
{/* Mobile Menu Button */}
<button
onClick={onMobileMenuToggle}
className="md:hidden p-2 rounded-sm
hover:bg-white/10 border border-transparent
hover:border-[#d4af37]/30 transition-all duration-300"
className="md:hidden p-3 rounded-lg
bg-[rgba(var(--luxury-gold-rgb),0.1)] hover:bg-[rgba(var(--luxury-gold-rgb),0.2)]
border border-[rgba(var(--luxury-gold-rgb),0.3)]
hover:border-[rgba(var(--luxury-gold-rgb),0.5)] transition-all duration-300
group shadow-lg"
aria-label="Toggle menu"
>
{isMobileMenuOpen ? (
<X className="w-6 h-6 text-[#d4af37]" />
<X className="w-6 h-6 text-[var(--luxury-gold)] transition-transform duration-300 group-hover:rotate-90" />
) : (
<Menu className="w-6 h-6 text-white/90" />
<Menu className="w-6 h-6 text-[var(--luxury-gold)] group-hover:text-[var(--luxury-gold-light)] transition-colors duration-300" />
)}
</button>
{/* Mobile Menu Dropdown - Absolute positioned */}
{isMobileMenuOpen && (
<div
className="md:hidden absolute right-0 mt-2 w-64
bg-gradient-to-b from-[#1a1a1a] to-[#0f0f0f]
rounded-sm shadow-2xl py-2 border border-[#d4af37]/20
z-50 backdrop-blur-xl animate-fade-in max-h-[calc(100vh-120px)]
overflow-y-auto"
>
<div className="flex flex-col space-y-1">
{navLinks.map((link) => (
<Link
key={link.to}
to={link.to}
onClick={handleLinkClick}
className="px-4 py-3 text-white/90
hover:bg-[#d4af37]/10 hover:text-[#d4af37]
rounded-sm transition-all duration-300
border-l-2 border-transparent
hover:border-[#d4af37] font-light tracking-wide"
>
{link.label}
</Link>
))}
{mobileMenuContent && (
<>
<div className="border-t border-[#d4af37]/20 my-2"></div>
{mobileMenuContent}
</>
)}
{/* Mobile Menu Backdrop and Dropdown - Rendered via Portal */}
{isMobileMenuOpen && typeof document !== 'undefined' && createPortal(
<>
{/* Mobile Menu Backdrop */}
<div
className="md:hidden fixed inset-0 bg-black/70 backdrop-blur-sm"
style={{
top: '73px',
zIndex: 99998,
position: 'fixed',
pointerEvents: 'auto'
} as React.CSSProperties}
onClick={(e) => {
// Only close if clicking directly on backdrop, not on dropdown content
const target = e.target as HTMLElement;
if (target === e.currentTarget) {
onMobileMenuToggle();
}
}}
onTouchStart={(e) => {
// Prevent backdrop from interfering with touch events on links
const target = e.target as HTMLElement;
if (mobileMenuDropdownRef.current?.contains(target)) {
e.stopPropagation();
}
}}
/>
{/* Mobile Menu Dropdown - Right side on mobile */}
<div
ref={mobileMenuDropdownRef}
className="md:hidden fixed top-[73px] right-0 w-80 max-w-[85vw]
bg-gradient-to-b from-[#0f0f0f] via-[#1a1a1a] to-[#0f0f0f]
shadow-[0_8px_32px_rgba(0,0,0,0.9),_-4px_0_20px_rgba(var(--luxury-gold-rgb),0.2)]
py-4 border-l-2 border-[rgba(var(--luxury-gold-rgb),0.4)]
backdrop-blur-xl animate-fade-in
overflow-y-auto h-[calc(100vh-73px)]"
style={{
zIndex: 99999,
position: 'fixed',
touchAction: 'auto',
pointerEvents: 'auto'
} as React.CSSProperties}
onClick={(e) => {
// Stop propagation to prevent backdrop from closing menu when clicking inside
e.stopPropagation();
}}
onTouchStart={(e) => {
// Stop touch events from propagating to backdrop
e.stopPropagation();
}}
onTouchEnd={(e) => {
// Stop touch end events from propagating
e.stopPropagation();
}}
>
<div className="flex flex-col space-y-1 px-2">
{navLinks.map((link) => (
<Link
key={link.to}
to={link.to}
onClick={(e) => {
// Stop propagation to prevent backdrop from closing menu
e.stopPropagation();
// Close mobile menu after navigation starts
setTimeout(() => {
if (handleLinkClick) {
handleLinkClick();
}
}, 150);
}}
onTouchStart={(e) => {
// Stop touch events from propagating to backdrop
e.stopPropagation();
}}
onTouchEnd={(e) => {
// Ensure touch end doesn't trigger backdrop
e.stopPropagation();
}}
onMouseDown={(e) => {
// Ensure mouse events work
e.stopPropagation();
}}
className="px-4 py-3.5 text-white/95
hover:bg-[rgba(var(--luxury-gold-rgb),0.15)] hover:text-[var(--luxury-gold)]
rounded-md transition-all duration-300
border-l-2 border-transparent
hover:border-[var(--luxury-gold)] font-light tracking-wider text-sm uppercase
group relative mx-2 cursor-pointer text-left w-full block"
style={{
touchAction: 'manipulation',
WebkitTapHighlightColor: 'transparent',
pointerEvents: 'auto'
}}
>
<span
className="relative z-10"
style={{ pointerEvents: 'none' }}
>
{link.label}
</span>
<span
className="absolute left-0 top-0 bottom-0 w-0 bg-gradient-to-r from-[rgba(var(--luxury-gold-rgb),0.15)] to-transparent group-hover:w-full transition-all duration-300 rounded-md"
style={{ pointerEvents: 'none' }}
></span>
</Link>
))}
{mobileMenuContent && (
<>
<div className="border-t border-[var(--luxury-gold)]/20 my-2"></div>
{mobileMenuContent}
</>
)}
</div>
</div>
</div>
</>,
document.body
)}
</div>
);

View File

@@ -14,19 +14,19 @@ const OfflineIndicator: React.FC = () => {
aria-live="polite"
>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pb-4 sm:pb-6">
<div className="relative overflow-hidden rounded-lg shadow-2xl border border-[#d4af37]/30 backdrop-blur-xl bg-gradient-to-r from-slate-900/95 via-slate-800/95 to-slate-900/95">
<div className="relative overflow-hidden rounded-lg shadow-2xl border border-[var(--luxury-gold)]/30 backdrop-blur-xl bg-gradient-to-r from-slate-900/95 via-slate-800/95 to-slate-900/95">
{/* Gold accent border top */}
<div className="absolute top-0 left-0 right-0 h-0.5 bg-gradient-to-r from-transparent via-[#d4af37] to-transparent"></div>
<div className="absolute top-0 left-0 right-0 h-0.5 bg-gradient-to-r from-transparent via-[var(--luxury-gold)] to-transparent"></div>
{/* Subtle glow effect */}
<div className="absolute inset-0 bg-gradient-to-r from-[#d4af37]/5 via-transparent to-[#d4af37]/5 pointer-events-none"></div>
<div className="absolute inset-0 bg-gradient-to-r from-[var(--luxury-gold)]/5 via-transparent to-[var(--luxury-gold)]/5 pointer-events-none"></div>
{/* Content */}
<div className="relative px-6 py-4 sm:px-8 sm:py-5 flex items-center justify-center gap-3 sm:gap-4">
{/* Icon with gold accent */}
<div className="relative flex-shrink-0">
<div className="absolute inset-0 bg-[#d4af37]/20 blur-xl rounded-full"></div>
<div className="relative bg-gradient-to-br from-[#d4af37] to-[#c9a227] p-2.5 rounded-full shadow-lg shadow-[#d4af37]/30">
<div className="absolute inset-0 bg-[var(--luxury-gold)]/20 blur-xl rounded-full"></div>
<div className="relative bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] p-2.5 rounded-full shadow-lg shadow-[var(--luxury-gold)]/30">
<WifiOff className="w-5 h-5 sm:w-6 sm:h-6 text-slate-900" strokeWidth={2.5} />
</div>
</div>
@@ -43,9 +43,9 @@ const OfflineIndicator: React.FC = () => {
{/* Decorative elements */}
<div className="hidden sm:flex absolute right-6 top-1/2 -translate-y-1/2 items-center gap-1 opacity-30">
<div className="w-1 h-1 rounded-full bg-[#d4af37] animate-pulse"></div>
<div className="w-1 h-1 rounded-full bg-[#d4af37] animate-pulse" style={{ animationDelay: '0.2s' }}></div>
<div className="w-1 h-1 rounded-full bg-[#d4af37] animate-pulse" style={{ animationDelay: '0.4s' }}></div>
<div className="w-1 h-1 rounded-full bg-[var(--luxury-gold)] animate-pulse"></div>
<div className="w-1 h-1 rounded-full bg-[var(--luxury-gold)] animate-pulse" style={{ animationDelay: '0.2s' }}></div>
<div className="w-1 h-1 rounded-full bg-[var(--luxury-gold)] animate-pulse" style={{ animationDelay: '0.4s' }}></div>
</div>
</div>
</div>

View File

@@ -177,6 +177,11 @@ const SidebarAdmin: React.FC<SidebarAdminProps> = ({
icon: FileText,
label: 'Invoices'
},
{
path: '/admin/promotions',
icon: Tag,
label: 'Promotions'
},
{
path: '/admin/financial-audit',
icon: FileCheck,
@@ -193,11 +198,6 @@ const SidebarAdmin: React.FC<SidebarAdminProps> = ({
icon: BarChart3,
label: 'Reports & Analytics'
},
{
path: '/admin/business',
icon: TrendingUp,
label: 'Business Insights'
},
]
},
{
@@ -367,7 +367,7 @@ const SidebarAdmin: React.FC<SidebarAdminProps> = ({
const isActive = (path: string) => {
if (location.pathname === path) return true;
if (path === '/admin/settings' || path === '/admin/analytics' || path === '/admin/business' || path === '/admin/reception' || path === '/admin/advanced-rooms' || path === '/admin/page-content' || path === '/admin/loyalty') {
if (path === '/admin/settings' || path === '/admin/analytics' || path === '/admin/reception' || path === '/admin/advanced-rooms' || path === '/admin/page-content' || path === '/admin/loyalty') {
return location.pathname === path;
}

View File

@@ -0,0 +1,162 @@
import React, {
createContext,
useContext,
useEffect,
useState,
ReactNode,
} from 'react';
import { themeService } from '../../features/system/services/systemSettingsService';
type ThemeColors = {
primary: string;
primaryLight: string;
primaryDark: string;
primaryAccent: string;
};
type ThemeContextValue = {
colors: ThemeColors;
isLoading: boolean;
refreshTheme: () => Promise<void>;
updateColors: (colors: Partial<ThemeColors>) => void;
};
const defaultColors: ThemeColors = {
primary: '#d4af37',
primaryLight: '#f5d76e',
primaryDark: '#c9a227',
primaryAccent: '#e8c547',
};
const ThemeContext = createContext<ThemeContextValue | undefined>(undefined);
export const useTheme = () => {
const context = useContext(ThemeContext);
if (!context) {
throw new Error('useTheme must be used within ThemeProvider');
}
return context;
};
interface ThemeProviderProps {
children: ReactNode;
}
/**
* Converts hex color to RGB values
*/
const hexToRgb = (hex: string): string => {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result
? `${parseInt(result[1], 16)}, ${parseInt(result[2], 16)}, ${parseInt(result[3], 16)}`
: '212, 175, 55'; // Default gold RGB
};
/**
* Applies theme colors as CSS variables to the document root
*/
const applyThemeColors = (colors: ThemeColors) => {
const root = document.documentElement;
// Apply CSS variables
root.style.setProperty('--luxury-gold', colors.primary);
root.style.setProperty('--luxury-gold-light', colors.primaryLight);
root.style.setProperty('--luxury-gold-dark', colors.primaryDark);
root.style.setProperty('--luxury-gold-accent', colors.primaryAccent);
// Add RGB versions for rgba() usage
root.style.setProperty('--luxury-gold-rgb', hexToRgb(colors.primary));
root.style.setProperty('--luxury-gold-light-rgb', hexToRgb(colors.primaryLight));
root.style.setProperty('--luxury-gold-dark-rgb', hexToRgb(colors.primaryDark));
root.style.setProperty('--luxury-gold-accent-rgb', hexToRgb(colors.primaryAccent));
// Also update gradient variables
root.style.setProperty(
'--gradient-gold',
`linear-gradient(135deg, ${colors.primary} 0%, ${colors.primaryLight} 100%)`
);
root.style.setProperty(
'--gradient-gold-dark',
`linear-gradient(135deg, ${colors.primaryDark} 0%, ${colors.primary} 100%)`
);
// Update shadow variables with proper opacity
const primaryRgb = hexToRgb(colors.primary);
root.style.setProperty(
'--shadow-luxury',
`0 4px 20px rgba(${primaryRgb}, 0.15)`
);
root.style.setProperty(
'--shadow-luxury-gold',
`0 8px 30px rgba(${primaryRgb}, 0.25)`
);
};
export const ThemeProvider: React.FC<ThemeProviderProps> = ({ children }) => {
const [colors, setColors] = useState<ThemeColors>(defaultColors);
const [isLoading, setIsLoading] = useState<boolean>(true);
const loadTheme = async () => {
try {
setIsLoading(true);
const response = await themeService.getThemeSettings();
if (response.data) {
const newColors: ThemeColors = {
primary: response.data.theme_primary_color || defaultColors.primary,
primaryLight: response.data.theme_primary_light || defaultColors.primaryLight,
primaryDark: response.data.theme_primary_dark || defaultColors.primaryDark,
primaryAccent: response.data.theme_primary_accent || defaultColors.primaryAccent,
};
setColors(newColors);
applyThemeColors(newColors);
}
} catch (error) {
console.error('Error loading theme settings:', error);
// Apply default colors on error
applyThemeColors(defaultColors);
setColors(defaultColors);
} finally {
setIsLoading(false);
}
};
useEffect(() => {
loadTheme();
// Listen for theme refresh events
const handleRefresh = () => {
loadTheme();
};
if (typeof window !== 'undefined') {
window.addEventListener('refreshTheme', handleRefresh);
return () => {
window.removeEventListener('refreshTheme', handleRefresh);
};
}
}, []);
const refreshTheme = async () => {
await loadTheme();
};
const updateColors = (newColors: Partial<ThemeColors>) => {
const updatedColors = { ...colors, ...newColors };
setColors(updatedColors);
applyThemeColors(updatedColors);
};
return (
<ThemeContext.Provider
value={{
colors,
isLoading,
refreshTheme,
updateColors,
}}
>
{children}
</ThemeContext.Provider>
);
};

View File

@@ -29,23 +29,23 @@ const NotFoundPage: React.FC = () => {
style={{ filter: 'drop-shadow(0 4px 6px rgba(0,0,0,0.1))' }}
/>
) : (
<div className="relative p-4 sm:p-5 bg-gradient-to-br from-[#d4af37] to-[#c9a227] rounded-full shadow-lg shadow-[#d4af37]/30">
<div className="relative p-4 sm:p-5 bg-gradient-to-br from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] rounded-full shadow-lg shadow-[var(--luxury-gold)]/30">
<Hotel className="w-12 h-12 sm:w-16 sm:h-16 lg:w-20 lg:h-20 text-[#0f0f0f] relative z-10" />
<div className="absolute inset-0 bg-gradient-to-br from-[#f5d76e] to-[#d4af37] rounded-full blur-xl opacity-50"></div>
<div className="absolute inset-0 bg-gradient-to-br from-[var(--luxury-gold-light)] to-[var(--luxury-gold)] rounded-full blur-xl opacity-50"></div>
</div>
)}
</div>
{/* Tagline */}
{settings.company_tagline && (
<p className="text-xs sm:text-sm text-[#d4af37] uppercase tracking-[2px] sm:tracking-[3px] mb-3 sm:mb-4 font-light">
<p className="text-xs sm:text-sm text-[var(--luxury-gold)] uppercase tracking-[2px] sm:tracking-[3px] mb-3 sm:mb-4 font-light">
{settings.company_tagline}
</p>
)}
{/* 404 Number */}
<div className="mb-6 sm:mb-8">
<h1 className="text-8xl sm:text-9xl lg:text-[12rem] font-display font-bold text-transparent bg-clip-text bg-gradient-to-r from-[#d4af37] via-[#f5d76e] to-[#d4af37] leading-none tracking-tight">
<h1 className="text-8xl sm:text-9xl lg:text-[12rem] font-display font-bold text-transparent bg-clip-text bg-gradient-to-r from-[var(--luxury-gold)] via-[var(--luxury-gold-light)] to-[var(--luxury-gold)] leading-none tracking-tight">
404
</h1>
</div>
@@ -78,7 +78,7 @@ const NotFoundPage: React.FC = () => {
<div className="flex flex-col sm:flex-row items-center justify-center gap-4">
<Link
to="/"
className="inline-flex items-center justify-center gap-2 px-8 py-3.5 sm:px-10 sm:py-4 bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-[#0f0f0f] font-semibold text-sm sm:text-base rounded-lg shadow-lg shadow-[#d4af37]/30 hover:from-[#f5d76e] hover:to-[#d4af37] hover:shadow-xl hover:shadow-[#d4af37]/40 transition-all duration-300 ease-out hover:-translate-y-0.5 active:translate-y-0 relative overflow-hidden group"
className="inline-flex items-center justify-center gap-2 px-8 py-3.5 sm:px-10 sm:py-4 bg-gradient-to-r from-[var(--luxury-gold)] to-[var(--luxury-gold-dark)] text-[#0f0f0f] font-semibold text-sm sm:text-base rounded-lg shadow-lg shadow-[var(--luxury-gold)]/30 hover:from-[var(--luxury-gold-light)] hover:to-[var(--luxury-gold)] hover:shadow-xl hover:shadow-[var(--luxury-gold)]/40 transition-all duration-300 ease-out hover:-translate-y-0.5 active:translate-y-0 relative overflow-hidden group"
>
<span className="absolute inset-0 bg-gradient-to-r from-white/0 via-white/20 to-white/0 translate-x-[-100%] group-hover:translate-x-[100%] transition-transform duration-700"></span>
<Home className="w-5 h-5 sm:w-6 sm:h-6 relative z-10" />
@@ -88,9 +88,9 @@ const NotFoundPage: React.FC = () => {
{/* Decorative Elements */}
<div className="mt-12 sm:mt-16 flex justify-center gap-2">
<div className="w-2 h-2 rounded-full bg-[#d4af37]/30"></div>
<div className="w-2 h-2 rounded-full bg-[#d4af37]/50"></div>
<div className="w-2 h-2 rounded-full bg-[#d4af37]/30"></div>
<div className="w-2 h-2 rounded-full bg-[var(--luxury-gold)]/30"></div>
<div className="w-2 h-2 rounded-full bg-[var(--luxury-gold)]/50"></div>
<div className="w-2 h-2 rounded-full bg-[var(--luxury-gold)]/30"></div>
</div>
</div>
</div>

View File

@@ -37,11 +37,11 @@
--shadow-luxury-gold: 0 8px 30px rgba(212, 175, 55, 0.25);
--gradient-gold: linear-gradient(135deg, #d4af37 0%, #f5d76e 100%);
--gradient-gold-dark: linear-gradient(135deg, #c9a227 0%, #d4af37 100%);
--gradient-gold: linear-gradient(135deg, var(--luxury-gold) 0%, var(--luxury-gold-light) 100%);
--gradient-gold-dark: linear-gradient(135deg, var(--luxury-gold-dark) 0%, var(--luxury-gold) 100%);
--gradient-dark: linear-gradient(180deg, #1a1a1a 0%, #0f0f0f 100%);
--gradient-overlay: linear-gradient(180deg, rgba(15, 15, 15, 0.8) 0%, rgba(15, 15, 15, 0.4) 100%);
--gradient-gold-overlay: linear-gradient(135deg, rgba(212, 175, 55, 0.1) 0%, rgba(245, 215, 110, 0.05) 100%);
--gradient-gold-overlay: linear-gradient(135deg, var(--luxury-gold)1a 0%, var(--luxury-gold-light)0d 100%);
}
::-webkit-scrollbar {
@@ -158,8 +158,12 @@ h3, h4, h5, h6 {
.luxury-card {
@apply bg-white rounded-sm shadow-lg border border-gray-100;
@apply transition-all duration-300 ease-out;
@apply hover:shadow-xl hover:shadow-[#d4af37]/10;
@apply hover:-translate-y-1;
box-shadow: var(--shadow-lg), 0 0 0 0 transparent;
}
.luxury-card:hover {
box-shadow: var(--shadow-xl), 0 0 20px rgba(var(--luxury-gold-rgb), 0.1);
}
@@ -167,35 +171,46 @@ h3, h4, h5, h6 {
@apply bg-white rounded-sm shadow-lg;
@apply relative overflow-hidden;
@apply transition-all duration-300 ease-out;
@apply hover:shadow-xl hover:shadow-[#d4af37]/20;
@apply border-t-2 border-[#d4af37];
border-top: 2px solid var(--luxury-gold);
}
.luxury-card-gold:hover {
box-shadow: var(--shadow-xl), 0 0 30px rgba(var(--luxury-gold-rgb), 0.2);
}
.luxury-card-dark {
@apply bg-gradient-to-b from-[#1a1a1a] to-[#0f0f0f] rounded-sm shadow-2xl;
@apply border border-[#d4af37]/20;
@apply transition-all duration-300 ease-out;
@apply hover:shadow-[#d4af37]/30 hover:border-[#d4af37]/40;
border: 1px solid rgba(var(--luxury-gold-rgb), 0.2);
}
.luxury-card-dark:hover {
box-shadow: 0 0 40px rgba(var(--luxury-gold-rgb), 0.3);
border-color: rgba(var(--luxury-gold-rgb), 0.4);
}
.btn-luxury-primary {
@apply px-6 py-3 rounded-sm font-medium tracking-wide;
@apply bg-gradient-to-r from-[#d4af37] to-[#c9a227] text-[#0f0f0f];
@apply shadow-lg shadow-[#d4af37]/30;
@apply text-[#0f0f0f];
@apply transition-all duration-300 ease-out;
@apply hover:from-[#f5d76e] hover:to-[#d4af37];
@apply hover:shadow-xl hover:shadow-[#d4af37]/40;
@apply hover:-translate-y-0.5;
@apply active:translate-y-0;
@apply disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:translate-y-0;
@apply relative overflow-hidden;
background: var(--gradient-gold-dark);
box-shadow: var(--shadow-lg), 0 0 30px rgba(var(--luxury-gold-rgb), 0.3);
font-family: 'Poppins', 'Inter', sans-serif;
font-weight: 500;
letter-spacing: 0.05em;
}
.btn-luxury-primary:hover {
background: var(--gradient-gold);
box-shadow: var(--shadow-xl), 0 0 40px rgba(var(--luxury-gold-rgb), 0.4);
}
.btn-luxury-primary::before {
content: '';
@apply absolute inset-0 bg-gradient-to-r from-white/0 via-white/20 to-white/0;
@@ -209,16 +224,23 @@ h3, h4, h5, h6 {
.btn-luxury-secondary {
@apply px-6 py-3 rounded-sm font-medium tracking-wide;
@apply bg-white/10 backdrop-blur-sm text-white border border-[#d4af37]/30;
@apply bg-white/10 backdrop-blur-sm text-white;
@apply transition-all duration-300 ease-out;
@apply hover:bg-[#d4af37]/10 hover:border-[#d4af37] hover:text-[#d4af37];
@apply hover:-translate-y-0.5;
@apply active:translate-y-0;
border: 1px solid rgba(var(--luxury-gold-rgb), 0.3);
}
.btn-luxury-secondary:hover {
background-color: rgba(var(--luxury-gold-rgb), 0.1);
border-color: var(--luxury-gold);
color: var(--luxury-gold);
}
.luxury-section-header {
@apply mb-8 pb-4 border-b border-[#d4af37]/20;
@apply mb-8 pb-4;
border-bottom: 1px solid rgba(var(--luxury-gold-rgb), 0.2);
}
.luxury-section-title {
@@ -254,7 +276,7 @@ h3, h4, h5, h6 {
.luxury-table thead {
@apply bg-gradient-to-r from-gray-50 to-gray-100;
@apply border-b-2 border-[#d4af37]/30;
border-bottom: 2px solid rgba(var(--luxury-gold-rgb), 0.3);
}
.luxury-table th {
@@ -270,7 +292,10 @@ h3, h4, h5, h6 {
.luxury-table tbody tr {
@apply transition-colors duration-150;
@apply hover:bg-[#d4af37]/5;
}
.luxury-table tbody tr:hover {
background-color: rgba(var(--luxury-gold-rgb), 0.05);
}
@@ -278,13 +303,14 @@ h3, h4, h5, h6 {
@apply inline-flex items-center px-3 py-1 rounded-sm;
@apply text-xs font-medium tracking-wide;
@apply transition-all duration-200;
@apply bg-[#d4af37]/10 text-[#c9a227] border border-[#d4af37]/30;
color: var(--luxury-gold-dark);
background-color: rgba(var(--luxury-gold-rgb), 0.1);
border: 1px solid rgba(var(--luxury-gold-rgb), 0.3);
}
.luxury-input {
@apply w-full px-4 py-3 rounded-sm border border-gray-300;
@apply focus:ring-2 focus:ring-[#d4af37]/50 focus:border-[#d4af37];
@apply transition-all duration-200;
@apply bg-white text-gray-900;
@apply placeholder:text-gray-400;
@@ -293,6 +319,13 @@ h3, h4, h5, h6 {
letter-spacing: 0.01em;
}
.luxury-input:focus {
outline: none;
ring: 2px;
ring-color: rgba(var(--luxury-gold-rgb), 0.5);
border-color: var(--luxury-gold);
}
.luxury-gradient-bg {
background: var(--gradient-gold);
@@ -301,8 +334,8 @@ h3, h4, h5, h6 {
.luxury-glass {
@apply bg-white/90 backdrop-blur-xl;
@apply border border-[#d4af37]/20;
@apply shadow-2xl;
border: 1px solid rgba(var(--luxury-gold-rgb), 0.2);
}
@@ -310,15 +343,18 @@ h3, h4, h5, h6 {
@apply bg-white rounded-lg shadow-xl border border-gray-200/60;
@apply relative overflow-hidden;
@apply transition-all duration-300 ease-out;
@apply hover:shadow-2xl hover:shadow-[#d4af37]/10;
@apply hover:-translate-y-0.5;
@apply backdrop-blur-sm;
}
.enterprise-card:hover {
box-shadow: var(--shadow-2xl), 0 0 30px rgba(var(--luxury-gold-rgb), 0.1);
}
.enterprise-card::before {
content: '';
@apply absolute top-0 left-0 right-0 h-0.5;
background: linear-gradient(90deg, transparent 0%, #d4af37 50%, transparent 100%);
background: linear-gradient(90deg, transparent 0%, var(--luxury-gold) 50%, transparent 100%);
opacity: 0;
transition: opacity 0.3s ease-out;
}
@@ -344,15 +380,19 @@ h3, h4, h5, h6 {
.btn-enterprise-primary {
@apply px-8 py-3.5 rounded-lg font-semibold tracking-wide text-sm;
@apply bg-gradient-to-r from-[#d4af37] via-[#e8c547] to-[#d4af37];
@apply text-[#0f0f0f] shadow-lg shadow-[#d4af37]/30;
@apply text-[#0f0f0f];
@apply transition-all duration-300 ease-out;
@apply hover:from-[#f5d76e] hover:via-[#d4af37] hover:to-[#f5d76e];
@apply hover:shadow-xl hover:shadow-[#d4af37]/40;
@apply hover:-translate-y-0.5 hover:scale-[1.02];
@apply active:translate-y-0 active:scale-100;
@apply disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:translate-y-0 disabled:hover:scale-100;
@apply relative overflow-hidden;
background: linear-gradient(to right, var(--luxury-gold), var(--luxury-gold-accent), var(--luxury-gold));
box-shadow: var(--shadow-lg), 0 0 30px rgba(var(--luxury-gold-rgb), 0.3);
}
.btn-enterprise-primary:hover {
background: linear-gradient(to right, var(--luxury-gold-light), var(--luxury-gold), var(--luxury-gold-light));
box-shadow: var(--shadow-xl), 0 0 40px rgba(var(--luxury-gold-rgb), 0.4);
}
.btn-enterprise-primary::before {
@@ -371,17 +411,21 @@ h3, h4, h5, h6 {
@apply bg-white border-2 border-gray-300 text-gray-700;
@apply shadow-md shadow-gray-200/50;
@apply transition-all duration-300 ease-out;
@apply hover:bg-gray-50 hover:border-[#d4af37] hover:text-[#c9a227];
@apply hover:shadow-lg hover:shadow-[#d4af37]/20;
@apply hover:-translate-y-0.5;
@apply active:translate-y-0;
@apply disabled:opacity-50 disabled:cursor-not-allowed;
}
.btn-enterprise-secondary:hover {
@apply hover:bg-gray-50;
border-color: var(--luxury-gold);
color: var(--luxury-gold-dark);
box-shadow: var(--shadow-lg), 0 0 20px rgba(var(--luxury-gold-rgb), 0.2);
}
.enterprise-input {
@apply w-full px-4 py-3 rounded-lg border-2 border-gray-200;
@apply focus:ring-2 focus:ring-[#d4af37]/30 focus:border-[#d4af37];
@apply transition-all duration-200;
@apply bg-white text-gray-900;
@apply placeholder:text-gray-400;
@@ -390,7 +434,11 @@ h3, h4, h5, h6 {
}
.enterprise-input:focus {
@apply shadow-md shadow-[#d4af37]/10;
outline: none;
ring: 2px;
ring-color: rgba(var(--luxury-gold-rgb), 0.3);
border-color: var(--luxury-gold);
box-shadow: var(--shadow-md), 0 0 20px rgba(var(--luxury-gold-rgb), 0.1);
}
}
@@ -399,6 +447,46 @@ h3, h4, h5, h6 {
text-wrap: balance;
}
/* Theme color utilities with opacity support */
.bg-luxury-gold {
background-color: var(--luxury-gold);
}
.bg-luxury-gold\/10 {
background-color: rgba(var(--luxury-gold-rgb), 0.1);
}
.bg-luxury-gold\/20 {
background-color: rgba(var(--luxury-gold-rgb), 0.2);
}
.text-luxury-gold {
color: var(--luxury-gold);
}
.text-luxury-gold\/70 {
color: rgba(var(--luxury-gold-rgb), 0.7);
}
.border-luxury-gold {
border-color: var(--luxury-gold);
}
.border-luxury-gold\/10 {
border-color: rgba(var(--luxury-gold-rgb), 0.1);
}
.border-luxury-gold\/20 {
border-color: rgba(var(--luxury-gold-rgb), 0.2);
}
.border-luxury-gold\/30 {
border-color: rgba(var(--luxury-gold-rgb), 0.3);
}
.border-luxury-gold\/40 {
border-color: rgba(var(--luxury-gold-rgb), 0.4);
}
.shadow-luxury {
box-shadow: var(--shadow-luxury);
@@ -409,7 +497,7 @@ h3, h4, h5, h6 {
}
.shadow-luxury-gold {
box-shadow: 0 8px 30px rgba(212, 175, 55, 0.25);
box-shadow: var(--shadow-luxury-gold);
}
@@ -523,8 +611,11 @@ h3, h4, h5, h6 {
.text-gradient-luxury {
@apply bg-gradient-to-r from-[#d4af37] via-[#f5d76e] to-[#d4af37];
@apply bg-clip-text text-transparent;
background: linear-gradient(to right, var(--luxury-gold), var(--luxury-gold-light), var(--luxury-gold));
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
color: transparent;
}
.text-gradient-luxury-dark {
@@ -581,11 +672,11 @@ img[loading="lazy"]:not([src]) {
.prose.prose-invert strong,
.prose.prose-invert b {
color: #d4af37 !important;
color: var(--luxury-gold) !important;
}
.prose.prose-invert a {
color: #d4af37 !important;
color: var(--luxury-gold) !important;
}
/* Custom luxury scrollbar for modals */
@@ -599,11 +690,11 @@ img[loading="lazy"]:not([src]) {
}
.custom-scrollbar::-webkit-scrollbar-thumb {
background: linear-gradient(180deg, #d4af37 0%, #c9a227 100%);
background: linear-gradient(180deg, var(--luxury-gold) 0%, var(--luxury-gold-dark) 100%);
border-radius: 10px;
border: 2px solid #f3f4f6;
}
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
background: linear-gradient(180deg, #f5d76e 0%, #d4af37 100%);
background: linear-gradient(180deg, var(--luxury-gold-light) 0%, var(--luxury-gold) 100%);
}

View File

@@ -15,9 +15,10 @@ export default {
},
colors: {
luxury: {
gold: '#d4af37',
'gold-light': '#f5d76e',
'gold-dark': '#c9a227',
gold: 'var(--luxury-gold)',
'gold-light': 'var(--luxury-gold-light)',
'gold-dark': 'var(--luxury-gold-dark)',
'gold-accent': 'var(--luxury-gold-accent)',
black: '#0f0f0f',
'black-light': '#1a1a1a',
},