diff --git a/backend/src/controllers/petController.js b/backend/src/controllers/petController.js index 0309df9..5799e15 100644 --- a/backend/src/controllers/petController.js +++ b/backend/src/controllers/petController.js @@ -1,6 +1,36 @@ 'use strict'; const db = require('../db/db'); const { awardCoins } = require('./gamificationController'); +const { ACHIEVEMENT_DEFS } = require('./gamification/_shared'); + +/* ── XP-log reason → человекочитаемый ярлык для ленты активности питомца ── + Сырые коды причин (`achievement:slug`, `tb:...`, `lesson_complete`, …) + не должны попадать в UID — резолвим их в понятные подписи. */ +const SOURCE_LABELS = { + hangman_win: 'Виселица', crossword_win: 'Кроссворд', + test_answer: 'Тест', challenge: 'Задание', + lab_activity: 'Лаборатория', lab_experiment: 'Лаборатория', + assignment: 'Домашнее задание', + pet_petting: 'Поглаживание', pet_feeding: 'Кормёжка питомца', + mood_ecstatic: 'Бонус настроения', correct_answers: 'Тест', + test_complete: 'Тест', 'test_90+': 'Тест 90%+', test_perfect: 'Тест 100%', + daily_activity: 'Активность дня', daily_goal: 'Цель дня', + lesson_complete: 'Урок пройден', +}; +const _ACH_TITLE = new Map(ACHIEVEMENT_DEFS.map(a => [a.slug, a.title])); + +function _xpReasonLabel(reason) { + if (!reason) return 'Награда'; + if (reason.startsWith('achievement:')) { + const t = _ACH_TITLE.get(reason.slice('achievement:'.length)); + return t ? `Достижение «${t}»` : 'Достижение'; + } + if (reason.startsWith('tb:')) return 'Учебник'; + if (SOURCE_LABELS[reason]) return SOURCE_LABELS[reason]; + // Уже читаемая фраза (например «Испытание: …») — содержит пробел/кириллицу. + if (/[А-Яа-яЁё ]/.test(reason)) return reason; + return 'Награда'; +} const BG_SHOP = [ { id:'space', name:'Космос', price:50, desc:'Звёздный простор' }, @@ -115,19 +145,11 @@ function getPet(req, res) { weeklyXP.push({ day: d.toLocaleDateString('ru', { weekday: 'short' }), xp: weekMap.get(dateStr) || 0 }); } - const SOURCE_LABELS = { - hangman_win: 'Виселица', crossword_win: 'Кроссворд', - test_answer: 'Тест', challenge: 'Задание', - lab_activity: 'Лаборатория', assignment: 'Домашнее задание', - pet_petting: 'Поглаживание', pet_feeding: 'Кормёжка питомца', - mood_ecstatic: 'Бонус настроения', correct_answers: 'Тест', - test_complete: 'Тест', 'test_90+': 'Тест 90%+', test_perfect: 'Тест 100%', - }; const rawActivity = db.prepare( "SELECT amount, reason, created_at FROM xp_log WHERE user_id = ? ORDER BY created_at DESC LIMIT 6" ).all(req.user.id); const recentActivity = rawActivity.map(r => ({ - xp: r.amount, label: SOURCE_LABELS[r.reason] || r.reason, at: r.created_at, + xp: r.amount, label: _xpReasonLabel(r.reason), at: r.created_at, })); const pettingCooldown = user.pet_last_petted