Files
tourrism_site/views/guides/profile.ejs
Andrey K. Choi a461fea9d9 Компактные hero секции и улучшенная инициализация БД
🎨 UI улучшения:
- Уменьшена высота синих панелей с 100vh до 70vh на главной
- Добавлен класс .compact (25vh) для всех остальных страниц
- Улучшена адаптивность для мобильных устройств
- Обновлены все шаблоны с hero секциями

🚀 Инфраструктура:
- Автоматическая инициализация базы данных при деплое
- Улучшены мокапные данные (больше отзывов, бронирований, сообщений)
- Добавлены настройки сайта в базу данных
- Создан скрипт автоматического деплоя deploy.sh

📦 Система сборки:
- Обновлен .gitignore с полным покрытием файлов
- Добавлена папка для загрузок с .gitkeep
- Улучшен README с инструкциями по запуску
- ES модули для инициализации базы данных

🐛 Исправления:
- Совместимость с ES модулями в Node.js
- Правильная обработка ошибок инициализации БД
- Корректные SQL запросы для PostgreSQL
2025-11-29 18:47:42 +09:00

260 lines
13 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- Hero Section -->
<section class="hero-section compact bg-primary text-white py-5">
<div class="container">
<div class="row align-items-center">
<div class="col-lg-4 text-center text-lg-start">
<% if (guide.image_url && guide.image_url.trim()) { %>
<img src="<%= guide.image_url %>" alt="<%= guide.name %>"
class="img-fluid rounded-circle shadow-lg mb-4 mb-lg-0"
style="width: 200px; height: 200px; object-fit: cover;">
<% } else { %>
<img src="/images/placeholder.jpg" alt="<%= guide.name %>"
class="img-fluid rounded-circle shadow-lg mb-4 mb-lg-0"
style="width: 200px; height: 200px; object-fit: cover;">
<% } %>
</div>
<div class="col-lg-8">
<h1 class="display-4 fw-bold mb-3"><%= guide.name %></h1>
<div class="mb-4">
<% if (guide.specialization === 'city') { %>
<span class="badge bg-info fs-6 me-2">
<i class="fas fa-city me-1"></i>Городские туры
</span>
<% } else if (guide.specialization === 'mountain') { %>
<span class="badge bg-success fs-6 me-2">
<i class="fas fa-mountain me-1"></i>Горные походы
</span>
<% } else if (guide.specialization === 'fishing') { %>
<span class="badge bg-info fs-6 me-2">
<i class="fas fa-fish me-1"></i>Рыбалка
</span>
<% } %>
<span class="badge bg-warning text-dark fs-6">
<i class="fas fa-star me-1"></i>
<%= guide.experience %> лет опыта
</span>
</div>
<% if (guide.languages) { %>
<p class="mb-3">
<strong>Языки:</strong> <%= guide.languages %>
</p>
<% } %>
<% if (guide.avg_rating) { %>
<div class="mb-3">
<span class="me-2">Рейтинг:</span>
<%- generateStars(guide.avg_rating) %>
<span class="ms-2">(<%= parseFloat(guide.avg_rating).toFixed(1) %>/5)</span>
<% if (guide.review_count) { %>
<small class="text-light-50 ms-2"><%= guide.review_count %> отзывов</small>
<% } %>
</div>
<% } %>
<div class="row">
<div class="col-md-6">
<p class="mb-1">
<i class="fas fa-route me-2"></i>
<strong><%= guide.route_count || 0 %></strong> туров
</p>
</div>
<% if (guide.phone) { %>
<div class="col-md-6">
<p class="mb-1">
<i class="fas fa-phone me-2"></i>
<a href="tel:<%= guide.phone %>" class="text-light"><%= guide.phone %></a>
</p>
</div>
<% } %>
</div>
</div>
</div>
</div>
</section>
<!-- Guide Details -->
<section class="py-5">
<div class="container">
<div class="row">
<div class="col-lg-8">
<!-- Bio -->
<% if (guide.bio) { %>
<div class="card mb-4">
<div class="card-header">
<h4 class="card-title mb-0">
<i class="fas fa-user me-2"></i>О гиде
</h4>
</div>
<div class="card-body">
<p class="mb-0"><%= guide.bio %></p>
</div>
</div>
<% } %>
<!-- Tours -->
<div class="card mb-4">
<div class="card-header">
<h4 class="card-title mb-0">
<i class="fas fa-route me-2"></i>Туры с этим гидом
</h4>
</div>
<div class="card-body">
<% if (routes && routes.length > 0) { %>
<div class="row">
<% routes.forEach(route => { %>
<div class="col-md-6 mb-3">
<div class="card h-100">
<%
let placeholderImage = '/images/placeholder.jpg';
if (route.type === 'city') {
placeholderImage = '/images/city-tour-placeholder.webp';
} else if (route.type === 'mountain') {
placeholderImage = '/images/mountain-placeholder.jpg';
} else if (route.type === 'fishing') {
placeholderImage = '/images/fish-placeholder.jpg';
}
%>
<% if (route.image_url && route.image_url.trim()) { %>
<img src="<%= route.image_url %>" class="card-img-top"
alt="<%= route.title %>" style="height: 150px; object-fit: cover;">
<% } else { %>
<img src="<%= placeholderImage %>" class="card-img-top"
alt="<%= route.title %>" style="height: 150px; object-fit: cover;">
<% } %>
<div class="card-body">
<h6 class="card-title"><%= route.title %></h6>
<p class="card-text text-muted small"><%= truncateText(route.description, 80) %></p>
<div class="d-flex justify-content-between align-items-center">
<strong class="text-primary">₩<%= formatCurrency(route.price) %></strong>
<small class="text-muted"><%= route.duration %> дн.</small>
</div>
<a href="/routes/<%= route.id %>" class="btn btn-outline-primary btn-sm mt-2 w-100">
Подробнее
</a>
</div>
</div>
</div>
<% }); %>
</div>
<% } else { %>
<p class="text-muted mb-0">В данный момент у этого гида нет активных туров.</p>
<% } %>
</div>
</div>
<!-- Reviews -->
<div class="card">
<div class="card-header">
<h4 class="card-title mb-0">
<i class="fas fa-star me-2"></i>Отзывы
</h4>
</div>
<div class="card-body">
<% if (reviews && reviews.length > 0) { %>
<% reviews.forEach(review => { %>
<div class="border-bottom pb-3 mb-3">
<div class="d-flex justify-content-between align-items-start mb-2">
<div>
<h6 class="mb-1"><%= review.author_name %></h6>
<% if (review.route_title) { %>
<small class="text-muted">Тур: <%= review.route_title %></small>
<% } %>
</div>
<div class="text-end">
<% if (review.rating) { %>
<div class="mb-1">
<%- generateStars(review.rating) %>
</div>
<% } %>
<small class="text-muted"><%= formatDateShort(review.created_at) %></small>
</div>
</div>
<p class="mb-0"><%= review.comment %></p>
</div>
<% }); %>
<% } else { %>
<p class="text-muted mb-0">Пока нет отзывов об этом гиде.</p>
<% } %>
</div>
</div>
</div>
<!-- Sidebar -->
<div class="col-lg-4">
<!-- Contact Card -->
<div class="card mb-4">
<div class="card-header">
<h5 class="card-title mb-0">
<i class="fas fa-address-card me-2"></i>Контактная информация
</h5>
</div>
<div class="card-body">
<% if (guide.phone) { %>
<p class="mb-2">
<i class="fas fa-phone me-2"></i>
<a href="tel:<%= guide.phone %>"><%= guide.phone %></a>
</p>
<% } %>
<% if (guide.email) { %>
<p class="mb-2">
<i class="fas fa-envelope me-2"></i>
<a href="mailto:<%= guide.email %>"><%= guide.email %></a>
</p>
<% } %>
<% if (guide.languages) { %>
<p class="mb-2">
<i class="fas fa-language me-2"></i>
<%= guide.languages %>
</p>
<% } %>
<a href="/contact" class="btn btn-primary w-100 mt-3">
<i class="fas fa-envelope me-1"></i>Связаться с гидом
</a>
</div>
</div>
<!-- Stats Card -->
<div class="card">
<div class="card-header">
<h5 class="card-title mb-0">
<i class="fas fa-chart-bar me-2"></i>Статистика
</h5>
</div>
<div class="card-body">
<div class="row text-center">
<div class="col-6 mb-3">
<div class="border-end">
<h4 class="text-primary mb-1"><%= guide.route_count || 0 %></h4>
<small class="text-muted">Туров</small>
</div>
</div>
<div class="col-6 mb-3">
<h4 class="text-success mb-1"><%= guide.experience %></h4>
<small class="text-muted">Лет опыта</small>
</div>
</div>
<% if (guide.avg_rating) { %>
<div class="text-center">
<h4 class="text-warning mb-1"><%= parseFloat(guide.avg_rating).toFixed(1) %></h4>
<small class="text-muted">Средний рейтинг</small>
</div>
<% } %>
</div>
</div>
<!-- Back Button -->
<div class="mt-4">
<a href="/guides" class="btn btn-outline-primary w-100">
<i class="fas fa-arrow-left me-1"></i>Все гиды
</a>
</div>
</div>
</div>
</div>
</section>