Add search functionality for vocabulary in VocabController and VocabService

- Implemented a new searchVocabs method in VocabService to allow users to search for vocabulary based on learning and mother tongue terms.
- Updated VocabController to include the searchVocabs method wrapped with user authentication.
- Added a new route in vocabRouter for searching vocabulary by language ID.
- Enhanced VocabChapterView and VocabLanguageView components to include a button for opening the search dialog.
- Added translations for search-related terms in both German and English locales, improving user accessibility.
This commit is contained in:
Torsten Schulz (local)
2026-01-05 16:53:38 +01:00
parent dab3391aa2
commit f5e3a9a4a2
8 changed files with 266 additions and 1 deletions

View File

@@ -408,6 +408,52 @@ export default class VocabService {
return { languageId: access.id, isOwner: access.isOwner, vocabs: rows };
}
async searchVocabs(hashedUserId, languageId, { learning = '', motherTongue = '' } = {}) {
const user = await this._getUserByHashedId(hashedUserId);
const access = await this._getLanguageAccess(user.id, languageId);
const learningTerm = typeof learning === 'string' ? learning.trim() : '';
const motherTerm = typeof motherTongue === 'string' ? motherTongue.trim() : '';
if (!learningTerm && !motherTerm) {
const err = new Error('Missing search term');
err.status = 400;
throw err;
}
const learningLike = learningTerm ? `%${learningTerm}%` : null;
const motherLike = motherTerm ? `%${motherTerm}%` : null;
const rows = await sequelize.query(
`
SELECT
cl.id,
c.id AS "chapterId",
c.title AS "chapterTitle",
l1.text AS "learning",
l2.text AS "motherTongue"
FROM community.vocab_chapter_lexeme cl
JOIN community.vocab_chapter c ON c.id = cl.chapter_id
JOIN community.vocab_lexeme l1 ON l1.id = cl.learning_lexeme_id
JOIN community.vocab_lexeme l2 ON l2.id = cl.reference_lexeme_id
WHERE c.language_id = :languageId
AND (:learningLike IS NULL OR l1.text ILIKE :learningLike)
AND (:motherLike IS NULL OR l2.text ILIKE :motherLike)
ORDER BY l2.text ASC, l1.text ASC, c.title ASC
LIMIT 200
`,
{
replacements: {
languageId: access.id,
learningLike,
motherLike,
},
type: sequelize.QueryTypes.SELECT,
}
);
return { languageId: access.id, results: rows };
}
async addVocabToChapter(hashedUserId, chapterId, { learning, reference }) {
const user = await this._getUserByHashedId(hashedUserId);
const ch = await this._getChapterAccess(user.id, chapterId);