diff --git a/public/components/encounter.html b/public/components/encounter.html
index ff79907..0de9f5a 100644
--- a/public/components/encounter.html
+++ b/public/components/encounter.html
@@ -56,7 +56,7 @@
@@ -71,7 +71,7 @@
-
+
diff --git a/public/css/styles.css b/public/css/styles.css
index df4a3f0..ee1b16e 100644
--- a/public/css/styles.css
+++ b/public/css/styles.css
@@ -153,6 +153,8 @@ body{font-family:'Inter',system-ui,sans-serif;background:var(--g50);color:var(--
.output-header{background:var(--green-light);border-bottom-color:var(--green);}
.output-actions{display:flex;align-items:center;gap:6px;flex-wrap:wrap;}
.output-text{padding:20px 24px;font-size:13px;line-height:1.9;outline:none;min-height:480px;white-space:pre-wrap;overflow-y:auto;}
+.output-text-large{min-height:600px;}
+.editable-box-large{min-height:400px;}
.model-tag{font-size:10px;padding:2px 7px;background:var(--g200);border-radius:4px;color:var(--g600);}
/* REFINE BAR */
diff --git a/public/js/admin.js b/public/js/admin.js
index 136bcf8..c882c67 100644
--- a/public/js/admin.js
+++ b/public/js/admin.js
@@ -571,7 +571,7 @@
fetch('/api/admin/config/models', { headers: getAuthHeaders() })
.then(function(r) { return r.json(); })
.then(function(data) {
- if (!data.success) return;
+ if (!data.success) { modelsLoaded = false; return; }
window._adminModelsData = data;
var providerEl = document.getElementById('admin-model-provider');
if (providerEl) providerEl.textContent = (data.provider || 'openrouter').toUpperCase();
@@ -579,7 +579,7 @@
renderCustomModels(data.custom || []);
populateDefaultModelSelect(data.models || [], data.custom || []);
})
- .catch(function(err) { console.error('[Admin] Models load failed:', err); });
+ .catch(function(err) { modelsLoaded = false; console.error('[Admin] Models load failed:', err); });
}
function renderModelTable(models) {
@@ -668,15 +668,22 @@
sel.appendChild(opt);
});
- // Load current default
- fetch('/api/admin/config', { headers: getAuthHeaders() })
- .then(function(r) { return r.json(); })
- .then(function(data) {
- if (!data.success) return;
- var cfg = {};
- (data.config || []).forEach(function(row) { cfg[row.key] = row.value; });
- if (cfg['models.default']) sel.value = cfg['models.default'];
- });
+ // Load current default from already-loaded config, or fetch if needed
+ var cfg = window._adminEmailConfig || {};
+ if (cfg['models.default']) {
+ sel.value = cfg['models.default'];
+ } else {
+ // Fetch only the default model setting
+ fetch('/api/admin/config', { headers: getAuthHeaders() })
+ .then(function(r) { return r.json(); })
+ .then(function(data) {
+ if (!data.success) return;
+ (data.config || []).forEach(function(row) {
+ if (row.key === 'models.default' && row.value) sel.value = row.value;
+ });
+ })
+ .catch(function() {});
+ }
}
function addCustomModel() {
diff --git a/public/js/encounters.js b/public/js/encounters.js
index 30d48d7..a4a8940 100644
--- a/public/js/encounters.js
+++ b/public/js/encounters.js
@@ -468,6 +468,17 @@
// Hide output card
var out = document.getElementById(outputElMap[type]);
if (out) out.classList.add('hidden');
+ // Clear refine input (textarea or input) for every tab
+ var refineEl = document.getElementById(pfx + '-refine-input');
+ if (refineEl) refineEl.value = '';
+ // Clear instructions textarea (SOAP, hospital, etc.)
+ var instrEl = document.getElementById(pfx + '-instructions');
+ if (instrEl) instrEl.value = '';
+ // Clear demographic fields
+ var ageEl = document.getElementById(pfx + '-age');
+ if (ageEl) ageEl.value = '';
+ var genderEl = document.getElementById(pfx + '-gender');
+ if (genderEl) genderEl.value = '';
// Reset saved ID and idempotency key (memory + sessionStorage)
window['_savedEncId_' + type] = null;
try { sessionStorage.removeItem('_savedEncId_' + type); } catch(e) {}
diff --git a/public/js/liveEncounter.js b/public/js/liveEncounter.js
index 4be3ba7..2972cab 100644
--- a/public/js/liveEncounter.js
+++ b/public/js/liveEncounter.js
@@ -131,6 +131,8 @@
window._savedEncId_encounter = null;
var labelEl = document.getElementById('enc-label');
if (labelEl) labelEl.value = '';
+ var refineEl = document.getElementById('enc-refine-input');
+ if (refineEl) refineEl.value = '';
});
generateBtn.addEventListener('click', function() {
diff --git a/public/js/voiceDictation.js b/public/js/voiceDictation.js
index 1b2ebf5..c49adf7 100644
--- a/public/js/voiceDictation.js
+++ b/public/js/voiceDictation.js
@@ -126,6 +126,8 @@
window._savedEncId_dictation = null;
var labelEl = document.getElementById('dict-label');
if (labelEl) labelEl.value = '';
+ var refineEl = document.getElementById('dict-refine-input');
+ if (refineEl) refineEl.value = '';
});
generateBtn.addEventListener('click', function() {
diff --git a/src/routes/encounters.js b/src/routes/encounters.js
index 8aaac12..4d6f9f1 100644
--- a/src/routes/encounters.js
+++ b/src/routes/encounters.js
@@ -56,6 +56,16 @@ router.post('/encounters/saved', async function(req, res) {
);
res.json({ success: true, id: id });
} else {
+ // Enforce unique label per user (within active/non-expired encounters)
+ if (label && label.trim()) {
+ var labelDup = await db.get(
+ "SELECT id FROM saved_encounters WHERE user_id = $1 AND LOWER(label) = LOWER($2) AND expires_at > NOW()",
+ [req.user.id, label.trim()]
+ );
+ if (labelDup) {
+ return res.status(409).json({ error: 'An encounter with this label already exists. Use a unique label or load the existing one.' });
+ }
+ }
// Check for duplicate via idempotency_key
if (idempotency_key) {
var dup = await db.get(