pediatric-ai-scribe-v3/public/components/settings.html
Daniel d893452d9a
Some checks failed
Forgejo Docker Build / End-to-end (browser) (push) Blocked by required conditions
Forgejo Docker Build / Root app tests (push) Successful in 55s
Forgejo Docker Build / Build Docker image (push) Has been cancelled
feat: the site's Nextcloud is filled in, not typed — the settings page is one button
nextcloud.url (or NEXTCLOUD_URL) names the site's Nextcloud. With it set,
the address field is hidden and the page reads "Sign in with Nextcloud",
with the app-password route underneath for whoever needs it; both routes
use the default when no address is given. Without it, nothing changes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
2026-09-13 14:33:25 +02:00

229 lines
16 KiB
HTML

<div class="module-header">
<h2><i class="fas fa-cog"></i> Settings</h2>
<p>Account security, integrations, and personal templates</p>
</div>
<div class="settings-page">
<!-- Voice Preferences (STT & TTS) -->
<div class="settings-section card" id="voice-preferences-section">
<h3><i class="fas fa-microphone-lines"></i> Voice Preferences</h3>
<p style="font-size:13px;color:var(--g600);">Customize your speech-to-text model and text-to-speech voice. These settings apply to all your recording and read-aloud features.</p>
<div style="margin-bottom:16px;">
<label style="display:block;font-size:13px;font-weight:600;color:var(--g700);margin-bottom:6px;">Speech-to-Text Model (Transcription)</label>
<p style="font-size:12px;color:var(--g500);margin:4px 0 8px;">Choose the AI model for transcribing your audio recordings. More accurate models may be slower.</p>
<select id="stt-model-select" style="font-size:13px;padding:6px 10px;border:1px solid var(--g300);border-radius:6px;width:100%;max-width:400px;">
<option value="">Server default</option>
</select>
</div>
<div data-feature="read_aloud" style="margin-bottom:16px;">
<label style="display:block;font-size:13px;font-weight:600;color:var(--g700);margin-bottom:6px;">Text-to-Speech Voice (Read Aloud)</label>
<p style="font-size:12px;color:var(--g500);margin:4px 0 8px;">Choose the voice for the "Read Aloud" feature. Preview available after selection.</p>
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap;">
<select id="tts-voice-select" style="font-size:13px;padding:6px 10px;border:1px solid var(--g300);border-radius:6px;flex:1;max-width:400px;">
<option value="">Server default</option>
</select>
<button id="btn-preview-voice" class="btn-sm btn-ghost"><i class="fas fa-play"></i> Preview</button>
</div>
</div>
<div style="margin-top:12px;">
<button id="btn-save-voice-prefs" class="btn-sm btn-primary"><i class="fas fa-save"></i> Save Voice Preferences</button>
</div>
</div>
<!-- Web Speech Recognition (Real-time Streaming) -->
<div class="settings-section card" id="web-speech-section" style="border-left:3px solid var(--orange);">
<h3><i class="fas fa-wave-square"></i> Real-Time Streaming Transcription</h3>
<div style="background:var(--orange-light);padding:12px;border-radius:6px;margin-bottom:12px;">
<p style="font-size:13px;color:var(--orange-dark);margin:0;"><i class="fas fa-exclamation-triangle"></i> <strong>Privacy Warning:</strong> Uses your browser's built-in speech recognition, which <strong>may send audio to cloud servers</strong> (Chrome/Edge send to Google). Only enable if you accept this trade-off for real-time transcription.</p>
</div>
<p style="font-size:13px;color:var(--g600);">See words appear as you speak (streaming). Overrides browser and server transcription when enabled. <strong>Not HIPAA-compliant</strong> in most browsers.</p>
<div style="display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:12px;">
<label style="font-size:13px;font-weight:600;">Enable real-time streaming:</label>
<label style="display:flex;align-items:center;gap:6px;cursor:pointer;">
<input type="checkbox" id="web-speech-enabled" style="accent-color:var(--orange);width:16px;height:16px;">
<span style="font-size:13px;" id="web-speech-status">Off</span>
</label>
</div>
<div id="web-speech-privacy-info" style="font-size:12px;color:var(--g500);padding:10px;background:var(--g50);border-radius:6px;margin-top:8px;">
<p style="margin:0 0 4px;font-weight:600;">Current Browser:</p>
<p style="margin:0;" id="web-speech-browser-info">Detecting...</p>
</div>
<p style="font-size:11px;color:var(--g400);margin:8px 0 0;"><i class="fas fa-info-circle"></i> <strong>Trade-off:</strong> Immediate transcription vs. privacy. For maximum privacy, use server transcription with a HIPAA-eligible provider.</p>
</div>
<!-- Change Password — hidden by default; unhidden only for users with a real password -->
<div class="settings-section card" id="change-password-section" style="display:none;">
<h3><i class="fas fa-key"></i> Change Password</h3>
<div class="form-group" style="max-width:340px;">
<label>Current Password</label>
<input type="password" id="pw-current" placeholder="Enter current password">
</div>
<div class="form-group" style="max-width:340px;">
<label>New Password (8+ characters)</label>
<input type="password" id="pw-new" minlength="8" placeholder="Enter new password">
</div>
<div class="form-group" style="max-width:340px;">
<label>Confirm New Password</label>
<input type="password" id="pw-confirm" minlength="8" placeholder="Confirm new password">
</div>
<button id="btn-change-password" class="btn-sm btn-primary"><i class="fas fa-check"></i> Change Password</button>
<span id="pw-change-status" style="font-size:13px;margin-left:8px;"></span>
</div>
<!-- 2FA — hidden by default; unhidden only for users with a real password (SSO users use their IdP's MFA) -->
<div class="settings-section card" id="2fa-section" style="display:none;">
<h3><i class="fas fa-shield-halved"></i> Two-Factor Authentication</h3>
<p id="2fa-status">Status: Loading...</p>
<button id="btn-setup-2fa" class="btn-sm btn-primary">Enable 2FA</button>
<button id="btn-disable-2fa" class="btn-sm btn-ghost hidden" style="color:var(--red);">Disable 2FA</button>
<div id="2fa-backup-info"></div>
<div id="2fa-disable-confirm" class="hidden" style="margin-top:10px;padding:12px;background:var(--g50);border-radius:8px;border:1px solid var(--g200);max-width:340px;">
<div class="form-group" style="margin-bottom:8px;">
<label>Enter your password to confirm:</label>
<input type="password" id="2fa-disable-password" placeholder="Password">
</div>
<div style="display:flex;gap:6px;">
<button id="btn-disable-2fa-confirm" class="btn-sm btn-primary" style="background:var(--red);border-color:var(--red);">Confirm Disable</button>
<button id="btn-disable-2fa-cancel" class="btn-sm btn-ghost">Cancel</button>
</div>
</div>
<div id="2fa-setup" class="hidden">
<p>Scan this QR code with your authenticator app:</p>
<img id="2fa-qr" src="" alt="QR Code">
<p>Or enter manually: <code id="2fa-secret"></code></p>
<div class="form-group">
<label>Enter the 6-digit code to verify:</label>
<input type="text" id="2fa-verify-code" maxlength="6" placeholder="123456">
<button id="btn-verify-2fa" class="btn-sm btn-success">Verify & Enable</button>
</div>
</div>
</div>
<!-- Active Sessions — hidden for SSO-only users (revoke can't stick against an active IdP session) -->
<div class="settings-section card" id="sessions-section" style="display:none;">
<h3><i class="fas fa-desktop"></i> Active Sessions</h3>
<p style="font-size:13px;color:var(--g600);">Devices where you are currently logged in. Revoke any session to immediately log that device out.</p>
<div style="margin-bottom:10px;">
<button id="btn-revoke-all-sessions" class="btn-sm btn-ghost" style="color:var(--red);font-size:12px;"><i class="fas fa-ban"></i> Revoke All Other Sessions</button>
</div>
<div id="sessions-list" style="display:flex;flex-direction:column;gap:6px;">
<p style="color:var(--g400);font-size:13px;">Loading sessions...</p>
</div>
</div>
<!-- Nextcloud -->
<div class="settings-section card" data-feature="nextcloud">
<h3><i class="fas fa-cloud"></i> Nextcloud Integration</h3>
<p>Save generated notes and teaching material to your own Nextcloud.</p>
<div id="nc-status">Not connected</div>
<!-- Shown only when the site has not set its own Nextcloud; then
there is nothing to type and the button below is the whole form. -->
<div class="form-group" id="nc-url-group">
<label for="nc-url">Nextcloud address</label>
<input type="text" id="nc-url" placeholder="https://cloud.example.com">
</div>
<!-- The ordinary way in: sign in on Nextcloud itself, however you
normally do, and it hands back a password made for this app. -->
<button id="btn-nc-login-flow" class="btn-sm btn-primary">
<i class="fas fa-arrow-up-right-from-square"></i> Sign in with Nextcloud
</button>
<p id="nc-login-flow-status" role="status" style="margin:6px 0 0;font-size:12px;color:var(--g600);"></p>
<details id="nc-manual" style="margin-top:12px;">
<summary style="cursor:pointer;font-size:13px;color:var(--g600);">Use an app password instead</summary>
<div class="form-group" style="margin-top:10px;">
<label for="nc-user">Username</label>
<input type="text" id="nc-user" placeholder="your-username">
</div>
<div class="form-group">
<label for="nc-pass">App password</label>
<input type="password" id="nc-pass" placeholder="Generate in Nextcloud → Settings → Security">
<small>Nextcloud → Settings → Security → Create new app password</small>
</div>
<button id="btn-nc-connect" class="btn-sm btn-primary">Connect</button>
</details>
<button id="btn-nc-disconnect" class="btn-sm btn-ghost hidden" style="margin-top:10px;">Disconnect</button>
</div>
<!-- My Templates / Memories -->
<div class="settings-section card" data-feature="memories">
<h3><i class="fas fa-book-medical"></i> My Templates</h3>
<p style="font-size:13px;color:var(--g600);">Save reusable templates for physical exam, ROS, encounter format, etc. Only template categories are sent to AI when generating notes &mdash; anything saved as <strong>Custom</strong> is never sent. Templates go out with Encounter HPI, Dictation HPI, SOAP, Sick Visit, Well Visit, ED Encounter and Hospital Course, and shape how a note is laid out and worded. The AI is told never to copy clinical content out of a template, so a template cannot supply findings you did not dictate: say them instead, for example &ldquo;normal cardiac exam&rdquo;, and they are documented.</p>
<div style="margin-bottom:10px;display:flex;gap:8px;flex-wrap:wrap;align-items:center;">
<select id="mem-category" style="font-size:13px;padding:5px 8px;border:1px solid var(--g300);border-radius:6px;">
<option value="physical_exam">Physical Exam Template</option>
<option value="ros">Review of Systems Template</option>
<option value="encounter_format">Encounter Note Format</option>
<option value="family_history">Family History Format</option>
<option value="assessment_plan">Assessment &amp; Plan Format</option>
<option value="template_soap">SOAP Note Template</option>
<option value="template_hpi">HPI Template</option>
<option value="template_wellvisit">Well Visit Template</option>
<option value="template_sickvisit">Sick Visit Template</option>
<option value="template_ed">ED Template</option>
</select>
<input type="text" id="mem-name" style="font-size:13px;padding:5px 8px;border:1px solid var(--g300);border-radius:6px;flex:1;min-width:150px;" placeholder="Template name (e.g. Normal PE)">
<a href="/template-guide.md" download="ped-ai-template-guide.md" class="btn-sm btn-ghost" style="text-decoration:none;"><i class="fas fa-download"></i> Template Guide</a>
</div>
<textarea id="mem-content" rows="5" style="width:100%;font-size:12px;padding:8px;border:1px solid var(--g300);border-radius:6px;resize:vertical;box-sizing:border-box;" placeholder="Paste your template here. Example: HEENT: Normocephalic, atraumatic. Eyes: PERRL. Ears: TMs clear. Throat: clear..."></textarea>
<div style="margin-top:8px;display:flex;gap:8px;">
<button id="btn-mem-save" class="btn-sm btn-primary"><i class="fas fa-plus"></i> Add Template</button>
</div>
<div id="mem-list" style="margin-top:12px;display:flex;flex-direction:column;gap:6px;">
<p style="color:var(--g400);font-size:13px;">Loading templates...</p>
</div>
</div>
<!-- Documents (S3) -->
<div class="settings-section card" id="documents-section">
<h3><i class="fas fa-file-arrow-up"></i> Documents</h3>
<p style="font-size:13px;color:var(--g600);">Upload and manage documents via S3 storage (PDF, images, Word docs, text files). Max 10 MB per file.</p>
<div id="doc-upload-area" style="margin-bottom:12px;">
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap;">
<input type="file" id="doc-file-input" accept=".pdf,.jpg,.jpeg,.png,.gif,.doc,.docx,.txt,.csv" style="font-size:13px;">
<input type="text" id="doc-description" placeholder="Description (optional)" style="font-size:13px;padding:5px 8px;border:1px solid var(--g300);border-radius:6px;flex:1;min-width:150px;">
<button id="btn-doc-upload" class="btn-sm btn-primary"><i class="fas fa-upload"></i> Upload</button>
</div>
</div>
<div id="documents-list" style="display:flex;flex-direction:column;gap:6px;">
<p style="color:var(--g400);font-size:13px;">Loading...</p>
</div>
</div>
<!-- Audio Backups -->
<div class="settings-section card">
<h3><i class="fas fa-microphone-lines"></i> Audio Backups</h3>
<p style="font-size:13px;color:var(--g600);">Recordings are automatically backed up locally and kept for 24 hours. Retry transcription if it failed.</p>
<div id="audio-backups-list" style="display:flex;flex-direction:column;gap:6px;">
<p style="color:var(--g400);font-size:13px;">Loading...</p>
</div>
</div>
<!-- Saved Encounters -->
<div class="settings-section card">
<h3><i class="fas fa-floppy-disk"></i> Saved Encounters</h3>
<p style="font-size:13px;color:var(--g600);">Encounters are automatically deleted after 7 days per site policy.</p>
<div id="saved-enc-list" style="display:flex;flex-direction:column;gap:6px;">
<p style="color:var(--g400);font-size:13px;">Loading...</p>
</div>
</div>
<!-- Compliance -->
<div class="settings-section card">
<h3><i class="fas fa-shield-halved"></i> Compliance & Usage</h3>
<div class="hipaa-info">
<p><strong>Important:</strong> Check with your institution's guidelines and policies before use. This tool is not intended for production clinical use without proper organizational authorization and provider BAAs in place. Use with caution.</p>
</div>
</div>
</div>