From 8a2e338e9d9a68cd03e1558631b23082a13fa200 Mon Sep 17 00:00:00 2001 From: neodk2004 Date: Sat, 18 Jul 2026 13:33:43 +0200 Subject: [PATCH] Sanfte Klapp-Animation, gestaffelte Interview-Fragen, Antragsdatum-Wheel - Akkordeon-Karten (rtable) animieren jetzt sanft statt abrupt: display:none/block durch max-height/opacity/padding-Transition ersetzt (display ist nicht transition-faehig, das war die Ursache des "Hau-Ruck"-Effekts). Per Mid-Transition-Screenshot verifiziert. - Interview Step 4 (Pflegealltag-Fragen) zeigt jetzt eine Frage nach der anderen statt einer langen Liste: neuWiz.q4sub trackt die Position, eigener duenner Fortschrittsbalken (.subdots) innerhalb des Schritts. Antwort-Klick rueckt automatisch zur naechsten Frage vor, ausser bei der letzten (dort erst per bewusstem "Weiter"). Zurueck von Schritt 5 landet korrekt auf der letzten Unterfrage. - openGebDatumPicker generalisiert zu openDatePicker(hiddenId,dispId, {fallback,titel,icon,yearMin,yearMax}) und beim Antragsdatum (#adt) im Antrag-Pflegegrad-Formular eingesetzt (Default-Scrollposition: heute, nicht heute-75 Jahre wie beim Geburtsdatum - fuer nahe Termine ist "heute" die sinnvollere Startposition) Verifiziert per Playwright: alle 6 Unterfragen in Step 4 einzeln durchgeklickt (inkl. Stopp vor Step 5 bei der letzten Frage und korrekte Zurueck-Navigation), Antragsdatum-Picker mit korrektem Titel/ Icon/Default getestet, Klapp-Animation per Mid-Transition-Screenshot bestaetigt. --- CLAUDE.md | 5 +- .../pflegepilot/templates/index.html | 125 ++++++++++++------ 2 files changed, 88 insertions(+), 42 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 758be7c..ff16ecc 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -69,8 +69,9 @@ The frontend was originally desktop-only (zero `@media` queries, fixed 228px sid - **Glass design system**: `:root` defines a dedicated token set — `--glass`/`--glass-strong` (translucent white fills), `--glass-border`, `--glass-blur`, `--glass-shadow`/`--glass-shadow-lg`, plus four `--bento-*` gradient tokens (mint/lavender/peach/rose) for tile accents. `body` has a fixed multi-blob `radial-gradient` background (`background-attachment:fixed`) that the translucent, `backdrop-filter:blur(...)` cards/sidebar/topbar/modal/login-box float over. Regular form inputs stay solid (`var(--surface)`, opaque white) — only container-level chrome (`.card`, `.modal`, `.sb`, `.topbar`, `.lo-box`) is glassy, intentionally, for text legibility. Always pair `backdrop-filter` with `-webkit-backdrop-filter` (Safari). - **Dashboard is a real Bento grid**, not just a relabeled stat row: `.bento` is a 4-column CSS grid with **explicit** `grid-column`/`grid-row` line placement per tile class (`.bento-stat`, `.bento-hero`, `.bento-aufg`, `.bento-quick`) — deliberately not relying on grid auto-placement, which does not reliably fill remaining same-row cells the way you'd expect when items of different spans are mixed. If you add/resize tiles, keep using explicit line numbers (or verify auto-placement with the debug technique below) rather than assuming `span N` will pack tiles the way you expect. - **Responsive tables → cards**: any live-UI (non-PDF-export) table that needs to stay usable at phone width gets `class="tw rtable"` on its wrapper and `data-label="…"` on every ``. Below 700px, `.rtable` CSS turns each `` into its own glass card (label stacked above value per cell, via `td[data-label]::before{content:attr(data-label)}`) instead of squeezing table columns. Applied to: Dashboard's recent-patients table, `renderPT` (Patientenliste), `pgAufgaben`, `renderAdminDash`'s Konten table **and** its Audit-Log (originally a fixed-min-width flex list — converted to an `.rtable` specifically because flex rows with `min-width` don't degrade gracefully, unlike this pattern), and the Patientenakte Anträge table. Follow this pattern for any new data table — don't ship a raw `` (or a fixed-width flex row list) without it. -- **Accordion on the card view**: within `.rtable`, exactly one row is expanded at a time — the rest collapse to a single header line (`td.rt-head`, marked explicitly per table since it's usually the first `data-label` cell) and stack tightly, so scanning many rows needs far less scrolling. `rtInit()` (shared helper, defined near `escH`) wires this up: on load the first row gets `.rt-open`; clicking any row's header toggles it open and closes the others (clicks on nested `button,a,select,input,textarea,.tl` are ignored so action buttons/links inside a row still work independently of the accordion). **Every function that renders an `.rtable` must call `rtInit()` after the DOM is in place** (see `pgDash`, `renderPT`, `pgAufgaben`, `renderAdminDash`, `loadPat`) — a new table using this pattern that forgets the call will render but never expand/collapse. Cells without `data-label` (action-button columns) are never hidden by the accordion, so those buttons stay reachable even on a collapsed row. The `.rt-chev` chevron icon is `display:none` by default and only shown inside the `max-width:700px` breakpoint — without that base rule it leaks into the plain desktop/tablet `
` as a stray icon. -- **Birth-date fields use a scroll-wheel picker, not native ``**: for a care app, birth years are routinely 60-100 years in the past, and a native calendar widget forces endless "previous month" clicking. `openGebDatumPicker(hiddenId, dispId)` opens an `OM()` modal with three CSS-scroll-snap columns (Tag/Monat/Jahr, `.dwheel`/`.dwheel-col`/`.dwheel-item`, `DW_ITEM_H=38`); the centered item per column is read on confirm (`dwConfirm()`), clamped for invalid day/month combos, and written back as an ISO string. The pattern is: a visible `.dw-trigger` div (click opens the picker, shows the formatted date via `dwTriggerLabel(hiddenId, dispId)`) plus a paired `` that holds the real `YYYY-MM-DD` value everything else in the codebase already expects — so `neuCollect()`/`fillWP()`/`fillM()`/`updM()` etc. needed no changes beyond calling `dwTriggerLabel()` after programmatically setting the hidden input (e.g. when a patient is selected and auto-fills the form). Applied only to actual birth-date fields — `fgeb` (interview wizard), `wgeb` (Widerspruch-Generator), `mpgeb` (Musterbrief) — **not** to near-term admin dates (Antragsdatum, Bescheiddatum, Fällig-am, etc.), which stay native `` since a normal calendar is faster for dates within the last/next few months. Defaults to *today − 75 years* rather than today, since that's a much better starting scroll position for this app's typical patient age. If you wire the picker to a field with existing live-update behavior (Musterbrief's `updM()` was previously triggered via `oninput`), you must call that update function explicitly from `dwConfirm()` — switching to `type="hidden"` removes the inline `oninput` handler, and events dispatched on a hidden input don't automatically reach anything unless something explicitly listens for them. +- **Accordion on the card view**: within `.rtable`, exactly one row is expanded at a time — the rest collapse to a single header line (`td.rt-head`, marked explicitly per table since it's usually the first `data-label` cell) and stack tightly, so scanning many rows needs far less scrolling. `rtInit()` (shared helper, defined near `escH`) wires this up: on load the first row gets `.rt-open`; clicking any row's header toggles it open and closes the others (clicks on nested `button,a,select,input,textarea,.tl` are ignored so action buttons/links inside a row still work independently of the accordion). **Every function that renders an `.rtable` must call `rtInit()` after the DOM is in place** (see `pgDash`, `renderPT`, `pgAufgaben`, `renderAdminDash`, `loadPat`) — a new table using this pattern that forgets the call will render but never expand/collapse. Cells without `data-label` (action-button columns) are never hidden by the accordion, so those buttons stay reachable even on a collapsed row. The `.rt-chev` chevron icon is `display:none` by default and only shown inside the `max-width:700px` breakpoint — without that base rule it leaks into the plain desktop/tablet `
` as a stray icon. **Expand/collapse animates** via `max-height`/`opacity`/`padding` transitions on each `td[data-label]` (a fixed `max-height:130px` ceiling, not `height:auto`, since `display` and `height:auto` aren't transition-able) — don't revert this to a `display:none`/`block` toggle, that's what made it feel instant/abrupt before. +- **Date-wheel picker, not native ``**, for any date field where users need to scroll far from today: `openDatePicker(hiddenId, dispId, {fallback, titel, icon, yearMin, yearMax})` opens an `OM()` modal with three CSS-scroll-snap columns (Tag/Monat/Jahr, `.dwheel`/`.dwheel-col`/`.dwheel-item`, `DW_ITEM_H=38`); the centered item per column is read on confirm (`dwConfirm()`), clamped for invalid day/month combos, and written back as an ISO string. The pattern is: a visible `.dw-trigger` div (click opens the picker, shows the formatted date via `dwTriggerLabel(hiddenId, dispId, icon)`) plus a paired `` that holds the real `YYYY-MM-DD` value everything else in the codebase already expects — so `neuCollect()`/`fillWP()`/`fillM()`/`updM()` etc. needed no changes beyond calling `dwTriggerLabel()` after programmatically setting the hidden input (e.g. when a patient is selected and auto-fills the form). `openGebDatumPicker(hiddenId, dispId)` is a thin wrapper around `openDatePicker` for birth dates specifically: `icon:'ti-cake'`, `fallback` = *today − 75 years* (a far better scroll starting point than today, given this app's typical patient age) — used on `fgeb` (interview wizard), `wgeb` (Widerspruch-Generator), `mpgeb` (Musterbrief). `openDatePicker` is called directly (no wrapper, default fallback = today, `icon:'ti-calendar'`) for near-term dates where "today" is already the right starting point, e.g. `adt` (Antragsdatum). Dates that are *always* within the last/next few months and don't need this at all (Bescheiddatum, Fällig-am, Tagebuch/Dokument-Datum, etc.) can stay a plain `` — only convert a field once someone actually needs to scroll years back from it. If you wire the picker to a field with existing live-update behavior (Musterbrief's `updM()` was previously triggered via `oninput`), you must call that update function explicitly from `dwConfirm()` — switching to `type="hidden"` removes the inline `oninput` handler, and events dispatched on a hidden input don't automatically reach anything unless something explicitly listens for them. +- **Interview wizard step 4 asks one question at a time**, not a long scrolling list: `neuWiz.q4sub` (0 = Zielgruppe, 1-5 = each `NEU_FRAGEN` entry) tracks position within the step; `NEU_Q4_TOTAL` is the count. A thin segmented progress bar (`.subdots`/`.subdot`, distinct from the big numbered `.wiz-steps` circles for the outer 6 steps) shows position within step 4 specifically. Answering a question (`neuAntwort`/`neuSetZG`) auto-advances `q4sub` to the next one — except on the last question, which waits for an explicit "Weiter" tap so the user gets a moment before jumping to the estimate in step 5. `neuNext()`/`neuBack()` both special-case `step===4`: they move `q4sub` within the step before ever touching the outer `step` counter, and entering step 4 from step 5 via "Zurück" lands on the *last* sub-question (`q4sub=NEU_Q4_TOTAL-1`), matching normal back-navigation expectations. If you add a 7th situational question, nothing else needs to change — `NEU_Q4_TOTAL` and the subdots derive from `NEU_FRAGEN.length` automatically. - **Mobile/tablet nav**: below 900px the `.sb` sidebar becomes a fixed off-canvas panel (`transform:translateX(-100%)`, slides in via `.sb.open`), toggled by a hamburger button (`#sb-toggle`, only visible in that breakpoint) and a `#sb-backdrop` overlay that closes it on tap. `toggleSidebar()`/`closeSidebar()` manage this; every nav-item click auto-closes it. Form grids (`.fg.c2/.c3`), stat grids (`.g4`), and the bento grid collapse to fewer columns at 900px/700px/560px. Modals go full-screen below 560px. Form inputs are forced to `font-size:16px` on phones to stop iOS Safari's auto-zoom-on-focus. - **Dashboard quick-actions become a sticky bottom bar on phones**: below 560px, `.bento-quick` (the "Schnellzugriff" tile) switches from a normal bento grid cell to `position:fixed;bottom:0`, a horizontal icon-only tab bar (`.bq-hd` heading hidden, `.bq-list` buttons go icon-over-2-line-label via `-webkit-line-clamp:2`), so the primary actions never require scrolling to reach. `.bento{padding-bottom:80px}` in that same breakpoint reserves the space the fixed bar would otherwise cover — this is scoped to `.bento` specifically (not a global `#content` padding) since `.bento-quick`/`.bento` only ever exist on the Dashboard page. - **Verification gotcha #1 — internal scroll**: `.content` scrolls internally (`overflow-y:auto` inside a `height:100vh` shell), so Playwright's `page.screenshot({fullPage:true})` does **not** capture content below the fold — only the viewport. Scroll `.content` itself (`document.querySelector('.content').scrollTop = ...`) before screenshotting to see the rest. diff --git a/pflegepilot_alpha_v2/pflegepilot/templates/index.html b/pflegepilot_alpha_v2/pflegepilot/templates/index.html index 2faaee7..3ba28d2 100644 --- a/pflegepilot_alpha_v2/pflegepilot/templates/index.html +++ b/pflegepilot_alpha_v2/pflegepilot/templates/index.html @@ -167,21 +167,22 @@ body{ @media (max-width:700px){ .rtable table,.rtable thead,.rtable tbody,.rtable tr,.rtable td{display:block;width:100%} .rtable thead{display:none} - .rtable tr{background:var(--glass);-webkit-backdrop-filter:blur(var(--glass-blur));backdrop-filter:blur(var(--glass-blur));border:1px solid var(--glass-border);border-radius:var(--r);margin-bottom:6px;padding:10px 12px;box-shadow:var(--glass-shadow);cursor:pointer} + .rtable tr{background:var(--glass);-webkit-backdrop-filter:blur(var(--glass-blur));backdrop-filter:blur(var(--glass-blur));border:1px solid var(--glass-border);border-radius:var(--r);margin-bottom:6px;padding:10px 12px;box-shadow:var(--glass-shadow);cursor:pointer;transition:box-shadow .25s ease,border-color .25s ease,padding-bottom .25s ease} .rtable tr:last-child{margin-bottom:0} - .rtable td{border:none;border-bottom:1px solid var(--border);padding:8px 0} - .rtable td:last-child{border-bottom:none} + .rtable td{border:none;padding:8px 0} .rtable td:empty{display:none} - .rtable td[data-label]::before{content:attr(data-label);display:block;font-size:10px;font-weight:600;color:var(--hint);text-transform:uppercase;letter-spacing:.04em;margin-bottom:3px} + .rtable td[data-label]::before{content:attr(data-label);display:block;font-size:10px;font-weight:600;color:var(--hint);text-transform:uppercase;letter-spacing:.04em;margin-bottom:3px;transition:opacity .2s ease} /* Akkordeon: nur die offene Karte zeigt alle Felder, der Rest ist auf - die Kopfzeile zusammengeklappt und stapelt sich eng - weniger Scrollen. */ - .rtable tr td[data-label]{display:none} - .rtable tr td.rt-head{display:flex!important;align-items:center;justify-content:space-between;gap:8px;border-bottom:none;padding:0} + die Kopfzeile zusammengeklappt und stapelt sich eng - weniger Scrollen. + max-height statt display:none, damit das Auf-/Zuklappen sanft animiert + (display ist nicht transition-fähig). */ + .rtable tr td[data-label]{max-height:0;opacity:0;overflow:hidden;padding-top:0;padding-bottom:0;border-bottom:1px solid transparent;transition:max-height .32s ease,opacity .22s ease,padding .32s ease,border-color .32s ease} + .rtable tr td.rt-head{max-height:none;opacity:1;overflow:visible;display:flex!important;align-items:center;justify-content:space-between;gap:8px;border-bottom:none!important;padding:0!important} .rtable tr td.rt-head::before{display:none} - .rtable tr .rt-chev{display:inline-block;font-size:16px;color:var(--hint);transition:transform .18s;flex-shrink:0} + .rtable tr .rt-chev{display:inline-block;font-size:16px;color:var(--hint);transition:transform .25s ease;flex-shrink:0} .rtable tr.rt-open{padding-bottom:2px;box-shadow:var(--glass-shadow-lg);border-color:var(--green)} - .rtable tr.rt-open td[data-label]{display:block} - .rtable tr.rt-open td.rt-head{border-bottom:1px solid var(--border);padding:0 0 8px;margin-bottom:6px} + .rtable tr.rt-open td[data-label]{max-height:130px;opacity:1;padding-top:8px;padding-bottom:8px;border-bottom-color:var(--border)} + .rtable tr.rt-open td.rt-head{border-bottom:1px solid var(--border)!important;padding:0 0 8px!important;margin-bottom:6px} .rtable tr.rt-open .rt-chev{transform:rotate(180deg);color:var(--green)} } table{width:100%;border-collapse:collapse} @@ -256,6 +257,9 @@ textarea{resize:vertical;min-height:80px} .wiz-line{flex:1;height:1px;background:var(--border)} .wiz-title{font-size:16px;font-weight:500;margin-bottom:4px} .wiz-hint{font-size:12.5px;color:var(--muted);margin-bottom:16px;line-height:1.5} +.subdots{display:flex;gap:5px;margin-bottom:18px} +.subdot{flex:1;height:4px;border-radius:2px;background:var(--border2);transition:background .25s ease} +.subdot.done{background:var(--green)} .ans-pill{display:flex;align-items:flex-start;gap:10px;padding:11px 14px;border-radius:var(--r);border:1px solid var(--border2);cursor:pointer;font-size:13.5px;color:var(--text);margin-bottom:8px;transition:all .12s} .ans-pill:hover{background:var(--bg)} .ans-pill.on{border-color:var(--green);background:var(--gbg);color:var(--gdk);font-weight:500} @@ -508,26 +512,33 @@ function rtInit(){ }); }); } -// ── Geburtsdatum-Wheel-Picker (Tag/Monat/Jahr-Scroll-Spalten) ─────────────── +// ── Datums-Wheel-Picker (Tag/Monat/Jahr-Scroll-Spalten) ───────────────────── +// Generisch fuer jedes Datumsfeld nutzbar (Geburtsdatum, Antragsdatum, ...) - +// unterscheidet sich pro Feld nur durch Titel/Icon/Default-Scrollposition. const DW_MONATE=['Januar','Februar','März','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember']; const DW_ITEM_H=38; -let _dwHidden=null,_dwDisp=null; -function dwTriggerLabel(hiddenId,dispId){ +let _dwHidden=null,_dwDisp=null,_dwIcon='ti-calendar'; +function dwTriggerLabel(hiddenId,dispId,icon){ const el=document.getElementById(dispId); const hid=document.getElementById(hiddenId); if(!el)return; - el.innerHTML=hid&&hid.value?''+fdate(hid.value):'Datum wählen…'; + icon=icon||'ti-calendar'; + el.innerHTML=hid&&hid.value?''+fdate(hid.value):'Datum wählen…'; } -function openGebDatumPicker(hiddenId,dispId){ - _dwHidden=hiddenId;_dwDisp=dispId; +function openDatePicker(hiddenId,dispId,opts){ + opts=opts||{}; + _dwHidden=hiddenId;_dwDisp=dispId;_dwIcon=opts.icon||'ti-calendar'; const cur=document.getElementById(hiddenId)?.value||''; const heute=new Date(); - let d=heute.getDate(),m=heute.getMonth()+1,y=heute.getFullYear()-75; // sinnvoller Default für Pflege-Patienten statt "heute" + let d=heute.getDate(),m=heute.getMonth()+1,y=heute.getFullYear(); + if(opts.fallback){const fp=opts.fallback.split('-');if(fp.length===3){y=parseInt(fp[0]);m=parseInt(fp[1]);d=parseInt(fp[2]);}} if(cur){const parts=cur.split('-');if(parts.length===3){y=parseInt(parts[0]);m=parseInt(parts[1]);d=parseInt(parts[2]);}} const dayItems=Array.from({length:31},(_,i)=>({v:i+1,label:String(i+1)})); const monthItems=DW_MONATE.map((n,i)=>({v:i+1,label:n})); - const yearItems=[];for(let yy=heute.getFullYear();yy>=1900;yy--)yearItems.push({v:yy,label:String(yy)}); - OM('Geburtsdatum wählen', + const yMax=opts.yearMax||heute.getFullYear()+1; + const yMin=opts.yearMin||1900; + const yearItems=[];for(let yy=yMax;yy>=yMin;yy--)yearItems.push({v:yy,label:String(yy)}); + OM(opts.titel||'Datum wählen', '
'+ '
'+ '
'+ @@ -563,6 +574,11 @@ function openGebDatumPicker(hiddenId,dispId){ }; }); } +function openGebDatumPicker(hiddenId,dispId){ + const heute=new Date(); + const fallback=(heute.getFullYear()-75)+'-'+String(heute.getMonth()+1).padStart(2,'0')+'-'+String(heute.getDate()).padStart(2,'0'); + openDatePicker(hiddenId,dispId,{fallback,titel:'Geburtsdatum wählen',icon:'ti-cake'}); +} function dwBuildCol(id,items){ const col=document.getElementById(id); const pad=(190-DW_ITEM_H)/2; @@ -589,7 +605,7 @@ function dwConfirm(){ const iso=y+'-'+String(m).padStart(2,'0')+'-'+String(d).padStart(2,'0'); const hid=document.getElementById(_dwHidden); if(hid){hid.value=iso;hid.dispatchEvent(new Event('change'));} - dwTriggerLabel(_dwHidden,_dwDisp); + dwTriggerLabel(_dwHidden,_dwDisp,_dwIcon); if(_dwHidden==='mpgeb'&&typeof updM==='function')updM(); // Musterbrief-Vorschau live nachziehen CM(); } @@ -1759,6 +1775,7 @@ const NEU_ZG_OPTIONEN=[ {label:'Behinderung (angeboren oder erworben)',zg:'behinderte',hinweis:'z. B. körperliche, geistige oder seelische Behinderung'}, {label:'Andere Bedürftigkeit oder soziale Notlage',zg:'beduerftige',hinweis:'z. B. vorübergehende Notlage ohne dauerhafte Behinderung'}, ]; +const NEU_Q4_TOTAL=1+NEU_FRAGEN.length; // Zielgruppe + 5 Situationsfragen, einzeln gestaffelt function neuSchaetzung(){ const a=neuWiz.antworten; const summe=NEU_FRAGEN.reduce((s,f)=>s+(a[f.key]??0),0); @@ -1772,10 +1789,10 @@ function neuSchaetzung(){ return {summe,von,bis,vorschlag:Math.round((von+bis)/2)}; } -let neuWiz={step:1,data:{},antworten:{},zielgruppe:'alterspflege'}; +let neuWiz={step:1,data:{},antworten:{},zielgruppe:'alterspflege',q4sub:0}; function pgNeu(){ - neuWiz={step:1,data:{},antworten:{},zielgruppe:'alterspflege'}; + neuWiz={step:1,data:{},antworten:{},zielgruppe:'alterspflege',q4sub:0}; neuRender(); } function neuSteps(){return ['Persönliche Daten','Kontakt & Adresse','Krankenversicherung','Pflegesituation','Einschätzung & Pflegeperson','Übersicht'];} @@ -1799,15 +1816,34 @@ function neuCollect(){ Object.assign(neuWiz.data,{pflegeperson:g('fpp'),notizen:g('fnotiz'),pflegegrad:g('fgrad')}); } } -function neuAntwort(key,wert){neuWiz.antworten[key]=wert;neuRender();} -function neuSetZG(zg){neuWiz.zielgruppe=zg;neuRender();} -function neuBack(){neuCollect();if(neuWiz.step>1){neuWiz.step--;neuRender();}} +function neuQ4Advance(){ + // Nach einer Antwort automatisch zur naechsten Frage - ausser bei der + // letzten, da rueckt man bewusst erst per "Weiter" weiter (kurzer Moment + // zum Nachdenken/Korrigieren statt sofortigem Sprung zu Schritt 5). + if(neuWiz.q4sub0){neuWiz.q4sub--;neuRender();return;} + if(neuWiz.step>1){ + neuWiz.step--; + if(neuWiz.step===4)neuWiz.q4sub=NEU_Q4_TOTAL-1; // von Schritt 5 zurueck: letzte Frage zeigen + neuRender(); + } +} function neuNext(){ neuCollect(); if(neuWiz.step===1&&(!neuWiz.data.vorname||!neuWiz.data.nachname)){ toast('Bitte Vor- und Nachname eintragen',false);return; } - if(neuWiz.step
`; }else if(step===4){ - body=`
Was beschreibt die Situation am besten?
-
Das hilft uns, passende Leistungen vorzuschlagen. Sie können das später jederzeit ändern.
-
`+NEU_ZG_OPTIONEN.map(o=> - `
${o.label}
${o.hinweis}
` - ).join('')+`
-
Wie sieht der Pflegealltag aus?
-
Diese Fragen helfen bei einer ersten groben Einschätzung. Sie ersetzen nicht die offizielle Begutachtung durch den Medizinischen Dienst.
`+ - NEU_FRAGEN.map(f=>`
-
${f.frage}
- ${f.optionen.map(o=>`
${o.label}
`).join('')} -
`).join(''); + // Eine Frage nach der anderen statt einer langen Liste - besser lesbar, + // und die letzte Frage ist so immer ohne Scrollen erreichbar. + const subdots='
'+Array.from({length:NEU_Q4_TOTAL},(_,i)=> + '
').join('')+'
'; + if(neuWiz.q4sub===0){ + body=subdots+`
Was beschreibt die Situation am besten?
+
Das hilft uns, passende Leistungen vorzuschlagen. Sie können das später jederzeit ändern.
+
`+NEU_ZG_OPTIONEN.map(o=> + `
${o.label}
${o.hinweis}
` + ).join('')+`
`; + }else{ + const f=NEU_FRAGEN[neuWiz.q4sub-1]; + body=subdots+`
Diese Fragen helfen bei einer ersten groben Einschätzung des Pflegealltags. Sie ersetzen nicht die offizielle Begutachtung durch den Medizinischen Dienst.
+
${f.frage}
+
`+f.optionen.map(o=> + `
${o.label}
` + ).join('')+`
`; + } }else if(step===5){ const est=neuSchaetzung(); body=`
@@ -2000,7 +2043,9 @@ async function pgAntrag(prefillPid){ 'reha:Reha-Antrag (§ 40 SGB V)','eingliederung:Eingliederungshilfe (SGB IX)', 'grundsicherung:Grundsicherung (§ 41 SGB XII)'].map(x=>{const[v,l]=x.split(':');return'';}).join('')+'
'+ '
'+ - '
'+ + '
'+ + '
Datum wählen…
'+ + '
'+ '
'+ '
'+ '
'+ @@ -2227,7 +2272,7 @@ async function fillWP(){ const pid=document.getElementById('wpid')?.value;if(!pid)return; const d=await api('/api/patienten/'+pid);const p=d.patient; const sv=(id,v)=>{const e=document.getElementById(id);if(e&&v)e.value=v;}; - sv('wname',p.vorname+' '+p.nachname);sv('wgeb',p.geburtsdatum);dwTriggerLabel('wgeb','wgeb_disp');sv('wvnr',p.versichertennummer); + sv('wname',p.vorname+' '+p.nachname);sv('wgeb',p.geburtsdatum);dwTriggerLabel('wgeb','wgeb_disp','ti-cake');sv('wvnr',p.versichertennummer); sv('waddr',(p.strasse?p.strasse+', ':'')+p.plz+' '+p.ort); if(p.krankenkasse)selKK('wkk_s','wkk',p.krankenkasse); if(p.pflegegrad)sv('wist',p.pflegegrad); @@ -2460,7 +2505,7 @@ async function fillM(pid){ const sv=(id,v)=>{const e=document.getElementById(id);if(e&&v!==undefined)e.value=v;}; sv('mn',p.vorname+' '+p.nachname);sv('ms',p.strasse||'');sv('mpo',(p.plz||'')+' '+(p.ort||'')); sv('mtel',p.telefon||'');sv('mpn',p.vorname+' '+p.nachname);sv('mpgeb',p.geburtsdatum||'');sv('mpvnr',p.versichertennummer||''); - dwTriggerLabel('mpgeb','mpgeb_disp'); + dwTriggerLabel('mpgeb','mpgeb_disp','ti-cake'); if(p.krankenkasse)selKK('mkk_s','mkk',p.krankenkasse); updM(); }