menu
This commit is contained in:
parent
a02a0d5d1d
commit
0c86868e0f
3 changed files with 601 additions and 38 deletions
|
|
@ -46,6 +46,9 @@ const GameManagementModal = ({
|
|||
const [selectedPack, setSelectedPack] = useState(null)
|
||||
const [packQuestions, setPackQuestions] = useState([])
|
||||
const [selectedQuestionIndices, setSelectedQuestionIndices] = useState(new Set())
|
||||
const [searchQuery, setSearchQuery] = useState('')
|
||||
const [viewingQuestion, setViewingQuestion] = useState(null)
|
||||
const [showAnswers, setShowAnswers] = useState(false)
|
||||
|
||||
if (!isOpen) return null
|
||||
|
||||
|
|
@ -244,6 +247,9 @@ const GameManagementModal = ({
|
|||
if (!packId) {
|
||||
setPackQuestions([])
|
||||
setSelectedPack(null)
|
||||
setSearchQuery('')
|
||||
setViewingQuestion(null)
|
||||
setShowAnswers(false)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -252,12 +258,70 @@ const GameManagementModal = ({
|
|||
setPackQuestions(response.data.questions || [])
|
||||
setSelectedPack(packId)
|
||||
setSelectedQuestionIndices(new Set())
|
||||
setSearchQuery('')
|
||||
setViewingQuestion(null)
|
||||
setShowAnswers(false)
|
||||
} catch (error) {
|
||||
console.error('Error fetching pack:', error)
|
||||
setJsonError('Ошибка загрузки пака вопросов')
|
||||
}
|
||||
}
|
||||
|
||||
// Фильтрация вопросов по поисковому запросу
|
||||
const filteredPackQuestions = packQuestions.filter((q) => {
|
||||
if (!searchQuery.trim()) return true
|
||||
const questionText = (q.text || q.question || '').toLowerCase()
|
||||
return questionText.includes(searchQuery.toLowerCase())
|
||||
})
|
||||
|
||||
// Выбор всех видимых вопросов
|
||||
const handleSelectAll = () => {
|
||||
const allVisibleIndices = new Set(
|
||||
filteredPackQuestions.map((q) => {
|
||||
const originalIndex = packQuestions.findIndex(pq => pq === q)
|
||||
return originalIndex
|
||||
}).filter(idx => idx !== -1)
|
||||
)
|
||||
const newSelected = new Set(selectedQuestionIndices)
|
||||
allVisibleIndices.forEach(idx => newSelected.add(idx))
|
||||
setSelectedQuestionIndices(newSelected)
|
||||
}
|
||||
|
||||
// Снятие выбора со всех видимых вопросов
|
||||
const handleDeselectAll = () => {
|
||||
const visibleIndices = new Set(
|
||||
filteredPackQuestions.map((q) => {
|
||||
const originalIndex = packQuestions.findIndex(pq => pq === q)
|
||||
return originalIndex
|
||||
}).filter(idx => idx !== -1)
|
||||
)
|
||||
const newSelected = new Set(selectedQuestionIndices)
|
||||
visibleIndices.forEach(idx => newSelected.delete(idx))
|
||||
setSelectedQuestionIndices(newSelected)
|
||||
}
|
||||
|
||||
// Проверка, выбраны ли все видимые вопросы
|
||||
const areAllVisibleSelected = () => {
|
||||
if (filteredPackQuestions.length === 0) return false
|
||||
const visibleIndices = filteredPackQuestions.map((q) => {
|
||||
const originalIndex = packQuestions.findIndex(pq => pq === q)
|
||||
return originalIndex
|
||||
}).filter(idx => idx !== -1)
|
||||
return visibleIndices.every(idx => selectedQuestionIndices.has(idx))
|
||||
}
|
||||
|
||||
// Просмотр вопроса
|
||||
const handleViewQuestion = (question) => {
|
||||
setViewingQuestion(question)
|
||||
setShowAnswers(false)
|
||||
}
|
||||
|
||||
// Закрытие просмотра вопроса
|
||||
const handleCloseViewer = () => {
|
||||
setViewingQuestion(null)
|
||||
setShowAnswers(false)
|
||||
}
|
||||
|
||||
const handleToggleQuestion = (index) => {
|
||||
const newSelected = new Set(selectedQuestionIndices)
|
||||
if (newSelected.has(index)) {
|
||||
|
|
@ -272,16 +336,17 @@ const GameManagementModal = ({
|
|||
const indices = Array.from(selectedQuestionIndices)
|
||||
const questionsToImport = indices.map(idx => packQuestions[idx]).filter(Boolean)
|
||||
|
||||
const copiedQuestions = questionsToImport.map(q => ({
|
||||
id: Date.now() + Math.random(),
|
||||
text: q.text,
|
||||
answers: q.answers.map(a => ({ text: a.text, points: a.points })),
|
||||
const copiedQuestions = questionsToImport.map((q, idx) => ({
|
||||
id: Date.now() + Math.random() + idx, // Generate new ID
|
||||
text: q.text || q.question || '',
|
||||
answers: (q.answers || []).map(a => ({ text: a.text, points: a.points })),
|
||||
}))
|
||||
|
||||
const updatedQuestions = [...questions, ...copiedQuestions]
|
||||
onUpdateQuestions(updatedQuestions)
|
||||
|
||||
setSelectedQuestionIndices(new Set())
|
||||
setSearchQuery('')
|
||||
setShowPackImport(false)
|
||||
setJsonError('')
|
||||
alert(`Импортировано ${copiedQuestions.length} вопросов`)
|
||||
|
|
@ -577,8 +642,42 @@ const GameManagementModal = ({
|
|||
|
||||
{packQuestions.length > 0 && (
|
||||
<div className="pack-questions-list">
|
||||
{/* Поиск */}
|
||||
<div className="pack-search-container">
|
||||
<input
|
||||
type="text"
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
placeholder="🔍 Поиск вопросов..."
|
||||
className="pack-search-input"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="pack-questions-header">
|
||||
<span>Выберите вопросы для импорта:</span>
|
||||
<div className="pack-questions-header-left">
|
||||
<span>Выберите вопросы для импорта:</span>
|
||||
<div className="pack-select-all-buttons">
|
||||
{filteredPackQuestions.length > 0 && (
|
||||
<>
|
||||
{areAllVisibleSelected() ? (
|
||||
<button
|
||||
onClick={handleDeselectAll}
|
||||
className="pack-select-all-button"
|
||||
>
|
||||
Снять выбор
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
onClick={handleSelectAll}
|
||||
className="pack-select-all-button"
|
||||
>
|
||||
Выбрать все ({filteredPackQuestions.length})
|
||||
</button>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={handleImportSelected}
|
||||
disabled={selectedQuestionIndices.size === 0}
|
||||
|
|
@ -589,21 +688,75 @@ const GameManagementModal = ({
|
|||
</div>
|
||||
|
||||
<div className="pack-questions-items">
|
||||
{packQuestions.map((q, idx) => (
|
||||
<div key={idx} className="pack-question-item">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={selectedQuestionIndices.has(idx)}
|
||||
onChange={() => handleToggleQuestion(idx)}
|
||||
/>
|
||||
<div className="pack-question-content">
|
||||
<strong>{q.text}</strong>
|
||||
<span className="pack-question-info">
|
||||
{q.answers.length} ответов
|
||||
</span>
|
||||
</div>
|
||||
{filteredPackQuestions.length === 0 ? (
|
||||
<div className="pack-no-results">
|
||||
{searchQuery ? 'Вопросы не найдены' : 'Нет вопросов в паке'}
|
||||
</div>
|
||||
))}
|
||||
) : (
|
||||
filteredPackQuestions.map((q, filteredIdx) => {
|
||||
const originalIndex = packQuestions.findIndex(pq => pq === q)
|
||||
return (
|
||||
<div key={originalIndex} className="pack-question-item">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={selectedQuestionIndices.has(originalIndex)}
|
||||
onChange={() => handleToggleQuestion(originalIndex)}
|
||||
/>
|
||||
<div className="pack-question-content">
|
||||
<strong>{q.text || q.question}</strong>
|
||||
<span className="pack-question-info">
|
||||
{q.answers?.length || 0} ответов
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => handleViewQuestion(q)}
|
||||
className="pack-view-question-button"
|
||||
title="Просмотр вопроса"
|
||||
>
|
||||
👁
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Модальное окно просмотра вопроса */}
|
||||
{viewingQuestion && (
|
||||
<div className="pack-question-viewer-backdrop" onClick={handleCloseViewer}>
|
||||
<div className="pack-question-viewer" onClick={(e) => e.stopPropagation()}>
|
||||
<div className="pack-question-viewer-header">
|
||||
<h4>Просмотр вопроса</h4>
|
||||
<button
|
||||
className="pack-question-viewer-close"
|
||||
onClick={handleCloseViewer}
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
<div className="pack-question-viewer-content">
|
||||
<div className="pack-question-viewer-text">
|
||||
{viewingQuestion.text || viewingQuestion.question}
|
||||
</div>
|
||||
<button
|
||||
className="pack-show-answers-button"
|
||||
onClick={() => setShowAnswers(!showAnswers)}
|
||||
>
|
||||
{showAnswers ? '🙈 Скрыть ответы' : '👁 Показать ответы'}
|
||||
</button>
|
||||
{showAnswers && (
|
||||
<div className="pack-question-answers">
|
||||
{viewingQuestion.answers?.map((answer, idx) => (
|
||||
<div key={idx} className="pack-answer-item">
|
||||
<span className="pack-answer-text">{answer.text}</span>
|
||||
<span className="pack-answer-points">{answer.points} очков</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -582,6 +582,234 @@
|
|||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
/* Search */
|
||||
.pack-search-container {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.pack-search-input {
|
||||
width: 100%;
|
||||
padding: 12px 15px;
|
||||
border: 2px solid rgba(255, 215, 0, 0.3);
|
||||
border-radius: 8px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: #fff;
|
||||
font-size: 1rem;
|
||||
outline: none;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.pack-search-input::placeholder {
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.pack-search-input:focus {
|
||||
border-color: #ffd700;
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
box-shadow: 0 0 10px rgba(255, 215, 0, 0.3);
|
||||
}
|
||||
|
||||
/* Header improvements */
|
||||
.pack-questions-header-left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.pack-select-all-buttons {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.pack-select-all-button {
|
||||
padding: 8px 15px;
|
||||
background: rgba(78, 205, 196, 0.3);
|
||||
color: #4ecdc4;
|
||||
border: 2px solid rgba(78, 205, 196, 0.5);
|
||||
border-radius: 8px;
|
||||
font-size: 0.9rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.pack-select-all-button:hover {
|
||||
background: rgba(78, 205, 196, 0.5);
|
||||
border-color: #4ecdc4;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
/* View question button */
|
||||
.pack-view-question-button {
|
||||
padding: 8px 12px;
|
||||
background: rgba(102, 126, 234, 0.3);
|
||||
color: #667eea;
|
||||
border: 2px solid rgba(102, 126, 234, 0.5);
|
||||
border-radius: 8px;
|
||||
font-size: 1rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
flex-shrink: 0;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.pack-view-question-button:hover {
|
||||
background: rgba(102, 126, 234, 0.5);
|
||||
border-color: #667eea;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
/* No results */
|
||||
.pack-no-results {
|
||||
text-align: center;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
padding: 40px 20px;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
/* Question viewer modal */
|
||||
.pack-question-viewer-backdrop {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
backdrop-filter: blur(5px);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 2000;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.pack-question-viewer {
|
||||
background: rgba(20, 20, 30, 0.95);
|
||||
backdrop-filter: blur(20px);
|
||||
border-radius: 20px;
|
||||
padding: 25px;
|
||||
max-width: 600px;
|
||||
width: 100%;
|
||||
max-height: 80vh;
|
||||
overflow-y: auto;
|
||||
border: 2px solid rgba(255, 215, 0, 0.3);
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.pack-question-viewer-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 15px;
|
||||
border-bottom: 2px solid rgba(255, 215, 0, 0.2);
|
||||
}
|
||||
|
||||
.pack-question-viewer-header h4 {
|
||||
color: #ffd700;
|
||||
font-size: 1.5rem;
|
||||
margin: 0;
|
||||
text-shadow: 0 0 10px rgba(255, 215, 0, 0.5);
|
||||
}
|
||||
|
||||
.pack-question-viewer-close {
|
||||
background: rgba(255, 107, 107, 0.2);
|
||||
color: #ff6b6b;
|
||||
border: 2px solid rgba(255, 107, 107, 0.5);
|
||||
border-radius: 50%;
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
font-size: 1.5rem;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.3s ease;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.pack-question-viewer-close:hover {
|
||||
background: rgba(255, 107, 107, 0.4);
|
||||
border-color: #ff6b6b;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.pack-question-viewer-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.pack-question-viewer-text {
|
||||
color: #fff;
|
||||
font-size: 1.2rem;
|
||||
line-height: 1.6;
|
||||
padding: 15px;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 12px;
|
||||
border: 2px solid rgba(255, 215, 0, 0.2);
|
||||
}
|
||||
|
||||
.pack-show-answers-button {
|
||||
padding: 12px 20px;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.pack-show-answers-button:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
|
||||
}
|
||||
|
||||
.pack-question-answers {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.pack-answer-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 15px;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border: 2px solid rgba(255, 215, 0, 0.2);
|
||||
border-radius: 12px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.pack-answer-item:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-color: rgba(255, 215, 0, 0.4);
|
||||
}
|
||||
|
||||
.pack-answer-text {
|
||||
color: #fff;
|
||||
font-size: 1rem;
|
||||
flex: 1;
|
||||
word-wrap: break-word;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.pack-answer-points {
|
||||
color: #ffd700;
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
flex-shrink: 0;
|
||||
text-shadow: 0 0 5px rgba(255, 215, 0, 0.5);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.pack-import-section {
|
||||
padding: 15px;
|
||||
|
|
@ -593,8 +821,37 @@
|
|||
gap: 10px;
|
||||
}
|
||||
|
||||
.pack-questions-header-left {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.pack-import-confirm-button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.pack-question-item {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.pack-view-question-button {
|
||||
width: 100%;
|
||||
margin-left: 0;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.pack-question-viewer {
|
||||
padding: 20px;
|
||||
max-height: 90vh;
|
||||
}
|
||||
|
||||
.pack-answer-item {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.pack-answer-points {
|
||||
align-self: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ const QuestionsModal = ({
|
|||
const [packQuestions, setPackQuestions] = useState([])
|
||||
const [selectedQuestionIndices, setSelectedQuestionIndices] = useState(new Set())
|
||||
const [savingToRoom, setSavingToRoom] = useState(false)
|
||||
const [searchQuery, setSearchQuery] = useState('')
|
||||
const [viewingQuestion, setViewingQuestion] = useState(null)
|
||||
const [showAnswers, setShowAnswers] = useState(false)
|
||||
|
||||
if (!isOpen) return null
|
||||
|
||||
|
|
@ -207,6 +210,9 @@ const QuestionsModal = ({
|
|||
if (!packId) {
|
||||
setPackQuestions([])
|
||||
setSelectedPack(null)
|
||||
setSearchQuery('')
|
||||
setViewingQuestion(null)
|
||||
setShowAnswers(false)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -215,12 +221,70 @@ const QuestionsModal = ({
|
|||
setPackQuestions(response.data.questions || [])
|
||||
setSelectedPack(packId)
|
||||
setSelectedQuestionIndices(new Set())
|
||||
setSearchQuery('')
|
||||
setViewingQuestion(null)
|
||||
setShowAnswers(false)
|
||||
} catch (error) {
|
||||
console.error('Error fetching pack:', error)
|
||||
setJsonError('Ошибка загрузки пака вопросов')
|
||||
}
|
||||
}
|
||||
|
||||
// Фильтрация вопросов по поисковому запросу
|
||||
const filteredPackQuestions = packQuestions.filter((q) => {
|
||||
if (!searchQuery.trim()) return true
|
||||
const questionText = (q.text || q.question || '').toLowerCase()
|
||||
return questionText.includes(searchQuery.toLowerCase())
|
||||
})
|
||||
|
||||
// Выбор всех видимых вопросов
|
||||
const handleSelectAll = () => {
|
||||
const allVisibleIndices = new Set(
|
||||
filteredPackQuestions.map((q) => {
|
||||
const originalIndex = packQuestions.findIndex(pq => pq === q)
|
||||
return originalIndex
|
||||
}).filter(idx => idx !== -1)
|
||||
)
|
||||
const newSelected = new Set(selectedQuestionIndices)
|
||||
allVisibleIndices.forEach(idx => newSelected.add(idx))
|
||||
setSelectedQuestionIndices(newSelected)
|
||||
}
|
||||
|
||||
// Снятие выбора со всех видимых вопросов
|
||||
const handleDeselectAll = () => {
|
||||
const visibleIndices = new Set(
|
||||
filteredPackQuestions.map((q) => {
|
||||
const originalIndex = packQuestions.findIndex(pq => pq === q)
|
||||
return originalIndex
|
||||
}).filter(idx => idx !== -1)
|
||||
)
|
||||
const newSelected = new Set(selectedQuestionIndices)
|
||||
visibleIndices.forEach(idx => newSelected.delete(idx))
|
||||
setSelectedQuestionIndices(newSelected)
|
||||
}
|
||||
|
||||
// Проверка, выбраны ли все видимые вопросы
|
||||
const areAllVisibleSelected = () => {
|
||||
if (filteredPackQuestions.length === 0) return false
|
||||
const visibleIndices = filteredPackQuestions.map((q) => {
|
||||
const originalIndex = packQuestions.findIndex(pq => pq === q)
|
||||
return originalIndex
|
||||
}).filter(idx => idx !== -1)
|
||||
return visibleIndices.every(idx => selectedQuestionIndices.has(idx))
|
||||
}
|
||||
|
||||
// Просмотр вопроса
|
||||
const handleViewQuestion = (question) => {
|
||||
setViewingQuestion(question)
|
||||
setShowAnswers(false)
|
||||
}
|
||||
|
||||
// Закрытие просмотра вопроса
|
||||
const handleCloseViewer = () => {
|
||||
setViewingQuestion(null)
|
||||
setShowAnswers(false)
|
||||
}
|
||||
|
||||
const handleToggleQuestion = (index) => {
|
||||
const newSelected = new Set(selectedQuestionIndices)
|
||||
if (newSelected.has(index)) {
|
||||
|
|
@ -236,10 +300,10 @@ const QuestionsModal = ({
|
|||
const questionsToImport = indices.map(idx => packQuestions[idx]).filter(Boolean)
|
||||
|
||||
// Create deep copies
|
||||
const copiedQuestions = questionsToImport.map(q => ({
|
||||
id: Date.now() + Math.random(), // Generate new ID
|
||||
text: q.text,
|
||||
answers: q.answers.map(a => ({ text: a.text, points: a.points })),
|
||||
const copiedQuestions = questionsToImport.map((q, idx) => ({
|
||||
id: Date.now() + Math.random() + idx, // Generate new ID
|
||||
text: q.text || q.question || '',
|
||||
answers: (q.answers || []).map(a => ({ text: a.text, points: a.points })),
|
||||
}))
|
||||
|
||||
const updatedQuestions = [...questions, ...copiedQuestions]
|
||||
|
|
@ -247,6 +311,7 @@ const QuestionsModal = ({
|
|||
|
||||
// Reset
|
||||
setSelectedQuestionIndices(new Set())
|
||||
setSearchQuery('')
|
||||
setShowPackImport(false)
|
||||
setJsonError('')
|
||||
alert(`Импортировано ${copiedQuestions.length} вопросов`)
|
||||
|
|
@ -307,8 +372,42 @@ const QuestionsModal = ({
|
|||
|
||||
{packQuestions.length > 0 && (
|
||||
<div className="pack-questions-list">
|
||||
{/* Поиск */}
|
||||
<div className="pack-search-container">
|
||||
<input
|
||||
type="text"
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
placeholder="🔍 Поиск вопросов..."
|
||||
className="pack-search-input"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="pack-questions-header">
|
||||
<span>Выберите вопросы для импорта:</span>
|
||||
<div className="pack-questions-header-left">
|
||||
<span>Выберите вопросы для импорта:</span>
|
||||
<div className="pack-select-all-buttons">
|
||||
{filteredPackQuestions.length > 0 && (
|
||||
<>
|
||||
{areAllVisibleSelected() ? (
|
||||
<button
|
||||
onClick={handleDeselectAll}
|
||||
className="pack-select-all-button"
|
||||
>
|
||||
Снять выбор
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
onClick={handleSelectAll}
|
||||
className="pack-select-all-button"
|
||||
>
|
||||
Выбрать все ({filteredPackQuestions.length})
|
||||
</button>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={handleImportSelected}
|
||||
disabled={selectedQuestionIndices.size === 0}
|
||||
|
|
@ -319,21 +418,75 @@ const QuestionsModal = ({
|
|||
</div>
|
||||
|
||||
<div className="pack-questions-items">
|
||||
{packQuestions.map((q, idx) => (
|
||||
<div key={idx} className="pack-question-item">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={selectedQuestionIndices.has(idx)}
|
||||
onChange={() => handleToggleQuestion(idx)}
|
||||
/>
|
||||
<div className="pack-question-content">
|
||||
<strong>{q.text}</strong>
|
||||
<span className="pack-question-info">
|
||||
{q.answers.length} ответов
|
||||
</span>
|
||||
</div>
|
||||
{filteredPackQuestions.length === 0 ? (
|
||||
<div className="pack-no-results">
|
||||
{searchQuery ? 'Вопросы не найдены' : 'Нет вопросов в паке'}
|
||||
</div>
|
||||
))}
|
||||
) : (
|
||||
filteredPackQuestions.map((q, filteredIdx) => {
|
||||
const originalIndex = packQuestions.findIndex(pq => pq === q)
|
||||
return (
|
||||
<div key={originalIndex} className="pack-question-item">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={selectedQuestionIndices.has(originalIndex)}
|
||||
onChange={() => handleToggleQuestion(originalIndex)}
|
||||
/>
|
||||
<div className="pack-question-content">
|
||||
<strong>{q.text || q.question}</strong>
|
||||
<span className="pack-question-info">
|
||||
{q.answers?.length || 0} ответов
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => handleViewQuestion(q)}
|
||||
className="pack-view-question-button"
|
||||
title="Просмотр вопроса"
|
||||
>
|
||||
👁
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Модальное окно просмотра вопроса */}
|
||||
{viewingQuestion && (
|
||||
<div className="pack-question-viewer-backdrop" onClick={handleCloseViewer}>
|
||||
<div className="pack-question-viewer" onClick={(e) => e.stopPropagation()}>
|
||||
<div className="pack-question-viewer-header">
|
||||
<h4>Просмотр вопроса</h4>
|
||||
<button
|
||||
className="pack-question-viewer-close"
|
||||
onClick={handleCloseViewer}
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
<div className="pack-question-viewer-content">
|
||||
<div className="pack-question-viewer-text">
|
||||
{viewingQuestion.text || viewingQuestion.question}
|
||||
</div>
|
||||
<button
|
||||
className="pack-show-answers-button"
|
||||
onClick={() => setShowAnswers(!showAnswers)}
|
||||
>
|
||||
{showAnswers ? '🙈 Скрыть ответы' : '👁 Показать ответы'}
|
||||
</button>
|
||||
{showAnswers && (
|
||||
<div className="pack-question-answers">
|
||||
{viewingQuestion.answers?.map((answer, idx) => (
|
||||
<div key={idx} className="pack-answer-item">
|
||||
<span className="pack-answer-text">{answer.text}</span>
|
||||
<span className="pack-answer-points">{answer.points} очков</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
Loading…
Reference in a new issue