Enforce job note number at toggle level and tighten save UX

This commit is contained in:
2026-03-29 02:36:07 +00:00
parent 9a6da32504
commit d042f00230
+46 -13
View File
@@ -167,7 +167,7 @@
</div> </div>
<label class="flex items-center gap-2 text-sm text-slate-300"> <label class="flex items-center gap-2 text-sm text-slate-300">
<input id="jobNoteToggle" type="checkbox" class="h-4 w-4 rounded border-slate-600 bg-slate-900 text-cyan-400 focus:ring-cyan-500" /> <input id="jobNoteToggle" type="checkbox" class="h-4 w-4 rounded border-slate-600 bg-slate-900 text-cyan-400 focus:ring-cyan-500" />
<span>Classify as Job Note</span> <span>Job Note</span>
</label> </label>
<textarea id="bodyInput" rows="8" class="field" placeholder="Write your note..."></textarea> <textarea id="bodyInput" rows="8" class="field" placeholder="Write your note..."></textarea>
<input id="shareInput" class="field" placeholder="Share with (comma separated names)" /> <input id="shareInput" class="field" placeholder="Share with (comma separated names)" />
@@ -279,14 +279,36 @@
output.textContent = typeof value === 'string' ? value : JSON.stringify(value, null, 2); output.textContent = typeof value === 'string' ? value : JSON.stringify(value, null, 2);
} }
function hasJobNumberRequirementMet() {
return !jobNoteToggle.checked || !!jobNumberInput.value.trim();
}
function refreshActionButtons() {
const blockedByJobNumber = !hasJobNumberRequirementMet();
const busy = !!actionInFlight;
createBtn.disabled = busy || !!selectedNote || blockedByJobNumber;
copyBtn.disabled = busy || !selectedNote || blockedByJobNumber;
saveBtn.disabled = busy || !selectedNote || blockedByJobNumber;
hideBtn.disabled = busy || !selectedNote;
deleteBtn.disabled = busy || !selectedNote;
}
function updateJobNoteUi() {
const required = !!jobNoteToggle.checked;
jobNumberInput.required = required;
if (required && !jobNumberInput.value.trim()) {
jobNumberInput.setAttribute('aria-invalid', 'true');
jobNumberInput.classList.add('border-rose-500');
} else {
jobNumberInput.removeAttribute('aria-invalid');
jobNumberInput.classList.remove('border-rose-500');
}
refreshActionButtons();
}
function setActionBusy(isBusy) { function setActionBusy(isBusy) {
actionInFlight = isBusy; actionInFlight = isBusy;
const disabled = !!isBusy; refreshActionButtons();
createBtn.disabled = disabled || !!selectedNote;
copyBtn.disabled = disabled || !selectedNote;
saveBtn.disabled = disabled || !selectedNote;
hideBtn.disabled = disabled || !selectedNote;
deleteBtn.disabled = disabled || !selectedNote;
} }
async function runNoteAction(handler) { async function runNoteAction(handler) {
@@ -628,7 +650,7 @@
const jobNumber = jobNumberInput.value.trim(); const jobNumber = jobNumberInput.value.trim();
const isJobNote = !!jobNoteToggle.checked; const isJobNote = !!jobNoteToggle.checked;
if (isJobNote && !jobNumber) { if (isJobNote && !jobNumber) {
throw new Error('Job Number is required when Classify as Job Note is enabled'); throw new Error('Job Number is required when Job Note is enabled');
} }
const sharedWith = normalizeShares(shareInput.value); const sharedWith = normalizeShares(shareInput.value);
@@ -785,8 +807,7 @@
selectedAttachmentsStatus.textContent = 'Select a note to view attachments.'; selectedAttachmentsStatus.textContent = 'Select a note to view attachments.';
selectedAttachmentsList.innerHTML = ''; selectedAttachmentsList.innerHTML = '';
setActionBusy(false); setActionBusy(false);
createBtn.disabled = false; updateJobNoteUi();
copyBtn.disabled = true;
} }
function selectNote(note) { function selectNote(note) {
@@ -809,8 +830,7 @@
recordStatus.textContent = 'Ready'; recordStatus.textContent = 'Ready';
lastRecordedFile = null; lastRecordedFile = null;
setActionBusy(false); setActionBusy(false);
createBtn.disabled = true; updateJobNoteUi();
copyBtn.disabled = false;
hideBtn.textContent = toBoolFlag(note.hidden) ? 'Unhide' : 'Hide'; hideBtn.textContent = toBoolFlag(note.hidden) ? 'Unhide' : 'Hide';
} }
@@ -965,7 +985,7 @@
selectNote(refreshed); selectNote(refreshed);
renderList(); renderList();
await renderSelectedAttachments(); await renderSelectedAttachments();
writeOutput({ message: 'Note updated', id: record.id, attachmentsUploaded: uploaded.length }); writeOutput({ message: 'Note updated', id: record.id, attachmentsUploaded: uploaded.length, job_note: payload.job_note, Job_Number: payload.Job_Number || '' });
} }
async function toggleHidden() { async function toggleHidden() {
@@ -1029,6 +1049,18 @@
renderPendingAttachments(); renderPendingAttachments();
}); });
jobNoteToggle.addEventListener('change', () => {
updateJobNoteUi();
if (jobNoteToggle.checked && !jobNumberInput.value.trim()) {
writeOutput('Job Number is required when Job Note is enabled.');
jobNumberInput.focus();
}
});
jobNumberInput.addEventListener('input', () => {
updateJobNoteUi();
});
startRecordBtn.addEventListener('click', async () => { startRecordBtn.addEventListener('click', async () => {
try { try {
await startAudioRecording(); await startAudioRecording();
@@ -1070,6 +1102,7 @@
bootstrapWorkspace(); bootstrapWorkspace();
clearForm(); clearForm();
updateJobNoteUi();
renderPendingAttachments(); renderPendingAttachments();
renderList(); renderList();
loadHealth(); loadHealth();