Initial commit
This commit is contained in:
163
play-life-web/src/components/AddWords.jsx
Normal file
163
play-life-web/src/components/AddWords.jsx
Normal file
@@ -0,0 +1,163 @@
|
||||
import React, { useState } from 'react'
|
||||
import './AddWords.css'
|
||||
|
||||
const API_URL = '/api'
|
||||
|
||||
function AddWords({ onNavigate, dictionaryId, dictionaryName }) {
|
||||
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 fetch(`${API_URL}/words`, {
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user