feat(falukant): enhance notification handling and localization updates
All checks were successful
Deploy to production / deploy (push) Successful in 2m52s
All checks were successful
Deploy to production / deploy (push) Successful in 2m52s
- Updated the `enrichNotificationsWithCharacterNames` method in FalukantService to include region name enrichment and handle additional character IDs. - Introduced a new `serializeNotificationForClient` function to format notifications for the client, ensuring all relevant data is included. - Enhanced the MessagesDialog component to merge notification payloads and extract parameters more effectively, improving the clarity of displayed messages. - Added new localization entries for director resignation risk and regional festival effects in multiple languages, ensuring comprehensive user notifications.
This commit is contained in:
@@ -7328,7 +7328,7 @@ ORDER BY r.id`,
|
||||
// Enrich notifications: parse JSON payloads and resolve character names
|
||||
await enrichNotificationsWithCharacterNames(notifications);
|
||||
|
||||
return notifications;
|
||||
return notifications.map(serializeNotificationForClient);
|
||||
}
|
||||
|
||||
async getAllNotifications(hashedUserId, page = 1, size = 10) {
|
||||
@@ -7344,7 +7344,12 @@ ORDER BY r.id`,
|
||||
|
||||
await enrichNotificationsWithCharacterNames(rows);
|
||||
|
||||
return { items: rows, total: count, page: Number(page) || 1, size: limit };
|
||||
return {
|
||||
items: rows.map(serializeNotificationForClient),
|
||||
total: count,
|
||||
page: Number(page) || 1,
|
||||
size: limit,
|
||||
};
|
||||
}
|
||||
|
||||
async markNotificationsShown(hashedUserId) {
|
||||
@@ -8536,6 +8541,14 @@ ORDER BY r.id`,
|
||||
|
||||
export default new FalukantService();
|
||||
|
||||
/** Stellt sicher, dass Anreicherungen (z. B. region_name ohne DB-Spalte) im API-JSON landen. */
|
||||
function serializeNotificationForClient(row) {
|
||||
const j = typeof row.toJSON === 'function' ? row.toJSON() : { ...row };
|
||||
const dv = row.dataValues || {};
|
||||
if (dv.region_name != null && j.region_name == null) j.region_name = dv.region_name;
|
||||
return j;
|
||||
}
|
||||
|
||||
// Helper: parse notifications for character references and attach characterName
|
||||
async function enrichNotificationsWithCharacterNames(notifications) {
|
||||
if (!Array.isArray(notifications) || notifications.length === 0) return;
|
||||
@@ -8552,7 +8565,7 @@ async function enrichNotificationsWithCharacterNames(notifications) {
|
||||
if (typeof obj !== 'object') return;
|
||||
for (const [k, v] of Object.entries(obj)) {
|
||||
if (!v) continue;
|
||||
if (k === 'character_id' || k === 'characterId') {
|
||||
if (k === 'character_id' || k === 'characterId' || k === 'director_character_id') {
|
||||
charIds.add(Number(v));
|
||||
continue;
|
||||
}
|
||||
@@ -8567,15 +8580,25 @@ async function enrichNotificationsWithCharacterNames(notifications) {
|
||||
}
|
||||
}
|
||||
|
||||
// First pass: collect all referenced character ids from notifications
|
||||
const regionIds = new Set();
|
||||
|
||||
// First pass: collect all referenced character ids and region ids from notifications
|
||||
for (const n of notifications) {
|
||||
// parse n.tr if it's JSON
|
||||
let parsed = null;
|
||||
try {
|
||||
if (typeof n.tr === 'string' && n.tr.trim().startsWith('{')) {
|
||||
const parsed = JSON.parse(n.tr);
|
||||
parsed = JSON.parse(n.tr);
|
||||
collectIds(parsed);
|
||||
} else if (n.tr && typeof n.tr === 'object') {
|
||||
parsed = n.tr;
|
||||
collectIds(parsed);
|
||||
}
|
||||
} catch (err) { /* ignore */ }
|
||||
} catch (err) {
|
||||
parsed = null;
|
||||
}
|
||||
if (parsed?.region_id != null) {
|
||||
regionIds.add(Number(parsed.region_id));
|
||||
}
|
||||
|
||||
// parse n.effects if present
|
||||
try {
|
||||
@@ -8591,24 +8614,34 @@ async function enrichNotificationsWithCharacterNames(notifications) {
|
||||
}
|
||||
|
||||
const ids = Array.from(charIds).filter(Boolean);
|
||||
if (!ids.length) return;
|
||||
|
||||
// Batch load characters and their display names
|
||||
const characters = await FalukantCharacter.findAll({
|
||||
where: { id: { [Op.in]: ids } },
|
||||
include: [
|
||||
{ model: FalukantPredefineFirstname, as: 'definedFirstName', attributes: ['name'] },
|
||||
{ model: FalukantPredefineLastname, as: 'definedLastName', attributes: ['name'] }
|
||||
],
|
||||
attributes: ['id']
|
||||
});
|
||||
const regionIdList = Array.from(regionIds).filter((id) => Number.isFinite(id));
|
||||
if (!ids.length && !regionIdList.length) return;
|
||||
|
||||
const nameMap = new Map();
|
||||
for (const c of characters) {
|
||||
const first = c.definedFirstName?.name || '';
|
||||
const last = c.definedLastName?.name || '';
|
||||
const display = `${first} ${last}`.trim() || null;
|
||||
nameMap.set(Number(c.id), display || `#${c.id}`);
|
||||
if (ids.length) {
|
||||
const characters = await FalukantCharacter.findAll({
|
||||
where: { id: { [Op.in]: ids } },
|
||||
include: [
|
||||
{ model: FalukantPredefineFirstname, as: 'definedFirstName', attributes: ['name'] },
|
||||
{ model: FalukantPredefineLastname, as: 'definedLastName', attributes: ['name'] }
|
||||
],
|
||||
attributes: ['id']
|
||||
});
|
||||
|
||||
for (const c of characters) {
|
||||
const first = c.definedFirstName?.name || '';
|
||||
const last = c.definedLastName?.name || '';
|
||||
const display = `${first} ${last}`.trim() || null;
|
||||
nameMap.set(Number(c.id), display || `#${c.id}`);
|
||||
}
|
||||
}
|
||||
let regionNameById = new Map();
|
||||
if (regionIdList.length) {
|
||||
const regions = await RegionData.findAll({
|
||||
where: { id: { [Op.in]: regionIdList } },
|
||||
attributes: ['id', 'name'],
|
||||
});
|
||||
regionNameById = new Map(regions.map((r) => [Number(r.id), r.name]));
|
||||
}
|
||||
|
||||
// helper to find first character id in an object
|
||||
@@ -8625,6 +8658,7 @@ async function enrichNotificationsWithCharacterNames(notifications) {
|
||||
for (const [k, v] of Object.entries(obj)) {
|
||||
if (!v) continue;
|
||||
if (k === 'character_id' || k === 'characterId') return Number(v);
|
||||
if (k === 'director_character_id') return Number(v);
|
||||
if (k === 'character' && typeof v === 'object') {
|
||||
if (v.id) return Number(v.id);
|
||||
const r = findFirstId(v);
|
||||
@@ -8638,10 +8672,23 @@ async function enrichNotificationsWithCharacterNames(notifications) {
|
||||
|
||||
// Attach resolved name to notifications (set character_name; characterName is a getter that reads from it)
|
||||
for (const n of notifications) {
|
||||
let foundId = null;
|
||||
let parsed = null;
|
||||
try {
|
||||
if (typeof n.tr === 'string' && n.tr.trim().startsWith('{')) {
|
||||
const parsed = JSON.parse(n.tr);
|
||||
parsed = JSON.parse(n.tr);
|
||||
} else if (n.tr && typeof n.tr === 'object') {
|
||||
parsed = n.tr;
|
||||
}
|
||||
} catch (err) {
|
||||
parsed = null;
|
||||
}
|
||||
|
||||
let foundId = null;
|
||||
if (parsed?.director_character_id != null) {
|
||||
foundId = Number(parsed.director_character_id);
|
||||
}
|
||||
try {
|
||||
if (!foundId && parsed) {
|
||||
foundId = findFirstId(parsed) || foundId;
|
||||
}
|
||||
} catch (err) { /* ignore */ }
|
||||
@@ -8661,5 +8708,11 @@ async function enrichNotificationsWithCharacterNames(notifications) {
|
||||
// Set character_name directly (characterName is a getter that reads from character_name)
|
||||
n.character_name = resolved;
|
||||
}
|
||||
|
||||
if (parsed?.region_id != null && regionNameById.has(Number(parsed.region_id))) {
|
||||
const rn = regionNameById.get(Number(parsed.region_id));
|
||||
// Kein DB-Feld: explizit in dataValues setzen, damit toJSON() es mitschickt
|
||||
if (n.dataValues) n.dataValues.region_name = rn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user