Show baseline/reference form in a modal with live month preview
Replaces the small inline form with a centred modal dialog. When both dates are selected, a live chip list shows every month covered (up to 36 months) so it is immediately clear what periods will be loaded. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
cfee3e96b9
commit
10441a4761
@ -375,10 +375,48 @@ function showLoadForm(op) {
|
|||||||
state.loadDataOp = op;
|
state.loadDataOp = op;
|
||||||
document.getElementById('load-data-title').textContent =
|
document.getElementById('load-data-title').textContent =
|
||||||
op === 'baseline' ? 'Load Baseline' : 'Load Reference';
|
op === 'baseline' ? 'Load Baseline' : 'Load Reference';
|
||||||
document.getElementById('load-data-form').classList.remove('hidden');
|
document.getElementById('load-date-from').value = '';
|
||||||
|
document.getElementById('load-date-to').value = '';
|
||||||
|
document.getElementById('load-note').value = '';
|
||||||
|
document.getElementById('load-date-preview').classList.add('hidden');
|
||||||
|
document.getElementById('load-data-modal').classList.remove('hidden');
|
||||||
document.getElementById('load-date-from').focus();
|
document.getElementById('load-date-from').focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hideLoadModal() {
|
||||||
|
document.getElementById('load-data-modal').classList.add('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDatePreview() {
|
||||||
|
const fromVal = document.getElementById('load-date-from').value;
|
||||||
|
const toVal = document.getElementById('load-date-to').value;
|
||||||
|
const preview = document.getElementById('load-date-preview');
|
||||||
|
const chips = document.getElementById('load-date-chips');
|
||||||
|
const label = preview.querySelector('.load-preview-label');
|
||||||
|
|
||||||
|
if (!fromVal || !toVal) { preview.classList.add('hidden'); return; }
|
||||||
|
|
||||||
|
const from = new Date(fromVal + 'T00:00:00');
|
||||||
|
const to = new Date(toVal + 'T00:00:00');
|
||||||
|
if (isNaN(from) || isNaN(to) || from > to) { preview.classList.add('hidden'); return; }
|
||||||
|
|
||||||
|
const months = [];
|
||||||
|
const cur = new Date(from.getFullYear(), from.getMonth(), 1);
|
||||||
|
const end = new Date(to.getFullYear(), to.getMonth(), 1);
|
||||||
|
while (cur <= end) { months.push(new Date(cur)); cur.setMonth(cur.getMonth() + 1); }
|
||||||
|
|
||||||
|
const fmt = new Intl.DateTimeFormat('en-US', { month: 'short', year: 'numeric' });
|
||||||
|
label.textContent = `${months.length} month${months.length !== 1 ? 's' : ''} covered`;
|
||||||
|
|
||||||
|
if (months.length <= 36) {
|
||||||
|
chips.innerHTML = months.map(m => `<span class="date-chip">${fmt.format(m)}</span>`).join('');
|
||||||
|
} else {
|
||||||
|
chips.innerHTML = `<span class="date-chip-summary">${months.length} months — ${fmt.format(months[0])} → ${fmt.format(months[months.length - 1])}</span>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
preview.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
async function submitLoadData() {
|
async function submitLoadData() {
|
||||||
const date_from = document.getElementById('load-date-from').value;
|
const date_from = document.getElementById('load-date-from').value;
|
||||||
const date_to = document.getElementById('load-date-to').value;
|
const date_to = document.getElementById('load-date-to').value;
|
||||||
@ -394,7 +432,7 @@ async function submitLoadData() {
|
|||||||
try {
|
try {
|
||||||
showStatus(`Loading ${state.loadDataOp}...`, 'info');
|
showStatus(`Loading ${state.loadDataOp}...`, 'info');
|
||||||
const result = await api('POST', `/versions/${state.selectedVersionId}/${state.loadDataOp}`, body);
|
const result = await api('POST', `/versions/${state.selectedVersionId}/${state.loadDataOp}`, body);
|
||||||
document.getElementById('load-data-form').classList.add('hidden');
|
hideLoadModal();
|
||||||
showStatus(`${state.loadDataOp} loaded — ${result.rows_affected} rows`, 'success');
|
showStatus(`${state.loadDataOp} loaded — ${result.rows_affected} rows`, 'success');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showStatus(err.message, 'error');
|
showStatus(err.message, 'error');
|
||||||
@ -879,9 +917,10 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
document.getElementById('vbtn-toggle').addEventListener('click', toggleVersionStatus);
|
document.getElementById('vbtn-toggle').addEventListener('click', toggleVersionStatus);
|
||||||
document.getElementById('vbtn-delete').addEventListener('click', deleteVersion);
|
document.getElementById('vbtn-delete').addEventListener('click', deleteVersion);
|
||||||
document.getElementById('btn-load-submit').addEventListener('click', submitLoadData);
|
document.getElementById('btn-load-submit').addEventListener('click', submitLoadData);
|
||||||
document.getElementById('btn-load-cancel').addEventListener('click', () => {
|
document.getElementById('btn-load-cancel').addEventListener('click', hideLoadModal);
|
||||||
document.getElementById('load-data-form').classList.add('hidden');
|
document.getElementById('btn-load-close').addEventListener('click', hideLoadModal);
|
||||||
});
|
document.getElementById('load-date-from').addEventListener('change', updateDatePreview);
|
||||||
|
document.getElementById('load-date-to').addEventListener('change', updateDatePreview);
|
||||||
|
|
||||||
// forecast view buttons
|
// forecast view buttons
|
||||||
document.getElementById('btn-forecast-refresh').addEventListener('click', loadForecastData);
|
document.getElementById('btn-forecast-refresh').addEventListener('click', loadForecastData);
|
||||||
|
|||||||
@ -94,18 +94,6 @@
|
|||||||
<button class="btn" id="vbtn-toggle">Close Version</button>
|
<button class="btn" id="vbtn-toggle">Close Version</button>
|
||||||
<button class="btn btn-danger" id="vbtn-delete">Delete</button>
|
<button class="btn btn-danger" id="vbtn-delete">Delete</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="load-data-form" class="inline-form hidden">
|
|
||||||
<h3 id="load-data-title">Load Baseline</h3>
|
|
||||||
<div class="form-row">
|
|
||||||
<label>Date From<input type="date" id="load-date-from" /></label>
|
|
||||||
<label>Date To<input type="date" id="load-date-to" /></label>
|
|
||||||
<label>Note<input type="text" id="load-note" placeholder="optional" /></label>
|
|
||||||
</div>
|
|
||||||
<div class="form-actions">
|
|
||||||
<button id="btn-load-submit" class="btn btn-primary">Load</button>
|
|
||||||
<button id="btn-load-cancel" class="btn">Cancel</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- ===== FORECAST VIEW ===== -->
|
<!-- ===== FORECAST VIEW ===== -->
|
||||||
@ -170,6 +158,31 @@
|
|||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Load baseline / reference modal -->
|
||||||
|
<div id="load-data-modal" class="modal-overlay hidden">
|
||||||
|
<div class="modal load-data-modal">
|
||||||
|
<div class="modal-header">
|
||||||
|
<span id="load-data-title">Load Baseline</span>
|
||||||
|
<button id="btn-load-close" class="btn-icon">×</button>
|
||||||
|
</div>
|
||||||
|
<div id="load-data-body">
|
||||||
|
<div class="load-form-fields">
|
||||||
|
<label>Date From<input type="date" id="load-date-from" /></label>
|
||||||
|
<label>Date To<input type="date" id="load-date-to" /></label>
|
||||||
|
<label>Note<input type="text" id="load-note" placeholder="optional" /></label>
|
||||||
|
</div>
|
||||||
|
<div id="load-date-preview" class="load-date-preview hidden">
|
||||||
|
<div class="load-preview-label"></div>
|
||||||
|
<div id="load-date-chips" class="date-chips"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button id="btn-load-submit" class="btn btn-primary">Load</button>
|
||||||
|
<button id="btn-load-cancel" class="btn">Cancel</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Table preview modal -->
|
<!-- Table preview modal -->
|
||||||
<div id="modal-overlay" class="modal-overlay hidden">
|
<div id="modal-overlay" class="modal-overlay hidden">
|
||||||
<div class="modal">
|
<div class="modal">
|
||||||
|
|||||||
@ -312,6 +312,83 @@ body {
|
|||||||
#modal-body { padding: 16px 18px; overflow-y: auto; flex: 1; font-size: 12px; }
|
#modal-body { padding: 16px 18px; overflow-y: auto; flex: 1; font-size: 12px; }
|
||||||
.modal-footer { padding: 10px 18px; border-top: 1px solid #eee; display: flex; justify-content: flex-end; gap: 8px; }
|
.modal-footer { padding: 10px 18px; border-top: 1px solid #eee; display: flex; justify-content: flex-end; gap: 8px; }
|
||||||
|
|
||||||
|
/* ============================================================
|
||||||
|
LOAD BASELINE / REFERENCE MODAL
|
||||||
|
============================================================ */
|
||||||
|
.load-data-modal { width: 480px; max-height: 80vh; }
|
||||||
|
|
||||||
|
#load-data-body {
|
||||||
|
padding: 20px 24px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 20px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.load-form-fields {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.load-form-fields label {
|
||||||
|
font-size: 11px;
|
||||||
|
color: #555;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.load-form-fields input[type=date],
|
||||||
|
.load-form-fields input[type=text] {
|
||||||
|
border: 1px solid #dce1e7;
|
||||||
|
padding: 7px 10px;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #333;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.load-form-fields input[type=date]:focus,
|
||||||
|
.load-form-fields input[type=text]:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #2980b9;
|
||||||
|
box-shadow: 0 0 0 2px rgba(41,128,185,.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.load-date-preview { display: flex; flex-direction: column; gap: 8px; }
|
||||||
|
.load-date-preview.hidden { display: none; }
|
||||||
|
|
||||||
|
.load-preview-label {
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #7f8c8d;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-chips {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-chip {
|
||||||
|
background: #eaf4fb;
|
||||||
|
color: #1a6fa8;
|
||||||
|
border: 1px solid #c5dff0;
|
||||||
|
padding: 3px 9px;
|
||||||
|
border-radius: 12px;
|
||||||
|
font-size: 11px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-chip-summary {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #555;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
.preview-section h4 { font-size: 12px; margin-bottom: 6px; color: #555; }
|
.preview-section h4 { font-size: 12px; margin-bottom: 6px; color: #555; }
|
||||||
.preview-section + .preview-section { margin-top: 16px; }
|
.preview-section + .preview-section { margin-top: 16px; }
|
||||||
.preview-table { border-collapse: collapse; width: 100%; font-size: 11px; }
|
.preview-table { border-collapse: collapse; width: 100%; font-size: 11px; }
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user