feature: Supporting Screens
This commit is contained in:
@@ -2,192 +2,325 @@
|
||||
<div class="h-full min-h-0 flex flex-col">
|
||||
<AppHeader title="Intake" />
|
||||
|
||||
<div class="page-container flex-1">
|
||||
<h1 class="text-2xl font-bold mb-6">Upload Scanned Document</h1>
|
||||
|
||||
<!-- Barcode-assisted upload -->
|
||||
<div class="card mb-6">
|
||||
<h2 class="text-lg font-semibold mb-4">Quick Upload with Cover Sheet</h2>
|
||||
<p class="text-sm text-gray-600 mb-4">
|
||||
Scan or type a cover sheet barcode to auto-populate batch details.
|
||||
</p>
|
||||
|
||||
<div class="flex gap-4 items-end">
|
||||
<div class="flex-1">
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">
|
||||
Cover Sheet Code
|
||||
</label>
|
||||
<input
|
||||
v-model="coverSheetCode"
|
||||
@keydown.enter.prevent="lookupCoverSheet"
|
||||
type="text"
|
||||
class="form-input"
|
||||
placeholder="VCR-CS-XXXXXXXX"
|
||||
autofocus
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
@click="lookupCoverSheet"
|
||||
class="btn-secondary"
|
||||
:disabled="!coverSheetCode.trim() || lookupLoading"
|
||||
>
|
||||
{{ lookupLoading ? 'Looking up...' : 'Lookup' }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="lookupError" class="text-clinical-danger text-sm mt-3">
|
||||
{{ lookupError }}
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="resolvedCoverSheet"
|
||||
class="mt-4 bg-green-50 border border-green-200 rounded-md p-4"
|
||||
>
|
||||
<p class="text-sm font-medium text-green-800">Cover Sheet Found</p>
|
||||
<dl class="mt-2 text-sm text-green-700 space-y-1">
|
||||
<div>
|
||||
<dt class="inline font-medium">Type:</dt>
|
||||
<dd class="inline">{{ formatBatchType(resolvedCoverSheet.batchType) }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="inline font-medium">Track:</dt>
|
||||
<dd class="inline">{{ formatTrack(resolvedCoverSheet.track) }}</dd>
|
||||
</div>
|
||||
<div v-if="resolvedCoverSheet.patientName">
|
||||
<dt class="inline font-medium">Patient:</dt>
|
||||
<dd class="inline">
|
||||
{{ resolvedCoverSheet.patientName }}
|
||||
({{ resolvedCoverSheet.patientMrn }})
|
||||
</dd>
|
||||
</div>
|
||||
<div v-if="resolvedCoverSheet.assignToUserName">
|
||||
<dt class="inline font-medium">Assign to:</dt>
|
||||
<dd class="inline">{{ resolvedCoverSheet.assignToUserName }}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<p class="text-sm text-green-600 mt-3">
|
||||
Select a file below and click "Upload with Cover Sheet" to create the batch.
|
||||
<div class="flex-1 overflow-y-auto p-4 sm:p-6 lg:p-8">
|
||||
<div class="max-w-7xl mx-auto">
|
||||
<div class="mb-6">
|
||||
<h1 class="text-[1.75rem] font-semibold text-ink-strong leading-tight tracking-tight">
|
||||
Upload Scanned Document
|
||||
</h1>
|
||||
<p class="mt-1 text-sm text-ink-secondary">
|
||||
Create a digitization batch from a PDF or image scan.
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
@click="clearCoverSheet"
|
||||
class="text-xs text-green-700 hover:text-green-900 mt-2"
|
||||
>
|
||||
Clear cover sheet (use manual upload)
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Upload form -->
|
||||
<div class="card mb-6">
|
||||
<h2 class="text-lg font-semibold mb-4">New Batch</h2>
|
||||
<div class="grid grid-cols-1 xl:grid-cols-[minmax(0,0.7fr)_minmax(0,0.3fr)] gap-6 lg:gap-8 items-start">
|
||||
<!-- Main — ~70%: upload + batch details -->
|
||||
<div class="space-y-6 min-w-0">
|
||||
<!-- Cover sheet quick lookup -->
|
||||
<section class="card">
|
||||
<h2 class="text-base font-semibold text-ink-strong mb-1">Cover Sheet Code</h2>
|
||||
<p class="text-sm text-ink-secondary mb-4">
|
||||
Optional. Scan or type a barcode to auto-fill batch details.
|
||||
</p>
|
||||
|
||||
<form @submit.prevent="handleUpload" class="space-y-4">
|
||||
<!-- File input -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">
|
||||
Scanned Document (PDF, JPEG, PNG — max 25 MB)
|
||||
</label>
|
||||
<input
|
||||
type="file"
|
||||
ref="fileInput"
|
||||
@change="onFileChange"
|
||||
accept=".pdf,.jpg,.jpeg,.png"
|
||||
class="block w-full text-sm text-gray-500
|
||||
file:mr-4 file:py-2 file:px-4
|
||||
file:rounded-md file:border-0
|
||||
file:text-sm file:font-semibold
|
||||
file:bg-primary-50 file:text-primary-700
|
||||
hover:file:bg-primary-100"
|
||||
/>
|
||||
<p v-if="selectedFile" class="text-sm text-gray-500 mt-2">
|
||||
{{ selectedFile.name }} ({{ (selectedFile.size / 1024 / 1024).toFixed(2) }} MB)
|
||||
</p>
|
||||
<div class="flex flex-col sm:flex-row gap-3 sm:items-end">
|
||||
<div class="flex-1 min-w-0">
|
||||
<label for="cover-sheet-code" class="block text-sm font-semibold text-ink mb-2">
|
||||
Code
|
||||
</label>
|
||||
<input
|
||||
id="cover-sheet-code"
|
||||
v-model="coverSheetCode"
|
||||
@keydown.enter.prevent="lookupCoverSheet"
|
||||
type="text"
|
||||
class="form-input font-mono"
|
||||
placeholder="VCR-CS-XXXXXXXX"
|
||||
autofocus
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
@click="lookupCoverSheet"
|
||||
class="btn-secondary shrink-0"
|
||||
:disabled="!coverSheetCode.trim() || lookupLoading"
|
||||
>
|
||||
{{ lookupLoading ? 'Looking up...' : 'Lookup' }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<InlineError
|
||||
v-if="lookupError"
|
||||
class="mt-4"
|
||||
title="Cover sheet lookup failed"
|
||||
:message="lookupError"
|
||||
preserved="You can still upload manually without a cover sheet."
|
||||
retry-label="Retry lookup"
|
||||
@retry="lookupCoverSheet"
|
||||
/>
|
||||
|
||||
<div
|
||||
v-if="resolvedCoverSheet"
|
||||
class="mt-4 rounded-input border border-[#ABEFC6] bg-clinical-safe-bg p-4"
|
||||
role="status"
|
||||
>
|
||||
<p class="text-sm font-semibold text-clinical-safe">Cover Sheet Found</p>
|
||||
<dl class="mt-2 text-sm text-ink space-y-1">
|
||||
<div>
|
||||
<dt class="inline font-medium text-ink-secondary">Type:</dt>
|
||||
<dd class="inline ml-1">{{ formatBatchType(resolvedCoverSheet.batchType) }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="inline font-medium text-ink-secondary">Track:</dt>
|
||||
<dd class="inline ml-1">{{ formatTrack(resolvedCoverSheet.track) }}</dd>
|
||||
</div>
|
||||
<div v-if="resolvedCoverSheet.patientName">
|
||||
<dt class="inline font-medium text-ink-secondary">Patient:</dt>
|
||||
<dd class="inline ml-1">
|
||||
{{ resolvedCoverSheet.patientName }}
|
||||
<span v-if="resolvedCoverSheet.patientMrn" class="text-ink-secondary">
|
||||
({{ resolvedCoverSheet.patientMrn }})
|
||||
</span>
|
||||
</dd>
|
||||
</div>
|
||||
<div v-if="resolvedCoverSheet.assignToUserName">
|
||||
<dt class="inline font-medium text-ink-secondary">Assign to:</dt>
|
||||
<dd class="inline ml-1">{{ resolvedCoverSheet.assignToUserName }}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<p class="text-sm text-ink-secondary mt-3">
|
||||
Select a file and upload to create the batch with this cover sheet.
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
@click="clearCoverSheet"
|
||||
class="text-xs font-medium text-clinical-safe hover:underline mt-2"
|
||||
>
|
||||
Clear cover sheet (use manual upload)
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Upload + batch form -->
|
||||
<section class="card">
|
||||
<h2 class="text-base font-semibold text-ink-strong mb-4">New Batch</h2>
|
||||
|
||||
<form @submit.prevent="handleUpload" class="space-y-5">
|
||||
<!-- Drop zone -->
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-ink mb-2">
|
||||
Scanned Document
|
||||
</label>
|
||||
|
||||
<div
|
||||
v-if="!selectedFile"
|
||||
class="upload-dropzone"
|
||||
:class="{
|
||||
'upload-dropzone--active': dragActive,
|
||||
'upload-dropzone--error': !!fileError,
|
||||
}"
|
||||
@dragenter.prevent="onDragEnter"
|
||||
@dragover.prevent="onDragEnter"
|
||||
@dragleave.prevent="onDragLeave"
|
||||
@drop.prevent="onDrop"
|
||||
@click="triggerFilePicker"
|
||||
@keydown.enter.prevent="triggerFilePicker"
|
||||
@keydown.space.prevent="triggerFilePicker"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
aria-label="Choose or drop a scanned document"
|
||||
>
|
||||
<input
|
||||
ref="fileInput"
|
||||
type="file"
|
||||
class="sr-only"
|
||||
accept=".pdf,.jpg,.jpeg,.png"
|
||||
@change="onFileChange"
|
||||
/>
|
||||
<div class="flex flex-col items-center text-center pointer-events-none">
|
||||
<svg
|
||||
class="w-10 h-10 text-primary-500 mb-3"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
d="M12 16V4m0 0L8 8m4-4l4 4M4 16v2a2 2 0 002 2h12a2 2 0 002-2v-2"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.75"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
<p class="text-sm font-semibold text-ink-strong">Upload Files</p>
|
||||
<p class="mt-1 text-sm text-ink-secondary">
|
||||
Drag and drop, or click to browse
|
||||
</p>
|
||||
<p class="mt-3 text-xs text-ink-disabled">
|
||||
PDF, JPEG, PNG — max 25 MB
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-else
|
||||
class="rounded-input border border-line bg-canvas p-4 flex items-start justify-between gap-3"
|
||||
>
|
||||
<div class="min-w-0">
|
||||
<p class="text-sm font-medium text-ink-strong truncate">
|
||||
{{ selectedFile.name }}
|
||||
</p>
|
||||
<p class="text-xs text-ink-secondary mt-0.5">
|
||||
{{ formatFileSize(selectedFile.size) }}
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="text-sm font-medium text-ink-secondary hover:text-ink-strong shrink-0"
|
||||
:disabled="batchStore.loading"
|
||||
@click="clearFile"
|
||||
>
|
||||
Remove
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p v-if="fileError" class="text-sm text-clinical-danger mt-2">{{ fileError }}</p>
|
||||
</div>
|
||||
|
||||
<!-- Batch type -->
|
||||
<div>
|
||||
<label for="batch-type" class="block text-sm font-semibold text-ink mb-2">
|
||||
Batch Type
|
||||
</label>
|
||||
<select
|
||||
id="batch-type"
|
||||
v-model="batchType"
|
||||
class="form-input"
|
||||
:required="!resolvedCoverSheet"
|
||||
:disabled="!!resolvedCoverSheet"
|
||||
>
|
||||
<option value="">Select batch type...</option>
|
||||
<option value="PATIENT_REGISTRATION">Patient Registration</option>
|
||||
<option value="ENCOUNTER_SUMMARY">Encounter Summary</option>
|
||||
<option value="VITALS_SHEET">Vitals Sheet</option>
|
||||
<option value="LAB_RESULTS">Lab Results</option>
|
||||
<option value="MEDICATION_LIST">Medication List</option>
|
||||
<option value="ALLERGY_UPDATE">Allergy Update</option>
|
||||
<option value="MIXED">Mixed</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Track -->
|
||||
<div>
|
||||
<label for="track" class="block text-sm font-semibold text-ink mb-2">Track</label>
|
||||
<select
|
||||
id="track"
|
||||
v-model="track"
|
||||
class="form-input"
|
||||
:disabled="!!resolvedCoverSheet"
|
||||
>
|
||||
<option value="BACKFILL">Backfill (Track A)</option>
|
||||
<option value="LIVE_CAPTURE">Live Capture (Track B)</option>
|
||||
</select>
|
||||
<p class="mt-1.5 text-xs text-ink-secondary">
|
||||
{{ track === 'BACKFILL'
|
||||
? 'Historical or archival document workflow.'
|
||||
: 'Documents from current bedside workflows.' }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Patient search -->
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-ink mb-2">
|
||||
Patient Link
|
||||
<span class="font-normal text-ink-secondary">(optional)</span>
|
||||
</label>
|
||||
<PatientSearch v-model="patientId" />
|
||||
</div>
|
||||
|
||||
<!-- Supersession (correction) -->
|
||||
<div
|
||||
v-if="supersedesBatchId"
|
||||
class="rounded-input border border-primary-100 bg-primary-50 p-4"
|
||||
>
|
||||
<p class="text-sm font-semibold text-primary-800">Correction Batch</p>
|
||||
<p class="text-sm text-primary-700 mt-1">
|
||||
This upload will supersede batch
|
||||
<span class="font-mono">{{ supersedesBatchId.substring(0, 8) }}…</span>
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
@click="clearCorrection"
|
||||
class="text-xs font-medium text-primary-700 hover:underline mt-2"
|
||||
>
|
||||
Cancel correction (upload as new batch)
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<InlineError
|
||||
v-if="uploadError"
|
||||
title="Upload failed"
|
||||
:message="uploadError"
|
||||
preserved="Your selected file and form values were kept."
|
||||
retry-label="Try again"
|
||||
@retry="handleUpload"
|
||||
/>
|
||||
|
||||
<div
|
||||
v-if="uploadSuccess"
|
||||
class="rounded-input border border-[#ABEFC6] bg-clinical-safe-bg p-4"
|
||||
role="status"
|
||||
>
|
||||
<p class="text-sm font-semibold text-clinical-safe">{{ uploadSuccess }}</p>
|
||||
<p class="text-sm text-ink-secondary mt-1">
|
||||
The batch appears in Recent Uploads and is ready for assignment.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="btn-primary"
|
||||
:disabled="!canUpload"
|
||||
>
|
||||
{{ uploadButtonLabel }}
|
||||
</button>
|
||||
</form>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<!-- Batch type -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Batch Type</label>
|
||||
<select
|
||||
v-model="batchType"
|
||||
class="form-input"
|
||||
:required="!resolvedCoverSheet"
|
||||
>
|
||||
<option value="">Select batch type...</option>
|
||||
<option value="PATIENT_REGISTRATION">Patient Registration</option>
|
||||
<option value="ENCOUNTER_SUMMARY">Encounter Summary</option>
|
||||
<option value="VITALS_SHEET">Vitals Sheet</option>
|
||||
<option value="LAB_RESULTS">Lab Results</option>
|
||||
<option value="MEDICATION_LIST">Medication List</option>
|
||||
<option value="ALLERGY_UPDATE">Allergy Update</option>
|
||||
<option value="MIXED">Mixed</option>
|
||||
</select>
|
||||
</div>
|
||||
<!-- Right — ~30%: guidance + recent uploads -->
|
||||
<aside class="space-y-6 min-w-0 xl:sticky xl:top-4">
|
||||
<section class="card">
|
||||
<h2 class="text-base font-semibold text-ink-strong mb-2">Guidance</h2>
|
||||
<ul class="text-sm text-ink-secondary space-y-2 list-disc pl-4">
|
||||
<li>Prefer cover sheet lookup when a printed separator is available.</li>
|
||||
<li>Link a patient now when known; otherwise assign later in the batch workflow.</li>
|
||||
<li>Uploaded batches stay here until an entry clerk is assigned.</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<!-- Track -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Track</label>
|
||||
<select v-model="track" class="form-input">
|
||||
<option value="BACKFILL">Backfill (Track A)</option>
|
||||
<option value="LIVE_CAPTURE">Live Capture (Track B)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Patient search -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">
|
||||
Patient (optional — can link later)
|
||||
</label>
|
||||
<PatientSearch v-model="patientId" />
|
||||
</div>
|
||||
|
||||
<!-- Supersession (correction) -->
|
||||
<div v-if="supersedesBatchId" class="bg-blue-50 border border-blue-200 rounded-md p-4">
|
||||
<p class="text-sm font-medium text-blue-800">Correction Batch</p>
|
||||
<p class="text-sm text-blue-700 mt-1">
|
||||
This upload will supersede batch
|
||||
<span class="font-mono">{{ supersedesBatchId.substring(0, 8) }}...</span>
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
@click="clearCorrection"
|
||||
class="text-xs text-blue-600 hover:text-blue-800 mt-2"
|
||||
>
|
||||
Cancel correction (upload as new batch)
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="uploadError" class="text-clinical-danger text-sm">
|
||||
{{ uploadError }}
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="btn-primary"
|
||||
:disabled="!canUpload"
|
||||
>
|
||||
{{ uploadButtonLabel }}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Recent uploads -->
|
||||
<div class="card">
|
||||
<h2 class="text-lg font-semibold mb-4">Recent Uploads</h2>
|
||||
<div v-if="assignError" class="text-clinical-danger text-sm mb-4">
|
||||
{{ assignError }}
|
||||
<section class="card">
|
||||
<h2 class="text-base font-semibold text-ink-strong mb-4">Recent Uploads</h2>
|
||||
<InlineError
|
||||
v-if="assignError"
|
||||
class="mb-4"
|
||||
title="Assignment failed"
|
||||
:message="assignError"
|
||||
preserved="The batch remains unassigned."
|
||||
retry-label=""
|
||||
/>
|
||||
<BatchList
|
||||
:batches="batchStore.batches"
|
||||
:loading="batchStore.loading"
|
||||
:error="batchStore.error"
|
||||
empty-title="No uploaded batches waiting for assignment."
|
||||
empty-description="New uploads appear here after a scan is submitted."
|
||||
show-assign
|
||||
@assign="openAssignDialog"
|
||||
@retry="loadRecent"
|
||||
/>
|
||||
</section>
|
||||
</aside>
|
||||
</div>
|
||||
<BatchList
|
||||
:batches="batchStore.batches"
|
||||
:loading="batchStore.loading"
|
||||
:error="batchStore.error"
|
||||
empty-title="No uploaded batches waiting for assignment."
|
||||
empty-description="New uploads appear here after a scan is submitted."
|
||||
show-assign
|
||||
@assign="openAssignDialog"
|
||||
@retry="loadRecent"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -210,18 +343,27 @@ import AppHeader from '../components/AppHeader.vue'
|
||||
import PatientSearch from '../components/PatientSearch.vue'
|
||||
import BatchList from '../components/BatchList.vue'
|
||||
import AssignClerkDialog from '../components/AssignClerkDialog.vue'
|
||||
import InlineError from '../components/InlineError.vue'
|
||||
import type { CoverSheetResponse } from '../types'
|
||||
|
||||
const MAX_FILE_BYTES = 25 * 1024 * 1024
|
||||
const ACCEPTED_TYPES = new Set(['application/pdf', 'image/jpeg', 'image/png'])
|
||||
|
||||
const route = useRoute()
|
||||
const batchStore = useBatchStore()
|
||||
const toast = useToast()
|
||||
|
||||
const fileInput = ref<HTMLInputElement | null>(null)
|
||||
const selectedFile = ref<File | null>(null)
|
||||
const dragActive = ref(false)
|
||||
const dragDepth = ref(0)
|
||||
const fileError = ref('')
|
||||
const batchType = ref((route.query.batchType as string) || '')
|
||||
const track = ref('BACKFILL')
|
||||
const patientId = ref<string | undefined>((route.query.patientId as string) || undefined)
|
||||
const supersedesBatchId = ref<string | undefined>((route.query.supersedesBatchId as string) || undefined)
|
||||
const uploadError = ref('')
|
||||
const uploadSuccess = ref('')
|
||||
const assignError = ref('')
|
||||
const assignDialogOpen = ref(false)
|
||||
const assignBatchId = ref<string | null>(null)
|
||||
@@ -258,9 +400,65 @@ function formatTrack(value: string): string {
|
||||
return value === 'BACKFILL' ? 'Backfill (Track A)' : 'Live Capture (Track B)'
|
||||
}
|
||||
|
||||
function formatFileSize(bytes: number): string {
|
||||
return `${(bytes / 1024 / 1024).toFixed(2)} MB`
|
||||
}
|
||||
|
||||
function triggerFilePicker() {
|
||||
fileInput.value?.click()
|
||||
}
|
||||
|
||||
function validateFile(file: File): string | null {
|
||||
if (file.size > MAX_FILE_BYTES) return 'File exceeds the 25 MB limit.'
|
||||
if (file.type && !ACCEPTED_TYPES.has(file.type)) {
|
||||
return 'Unsupported file type. Use PDF, JPEG, or PNG.'
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
function setSelectedFile(file: File | null) {
|
||||
fileError.value = ''
|
||||
uploadError.value = ''
|
||||
uploadSuccess.value = ''
|
||||
if (!file) {
|
||||
selectedFile.value = null
|
||||
return
|
||||
}
|
||||
const error = validateFile(file)
|
||||
if (error) {
|
||||
selectedFile.value = null
|
||||
fileError.value = error
|
||||
return
|
||||
}
|
||||
selectedFile.value = file
|
||||
}
|
||||
|
||||
function onFileChange(event: Event) {
|
||||
const input = event.target as HTMLInputElement
|
||||
selectedFile.value = input.files?.[0] ?? null
|
||||
setSelectedFile(input.files?.[0] ?? null)
|
||||
}
|
||||
|
||||
function clearFile() {
|
||||
selectedFile.value = null
|
||||
fileError.value = ''
|
||||
if (fileInput.value) fileInput.value.value = ''
|
||||
}
|
||||
|
||||
function onDragEnter() {
|
||||
dragDepth.value += 1
|
||||
dragActive.value = true
|
||||
}
|
||||
|
||||
function onDragLeave() {
|
||||
dragDepth.value = Math.max(0, dragDepth.value - 1)
|
||||
if (dragDepth.value === 0) dragActive.value = false
|
||||
}
|
||||
|
||||
function onDrop(event: DragEvent) {
|
||||
dragDepth.value = 0
|
||||
dragActive.value = false
|
||||
const file = event.dataTransfer?.files?.[0] ?? null
|
||||
setSelectedFile(file)
|
||||
}
|
||||
|
||||
async function lookupCoverSheet(): Promise<void> {
|
||||
@@ -309,6 +507,7 @@ async function handleUpload() {
|
||||
if (!selectedFile.value || !canUpload.value) return
|
||||
|
||||
uploadError.value = ''
|
||||
uploadSuccess.value = ''
|
||||
try {
|
||||
const batch = await batchStore.uploadBatch(
|
||||
selectedFile.value,
|
||||
@@ -322,18 +521,19 @@ async function handleUpload() {
|
||||
const isCorrection = !!supersedesBatchId.value
|
||||
const usedCoverSheet = !!resolvedCoverSheet.value
|
||||
selectedFile.value = null
|
||||
if (fileInput.value) fileInput.value.value = ''
|
||||
batchType.value = ''
|
||||
track.value = 'BACKFILL'
|
||||
patientId.value = undefined
|
||||
supersedesBatchId.value = undefined
|
||||
clearCoverSheet()
|
||||
toast.success(
|
||||
isCorrection
|
||||
? 'Correction batch created'
|
||||
: usedCoverSheet
|
||||
? 'Batch uploaded with cover sheet'
|
||||
: 'Batch uploaded successfully',
|
||||
)
|
||||
const message = isCorrection
|
||||
? 'Correction batch created'
|
||||
: usedCoverSheet
|
||||
? 'Batch uploaded with cover sheet'
|
||||
: 'Batch uploaded successfully'
|
||||
uploadSuccess.value = message
|
||||
toast.success(message)
|
||||
await loadRecent()
|
||||
}
|
||||
} catch (e: unknown) {
|
||||
|
||||
Reference in New Issue
Block a user