Sprint 15: Suche, Ausweis, Teilen, Widget
- Volltext-Suche im Tagebuch (LIKE über Titel/Text/Tags, Debounce 350ms)
- Digitaler Heimtierausweis als druckbare HTML-Seite (/ausweis/{dog_id})
Enthält Impfungen, Medikamente, Allergien, Tierärzte, Chip-Nr.
- Hund teilen: Einladungslink-System (dog_shares-Tabelle, /teilen/{token})
Geteilte Hunde erscheinen in der Hundeliste, Tagebuch/Gesundheit lesbar
- Widget-Seite /#widget: zufälliges Tagebuchbild + nächste Erinnerung
Als PWA-Shortcut im Manifest verankert
- SW-Cache by-v144, APP_VER 117
This commit is contained in:
parent
d5f09cd16b
commit
34f29f9d0a
16 changed files with 917 additions and 35 deletions
|
|
@ -9,11 +9,12 @@ window.Page_diary = (() => {
|
|||
// ----------------------------------------------------------
|
||||
// MODUL-STATE
|
||||
// ----------------------------------------------------------
|
||||
let _container = null;
|
||||
let _appState = null;
|
||||
let _entries = [];
|
||||
let _offset = 0;
|
||||
const LIMIT = 20;
|
||||
let _container = null;
|
||||
let _appState = null;
|
||||
let _entries = [];
|
||||
let _offset = 0;
|
||||
let _searchQuery = '';
|
||||
const LIMIT = 20;
|
||||
|
||||
const TYPEN = {
|
||||
eintrag: { label: 'Eintrag', icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#book-open"></use></svg>' },
|
||||
|
|
@ -53,9 +54,9 @@ window.Page_diary = (() => {
|
|||
// ON DOG CHANGE — vom Header-Switcher ausgelöst
|
||||
// ----------------------------------------------------------
|
||||
async function onDogChange(dog) {
|
||||
_offset = 0;
|
||||
_entries = [];
|
||||
// Direkt Diary laden — Hund wurde bereits extern gewählt
|
||||
_offset = 0;
|
||||
_entries = [];
|
||||
_searchQuery = '';
|
||||
await _renderDiary();
|
||||
}
|
||||
|
||||
|
|
@ -136,9 +137,13 @@ window.Page_diary = (() => {
|
|||
async function _renderDiary() {
|
||||
_container.innerHTML = `
|
||||
<div class="by-toolbar diary-toolbar">
|
||||
<button class="btn btn-secondary btn-sm" id="diary-import-btn">
|
||||
<div class="diary-search-wrap" id="diary-search-wrap">
|
||||
<svg class="ph-icon diary-search-icon" aria-hidden="true"><use href="/icons/phosphor.svg#magnifying-glass"></use></svg>
|
||||
<input type="search" class="diary-search-input" id="diary-search-input"
|
||||
placeholder="Einträge durchsuchen…" autocomplete="off">
|
||||
</div>
|
||||
<button class="btn btn-secondary btn-sm" id="diary-import-btn" title="Importieren">
|
||||
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#download-simple"></use></svg>
|
||||
Importieren
|
||||
</button>
|
||||
</div>
|
||||
<div id="diary-list"></div>
|
||||
|
|
@ -152,6 +157,20 @@ window.Page_diary = (() => {
|
|||
_container.querySelector('#diary-btn-more')
|
||||
?.addEventListener('click', () => _loadMore());
|
||||
|
||||
// Suche mit Debounce
|
||||
let _searchTimer = null;
|
||||
_container.querySelector('#diary-search-input')
|
||||
?.addEventListener('input', e => {
|
||||
clearTimeout(_searchTimer);
|
||||
_searchTimer = setTimeout(async () => {
|
||||
_offset = 0;
|
||||
_entries = [];
|
||||
_searchQuery = e.target.value.trim();
|
||||
await _load();
|
||||
_renderList();
|
||||
}, 350);
|
||||
});
|
||||
|
||||
await _load();
|
||||
_renderList();
|
||||
}
|
||||
|
|
@ -163,7 +182,9 @@ window.Page_diary = (() => {
|
|||
const dog = _appState.activeDog;
|
||||
if (!dog) return;
|
||||
try {
|
||||
const batch = await API.diary.list(dog.id, { limit: LIMIT, offset: _offset });
|
||||
const params = { limit: LIMIT, offset: _offset };
|
||||
if (_searchQuery) params.q = _searchQuery;
|
||||
const batch = await API.diary.list(dog.id, params);
|
||||
_entries = _entries.concat(batch);
|
||||
|
||||
// "Mehr laden" anzeigen wenn volle Page geladen wurde
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue