- Implemented Znakopis page with document and sentence CRUD operations - Added backend routes for documents and sentences - Created UI components for sentence editing and display - Added sentence store for state management - Integrated select component for document selection - Updated README with Phase 3 completion status - Removed obsolete fix-colors.md file
111 lines
2.9 KiB
TypeScript
111 lines
2.9 KiB
TypeScript
import { useState, useEffect } from 'react';
|
|
import { Layout } from '../components/layout/Layout';
|
|
import { FilterBar } from '../components/dictionary/FilterBar';
|
|
import { WordGrid } from '../components/dictionary/WordGrid';
|
|
import { WordDetailModal } from '../components/dictionary/WordDetailModal';
|
|
import { Term, TermFilters } from '../types/term';
|
|
import { fetchTerms } from '../lib/termApi';
|
|
import { useSentenceStore } from '../stores/sentenceStore';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import { toast } from 'sonner';
|
|
|
|
function Dictionary() {
|
|
const navigate = useNavigate();
|
|
const addToken = useSentenceStore((state) => state.addToken);
|
|
|
|
const [terms, setTerms] = useState<Term[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
const [selectedTerm, setSelectedTerm] = useState<Term | null>(null);
|
|
const [filters, setFilters] = useState<TermFilters>({
|
|
query: '',
|
|
wordType: '',
|
|
cefrLevel: '',
|
|
page: 1,
|
|
limit: 20,
|
|
});
|
|
const [pagination, setPagination] = useState({
|
|
page: 1,
|
|
limit: 20,
|
|
total: 0,
|
|
totalPages: 0,
|
|
});
|
|
|
|
useEffect(() => {
|
|
loadTerms();
|
|
}, [filters]);
|
|
|
|
const loadTerms = async () => {
|
|
try {
|
|
setLoading(true);
|
|
const response = await fetchTerms(filters);
|
|
setTerms(response.terms);
|
|
setPagination(response.pagination);
|
|
} catch (error) {
|
|
console.error('Failed to load terms:', error);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
const handleFilterChange = (newFilters: TermFilters) => {
|
|
setFilters(newFilters);
|
|
};
|
|
|
|
const handlePageChange = (page: number) => {
|
|
setFilters({ ...filters, page });
|
|
};
|
|
|
|
const handleTermInfo = (term: Term) => {
|
|
setSelectedTerm(term);
|
|
};
|
|
|
|
const handleAddToSentence = (term: Term) => {
|
|
addToken(term);
|
|
toast.success(`Dodano: "${term.wordText}"`, {
|
|
description: 'Riječ je dodana u rečenicu. Idite na Znakopis za uređivanje.',
|
|
action: {
|
|
label: 'Idi na Znakopis',
|
|
onClick: () => navigate('/znakopis'),
|
|
},
|
|
});
|
|
};
|
|
|
|
return (
|
|
<Layout>
|
|
<div className="space-y-6">
|
|
{/* Header */}
|
|
<div>
|
|
<h1 className="text-3xl font-bold text-gray-900 mb-2">Rječnik</h1>
|
|
<p className="text-gray-600">
|
|
Pretražite i pregledajte hrvatski znakovni jezik
|
|
</p>
|
|
</div>
|
|
|
|
{/* Filters */}
|
|
<FilterBar filters={filters} onFilterChange={handleFilterChange} />
|
|
|
|
{/* Word Grid */}
|
|
<WordGrid
|
|
terms={terms}
|
|
loading={loading}
|
|
onInfo={handleTermInfo}
|
|
onAddToSentence={handleAddToSentence}
|
|
pagination={pagination}
|
|
onPageChange={handlePageChange}
|
|
/>
|
|
|
|
{/* Word Detail Modal */}
|
|
<WordDetailModal
|
|
term={selectedTerm}
|
|
open={!!selectedTerm}
|
|
onClose={() => setSelectedTerm(null)}
|
|
onAddToSentence={handleAddToSentence}
|
|
/>
|
|
</div>
|
|
</Layout>
|
|
);
|
|
}
|
|
|
|
export default Dictionary;
|
|
|