128 lines
3.9 KiB
Svelte
128 lines
3.9 KiB
Svelte
<script>
|
|
import { Plus, FileText, RefreshCw } from 'lucide-svelte';
|
|
import OrderCard from './OrderCard.svelte';
|
|
import { formatPatientName } from '$lib/utils/patients.js';
|
|
|
|
/**
|
|
* @typedef {Object} Patient
|
|
* @property {string} InternalPID
|
|
* @property {string} PatientID
|
|
* @property {string} [FullName]
|
|
* @property {string} [Prefix]
|
|
* @property {string} [NameFirst]
|
|
* @property {string} [NameMiddle]
|
|
* @property {string} [NameLast]
|
|
*/
|
|
|
|
/**
|
|
* @typedef {Object} Order
|
|
* @property {string} [OrderID]
|
|
* @property {string} [OrderNumber]
|
|
* @property {string} [Status]
|
|
* @property {string} [TestName]
|
|
*/
|
|
|
|
/** @type {{
|
|
* patient: Patient | null,
|
|
* orders: Order[],
|
|
* loading: boolean,
|
|
* onCreateOrder: () => void,
|
|
* onViewOrder: (order: Order) => void,
|
|
* onPrintBarcode: (order: Order) => void,
|
|
* onRefresh: () => void
|
|
* }} */
|
|
let {
|
|
patient = null,
|
|
orders = [],
|
|
loading = false,
|
|
onCreateOrder,
|
|
onViewOrder,
|
|
onPrintBarcode,
|
|
onRefresh
|
|
} = $props();
|
|
|
|
let patientName = $derived(formatPatientName(patient));
|
|
let hasOrders = $derived(orders.length > 0);
|
|
</script>
|
|
|
|
<div class="bg-base-100 rounded-lg shadow border border-base-200 flex flex-col h-full overflow-hidden">
|
|
{#if patient}
|
|
<!-- Patient Header -->
|
|
<div class="p-3 bg-base-200 border-b border-base-200">
|
|
<div class="flex items-center justify-between">
|
|
<div class="min-w-0 flex-1">
|
|
<h3 class="font-bold text-base truncate" title={patientName}>
|
|
{patientName}
|
|
</h3>
|
|
<p class="text-xs text-gray-600">ID: {patient.PatientID}</p>
|
|
</div>
|
|
<div class="flex gap-1 ml-2">
|
|
<button
|
|
class="btn btn-sm btn-ghost"
|
|
title="Refresh"
|
|
onclick={onRefresh}
|
|
disabled={loading}
|
|
>
|
|
<RefreshCw class="w-4 h-4" />
|
|
</button>
|
|
<button
|
|
class="btn btn-primary btn-sm"
|
|
onclick={onCreateOrder}
|
|
>
|
|
<Plus class="w-4 h-4 mr-1" />
|
|
New Order
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Orders List -->
|
|
<div class="flex-1 overflow-auto p-3">
|
|
{#if loading}
|
|
<div class="flex items-center justify-center py-12">
|
|
<span class="loading loading-spinner loading-lg text-primary"></span>
|
|
</div>
|
|
{:else if !hasOrders}
|
|
<div class="text-center py-12 text-gray-500">
|
|
<FileText class="w-12 h-12 mx-auto mb-3 opacity-50" />
|
|
<p class="text-base">No orders found</p>
|
|
<p class="text-sm mt-1">This patient has no lab orders.</p>
|
|
<button
|
|
class="btn btn-primary btn-sm mt-4"
|
|
onclick={onCreateOrder}
|
|
>
|
|
<Plus class="w-4 h-4 mr-1" />
|
|
Create First Order
|
|
</button>
|
|
</div>
|
|
{:else}
|
|
<!-- Compact Orders Table Header -->
|
|
<div class="flex items-center py-1 px-2 text-xs font-medium text-gray-500 border-b border-base-300 bg-base-100">
|
|
<span class="w-24">Order #</span>
|
|
<span class="w-24">Date</span>
|
|
<span class="flex-1">Doctor</span>
|
|
<span class="w-8"></span>
|
|
</div>
|
|
<div class="divide-y divide-base-200">
|
|
{#each orders as order (order.OrderID || order.OrderNumber)}
|
|
<OrderCard
|
|
{order}
|
|
onView={() => onViewOrder(order)}
|
|
onPrintBarcode={() => onPrintBarcode(order)}
|
|
/>
|
|
{/each}
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
{:else}
|
|
<!-- Empty State -->
|
|
<div class="flex-1 flex items-center justify-center text-gray-500 p-6">
|
|
<div class="text-center">
|
|
<FileText class="w-16 h-16 mx-auto mb-4 opacity-50" />
|
|
<p class="text-lg">Select a patient</p>
|
|
<p class="text-sm">Click a patient to view lab orders</p>
|
|
</div>
|
|
</div>
|
|
{/if}
|
|
</div>
|