import React, { useState, useEffect } from 'react' import { useAuth } from './auth/AuthContext' import LoadingError from './LoadingError' import './WordList.css' const API_URL = '/api' function WordList({ onNavigate, dictionaryId, isNewDictionary, refreshTrigger = 0 }) { const { authFetch } = useAuth() const [words, setWords] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState('') const [dictionary, setDictionary] = useState(null) const [dictionaryName, setDictionaryName] = useState('') const [originalDictionaryName, setOriginalDictionaryName] = useState('') const [isSavingName, setIsSavingName] = useState(false) const [selectedWord, setSelectedWord] = useState(null) // Normalize undefined to null for clarity: new dictionary if dictionaryId is null or undefined const [currentDictionaryId, setCurrentDictionaryId] = useState(dictionaryId ?? null) // isNewDict is computed from currentDictionaryId: new dictionary if currentDictionaryId == null const isNewDict = currentDictionaryId == null // Helper function to check if dictionary exists and is not new const hasValidDictionary = (dictId) => { return dictId !== undefined && dictId !== null } useEffect(() => { // Normalize undefined to null: if dictionaryId is undefined, treat it as null (new dictionary) const normalizedDictionaryId = dictionaryId ?? null setCurrentDictionaryId(normalizedDictionaryId) if (normalizedDictionaryId == null) { setLoading(false) setDictionary(null) setDictionaryName('') setOriginalDictionaryName('') setWords([]) } else if (hasValidDictionary(normalizedDictionaryId)) { fetchDictionary(normalizedDictionaryId) fetchWords(normalizedDictionaryId) } else { setLoading(false) setWords([]) } }, [dictionaryId, refreshTrigger]) const fetchDictionary = async (dictId) => { try { const response = await authFetch(`${API_URL}/dictionaries`) if (!response.ok) { throw new Error('Ошибка при загрузке словарей') } const dictionaries = await response.json() const dict = dictionaries.find(d => d.id === dictId) if (dict) { setDictionary(dict) setDictionaryName(dict.name) setOriginalDictionaryName(dict.name) } } catch (err) { console.error('Error fetching dictionary:', err) } } const fetchWords = async (dictId) => { if (!hasValidDictionary(dictId)) { setWords([]) setLoading(false) return } await fetchWordsForDictionary(dictId) } const fetchWordsForDictionary = async (dictId) => { try { setLoading(true) const url = `${API_URL}/words?dictionary_id=${dictId}` const response = await authFetch(url) if (!response.ok) { throw new Error('Ошибка при загрузке слов') } const data = await response.json() setWords(Array.isArray(data) ? data : []) setError('') } catch (err) { setError(err.message) setWords([]) } finally { setLoading(false) } } const handleWordClick = (word) => { setSelectedWord(word) } const handleDeleteWord = async () => { if (!selectedWord) return if (!window.confirm('Вы уверены, что хотите удалить это слово?')) { return } try { const response = await authFetch(`${API_URL}/words/${selectedWord.id}`, { method: 'DELETE', }) if (!response.ok) { throw new Error('Ошибка при удалении слова') } // Remove word from local state setWords(words.filter(word => word.id !== selectedWord.id)) setSelectedWord(null) } catch (err) { setError(err.message) } } const handleResetProgress = async () => { if (!selectedWord) return if (!window.confirm('Вы уверены, что хотите сбросить прогресс этого слова?')) { return } try { const response = await authFetch(`${API_URL}/words/${selectedWord.id}/reset-progress`, { method: 'POST', }) if (!response.ok) { throw new Error('Ошибка при сбросе прогресса') } // Update word in local state - reset progress fields setWords(words.map(word => word.id === selectedWord.id ? { ...word, success: 0, failure: 0, last_success_at: null, last_failure_at: null } : word )) setSelectedWord(null) } catch (err) { setError(err.message) } } const handleNameChange = (e) => { setDictionaryName(e.target.value) } const handleNameSave = async () => { if (!dictionaryName.trim()) { return } setIsSavingName(true) try { if (!hasValidDictionary(currentDictionaryId)) { // Create new dictionary const response = await authFetch(`${API_URL}/dictionaries`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ name: dictionaryName.trim() }), }) if (!response.ok) { throw new Error('Ошибка при создании словаря') } const newDict = await response.json() const newDictionaryId = newDict.id // Update local state setOriginalDictionaryName(newDict.name) setDictionaryName(newDict.name) setDictionary(newDict) setCurrentDictionaryId(newDictionaryId) // Reinitialize screen: fetch dictionary info and words for the new dictionary await fetchDictionary(newDictionaryId) await fetchWordsForDictionary(newDictionaryId) // Update navigation to use the new dictionary ID and name (replace history entry so back goes to dictionaries) onNavigate?.('words', { dictionaryId: newDictionaryId, dictionaryName: newDict.name }, { replace: true }) } else if (hasValidDictionary(currentDictionaryId)) { // Update existing dictionary (rename) const response = await authFetch(`${API_URL}/dictionaries/${currentDictionaryId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ name: dictionaryName.trim() }), }) if (!response.ok) { throw new Error('Ошибка при обновлении словаря') } setOriginalDictionaryName(dictionaryName.trim()) if (dictionary) { setDictionary({ ...dictionary, name: dictionaryName.trim() }) } } } catch (err) { setError(err.message) } finally { setIsSavingName(false) } } // Show save button only if name is not empty and has changed const showSaveButton = dictionaryName.trim() !== '' && dictionaryName.trim() !== originalDictionaryName if (error && !loading) { return (
{ if (hasValidDictionary(currentDictionaryId)) { fetchWordsForDictionary(currentDictionaryId) } }} />
) } return (
{loading && (
Загрузка...
)} {/* Dictionary name input */}
{showSaveButton && ( )}
{/* Show add button and words list only if dictionaryId exists and is not new */} {hasValidDictionary(currentDictionaryId) && ( <> {(!words || words.length === 0) ? ( <>

Слов пока нет. Добавьте слова через экран "Добавить слова".

) : ( <>
{words.map((word) => (
handleWordClick(word)} >

{word.name}

{word.translation}
{word.description && (
{word.description}
)}
{word.success || 0} | {word.failure || 0}
))}
)} )} {/* Модальное окно для действий со словом */} {selectedWord && (
setSelectedWord(null)}>
e.stopPropagation()}>

{selectedWord.name}

)}
) } export default WordList