Enforce job note number at toggle level and tighten save UX
This commit is contained in:
+46
-13
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user