hesabixSite/templates/qa/question_show.html.twig
Hesabix 06a2fb398d
Some checks are pending
PHP Composer / build (push) Waiting to run
progress in site customer part
2025-09-05 09:37:27 +03:30

342 lines
17 KiB
Twig

{% extends 'base.html.twig' %}
{% block title %}{{ question.title }} - پرسش و پاسخ{% endblock %}
{% block body %}
<div class="container my-4">
<div class="row">
<div class="col-12">
<!-- سوال -->
<div class="card mb-4">
<div class="card-body">
<div class="row">
<div class="col-1 text-center">
<div class="vote-section">
<button class="btn btn-outline-success btn-sm vote-btn"
data-type="question"
data-id="{{ question.id }}"
data-upvote="true"
{% if not app.user or 'ROLE_CUSTOMER' not in app.user.roles %}disabled{% endif %}>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="18,15 12,9 6,15"></polyline>
</svg>
</button>
<div class="vote-count mt-2 mb-2" id="question-votes-{{ question.id }}">
{{ question.votes }}
</div>
<button class="btn btn-outline-danger btn-sm vote-btn"
data-type="question"
data-id="{{ question.id }}"
data-upvote="false"
{% if not app.user or 'ROLE_CUSTOMER' not in app.user.roles %}disabled{% endif %}>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="6,9 12,15 18,9"></polyline>
</svg>
</button>
</div>
</div>
<div class="col-11">
<div class="d-flex justify-content-between align-items-start mb-3">
<h1 class="card-title mb-0">{{ question.title }}</h1>
{% if question.isSolved %}
<span class="badge bg-success fs-6">
<i class="fas fa-check me-1"></i>حل شده
</span>
{% endif %}
</div>
<div class="question-content mb-3">
{{ question.content|markdown|raw }}
</div>
<div class="d-flex justify-content-between align-items-center">
<div class="tags">
{% for tagRelation in question.tagRelations %}
<a href="{{ path('qa_tag_questions', {'name': tagRelation.tag.name}) }}"
class="badge bg-light text-dark text-decoration-none me-1">
{{ tagRelation.tag.name }}
</a>
{% endfor %}
</div>
<div class="text-muted small">
<i class="fas fa-user me-1"></i>{{ question.author.name }}
<i class="fas fa-clock ms-3 me-1"></i>{{ question.createdAt|date('Y/m/d H:i') }}
<i class="fas fa-eye ms-3 me-1"></i>{{ question.views }} بازدید
</div>
</div>
</div>
</div>
</div>
</div>
<!-- پاسخ‌ها -->
<div class="mb-4">
<div class="d-flex justify-content-between align-items-center mb-3">
<h3>
<i class="fas fa-comments me-2"></i>پاسخ‌ها
<span class="badge bg-primary">{{ totalAnswers }}</span>
</h3>
{% if app.user and 'ROLE_CUSTOMER' in app.user.roles %}
<a href="{{ path('qa_answer', {'id': question.id}) }}" class="btn btn-primary">
<i class="fas fa-plus me-2"></i>پاسخ دهید
</a>
{% else %}
<a href="{{ path('customer_login') }}" class="btn btn-outline-primary">
<i class="fas fa-sign-in-alt me-2"></i>ورود برای پاسخ دادن
</a>
{% endif %}
</div>
{% if answers is empty %}
<div class="card">
<div class="card-body text-center py-5">
<i class="fas fa-comment-slash fa-3x text-muted mb-3"></i>
<h4 class="text-muted">هنوز پاسخی داده نشده</h4>
<p class="text-muted">اولین کسی باشید که به این سوال پاسخ می‌دهد.</p>
</div>
</div>
{% else %}
{% for answer in answers %}
<div class="card mb-3 answer-card {{ answer.isAccepted ? 'border-success' : '' }}">
<div class="card-body">
<div class="row">
<div class="col-1 text-center">
<div class="vote-section">
<button class="btn btn-outline-success btn-sm vote-btn"
data-type="answer"
data-id="{{ answer.id }}"
data-upvote="true"
{% if not app.user or 'ROLE_CUSTOMER' not in app.user.roles %}disabled{% endif %}>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="18,15 12,9 6,15"></polyline>
</svg>
</button>
<div class="vote-count mt-2 mb-2" id="answer-votes-{{ answer.id }}">
{{ answer.votes }}
</div>
<button class="btn btn-outline-danger btn-sm vote-btn"
data-type="answer"
data-id="{{ answer.id }}"
data-upvote="false"
{% if not app.user or 'ROLE_CUSTOMER' not in app.user.roles %}disabled{% endif %}>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="6,9 12,15 18,9"></polyline>
</svg>
</button>
</div>
</div>
<div class="col-11">
<div class="d-flex justify-content-between align-items-start mb-2">
<div class="answer-content">
{{ answer.content|markdown|raw }}
</div>
{% if answer.isAccepted %}
<span class="badge bg-success ms-2">
<i class="fas fa-check me-1"></i>پاسخ پذیرفته شده
</span>
{% endif %}
</div>
<div class="d-flex justify-content-between align-items-center">
<div class="text-muted small">
<i class="fas fa-user me-1"></i>{{ answer.author.name }}
<i class="fas fa-clock ms-3 me-1"></i>{{ answer.createdAt|date('Y/m/d H:i') }}
</div>
{% if app.user and app.user == question.author and not answer.isAccepted %}
<button class="btn btn-outline-success btn-sm accept-answer-btn"
data-answer-id="{{ answer.id }}">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="me-1">
<polyline points="20,6 9,17 4,12"></polyline>
</svg>پذیرفتن پاسخ
</button>
{% endif %}
</div>
</div>
</div>
</div>
</div>
{% endfor %}
<!-- صفحه‌بندی پاسخ‌ها -->
{% if totalPages > 1 %}
<nav aria-label="صفحه‌بندی پاسخ‌ها" class="mt-4">
<ul class="pagination justify-content-center">
{% if currentPage > 1 %}
<li class="page-item">
<a class="page-link" href="?page={{ currentPage - 1 }}">قبلی</a>
</li>
{% endif %}
{% for page in 1..totalPages %}
{% if page == currentPage %}
<li class="page-item active">
<span class="page-link">{{ page }}</span>
</li>
{% else %}
<li class="page-item">
<a class="page-link" href="?page={{ page }}">{{ page }}</a>
</li>
{% endif %}
{% endfor %}
{% if currentPage < totalPages %}
<li class="page-item">
<a class="page-link" href="?page={{ currentPage + 1 }}">بعدی</a>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
{% endif %}
</div>
<!-- دکمه بازگشت -->
<div class="text-center">
<a href="{{ path('qa_index') }}" class="btn btn-outline-secondary">
<i class="fas fa-arrow-right me-2"></i>بازگشت به لیست سوالات
</a>
</div>
</div>
</div>
</div>
<style>
.vote-section {
display: flex;
flex-direction: column;
align-items: center;
}
.vote-btn {
width: 30px;
height: 30px;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
}
.vote-count {
font-size: 1.1rem;
font-weight: bold;
min-width: 30px;
text-align: center;
}
.answer-card.border-success {
border-left: 4px solid #198754 !important;
}
.question-content, .answer-content {
line-height: 1.6;
font-size: 1.1rem;
}
.tags .badge {
font-size: 0.9rem;
transition: all 0.3s ease;
}
.tags .badge:hover {
background-color: #0d6efd !important;
color: white !important;
}
</style>
<script>
function initializeVoteButtons() {
// رای‌دهی
document.querySelectorAll('.vote-btn').forEach(button => {
button.addEventListener('click', function() {
if (this.disabled) return;
const type = this.dataset.type;
const id = this.dataset.id;
const upvote = this.dataset.upvote === 'true';
fetch(`/qa/${type}/${id}/vote`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-Requested-With': 'XMLHttpRequest'
},
body: `upvote=${upvote}&_token={{ csrf_token('vote') }}`
})
.then(response => response.json())
.then(data => {
if (data.error) {
alert(data.error);
return;
}
document.getElementById(`${type}-votes-${id}`).textContent = data.votes;
// تغییر رنگ دکمه‌ها
const buttons = document.querySelectorAll(`[data-type="${type}"][data-id="${id}"]`);
buttons.forEach(btn => {
btn.classList.remove('btn-success', 'btn-danger', 'btn-outline-success', 'btn-outline-danger');
btn.classList.add(btn.dataset.upvote === 'true' ? 'btn-outline-success' : 'btn-outline-danger');
});
if (data.userVote) {
const activeButton = document.querySelector(`[data-type="${type}"][data-id="${id}"][data-upvote="${data.userVote === 'up' ? 'true' : 'false'}"]`);
if (activeButton) {
activeButton.classList.remove('btn-outline-success', 'btn-outline-danger');
activeButton.classList.add(data.userVote === 'up' ? 'btn-success' : 'btn-danger');
}
} else {
// اگر رای حذف شده، همه دکمه‌ها را به حالت عادی برگردان
buttons.forEach(btn => {
btn.classList.remove('btn-success', 'btn-danger');
btn.classList.add(btn.dataset.upvote === 'true' ? 'btn-outline-success' : 'btn-outline-danger');
});
}
})
.catch(error => {
console.error('Error:', error);
alert('خطا در ارسال رای');
});
});
});
// پذیرفتن پاسخ
document.querySelectorAll('.accept-answer-btn').forEach(button => {
button.addEventListener('click', function() {
const answerId = this.dataset.answerId;
if (!confirm('آیا مطمئن هستید که می‌خواهید این پاسخ را بپذیرید؟')) {
return;
}
fetch(`/qa/answer/${answerId}/accept`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-Requested-With': 'XMLHttpRequest'
},
body: `_token={{ csrf_token('accept') }}`
})
.then(response => response.json())
.then(data => {
if (data.error) {
alert(data.error);
return;
}
location.reload();
})
.catch(error => {
console.error('Error:', error);
alert('خطا در پذیرفتن پاسخ');
});
});
});
}
// اجرا در هر دو حالت
document.addEventListener('DOMContentLoaded', initializeVoteButtons);
document.addEventListener('turbo:load', initializeVoteButtons);
</script>
{% endblock %}