Fix: Benachrichtigungen navigieren jetzt in den richtigen Kontext
- App.callModule() öffentlich: navigiert + ruft Modul-Methode auf - chat_message → öffnet direkt den richtigen Chat-Thread (conversation_id) - friend_request → Freunde-Seite - walk_invite → Gassi-Treffen (+ page-Feld im Push-Payload ergänzt) - poison_alert → Giftköder-Seite - health_reminder → Gesundheit - _execNav() zentralisiert alle typ-spezifischen Navigationen
This commit is contained in:
parent
8386e20ca1
commit
f05ef9eeca
4 changed files with 90 additions and 23 deletions
|
|
@ -3,7 +3,7 @@
|
|||
Router, State-Management, Navigation, Initialisierung.
|
||||
============================================================ */
|
||||
|
||||
const APP_VER = '205'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
||||
const APP_VER = '206'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
||||
|
||||
const App = (() => {
|
||||
|
||||
|
|
@ -748,7 +748,13 @@ const App = (() => {
|
|||
// ÖFFENTLICHE API
|
||||
// (andere Module können App.state, App.navigate etc. nutzen)
|
||||
// ----------------------------------------------------------
|
||||
return { init, navigate, state, setActiveDog, renderDogSwitcher: _renderDogSwitcher,
|
||||
function callModule(pageId, method, ...args) {
|
||||
navigate(pageId);
|
||||
setTimeout(() => pages[pageId]?.module?.[method]?.(...args), 500);
|
||||
}
|
||||
|
||||
return { init, navigate, callModule, state, setActiveDog,
|
||||
renderDogSwitcher: _renderDogSwitcher,
|
||||
getInstallPrompt: () => _installPrompt, requireAuth,
|
||||
showOnboarding: _showOnboardingModal,
|
||||
updateNotifBadge: _updateNotifBadge };
|
||||
|
|
|
|||
|
|
@ -40,18 +40,60 @@ window.Page_notifications = (() => {
|
|||
try { return JSON.parse(raw); } catch (_) { return {}; }
|
||||
}
|
||||
|
||||
/** Ermittelt Ziel-Seite und optionale Label für den Toast */
|
||||
/**
|
||||
* Gibt { page, label, go } zurück.
|
||||
* go() führt die Navigation inklusive kontextspezifischer Aktion aus.
|
||||
*/
|
||||
function _navTarget(n) {
|
||||
const d = _parseData(n.data);
|
||||
// Explizit gesetzte Zielseite hat Vorrang
|
||||
if (d.page) return { page: d.page, label: d.page };
|
||||
// Typ-basiertes Fallback
|
||||
|
||||
switch (n.type) {
|
||||
case 'chat_message': return { page: d.conversation_id ? `chat?id=${d.conversation_id}` : 'chat', label: 'Chat' };
|
||||
case 'friend_request': return { page: 'friends', label: 'Freunde' };
|
||||
case 'milestone': return { page: 'diary', label: 'Tagebuch' };
|
||||
case 'poison_alert': return { page: 'map', label: 'Karte' };
|
||||
default: return { page: '', label: '' };
|
||||
case 'chat_message':
|
||||
return {
|
||||
page: 'chat', label: 'Chat',
|
||||
go: d.conversation_id
|
||||
? () => App.callModule('chat', '_openThread', d.conversation_id)
|
||||
: () => App.navigate('chat'),
|
||||
};
|
||||
|
||||
case 'friend_request':
|
||||
return {
|
||||
page: 'friends', label: 'Freunde',
|
||||
go: () => App.navigate('friends'),
|
||||
};
|
||||
|
||||
case 'walk_invite':
|
||||
return {
|
||||
page: 'walks', label: 'Gassi-Treffen',
|
||||
go: () => App.navigate('walks'),
|
||||
};
|
||||
|
||||
case 'poison_alert':
|
||||
return {
|
||||
page: 'poison', label: 'Giftköder-Alarm',
|
||||
go: () => App.navigate('poison'),
|
||||
};
|
||||
|
||||
case 'health_reminder':
|
||||
return {
|
||||
page: 'health', label: 'Gesundheit',
|
||||
go: () => App.navigate('health'),
|
||||
};
|
||||
|
||||
case 'milestone':
|
||||
return {
|
||||
page: 'diary', label: 'Tagebuch',
|
||||
go: () => App.navigate('diary'),
|
||||
};
|
||||
|
||||
default: {
|
||||
const page = d.page || '';
|
||||
return {
|
||||
page,
|
||||
label: page,
|
||||
go: page ? () => App.navigate(page) : null,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -61,9 +103,12 @@ window.Page_notifications = (() => {
|
|||
const iconName = unread ? _iconForType(n.type) : 'bell';
|
||||
const cls = ['notif-item', unread ? 'notif-unread' : ''].filter(Boolean).join(' ');
|
||||
const nav = _navTarget(n);
|
||||
// Nur serialisierbare Felder speichern (go ist eine Funktion, nicht serialisierbar)
|
||||
const navData = JSON.stringify({ page: nav.page, label: nav.label, type: n.type,
|
||||
data: _parseData(n.data) });
|
||||
|
||||
return `
|
||||
<div class="${cls}" data-id="${n.id}" data-page="${UI.escape(nav.page)}" data-nav-label="${UI.escape(nav.label)}">
|
||||
<div class="${cls}" data-id="${n.id}" data-nav="${UI.escape(navData)}">
|
||||
<span class="notif-icon">${UI.icon(iconName)}</span>
|
||||
<div class="notif-content">
|
||||
<div class="notif-title">${UI.escape(n.title)}</div>
|
||||
|
|
@ -77,6 +122,24 @@ window.Page_notifications = (() => {
|
|||
</div>`;
|
||||
}
|
||||
|
||||
/** Führt die kontextspezifische Navigation aus */
|
||||
function _execNav(nav) {
|
||||
switch (nav.type) {
|
||||
case 'chat_message':
|
||||
nav.data?.conversation_id
|
||||
? App.callModule('chat', '_openThread', nav.data.conversation_id)
|
||||
: App.navigate('chat');
|
||||
break;
|
||||
case 'friend_request': App.navigate('friends'); break;
|
||||
case 'walk_invite': App.navigate('walks'); break;
|
||||
case 'poison_alert': App.navigate('poison'); break;
|
||||
case 'health_reminder':App.navigate('health'); break;
|
||||
case 'milestone': App.navigate('diary'); break;
|
||||
default:
|
||||
if (nav.page) App.navigate(nav.page);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// init
|
||||
// ----------------------------------------------------------
|
||||
|
|
@ -141,23 +204,20 @@ window.Page_notifications = (() => {
|
|||
// Löschen-Button nicht doppelt behandeln
|
||||
if (e.target.closest('.notif-del-btn')) return;
|
||||
|
||||
const id = parseInt(el.dataset.id, 10);
|
||||
const page = el.dataset.page;
|
||||
const navLabel = el.dataset.navLabel;
|
||||
const id = parseInt(el.dataset.id, 10);
|
||||
const nav = JSON.parse(el.dataset.nav || '{}');
|
||||
|
||||
// Sofortiges visuelles Feedback: als gelesen markieren
|
||||
// Sofortiges visuelles Feedback
|
||||
el.classList.remove('notif-unread');
|
||||
el.style.opacity = '0.6';
|
||||
|
||||
// API-Call im Hintergrund — nicht abwarten
|
||||
// Als gelesen markieren (fire & forget)
|
||||
API.notifications.read(id).catch(() => {});
|
||||
|
||||
if (page && window.App?.navigate) {
|
||||
if (navLabel) UI.toast?.(`Öffne ${navLabel}…`, 'info');
|
||||
// Kurze Pause damit der Toast sichtbar wird, dann navigieren
|
||||
setTimeout(() => window.App.navigate(page), 150);
|
||||
if (nav.page) {
|
||||
if (nav.label) UI.toast?.(`Öffne ${nav.label}…`, 'info');
|
||||
setTimeout(() => _execNav(nav), 150);
|
||||
} else {
|
||||
// Keine Zielseite — Opacity nach kurzer Zeit zurücksetzen
|
||||
setTimeout(() => { el.style.opacity = ''; }, 800);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue