Files
play-life/play-life-web/src/components/AddWords.jsx

166 lines
4.8 KiB
React
Raw Normal View History

2025-12-29 20:01:55 +03:00
import React, { useState } from 'react'
import { useAuth } from './auth/AuthContext'
2025-12-29 20:01:55 +03:00
import './AddWords.css'
const API_URL = '/api'
function AddWords({ onNavigate, dictionaryId, dictionaryName }) {
const { authFetch } = useAuth()
2025-12-29 20:01:55 +03:00
const [markdownText, setMarkdownText] = useState('')
const [message, setMessage] = useState('')
const [loading, setLoading] = useState(false)
// Hide add button if dictionary name is not set
const canAddWords = dictionaryName && dictionaryName.trim() !== ''
const parseMarkdownTable = (text) => {
const lines = text.split('\n')
const words = []
let foundTable = false
let headerFound = false
for (let i = 0; i < lines.length; i++) {
const line = lines[i].trim()
// Skip empty lines
if (!line) continue
// Look for table start (markdown table with |)
if (line.includes('|') && line.includes('Слово')) {
foundTable = true
headerFound = true
continue
}
// Skip separator line (|---|---|)
if (foundTable && line.match(/^\|[\s\-|:]+\|$/)) {
continue
}
// Parse table rows
if (foundTable && headerFound && line.includes('|')) {
const cells = line
.split('|')
.map(cell => (cell || '').trim())
.filter(cell => cell && cell.length > 0)
if (cells.length >= 2) {
// Remove markdown formatting (**bold**, etc.)
const word = cells[0].replace(/\*\*/g, '').trim()
const translation = cells[1].replace(/\*\*/g, '').trim()
if (word && translation) {
words.push({
name: word,
translation: translation,
description: ''
})
}
}
}
}
return words
}
const handleSubmit = async (e) => {
e.preventDefault()
setMessage('')
setLoading(true)
try {
const words = parseMarkdownTable(markdownText)
if (words.length === 0) {
setMessage('Не удалось найти слова в таблице. Убедитесь, что таблица содержит колонки "Слово" и "Перевод".')
setLoading(false)
return
}
// Add dictionary_id to each word if dictionaryId is provided
const wordsWithDictionary = words.map(word => ({
...word,
dictionary_id: dictionaryId !== undefined && dictionaryId !== null ? dictionaryId : undefined
}))
const response = await authFetch(`${API_URL}/words`, {
2025-12-29 20:01:55 +03:00
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ words: wordsWithDictionary }),
})
if (!response.ok) {
throw new Error('Ошибка при добавлении слов')
}
const data = await response.json()
const addedCount = data?.added || 0
setMessage(`Успешно добавлено ${addedCount} слов(а)!`)
setMarkdownText('')
} catch (error) {
setMessage(`Ошибка: ${error.message}`)
} finally {
setLoading(false)
}
}
const handleClose = () => {
onNavigate?.('words', dictionaryId !== undefined && dictionaryId !== null ? { dictionaryId } : {})
}
return (
<div className="add-words">
<button className="close-x-button" onClick={handleClose}>
</button>
<h2>Добавить слова</h2>
<p className="description">
Вставьте текст в формате Markdown с таблицей, содержащей колонки "Слово" и "Перевод"
</p>
<form onSubmit={handleSubmit}>
<textarea
className="markdown-input"
value={markdownText}
onChange={(e) => setMarkdownText(e.target.value)}
placeholder={`Вот таблица, содержащая только слова и их перевод:
| Слово (Word) | Перевод |
| --- | --- |
| **Adventure** | Приключение |
| **Challenge** | Вызов, сложная задача |
| **Decision** | Решение |`}
rows={15}
/>
{canAddWords && (
<button
type="submit"
className="submit-button"
disabled={loading || !markdownText.trim()}
>
{loading ? 'Добавление...' : 'Добавить слова'}
</button>
)}
{!canAddWords && (
<div className="message error">
Сначала установите название словаря на экране списка слов
</div>
)}
</form>
{message && (
<div className={`message ${message.includes('Ошибка') ? 'error' : 'success'}`}>
{message}
</div>
)}
</div>
)
}
export default AddWords