diff --git a/modules/translations/index.js b/modules/translations/index.js index 7aca60d..81af4a7 100644 --- a/modules/translations/index.js +++ b/modules/translations/index.js @@ -26,7 +26,7 @@ const translations = { 'select.alphabetical': 'По алфавиту', // Review Form - 'form.select_country': 'Выберите страну', + 'form.select_country': 'Выберите страну (необязательно)', 'form.select_city': 'Город (необязательно)', 'form.another_country': 'Другая страна', 'form.country_placeholder': 'Введите название страны', @@ -355,7 +355,7 @@ const translations = { 'select.alphabetical': 'Alphabetical', // Review Form - 'form.select_country': 'Select country', + 'form.select_country': 'Select country (optional)', 'form.select_city': 'City (optional)', 'form.another_country': 'Other country', 'form.country_placeholder': 'Enter country name', @@ -684,7 +684,7 @@ const translations = { 'select.alphabetical': 'Алфавит ала', // Review Form - 'form.select_country': 'Атәыла алхразы', + 'form.select_country': 'Атәыла алхразы (иахәҭахым)', 'form.select_city': 'Ақалақь (иахәҭахым)', 'form.another_country': 'Атәыла даҽаны', 'form.country_placeholder': 'Атәыла ахьӡ аҭазыргыла', diff --git a/public/data/countries.js b/public/data/countries.js index df9a784..b120837 100644 --- a/public/data/countries.js +++ b/public/data/countries.js @@ -1,5 +1,6 @@ const COUNTRIES = [ { code: 'AF', name: 'Afghanistan', nameRu: 'Афганистан' }, + { code: 'AB', name: 'Abkhazia', nameRu: 'Абхазия' }, { code: 'AL', name: 'Albania', nameRu: 'Албания' }, { code: 'DZ', name: 'Algeria', nameRu: 'Алжир' }, { code: 'AD', name: 'Andorra', nameRu: 'Андорра' }, diff --git a/public/index.html b/public/index.html index 700576f..ba5a7ba 100644 --- a/public/index.html +++ b/public/index.html @@ -80,14 +80,14 @@
-
0
+
0
категории
-
0%
+
0%
довольных гостей
@@ -936,7 +936,7 @@
Выберите страну
diff --git a/public/js/main.js b/public/js/main.js index aff9b3d..f101479 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -37,9 +37,22 @@ document.querySelectorAll('.animate-on-scroll').forEach(el => { }); // Counter animation -const counterObserver = new IntersectionObserver((entries) => { +const statsPromise = fetch('/api/stats').then(r => r.ok ? r.json() : null).catch(() => null); + +const counterObserver = new IntersectionObserver(async (entries) => { + const stats = await statsPromise; + entries.forEach(entry => { if (entry.isIntersecting) { + if (stats) { + entry.target.querySelectorAll('.counter[data-stat]').forEach(el => { + const stat = el.getAttribute('data-stat'); + if (stats[stat] !== undefined) { + el.setAttribute('data-target', stats[stat]); + } + }); + } + const counters = entry.target.querySelectorAll('.counter'); counters.forEach(counter => { const target = parseInt(counter.getAttribute('data-target')); diff --git a/public/js/reviews.js b/public/js/reviews.js index d8caafa..776088d 100644 --- a/public/js/reviews.js +++ b/public/js/reviews.js @@ -140,13 +140,24 @@ function populateCountrySelect() { const select = document.getElementById('reviewCountry'); if (!select) return; + const PINNED_CODES = ['RU', 'AB']; + select.innerHTML = ''; + const pinnedCountries = countriesCache.filter(c => PINNED_CODES.includes(c.code)); + pinnedCountries.forEach(country => { + const opt = document.createElement('option'); + opt.value = country.code; + opt.textContent = I18n.currentLang === 'ru' ? country.nameRu : country.name; + select.appendChild(opt); + }); + const popularCodes = popularCountriesCache.map(c => c.country_code); const popularCountries = []; const otherCountries = []; countriesCache.forEach(country => { + if (PINNED_CODES.includes(country.code)) return; if (popularCodes.includes(country.code)) { popularCountries.push(country); } else { diff --git a/server.js b/server.js index 0f6ff4e..30b9114 100644 --- a/server.js +++ b/server.js @@ -392,6 +392,28 @@ app.get('/api/translations/:lang', (req, res) => { res.json(translations); }); +app.get('/api/stats', (req, res) => { + db.get(`SELECT COUNT(DISTINCT type) as count FROM rooms WHERE is_active = 1`, [], (err, row) => { + if (err) { + console.error('Stats categories error:', err); + return res.status(500).json({ error: 'Database error' }); + } + const categories = (row && row.count > 0) ? row.count : Object.keys(config.ROOM_TYPES).length; + + db.get(`SELECT COUNT(*) as total, SUM(CASE WHEN stars >= 4 THEN 1 ELSE 0 END) as satisfied FROM reviews WHERE is_approved = 1`, [], (err2, row2) => { + if (err2) { + console.error('Stats reviews error:', err2); + return res.status(500).json({ error: 'Database error' }); + } + let satisfaction = 100; + if (row2 && row2.total > 0) { + satisfaction = Math.round((row2.satisfied / row2.total) * 100); + } + res.json({ categories, satisfaction }); + }); + }); +}); + app.get('/api/countries-cities', (req, res) => { res.sendFile(path.join(__dirname, 'public', 'data', 'countries-cities.js')); }); @@ -404,6 +426,7 @@ app.get('/api/countries', (req, res) => { if (match) { try { let jsonStr = match[1]; + jsonStr = jsonStr.replace(/(\{|\,)\s*(\w+):/g, '$1"$2":'); jsonStr = jsonStr.replace(/'/g, '"'); const countries = JSON.parse(jsonStr); res.json(countries);