Skip to main content
Where Comfort Meets the Wild
About Us Fox Cabins are uniquely designed A-frame cabins blending modern architecture with natural elements. Nestled in Valea Doftanei, we offer breathtaking views of the Negras Mountains, making it a perfect getaway for relaxation and outdoor adventures. Our cabins cater to both adults and children, providing a holistic experience of leisure and entertainment.
Our Values
Comfort and Style At Fox Cabins, we focus on providing a unique blend of comfort and modern design. Our A-frame cabins are thoughtfully crafted to offer an inviting atmosphere that enriches your stay.
Nature Connection Nestled in the scenic Valea Doftanei, our cabins invite you to connect with nature. Enjoy breathtaking views of the Negras Mountains right from your doorstep.
Family Friendly Fun We prioritize family enjoyment with activities tailored to all ages. Whether you’re seeking adventure or relaxation, we have something for everyone.
Our Services
Cabin Accommodations Experience cozy living in our specially designed A-frame cabins, ideal for families and groups.
Adventure Awaits Enjoy a range of outdoor activities including hiking, biking, and nature walks.
Rent a ATV, bike or just hiking
Fun for Everyone We offer activities and facilities tailored for both adults and children.
Gastronomic Experiences Savor delicious meals crafted with local ingredients at local restaurants.
Unwind in Nature Participate in engaging wellness programs and relaxation sessions surrounded by nature.
Memorable Gatherings Host special events or retreats with stunning mountain views.
Escape to Nature at Fox Cabins Your family getaway awaits in the heart of Valea Doftanei.
Choose Your Stay at Fox Cabins Accommodates up to 6 adults 3 bedrooms + Living + 3 balcony 2 bathrooms Hot tub with special view Panoramic views of Negras Mountains Fully equipped kitchen Accommodates up to 4 adults 2 bedroom+Living+balcony 1 bathroom Beautiful views of Valea Doftanei Ideal for couples or small families Special Package FOX 1 & 2
Stay in both cabins (sleep up to 10 adults and 5 kids) Exclusive access to amenities Perfect for larger groups or families Make the party be PARTY
🍳 Private Dining & Local Food at Cabins
La Cabană
RENT A COOK
You can hire a cook to make traditional food. It will come directly to Fox Cabins.
Show Chef
RENT A SHOW CHEF
Traditional cooking method for goat or a Romanian fine dining grill experience.
3 Km away
Burgeri Artizanali Valea Doftanei
Craft burgers cooked locally with fresh ingredients.
500m away
CASA TELEANU
Only Romanian food & drink.
1.2 Km away
LA COVRIGU'
Only Romanian food & drink.
4 Km away
LA MAMA LILI
Punct Gastronomic Local - Traditional Romanian home-cooked food.
6 Km away
LA CEAPA
Only Romanian food & drink.
🍽️ Nearby Restaurants (À la carte)
800m away
Cabana Veverița
A la carte menu & restaurant.
1.6 Km away
Loussiana
A la carte menu.
4.5 Km away
Doftana Nature Events
A la carte menu & events location.
11 Km away
Conacul Dascălu
A la carte menu.
4 Km away
Cabana Izvoarele Doftanei
A la carte menu.
11 Km away
La Taverna
A la carte menu.
🛒 Fast Food & Essentials
3.7 Km away
Daisy
Fast food with home delivery (approx. 30 min).
3.8 Km away
Profi fast food
Quick food & supermarket items.
20 Km away
Păstrăvăria Doftana
Fish specialty restaurant. Ideal stop when leaving or exploring the area.
300m away
Local shop
Convenience store nearby for daily basics.
500m away
Gas station
Fuel & quick essentials.
FAQ The Fox Cabins are fully equipped with modern amenities including Wi-Fi, a complete kitchen, bathrooms, and comfortable living spaces designed for relaxation. Children’s entertainment options are available to ensure a fun stay for all ages!
Fox Cabin 1 accommodates up to 6 adults, while Fox Cabin 2 is designed for 4 adults, making them perfect for family vacations or trips with friends.
The Fox Cabins are located in Valea Doftanei, a great spot for hiking, mountain biking, and exploring the stunning natural scenery of the Negras Mountains, Baiului Mountains, Glodeasca, Paltinu dam and many others. Plenty of outdoor adventures await!
Yes, complimentary parking is available on-site for all guests, making it easy to explore the surrounding area.
Widget Rezervări & Sincronizare Airbnb - Fox Cabins< test /title>
<!-- Fonts & Tailwind CSS CDN -->
<div class="script-placeholder"></div><!--script src="https://cdn.tailwindcss.com"></script-->
<link href="/g/fonts.css2?family=Plus+Jakarta+Sans:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
body {
font-family: 'Plus Jakarta Sans', sans-serif;
background-color: #f3f4f6;
margin: 0;
padding: 12px;
color: #1f2937;
}
#fox-booking-widget {
max-width: 920px;
width: 100%;
margin: 0 auto;
background: #ffffff;
border-radius: 20px;
box-shadow: 0 10px 30px rgba(0,0,0,0.06);
border: 1px solid #e5e7eb;
overflow: hidden;
position: relative;
box-sizing: border-box;
}
#fox-booking-widget * {
box-sizing: border-box;
}
#fox-booking-widget .fox-header {
padding: 20px 24px;
background: #fafcfb;
border-bottom: 1px solid #e5e7eb;
display: flex;
justify-content: space-between;
align-items: center;
}
#fox-booking-widget .fox-brand-title {
font-size: 1.25rem;
font-weight: 700;
color: #2d4a3e;
}
#fox-booking-widget .fox-brand-subtitle {
font-size: 0.85rem;
color: #6b7280;
margin-top: 2px;
}
#fox-booking-widget .fox-secret-dot {
width: 12px;
height: 12px;
background-color: #d1d5db;
border-radius: 50%;
cursor: pointer;
transition: all 0.2s ease;
}
#fox-booking-widget .fox-secret-dot:hover {
background-color: #2d4a3e;
transform: scale(1.2);
}
#fox-booking-widget .fox-body {
display: grid;
grid-template-columns: 1fr 330px;
gap: 20px;
padding: 20px;
}
@media (max-width: 840px) {
#fox-booking-widget .fox-body {
grid-template-columns: 1fr;
}
}
#fox-booking-widget .fox-calendar-nav {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
}
#fox-booking-widget .fox-calendar-nav h4 {
font-size: 0.95rem;
font-weight: 600;
margin: 0;
color: #1f2937;
}
#fox-booking-widget .fox-nav-btn {
background: #f3f4f6;
border: none;
width: 32px;
height: 32px;
border-radius: 50%;
cursor: pointer;
font-weight: bold;
color: #1f2937;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.15s ease;
}
#fox-booking-widget .fox-nav-btn:hover {
background: #2d4a3e;
color: white;
}
#fox-booking-widget .fox-calendars-container {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
}
@media (max-width: 600px) {
#fox-booking-widget .fox-calendars-container {
grid-template-columns: 1fr;
}
}
#fox-booking-widget .fox-month-title {
text-align: center;
font-weight: 600;
font-size: 0.9rem;
margin-bottom: 10px;
color: #2d4a3e;
}
#fox-booking-widget .fox-days-header {
display: grid;
grid-template-columns: repeat(7, 1fr);
text-align: center;
font-size: 0.75rem;
font-weight: 700;
color: #6b7280;
margin-bottom: 6px;
}
#fox-booking-widget .fox-days-grid {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 4px;
}
#fox-booking-widget .fox-day-cell {
aspect-ratio: 1;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.85rem;
font-weight: 500;
border-radius: 8px;
cursor: pointer;
user-select: none;
transition: background 0.1s ease, color 0.1s ease;
}
#fox-booking-widget .fox-day-cell.available:hover {
background-color: #e8f0ec;
color: #2d4a3e;
}
#fox-booking-widget .fox-day-cell.blocked {
background-color: #fee2e2 !important;
color: #dc2626 !important;
border: 1px solid #fca5a5 !important;
font-weight: 700 !important;
text-decoration: line-through;
cursor: not-allowed;
opacity: 0.9;
}
#fox-booking-widget .fox-day-cell.past {
color: #d1d5db;
cursor: not-allowed;
}
#fox-booking-widget .fox-day-cell.selected {
background-color: #2d4a3e !important;
color: white !important;
font-weight: 700;
}
#fox-booking-widget .fox-day-cell.in-range {
background-color: #e8f0ec !important;
color: #2d4a3e !important;
border-radius: 0 !important;
}
#fox-booking-widget .fox-sidebar {
background: #fafcfb;
border: 1px solid #e5e7eb;
border-radius: 16px;
padding: 16px;
display: flex;
flex-direction: column;
justify-content: space-between;
}
#fox-booking-widget .fox-price-tag {
font-size: 1.15rem;
font-weight: 700;
color: #2d4a3e;
margin-bottom: 12px;
}
#fox-booking-widget .fox-price-tag span {
font-size: 0.8rem;
font-weight: 400;
color: #6b7280;
}
#fox-booking-widget .fox-dates-box {
background: white;
border: 1px solid #e5e7eb;
border-radius: 8px;
padding: 10px;
margin-bottom: 12px;
}
#fox-booking-widget .fox-date-row {
display: flex;
justify-content: space-between;
font-size: 0.8rem;
padding: 3px 0;
}
#fox-booking-widget .fox-form-group {
margin-bottom: 10px;
}
#fox-booking-widget .fox-form-group-inline {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
}
#fox-booking-widget .fox-form-group label,
#fox-booking-widget .fox-form-group-inline label {
display: block;
font-size: 0.72rem;
font-weight: 600;
margin-bottom: 3px;
color: #1f2937;
}
#fox-booking-widget .fox-form-group input,
#fox-booking-widget .fox-form-group select,
#fox-booking-widget .fox-form-group-inline input {
width: 100%;
padding: 8px 10px;
border: 1px solid #e5e7eb;
border-radius: 6px;
font-size: 0.85rem;
background: #ffffff;
outline: none;
}
#fox-booking-widget .fox-form-group select:focus,
#fox-booking-widget .fox-form-group input:focus {
border-color: #2d4a3e;
}
#fox-booking-widget .fox-price-summary {
border-top: 1px dashed #e5e7eb;
padding-top: 10px;
margin-top: 10px;
margin-bottom: 12px;
}
#fox-booking-widget .fox-summary-row {
display: flex;
justify-content: space-between;
font-size: 0.78rem;
margin-bottom: 5px;
color: #4b5563;
}
#fox-booking-widget .fox-summary-row.fox-total {
font-weight: 700;
font-size: 0.95rem;
color: #1f2937;
border-top: 1px solid #e5e7eb;
padding-top: 6px;
margin-top: 6px;
}
#fox-booking-widget .fox-btn-submit {
width: 100%;
background-color: #2d4a3e;
color: white;
border: none;
padding: 10px;
border-radius: 8px;
font-weight: 600;
font-size: 0.85rem;
cursor: pointer;
transition: background 0.15s ease;
}
#fox-booking-widget .fox-btn-whatsapp {
background-color: #25D366;
}
#fox-booking-widget .fox-btn-whatsapp:hover {
background-color: #1eb855;
}
#fox-booking-widget .fox-sync-info {
font-size: 0.74rem;
color: #4b5563;
text-align: center;
margin-top: 10px;
background: #f9fafb;
padding: 6px;
border-radius: 6px;
border: 1px dashed #d1d5db;
}
#fox-booking-widget .fox-modal-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
display: none;
align-items: center;
justify-content: center;
z-index: 100;
padding: 16px;
}
#fox-booking-widget .fox-modal-overlay.active {
display: flex;
}
#fox-booking-widget .fox-modal-card {
background: white;
border-radius: 12px;
padding: 20px;
max-width: 480px;
width: 100%;
}
#fox-booking-widget .fox-modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
#fox-booking-widget .fox-close-btn {
background: none;
border: none;
font-size: 1.2rem;
cursor: pointer;
}
</style>
</head>
<body>
<!-- WIDGET REZERVARI FOX CABINS -->
<div id="fox-booking-widget">
<!-- Header Widget -->
<div class="fox-header">
<div>
<div class="fox-brand-title">🏡 Fox Cabins - Valea Doftanei</div>
<div class="fox-brand-subtitle">Verifică disponibilitatea & rezervă direct pe WhatsApp</div>
</div>
<!-- Secret admin trigger dot -->
<div class="fox-secret-dot" id="foxSecretDot" title="Setări confidențiale admin"></div>
</div>
<!-- Body -->
<div class="fox-body">
<!-- Calendar Section -->
<div class="fox-calendar-section">
<div class="fox-calendar-nav">
<button class="fox-nav-btn" id="foxPrevBtn"><</button>
<h4 id="foxCurrentMonthYear">Se încarcă...</h4>
<button class="fox-nav-btn" id="foxNextBtn">></button>
</div>
<div class="fox-calendars-container">
<!-- Month 1 -->
<div>
<div class="fox-month-title" id="foxM1Title">Luna 1</div>
<div class="fox-days-header">
<div>L</div><div>M</div><div>M</div><div>J</div><div>V</div><div>S</div><div>D</div>
</div>
<div class="fox-days-grid" id="foxM1Grid"></div>
</div>
<!-- Month 2 -->
<div>
<div class="fox-month-title" id="foxM2Title">Luna 2</div>
<div class="fox-days-header">
<div>L</div><div>M</div><div>M</div><div>J</div><div>V</div><div>S</div><div>D</div>
</div>
<div class="fox-days-grid" id="foxM2Grid"></div>
</div>
</div>
<div class="fox-sync-info">
<span id="foxSyncStatus">⚡ Sincronizare rapidă...</span>
</div>
</div>
<!-- Sidebar Rezervare -->
<div class="fox-sidebar">
<div>
<!-- Selectie Cabana -->
<div class="fox-form-group" style="margin-bottom: 14px;">
<label style="font-weight: 700; color: #2d4a3e;">Selectează Cabana</label>
<select id="foxCabinSelect" style="font-weight: 600; border: 2px solid #2d4a3e; background-color: #f0f7f4;">
<option value="fox1">🦊 Fox Cabin 1 (max. 6 persoane)</option>
<option value="fox2">🦊 Fox Cabin 2 (max. 4 persoane)</option>
<option value="both">🏡 Fox 1 + Fox 2 (Toată proprietatea - max. 10 pers.)</option>
</select>
</div>
<div class="fox-price-tag" id="foxDisplayPrice">De la 500 RON <span>/ noapte</span></div>
<div class="fox-dates-box">
<div class="fox-date-row">
<label>Check-in:</label>
<span id="foxDisplayCheckin">Selectează</span>
</div>
<div class="fox-date-row">
<label>Check-out:</label>
<span id="foxDisplayCheckout">Selectează</span>
</div>
</div>
<div class="fox-form-group">
<label>Nume complet</label>
<input type="text" id="foxGuestName" placeholder="Numele tău">
</div>
<div class="fox-form-group">
<label>Număr oaspeți</label>
<select id="foxGuestCount">
<option value="1-2">1 - 2 Oaspeți</option>
<option value="3-4" selected>3 - 4 Oaspeți</option>
<option value="5-6">5 - 6 Oaspeți</option>
<option value="7-10">7 - 10 Oaspeți (Grup complet)</option>
</select>
</div>
<div class="fox-price-summary" id="foxSummaryBox" style="display: none;">
<div id="foxSummaryRowsContainer"></div>
<div class="fox-summary-row" id="foxCleaningFeeRow">
<span>Taxă curățenie</span>
<span id="foxCalcCleaning">0 RON</span>
</div>
<div class="fox-summary-row fox-total">
<span>Total estimat</span>
<span id="foxCalcTotal">0 RON</span>
</div>
</div>
</div>
<div style="margin-top: 12px;">
<button class="fox-btn-submit fox-btn-whatsapp" id="foxBtnWhatsApp">
💬 Trimite Solicitare pe WhatsApp
</button>
</div>
</div>
</div>
<!-- Modal Admin Settings -->
<div class="fox-modal-overlay" id="foxAdminModal">
<div class="fox-modal-card">
<div class="fox-modal-header">
<h3 style="font-weight: 700; color: #2d4a3e;">⚙️ Panou Admin - Fox Cabins</h3>
<button class="fox-close-btn" id="foxCloseAdmin">×</button>
</div>
<div style="max-height: 420px; overflow-y: auto; padding-right: 6px;">
<!-- FOX 1 -->
<h4 style="color: #2d4a3e; margin: 10px 0 6px 0; border-bottom: 1px solid #e5e7eb; padding-bottom: 4px; font-weight: 700;">🦊 Fox Cabin 1</h4>
<div class="fox-form-group">
<label>Link iCal Airbnb Fox 1</label>
<input type="text" id="foxCfgIcal1" placeholder="https://www.airbnb.com/calendar/ical/...">
</div>
<div class="fox-form-group-inline">
<div>
<label>Cursul săptămânii (RON)</label>
<input type="number" id="foxCfgPriceWeekday1" value="500">
</div>
<div>
<label>Weekend (Vin-Sâm) (RON)</label>
<input type="number" id="foxCfgPriceWeekend1" value="700">
</div>
</div>
<div class="fox-form-group" style="margin-top:6px;">
<label>Taxă curățenie Fox 1 (RON)</label>
<input type="number" id="foxCfgCleaning1" value="100">
</div>
<!-- FOX 2 -->
<h4 style="color: #2d4a3e; margin: 16px 0 6px 0; border-bottom: 1px solid #e5e7eb; padding-bottom: 4px; font-weight: 700;">🦊 Fox Cabin 2</h4>
<div class="fox-form-group">
<label>Link iCal Airbnb Fox 2</label>
<input type="text" id="foxCfgIcal2" placeholder="https://www.airbnb.com/calendar/ical/...">
</div>
<div class="fox-form-group-inline">
<div>
<label>Cursul săptămânii (RON)</label>
<input type="number" id="foxCfgPriceWeekday2" value="400">
</div>
<div>
<label>Weekend (Vin-Sâm) (RON)</label>
<input type="number" id="foxCfgPriceWeekend2" value="600">
</div>
</div>
<div class="fox-form-group" style="margin-top:6px;">
<label>Taxă curățenie Fox 2 (RON)</label>
<input type="number" id="foxCfgCleaning2" value="100">
</div>
<!-- FOX 1 + FOX 2 -->
<h4 style="color: #2d4a3e; margin: 16px 0 6px 0; border-bottom: 1px solid #e5e7eb; padding-bottom: 4px; font-weight: 700;">🏡 Fox 1 + Fox 2 (Toată proprietatea)</h4>
<div class="fox-form-group">
<label>Link iCal Airbnb Fox 1 + Fox 2 (Anunțul complet)</label>
<input type="text" id="foxCfgIcalBoth" placeholder="https://www.airbnb.com/calendar/ical/...">
</div>
<div class="fox-form-group-inline">
<div>
<label>Cursul săptămânii (RON)</label>
<input type="number" id="foxCfgPriceWeekdayBoth" value="850">
</div>
<div>
<label>Weekend (Vin-Sâm) (RON)</label>
<input type="number" id="foxCfgPriceWeekendBoth" value="1200">
</div>
</div>
<div class="fox-form-group" style="margin-top:6px;">
<label>Taxă curățenie Pachet Ambele (RON)</label>
<input type="number" id="foxCfgCleaningBoth" value="150">
</div>
<!-- GENERAL -->
<h4 style="color: #2d4a3e; margin: 16px 0 6px 0; border-bottom: 1px solid #e5e7eb; padding-bottom: 4px; font-weight: 700;">📱 Setări Generale</h4>
<div class="fox-form-group">
<label>Număr WhatsApp proprietar (ex: 40722123456)</label>
<input type="text" id="foxCfgPhone" placeholder="407xxxxxxxxx">
</div>
<div class="fox-form-group">
<label>Modifică Parola Admin</label>
<input type="password" id="foxCfgPass" placeholder="Lăsați gol dacă nu schimbați">
</div>
</div>
<div style="display: flex; gap: 8px; margin-top: 14px;">
<button class="fox-btn-submit" id="foxSaveAdmin" style="flex: 2;">
💾 Salvează Setările
</button>
<button class="fox-btn-submit" id="foxResetAdmin" style="flex: 1; background-color: #dc2626;" title="Șterge datele vechi salvate">
🗑️ Resetare
</button>
</div>
</div>
</div>
</div>
<div class="script-placeholder"></div><!--script>
(function() {
const CACHE_KEY = 'fox_cabins_ical_cache';
const CACHE_TIME_MS = 15 * 60 * 1000; // 15 min cache
const defaultConfig = {
adminPassword: 'Qwl$!#ks2',
whatsappPhone: '40700000000',
currency: 'RON',
fox1: { icalUrl: '', priceWeekday: 500, priceWeekend: 700, cleaning: 100 },
fox2: { icalUrl: '', priceWeekday: 400, priceWeekend: 600, cleaning: 100 },
both: { icalUrl: '', priceWeekday: 850, priceWeekend: 1200, cleaning: 150 }
};
let rawSaved = localStorage.getItem('fox_cabins_rates_config');
let savedConfig = rawSaved ? JSON.parse(rawSaved) : {};
let config = {
adminPassword: savedConfig.adminPassword || defaultConfig.adminPassword,
whatsappPhone: savedConfig.whatsappPhone || defaultConfig.whatsappPhone,
currency: defaultConfig.currency,
fox1: { ...defaultConfig.fox1, ...(savedConfig.fox1 || {}) },
fox2: { ...defaultConfig.fox2, ...(savedConfig.fox2 || {}) },
both: { ...defaultConfig.both, ...(savedConfig.both || {}) }
};
let blockedDatesFox1 = [];
let blockedDatesFox2 = [];
let blockedDatesBoth = [];
let currentMonthDate = new Date();
currentMonthDate.setDate(1);
let checkInDate = null;
let checkOutDate = null;
const cabinSelect = document.getElementById('foxCabinSelect');
const m1Title = document.getElementById('foxM1Title');
const m2Title = document.getElementById('foxM2Title');
const m1Grid = document.getElementById('foxM1Grid');
const m2Grid = document.getElementById('foxM2Grid');
const currentMonthYear = document.getElementById('foxCurrentMonthYear');
const prevBtn = document.getElementById('foxPrevBtn');
const nextBtn = document.getElementById('foxNextBtn');
const syncStatus = document.getElementById('foxSyncStatus');
const displayCheckin = document.getElementById('foxDisplayCheckin');
const displayCheckout = document.getElementById('foxDisplayCheckout');
const displayPrice = document.getElementById('foxDisplayPrice');
const summaryBox = document.getElementById('foxSummaryBox');
const summaryRowsContainer = document.getElementById('foxSummaryRowsContainer');
const calcCleaning = document.getElementById('foxCalcCleaning');
const calcTotal = document.getElementById('foxCalcTotal');
const cleaningFeeRow = document.getElementById('foxCleaningFeeRow');
const secretDot = document.getElementById('foxSecretDot');
const adminModal = document.getElementById('foxAdminModal');
const closeAdmin = document.getElementById('foxCloseAdmin');
const saveAdmin = document.getElementById('foxSaveAdmin');
const resetAdmin = document.getElementById('foxResetAdmin');
const cfgIcal1 = document.getElementById('foxCfgIcal1');
const cfgPriceWeekday1 = document.getElementById('foxCfgPriceWeekday1');
const cfgPriceWeekend1 = document.getElementById('foxCfgPriceWeekend1');
const cfgCleaning1 = document.getElementById('foxCfgCleaning1');
const cfgIcal2 = document.getElementById('foxCfgIcal2');
const cfgPriceWeekday2 = document.getElementById('foxCfgPriceWeekday2');
const cfgPriceWeekend2 = document.getElementById('foxCfgPriceWeekend2');
const cfgCleaning2 = document.getElementById('foxCfgCleaning2');
const cfgIcalBoth = document.getElementById('foxCfgIcalBoth');
const cfgPriceWeekdayBoth = document.getElementById('foxCfgPriceWeekdayBoth');
const cfgPriceWeekendBoth = document.getElementById('foxCfgPriceWeekendBoth');
const cfgCleaningBoth = document.getElementById('foxCfgCleaningBoth');
const cfgPhone = document.getElementById('foxCfgPhone');
const cfgPass = document.getElementById('foxCfgPass');
function init() {
updateUIConfig();
// Load from cache if valid
const loadedFromCache = loadCachedIcals();
renderCalendars();
// Background async fetch
fetchAllIcals(!loadedFromCache);
// SYNC FIX FOR PROBLEM #2: Reset selection and immediately re-render matrix calendar when changing cabin
cabinSelect.addEventListener('change', () => {
checkInDate = null;
checkOutDate = null;
updateDatesDisplay();
updateUIConfig();
renderCalendars(); // Forcibly recalculates blocked dates for selected cabin
});
secretDot.addEventListener('click', () => {
const userPass = prompt('Introduceți parola de administrare:');
if (userPass === null) return;
if (userPass === (config.adminPassword || 'Qwl$!#ks2')) {
cfgIcal1.value = config.fox1?.icalUrl || '';
cfgPriceWeekday1.value = config.fox1?.priceWeekday || 500;
cfgPriceWeekend1.value = config.fox1?.priceWeekend || 700;
cfgCleaning1.value = config.fox1?.cleaning || 100;
cfgIcal2.value = config.fox2?.icalUrl || '';
cfgPriceWeekday2.value = config.fox2?.priceWeekday || 400;
cfgPriceWeekend2.value = config.fox2?.priceWeekend || 600;
cfgCleaning2.value = config.fox2?.cleaning || 100;
cfgIcalBoth.value = config.both?.icalUrl || '';
cfgPriceWeekdayBoth.value = config.both?.priceWeekday || 850;
cfgPriceWeekendBoth.value = config.both?.priceWeekend || 1200;
cfgCleaningBoth.value = config.both?.cleaning || 150;
cfgPhone.value = config.whatsappPhone || '';
cfgPass.value = '';
adminModal.classList.add('active');
} else {
alert('❌ Parolă incorectă!');
}
});
closeAdmin.addEventListener('click', () => {
adminModal.classList.remove('active');
});
saveAdmin.addEventListener('click', () => {
config.fox1 = {
icalUrl: cfgIcal1.value.trim(),
priceWeekday: parseFloat(cfgPriceWeekday1.value) || 0,
priceWeekend: parseFloat(cfgPriceWeekend1.value) || 0,
cleaning: parseFloat(cfgCleaning1.value) || 0
};
config.fox2 = {
icalUrl: cfgIcal2.value.trim(),
priceWeekday: parseFloat(cfgPriceWeekday2.value) || 0,
priceWeekend: parseFloat(cfgPriceWeekend2.value) || 0,
cleaning: parseFloat(cfgCleaning2.value) || 0
};
config.both = {
icalUrl: cfgIcalBoth.value.trim(),
priceWeekday: parseFloat(cfgPriceWeekdayBoth.value) || 0,
priceWeekend: parseFloat(cfgPriceWeekendBoth.value) || 0,
cleaning: parseFloat(cfgCleaningBoth.value) || 0
};
config.whatsappPhone = cfgPhone.value.trim();
if (cfgPass.value.trim() !== '') {
config.adminPassword = cfgPass.value.trim();
}
localStorage.setItem('fox_cabins_rates_config', JSON.stringify(config));
localStorage.removeItem(CACHE_KEY); // Reset cache
adminModal.classList.remove('active');
alert('✅ Setările au fost salvate!');
updateUIConfig();
fetchAllIcals(true);
});
resetAdmin.addEventListener('click', () => {
if (confirm('Sigur dorești să ștergi toate linkurile și tarifele salvate în browser?')) {
localStorage.removeItem('fox_cabins_rates_config');
localStorage.removeItem(CACHE_KEY);
alert('🧹 Memoria a fost curățată! Pagina se va reîncărca.');
window.location.reload();
}
});
prevBtn.addEventListener('click', () => {
currentMonthDate.setMonth(currentMonthDate.getMonth() - 1);
renderCalendars();
});
nextBtn.addEventListener('click', () => {
currentMonthDate.setMonth(currentMonthDate.getMonth() + 1);
renderCalendars();
});
document.getElementById('foxBtnWhatsApp').addEventListener('click', sendWhatsApp);
}
function loadCachedIcals() {
try {
const cached = localStorage.getItem(CACHE_KEY);
if (!cached) return false;
const data = JSON.parse(cached);
if (Date.now() - data.timestamp > CACHE_TIME_MS) return false;
if (data.fox1) blockedDatesFox1 = data.fox1.map(d => new Date(d));
if (data.fox2) blockedDatesFox2 = data.fox2.map(d => new Date(d));
if (data.both) blockedDatesBoth = data.both.map(d => new Date(d));
syncStatus.innerText = '⚡ Calendare încărcate (Sincronizat recent)';
return true;
} catch (e) {
return false;
}
}
function getCurrentCabinData() {
const selected = cabinSelect.value;
if (selected === 'fox1') {
return {
name: 'Fox Cabin 1',
priceWeekday: config.fox1.priceWeekday,
priceWeekend: config.fox1.priceWeekend,
cleaning: config.fox1.cleaning
};
} else if (selected === 'fox2') {
return {
name: 'Fox Cabin 2',
priceWeekday: config.fox2.priceWeekday,
priceWeekend: config.fox2.priceWeekend,
cleaning: config.fox2.cleaning
};
} else {
return {
name: 'Fox 1 + Fox 2 (Ambele Cabane)',
priceWeekday: config.both.priceWeekday,
priceWeekend: config.both.priceWeekend,
cleaning: config.both.cleaning
};
}
}
function updateUIConfig() {
const cabinData = getCurrentCabinData();
displayPrice.innerHTML = `${cabinData.priceWeekday} - ${cabinData.priceWeekend} ${config.currency} <span>/ noapte</span>`;
calculatePrice();
}
async function fetchWithTimeout(resource, options = {}) {
const { timeout = 3500 } = options;
const controller = new AbortController();
const id = setTimeout(() => controller.abort(), timeout);
try {
const response = await fetch(resource, { ...options, signal: controller.signal });
clearTimeout(id);
return response;
} catch (error) {
clearTimeout(id);
throw error;
}
}
async function fetchAllIcals(showLoading = false) {
if (showLoading) syncStatus.innerHTML = '🔄 Sincronizare calendare...';
const promises = [
config.fox1?.icalUrl ? fetchSingleIcal(config.fox1.icalUrl) : Promise.resolve({ ok: false, dates: [] }),
config.fox2?.icalUrl ? fetchSingleIcal(config.fox2.icalUrl) : Promise.resolve({ ok: false, dates: [] }),
config.both?.icalUrl ? fetchSingleIcal(config.both.icalUrl) : Promise.resolve({ ok: false, dates: [] })
];
const [res1, res2, resBoth] = await Promise.all(promises);
if (res1.ok) blockedDatesFox1 = res1.dates;
if (res2.ok) blockedDatesFox2 = res2.dates;
if (resBoth.ok) blockedDatesBoth = resBoth.dates;
try {
const cacheData = {
timestamp: Date.now(),
fox1: blockedDatesFox1.map(d => d.toISOString()),
fox2: blockedDatesFox2.map(d => d.toISOString()),
both: blockedDatesBoth.map(d => d.toISOString())
};
localStorage.setItem(CACHE_KEY, JSON.stringify(cacheData));
} catch(e) {}
let parts = [];
parts.push(config.fox1?.icalUrl ? (res1.ok ? '🦊 Fox 1: ✅' : '🦊 Fox 1: ❌') : '🦊 Fox 1: ⚠️');
parts.push(config.fox2?.icalUrl ? (res2.ok ? '🦊 Fox 2: ✅' : '🦊 Fox 2: ❌') : '🦊 Fox 2: ⚠️');
parts.push(config.both?.icalUrl ? (resBoth.ok ? '🏡 Fox 1+2: ✅' : '🏡 Fox 1+2: ❌') : '🏡 Fox 1+2: ⚠️');
syncStatus.innerText = parts.join(' | ') + ' (Sincronizat)';
renderCalendars();
}
async function fetchSingleIcal(url) {
if (!url || !url.trim()) return { ok: false, dates: [] };
let cleanUrl = url.trim().replace(/^webcal:\/\//i, 'https://');
const proxies = [
u => `https://corsproxy.io/?${encodeURIComponent(u)}`,
u => `https://api.allorigins.win/raw?url=${encodeURIComponent(u)}`,
u => `https://api.codetabs.com/v1/proxy?quest=${encodeURIComponent(u)}`
];
for (const proxyFn of proxies) {
try {
const proxyUrl = proxyFn(cleanUrl);
const res = await fetchWithTimeout(proxyUrl, { timeout: 3500 });
if (res.ok) {
const text = await res.text();
if (text && text.includes('BEGIN:VCALENDAR')) {
return { ok: true, dates: parseIcal(text) };
}
}
} catch (e) {}
}
return { ok: false, dates: [] };
}
function parseIcal(text) {
const blocked = [];
const lines = text.split(/\r\n|\n|\r/);
let inEvent = false;
let dtStart = null;
let dtEnd = null;
for (let line of lines) {
if (line.startsWith('BEGIN:VEVENT')) {
inEvent = true;
dtStart = null;
dtEnd = null;
} else if (line.startsWith('END:VEVENT')) {
if (dtStart && dtEnd) {
let curr = new Date(dtStart);
while (curr < dtEnd) {
blocked.push(new Date(curr));
curr.setDate(curr.getDate() + 1);
}
}
inEvent = false;
} else if (inEvent) {
if (line.startsWith('DTSTART')) {
dtStart = parseIcalDate(line.split(':')[1]);
} else if (line.startsWith('DTEND')) {
dtEnd = parseIcalDate(line.split(':')[1]);
}
}
}
return blocked;
}
function parseIcalDate(str) {
if (!str) return null;
const val = str.includes(';') ? str.split(';')[1].split(':')[1] : str;
const y = parseInt(val.substring(0, 4));
const m = parseInt(val.substring(4, 6)) - 1;
const d = parseInt(val.substring(6, 8));
return new Date(y, m, d);
}
// STRICT CHECK BASED ON SELECTED CABIN REGULATION
function isDateBlocked(d) {
const selected = cabinSelect.value;
const inFox1 = blockedDatesFox1.some(bd => isSameDay(bd, d));
const inFox2 = blockedDatesFox2.some(bd => isSameDay(bd, d));
const inBoth = blockedDatesBoth.some(bd => isSameDay(bd, d));
if (selected === 'fox1') {
return inFox1 || inBoth;
} else if (selected === 'fox2') {
return inFox2 || inBoth;
} else if (selected === 'both') {
return inFox1 || inFox2 || inBoth;
}
return false;
}
function isSameDay(d1, d2) {
if (!d1 || !d2) return false;
return d1.getFullYear() === d2.getFullYear() &&
d1.getMonth() === d2.getMonth() &&
d1.getDate() === d2.getDate();
}
function renderCalendars() {
const month1 = new Date(currentMonthDate);
const month2 = new Date(currentMonthDate);
month2.setMonth(month2.getMonth() + 1);
const roMonths = ['Ianuarie', 'Februarie', 'Martie', 'Aprilie', 'Mai', 'Iunie', 'Iulie', 'August', 'Septembrie', 'Octombrie', 'Noiembrie', 'Decembrie'];
m1Title.innerText = `${roMonths[month1.getMonth()]} ${month1.getFullYear()}`;
m2Title.innerText = `${roMonths[month2.getMonth()]} ${month2.getFullYear()}`;
currentMonthYear.innerText = `${roMonths[month1.getMonth()]} - ${roMonths[month2.getMonth()]} ${month2.getFullYear()}`;
renderMonthGrid(m1Grid, month1);
renderMonthGrid(m2Grid, month2);
}
function renderMonthGrid(container, monthDate) {
container.innerHTML = '';
const year = monthDate.getFullYear();
const month = monthDate.getMonth();
const firstDay = new Date(year, month, 1);
const lastDay = new Date(year, month + 1, 0);
let startingDay = firstDay.getDay() - 1;
if (startingDay === -1) startingDay = 6;
const today = new Date();
today.setHours(0,0,0,0);
for (let i = 0; i < startingDay; i++) {
const cell = document.createElement('div');
cell.className = 'fox-day-cell empty';
container.appendChild(cell);
}
for (let day = 1; day <= lastDay.getDate(); day++) {
const cellDate = new Date(year, month, day);
const cell = document.createElement('div');
cell.className = 'fox-day-cell';
cell.innerText = day;
const isPast = cellDate < today;
const isBlocked = isDateBlocked(cellDate);
if (isPast) {
cell.classList.add('past');
} else if (isBlocked) {
cell.classList.add('blocked');
} else {
cell.classList.add('available');
if (isSameDay(cellDate, checkInDate) || isSameDay(cellDate, checkOutDate)) {
cell.classList.add('selected');
}
if (checkInDate && checkOutDate && cellDate > checkInDate && cellDate < checkOutDate) {
cell.classList.add('in-range');
}
cell.addEventListener('click', () => handleDateClick(cellDate));
}
container.appendChild(cell);
}
}
function handleDateClick(date) {
if (!checkInDate || (checkInDate && checkOutDate)) {
checkInDate = date;
checkOutDate = null;
} else if (checkInDate && !checkOutDate) {
if (date <= checkInDate) {
checkInDate = date;
} else {
let hasBlockedBetween = false;
let curr = new Date(checkInDate);
while (curr < date) {
if (isDateBlocked(curr)) {
hasBlockedBetween = true;
break;
}
curr.setDate(curr.getDate() + 1);
}
if (hasBlockedBetween) {
alert('Perioada selectată conține zile deja rezervate!');
checkInDate = date;
checkOutDate = null;
} else {
checkOutDate = date;
}
}
}
updateDatesDisplay();
renderCalendars();
}
function updateDatesDisplay() {
displayCheckin.innerText = checkInDate ? formatDate(checkInDate) : 'Selectează';
displayCheckout.innerText = checkOutDate ? formatDate(checkOutDate) : 'Selectează';
calculatePrice();
}
function formatDate(d) {
return `${String(d.getDate()).padStart(2, '0')}.${String(d.getMonth() + 1).padStart(2, '0')}.${d.getFullYear()}`;
}
function calculatePriceDetails() {
if (!checkInDate || !checkOutDate) return null;
const cabinData = getCurrentCabinData();
let weekdayNights = 0;
let weekendNights = 0;
let curr = new Date(checkInDate);
while (curr < checkOutDate) {
const dayOfWeek = curr.getDay();
if (dayOfWeek === 5 || dayOfWeek === 6) {
weekendNights++;
} else {
weekdayNights++;
}
curr.setDate(curr.getDate() + 1);
}
const weekdaySubtotal = weekdayNights * cabinData.priceWeekday;
const weekendSubtotal = weekendNights * cabinData.priceWeekend;
const subtotal = weekdaySubtotal + weekendSubtotal;
const total = subtotal + cabinData.cleaning;
return {
weekdayNights,
weekendNights,
weekdaySubtotal,
weekendSubtotal,
subtotal,
total,
cleaning: cabinData.cleaning,
priceWeekday: cabinData.priceWeekday,
priceWeekend: cabinData.priceWeekend
};
}
function calculatePrice() {
const details = calculatePriceDetails();
if (details) {
let summaryHtml = '';
if (details.weekdayNights > 0) {
summaryHtml += `<div class="fox-summary-row">
<span>Cursul săptămânii (${details.weekdayNights} ${details.weekdayNights === 1 ? 'noapte' : 'nopți'} x ${details.priceWeekday} ${config.currency})</span>
<span>${details.weekdaySubtotal} ${config.currency}</span>
</div>`;
}
if (details.weekendNights > 0) {
summaryHtml += `<div class="fox-summary-row">
<span>Weekend (${details.weekendNights} ${details.weekendNights === 1 ? 'noapte' : 'nopți'} x ${details.priceWeekend} ${config.currency})</span>
<span>${details.weekendSubtotal} ${config.currency}</span>
</div>`;
}
summaryRowsContainer.innerHTML = summaryHtml;
if (details.cleaning > 0) {
cleaningFeeRow.style.display = 'flex';
calcCleaning.innerText = `${details.cleaning} ${config.currency}`;
} else {
cleaningFeeRow.style.display = 'none';
}
calcTotal.innerText = `${details.total} ${config.currency}`;
summaryBox.style.display = 'block';
} else {
summaryBox.style.display = 'none';
}
}
function sendWhatsApp() {
if (!checkInDate || !checkOutDate) {
alert('Te rugăm să selectezi mai întâi perioada de cazare.');
return;
}
const details = calculatePriceDetails();
const cabinData = getCurrentCabinData();
const name = document.getElementById('foxGuestName').value.trim() || 'Nespecificat';
const guests = document.getElementById('foxGuestCount').value;
let breakdownMsg = '';
if (details.weekdayNights > 0) {
breakdownMsg += `%0A • Cursul săptămânii: ${details.weekdayNights} nopți x ${details.priceWeekday} ${config.currency} = ${details.weekdaySubtotal} ${config.currency}`;
}
if (details.weekendNights > 0) {
breakdownMsg += `%0A • Weekend: ${details.weekendNights} nopți x ${details.priceWeekend} ${config.currency} = ${details.weekendSubtotal} ${config.currency}`;
}
if (details.cleaning > 0) {
breakdownMsg += `%0A • Curățenie: ${details.cleaning} ${config.currency}`;
}
const totalNights = details.weekdayNights + details.weekendNights;
const msg = `Bună ziua! Aș dori să solicit o rezervare la *Fox Cabins - Valea Doftanei*:%0A%0A` +
`🏡 *Opțiune aleasă:* ${cabinData.name}%0A` +
`📅 *Check-in:* ${formatDate(checkInDate)}%0A` +
`📅 *Check-out:* ${formatDate(checkOutDate)}%0A` +
`🌙 *Total Nopți:* ${totalNights}%0A` +
`👥 *Oaspeți:* ${guests}%0A` +
`👤 *Nume Client:* ${name}%0A%0A` +
`📊 *Calcul preț:*${breakdownMsg}%0A` +
`💰 *TOTAL ESTIMAT:* ${details.total} ${config.currency}%0A%0A` +
`Este disponibilă această perioadă? Mulțumesc!`;
const waUrl = `https://wa.me/${config.whatsappPhone}?text=${msg}`;
window.open(waUrl, '_blank');
}
init();
})();
</script-->
</body>
</html>
FOX CABINS
Where Comfort Meets the Wild
Un voucher.
Amintiri pentru o viata.
Ofera o experienta speciala in mijlocul naturii.
Alege valoarea voucherului si, optional,
perioada sejurului.
Noi ne ocupam de verificarea disponibilitatii,
factura si pregatirea cadoului.
1 Completezi cererea
2 Trimiti pe WhatsApp
3 Primesti factura si achiti
4 Primesti voucherul si PIN-ul
Solicita un voucher cadou
Completeaza formularul de mai jos. Nu platesti nimic pe site.
Asa va arata voucherul tau premium, printat de noi
Un cadou elegant, pregatit pentru a fi oferit intr-un plic.
FOX CABINS
VOUCHER CADOU
Where Comfort Meets the Wild
Mai mult decat o cazare, o poveste in natura.
Voucherul final va fi personalizat cu numele beneficiarului.
Un cadou care devine o poveste
Valabil 12 luni de la activare pentru voucherele flexibile.
Beneficiarul alege cabana si perioada in functie de disponibilitate.
Recomandam rezervarea cu 60 de zile inainte.
Sarbatorile si perioadele speciale sunt excluse.
Diferenta de pret, daca exista, este achitata de beneficiar.
Voucherul se utilizeaza intr-o singura rezervare.
Voucherul este transferabil inainte de prima utilizare.
PIN-ul unic este trimis separat prin WhatsApp dupa confirmarea incasarii.
PIN-ul este necesar pentru validarea rezervarii.
Datele se blocheaza exclusiv manual de Fox Cabins.