Add focus-within input patterns, update Sidebar, TestMapModal, and PatientSearchBar components
This commit is contained in:
parent
ad1618efec
commit
ecc4822a38
33
AGENTS.md
33
AGENTS.md
@ -194,6 +194,39 @@ try {
|
|||||||
- **Sizes**: `btn-sm`, `input-sm`, `select-sm` for compact forms
|
- **Sizes**: `btn-sm`, `input-sm`, `select-sm` for compact forms
|
||||||
- **Custom**: `.compact-y`, `.compact-p`, `.compact-input`, `.compact-btn`, `.compact-card`
|
- **Custom**: `.compact-y`, `.compact-p`, `.compact-input`, `.compact-btn`, `.compact-card`
|
||||||
|
|
||||||
|
### Input with Icons (DaisyUI Pattern)
|
||||||
|
|
||||||
|
**Correct way** - Use DaisyUI's built-in input with icon support:
|
||||||
|
|
||||||
|
```svelte
|
||||||
|
<!-- WRONG: Absolute positioning (icons may not render) -->
|
||||||
|
<div class="relative">
|
||||||
|
<span class="absolute left-3 top-1/2 -translate-y-1/2">
|
||||||
|
<User class="w-4 h-4" />
|
||||||
|
</span>
|
||||||
|
<input class="input input-sm input-bordered pl-9" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- CORRECT: DaisyUI input with flex layout -->
|
||||||
|
<label class="input input-sm input-bordered flex items-center gap-2 w-full focus-within:input-primary">
|
||||||
|
<User class="w-4 h-4 text-gray-400" />
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="grow bg-transparent outline-none"
|
||||||
|
placeholder="Enter value..."
|
||||||
|
bind:value={someValue}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key points:**
|
||||||
|
- Use `<label>` element as the input container with `input input-bordered` classes
|
||||||
|
- Add `flex items-center gap-2` for layout
|
||||||
|
- Icon is a **sibling** of the input, not absolutely positioned
|
||||||
|
- Input uses `class="grow bg-transparent outline-none"` to fill space
|
||||||
|
- Use `focus-within:input-primary` for focus state on the container
|
||||||
|
- Always add `text-gray-400` or similar color to the icon for visibility
|
||||||
|
|
||||||
## Project Structure
|
## Project Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@ -34,8 +34,10 @@ import {
|
|||||||
|
|
||||||
// Collapsible section states - default collapsed
|
// Collapsible section states - default collapsed
|
||||||
let laboratoryExpanded = $state(false);
|
let laboratoryExpanded = $state(false);
|
||||||
let masterDataExpanded = $state(false);
|
|
||||||
let organizationExpanded = $state(false);
|
let organizationExpanded = $state(false);
|
||||||
|
let labSetupExpanded = $state(false);
|
||||||
|
let usersContactsExpanded = $state(false);
|
||||||
|
let referenceDataExpanded = $state(false);
|
||||||
|
|
||||||
// Load states from localStorage on mount
|
// Load states from localStorage on mount
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
@ -45,8 +47,10 @@ import {
|
|||||||
try {
|
try {
|
||||||
const parsed = JSON.parse(savedStates);
|
const parsed = JSON.parse(savedStates);
|
||||||
laboratoryExpanded = parsed.laboratory ?? false;
|
laboratoryExpanded = parsed.laboratory ?? false;
|
||||||
masterDataExpanded = parsed.masterData ?? false;
|
|
||||||
organizationExpanded = parsed.organization ?? false;
|
organizationExpanded = parsed.organization ?? false;
|
||||||
|
labSetupExpanded = parsed.labSetup ?? false;
|
||||||
|
usersContactsExpanded = parsed.usersContacts ?? false;
|
||||||
|
referenceDataExpanded = parsed.referenceData ?? false;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Keep defaults if parsing fails
|
// Keep defaults if parsing fails
|
||||||
}
|
}
|
||||||
@ -59,8 +63,10 @@ import {
|
|||||||
if (browser) {
|
if (browser) {
|
||||||
localStorage.setItem('sidebar_section_states', JSON.stringify({
|
localStorage.setItem('sidebar_section_states', JSON.stringify({
|
||||||
laboratory: laboratoryExpanded,
|
laboratory: laboratoryExpanded,
|
||||||
masterData: masterDataExpanded,
|
organization: organizationExpanded,
|
||||||
organization: organizationExpanded
|
labSetup: labSetupExpanded,
|
||||||
|
usersContacts: usersContactsExpanded,
|
||||||
|
referenceData: referenceDataExpanded
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -69,8 +75,10 @@ import {
|
|||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (!isOpen) {
|
if (!isOpen) {
|
||||||
laboratoryExpanded = false;
|
laboratoryExpanded = false;
|
||||||
masterDataExpanded = false;
|
|
||||||
organizationExpanded = false;
|
organizationExpanded = false;
|
||||||
|
labSetupExpanded = false;
|
||||||
|
usersContactsExpanded = false;
|
||||||
|
referenceDataExpanded = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -96,19 +104,33 @@ function toggleLaboratory() {
|
|||||||
laboratoryExpanded = !laboratoryExpanded;
|
laboratoryExpanded = !laboratoryExpanded;
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleMasterData() {
|
|
||||||
if (!isOpen) {
|
|
||||||
expandSidebar();
|
|
||||||
}
|
|
||||||
masterDataExpanded = !masterDataExpanded;
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleOrganization() {
|
function toggleOrganization() {
|
||||||
if (!isOpen) {
|
if (!isOpen) {
|
||||||
expandSidebar();
|
expandSidebar();
|
||||||
}
|
}
|
||||||
organizationExpanded = !organizationExpanded;
|
organizationExpanded = !organizationExpanded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleLabSetup() {
|
||||||
|
if (!isOpen) {
|
||||||
|
expandSidebar();
|
||||||
|
}
|
||||||
|
labSetupExpanded = !labSetupExpanded;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleUsersContacts() {
|
||||||
|
if (!isOpen) {
|
||||||
|
expandSidebar();
|
||||||
|
}
|
||||||
|
usersContactsExpanded = !usersContactsExpanded;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleReferenceData() {
|
||||||
|
if (!isOpen) {
|
||||||
|
expandSidebar();
|
||||||
|
}
|
||||||
|
referenceDataExpanded = !referenceDataExpanded;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- Mobile Overlay Backdrop -->
|
<!-- Mobile Overlay Backdrop -->
|
||||||
@ -212,52 +234,101 @@ function toggleLaboratory() {
|
|||||||
<li class="menu-title uppercase font-bold text-xs text-secondary/70 mt-4">Configuration</li>
|
<li class="menu-title uppercase font-bold text-xs text-secondary/70 mt-4">Configuration</li>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<!-- Master Data -->
|
<!-- Organization -->
|
||||||
<li class="nav-group" class:collapsed={!isOpen}>
|
<li class="nav-group" class:collapsed={!isOpen}>
|
||||||
<button
|
<button
|
||||||
onclick={toggleMasterData}
|
onclick={toggleOrganization}
|
||||||
class="nav-link"
|
class="nav-link"
|
||||||
class:centered={!isOpen}
|
class:centered={!isOpen}
|
||||||
title={!isOpen ? 'Master Data' : ''}
|
title={!isOpen ? 'Organization' : ''}
|
||||||
>
|
>
|
||||||
<Database size={20} class="text-secondary flex-shrink-0" />
|
<Building2 size={20} class="text-secondary flex-shrink-0" />
|
||||||
{#if isOpen}
|
{#if isOpen}
|
||||||
<span class="nav-text">Master Data</span>
|
<span class="nav-text">Organization</span>
|
||||||
<ChevronDown size={16} class="chevron {masterDataExpanded ? 'expanded' : ''}" />
|
<ChevronDown size={16} class="chevron {organizationExpanded ? 'expanded' : ''}" />
|
||||||
{/if}
|
{/if}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{#if isOpen && masterDataExpanded}
|
{#if isOpen && organizationExpanded}
|
||||||
<ul class="submenu">
|
<ul class="submenu">
|
||||||
<!-- Organization with nested submenu -->
|
<li><a href="/master-data/organization/account" class="submenu-link"><User size={16} /> Account</a></li>
|
||||||
<li class="nav-group">
|
<li><a href="/master-data/organization/site" class="submenu-link"><LandPlot size={16} /> Site</a></li>
|
||||||
<button
|
<li><a href="/master-data/organization/department" class="submenu-link"><Users size={16} /> Department</a></li>
|
||||||
onclick={toggleOrganization}
|
<li><a href="/master-data/organization/discipline" class="submenu-link"><Building2 size={16} /> Discipline</a></li>
|
||||||
class="submenu-link"
|
<li><a href="/master-data/organization/workstation" class="submenu-link"><Monitor size={16} /> Workstation</a></li>
|
||||||
>
|
<li><a href="/master-data/organization/instrument" class="submenu-link"><Activity size={16} /> Instrument</a></li>
|
||||||
<Building2 size={16} /> Organization
|
|
||||||
<ChevronDown size={14} class="chevron ml-auto {organizationExpanded ? 'expanded' : ''}" />
|
|
||||||
</button>
|
|
||||||
{#if organizationExpanded}
|
|
||||||
<ul class="submenu nested">
|
|
||||||
<li><a href="/master-data/organization/account" class="submenu-link"><User size={14} /> Account</a></li>
|
|
||||||
<li><a href="/master-data/organization/site" class="submenu-link"><LandPlot size={14} /> Site</a></li>
|
|
||||||
<li><a href="/master-data/organization/department" class="submenu-link"><Users size={14} /> Department</a></li>
|
|
||||||
<li><a href="/master-data/organization/discipline" class="submenu-link"><Building2 size={14} /> Discipline</a></li>
|
|
||||||
<li><a href="/master-data/organization/workstation" class="submenu-link"><Monitor size={14} /> Workstation</a></li>
|
|
||||||
<li><a href="/master-data/organization/instrument" class="submenu-link"><Activity size={14} /> Instrument</a></li>
|
|
||||||
</ul>
|
</ul>
|
||||||
{/if}
|
{/if}
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<!-- Lab Setup -->
|
||||||
|
<li class="nav-group" class:collapsed={!isOpen}>
|
||||||
|
<button
|
||||||
|
onclick={toggleLabSetup}
|
||||||
|
class="nav-link"
|
||||||
|
class:centered={!isOpen}
|
||||||
|
title={!isOpen ? 'Lab Setup' : ''}
|
||||||
|
>
|
||||||
|
<FlaskConical size={20} class="text-secondary flex-shrink-0" />
|
||||||
|
{#if isOpen}
|
||||||
|
<span class="nav-text">Lab Setup</span>
|
||||||
|
<ChevronDown size={16} class="chevron {labSetupExpanded ? 'expanded' : ''}" />
|
||||||
|
{/if}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{#if isOpen && labSetupExpanded}
|
||||||
|
<ul class="submenu">
|
||||||
<li><a href="/master-data/containers" class="submenu-link"><FlaskConical size={16} /> Containers</a></li>
|
<li><a href="/master-data/containers" class="submenu-link"><FlaskConical size={16} /> Containers</a></li>
|
||||||
<li><a href="/master-data/tests" class="submenu-link"><TestTube size={16} /> Test Definitions</a></li>
|
<li><a href="/master-data/tests" class="submenu-link"><TestTube size={16} /> Test Definitions</a></li>
|
||||||
<li><a href="/master-data/testmap" class="submenu-link"><Link size={16} /> Test Mapping</a></li>
|
<li><a href="/master-data/testmap" class="submenu-link"><Link size={16} /> Test Mapping</a></li>
|
||||||
|
</ul>
|
||||||
|
{/if}
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<!-- Users & Contacts -->
|
||||||
|
<li class="nav-group" class:collapsed={!isOpen}>
|
||||||
|
<button
|
||||||
|
onclick={toggleUsersContacts}
|
||||||
|
class="nav-link"
|
||||||
|
class:centered={!isOpen}
|
||||||
|
title={!isOpen ? 'Users & Contacts' : ''}
|
||||||
|
>
|
||||||
|
<Users size={20} class="text-secondary flex-shrink-0" />
|
||||||
|
{#if isOpen}
|
||||||
|
<span class="nav-text">Users & Contacts</span>
|
||||||
|
<ChevronDown size={16} class="chevron {usersContactsExpanded ? 'expanded' : ''}" />
|
||||||
|
{/if}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{#if isOpen && usersContactsExpanded}
|
||||||
|
<ul class="submenu">
|
||||||
<li><a href="/master-data/users" class="submenu-link"><UserCircle size={16} /> Users</a></li>
|
<li><a href="/master-data/users" class="submenu-link"><UserCircle size={16} /> Users</a></li>
|
||||||
<li><a href="/master-data/valuesets" class="submenu-link"><List size={16} /> ValueSets</a></li>
|
|
||||||
<li><a href="/master-data/locations" class="submenu-link"><MapPin size={16} /> Locations</a></li>
|
|
||||||
<li><a href="/master-data/contacts" class="submenu-link"><Users size={16} /> Contacts</a></li>
|
<li><a href="/master-data/contacts" class="submenu-link"><Users size={16} /> Contacts</a></li>
|
||||||
<li><a href="/master-data/specialties" class="submenu-link"><Stethoscope size={16} /> Specialties</a></li>
|
<li><a href="/master-data/specialties" class="submenu-link"><Stethoscope size={16} /> Specialties</a></li>
|
||||||
<li><a href="/master-data/occupations" class="submenu-link"><Briefcase size={16} /> Occupations</a></li>
|
<li><a href="/master-data/occupations" class="submenu-link"><Briefcase size={16} /> Occupations</a></li>
|
||||||
|
</ul>
|
||||||
|
{/if}
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<!-- Reference Data -->
|
||||||
|
<li class="nav-group" class:collapsed={!isOpen}>
|
||||||
|
<button
|
||||||
|
onclick={toggleReferenceData}
|
||||||
|
class="nav-link"
|
||||||
|
class:centered={!isOpen}
|
||||||
|
title={!isOpen ? 'Reference Data' : ''}
|
||||||
|
>
|
||||||
|
<Database size={20} class="text-secondary flex-shrink-0" />
|
||||||
|
{#if isOpen}
|
||||||
|
<span class="nav-text">Reference Data</span>
|
||||||
|
<ChevronDown size={16} class="chevron {referenceDataExpanded ? 'expanded' : ''}" />
|
||||||
|
{/if}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{#if isOpen && referenceDataExpanded}
|
||||||
|
<ul class="submenu">
|
||||||
|
<li><a href="/master-data/valuesets" class="submenu-link"><List size={16} /> ValueSets</a></li>
|
||||||
|
<li><a href="/master-data/locations" class="submenu-link"><MapPin size={16} /> Locations</a></li>
|
||||||
<li><a href="/master-data/counters" class="submenu-link"><Hash size={16} /> Counters</a></li>
|
<li><a href="/master-data/counters" class="submenu-link"><Hash size={16} /> Counters</a></li>
|
||||||
<li><a href="/master-data/geography" class="submenu-link"><Globe size={16} /> Geography</a></li>
|
<li><a href="/master-data/geography" class="submenu-link"><Globe size={16} /> Geography</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@ -323,6 +323,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Scrollable Middle Section: Editable Table -->
|
<!-- Scrollable Middle Section: Editable Table -->
|
||||||
<div class="flex-1 overflow-y-auto space-y-1 py-2">
|
<div class="flex-1 overflow-y-auto space-y-1 py-2">
|
||||||
|
|||||||
@ -14,7 +14,9 @@
|
|||||||
patientId: '',
|
patientId: '',
|
||||||
patientName: '',
|
patientName: '',
|
||||||
visitNumber: '',
|
visitNumber: '',
|
||||||
orderNumber: ''
|
orderNumber: '',
|
||||||
|
orderDateFrom: '',
|
||||||
|
orderDateTo: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
// List state
|
// List state
|
||||||
@ -73,6 +75,12 @@
|
|||||||
if (searchFilters.orderNumber.trim()) {
|
if (searchFilters.orderNumber.trim()) {
|
||||||
params.OrderNumber = searchFilters.orderNumber.trim();
|
params.OrderNumber = searchFilters.orderNumber.trim();
|
||||||
}
|
}
|
||||||
|
if (searchFilters.orderDateFrom) {
|
||||||
|
params.OrderDateFrom = searchFilters.orderDateFrom;
|
||||||
|
}
|
||||||
|
if (searchFilters.orderDateTo) {
|
||||||
|
params.OrderDateTo = searchFilters.orderDateTo;
|
||||||
|
}
|
||||||
|
|
||||||
const response = await fetchPatients(params);
|
const response = await fetchPatients(params);
|
||||||
patients = Array.isArray(response.data) ? response.data : [];
|
patients = Array.isArray(response.data) ? response.data : [];
|
||||||
@ -94,7 +102,9 @@
|
|||||||
patientId: '',
|
patientId: '',
|
||||||
patientName: '',
|
patientName: '',
|
||||||
visitNumber: '',
|
visitNumber: '',
|
||||||
orderNumber: ''
|
orderNumber: '',
|
||||||
|
orderDateFrom: '',
|
||||||
|
orderDateTo: ''
|
||||||
};
|
};
|
||||||
patients = [];
|
patients = [];
|
||||||
selectedPatient = null;
|
selectedPatient = null;
|
||||||
@ -246,7 +256,7 @@
|
|||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<h1 class="text-2xl font-bold text-gray-800">Laboratory Orders</h1>
|
<h1 class="text-2xl font-bold text-gray-800">Patient Search</h1>
|
||||||
<p class="text-sm text-gray-600">Search patients and manage lab orders</p>
|
<p class="text-sm text-gray-600">Search patients and manage lab orders</p>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-primary btn-sm" onclick={openCreateModal}>
|
<button class="btn btn-primary btn-sm" onclick={openCreateModal}>
|
||||||
@ -261,6 +271,8 @@
|
|||||||
bind:patientName={searchFilters.patientName}
|
bind:patientName={searchFilters.patientName}
|
||||||
bind:visitNumber={searchFilters.visitNumber}
|
bind:visitNumber={searchFilters.visitNumber}
|
||||||
bind:orderNumber={searchFilters.orderNumber}
|
bind:orderNumber={searchFilters.orderNumber}
|
||||||
|
bind:orderDateFrom={searchFilters.orderDateFrom}
|
||||||
|
bind:orderDateTo={searchFilters.orderDateTo}
|
||||||
{loading}
|
{loading}
|
||||||
onSearch={handleSearch}
|
onSearch={handleSearch}
|
||||||
onClear={handleClear}
|
onClear={handleClear}
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
<script>
|
<script>
|
||||||
import { Search, X } from 'lucide-svelte';
|
import { Search, X, User, FileUser, ClipboardList, FileText, Calendar } from 'lucide-svelte';
|
||||||
import { debounce } from '$lib/utils/patients.js';
|
|
||||||
|
|
||||||
/** @type {{
|
/** @type {{
|
||||||
* patientId: string,
|
* patientId: string,
|
||||||
* patientName: string,
|
* patientName: string,
|
||||||
* visitNumber: string,
|
* visitNumber: string,
|
||||||
* orderNumber: string,
|
* orderNumber: string,
|
||||||
|
* orderDateFrom: string,
|
||||||
|
* orderDateTo: string,
|
||||||
* loading: boolean,
|
* loading: boolean,
|
||||||
* onSearch: () => void,
|
* onSearch: () => void,
|
||||||
* onClear: () => void
|
* onClear: () => void
|
||||||
@ -16,6 +17,8 @@
|
|||||||
patientName = '',
|
patientName = '',
|
||||||
visitNumber = '',
|
visitNumber = '',
|
||||||
orderNumber = '',
|
orderNumber = '',
|
||||||
|
orderDateFrom = '',
|
||||||
|
orderDateTo = '',
|
||||||
loading = false,
|
loading = false,
|
||||||
onSearch,
|
onSearch,
|
||||||
onClear
|
onClear
|
||||||
@ -28,85 +31,139 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function hasFilters() {
|
function hasFilters() {
|
||||||
return patientId || patientName || visitNumber || orderNumber;
|
return patientId || patientName || visitNumber || orderNumber || orderDateFrom || orderDateTo;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="bg-base-100 rounded-lg shadow-sm border border-base-200 p-3">
|
<div class="bg-base-100 rounded-xl shadow-lg border border-base-300/50 p-3">
|
||||||
<div class="flex flex-wrap items-end gap-2">
|
<div class="flex flex-col gap-3">
|
||||||
|
<!-- Row 1: Patient ID and Patient Name -->
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-3">
|
||||||
<!-- Patient ID -->
|
<!-- Patient ID -->
|
||||||
<div class="flex-1 min-w-[140px]">
|
<div class="form-control">
|
||||||
<label class="label py-0 mb-1" for="searchPatientId">
|
<label class="label py-0 mb-1" for="searchPatientId">
|
||||||
<span class="label-text text-xs text-gray-500">Patient ID</span>
|
<span class="label-text text-xs font-medium text-gray-600">Patient ID</span>
|
||||||
</label>
|
</label>
|
||||||
|
<label class="input input-sm input-bordered flex items-center gap-2 w-full focus-within:input-primary">
|
||||||
|
<User class="w-4 h-4 text-gray-400" />
|
||||||
<input
|
<input
|
||||||
id="searchPatientId"
|
id="searchPatientId"
|
||||||
type="text"
|
type="text"
|
||||||
class="input input-sm input-bordered w-full"
|
class="grow bg-transparent outline-none"
|
||||||
placeholder="e.g. P001234"
|
placeholder="e.g. P001234"
|
||||||
bind:value={patientId}
|
bind:value={patientId}
|
||||||
onkeydown={handleKeydown}
|
onkeydown={handleKeydown}
|
||||||
/>
|
/>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Patient Name -->
|
<!-- Patient Name -->
|
||||||
<div class="flex-[2] min-w-[180px]">
|
<div class="form-control md:col-span-2">
|
||||||
<label class="label py-0 mb-1" for="searchPatientName">
|
<label class="label py-0 mb-1" for="searchPatientName">
|
||||||
<span class="label-text text-xs text-gray-500">Patient Name</span>
|
<span class="label-text text-xs font-medium text-gray-600">Patient Name</span>
|
||||||
</label>
|
</label>
|
||||||
|
<label class="input input-sm input-bordered flex items-center gap-2 w-full focus-within:input-primary">
|
||||||
|
<FileUser class="w-4 h-4 text-gray-400" />
|
||||||
<input
|
<input
|
||||||
id="searchPatientName"
|
id="searchPatientName"
|
||||||
type="text"
|
type="text"
|
||||||
class="input input-sm input-bordered w-full"
|
class="grow bg-transparent outline-none"
|
||||||
placeholder="Search by name..."
|
placeholder="Search by name..."
|
||||||
bind:value={patientName}
|
bind:value={patientName}
|
||||||
onkeydown={handleKeydown}
|
onkeydown={handleKeydown}
|
||||||
/>
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Row 2: Visit #, Order #, Date From, Date To -->
|
||||||
|
<div class="grid grid-cols-2 md:grid-cols-6 gap-3">
|
||||||
<!-- Visit Number -->
|
<!-- Visit Number -->
|
||||||
<div class="flex-1 min-w-[120px]">
|
<div class="form-control col-span-1">
|
||||||
<label class="label py-0 mb-1" for="searchVisitNumber">
|
<label class="label py-0 mb-1" for="searchVisitNumber">
|
||||||
<span class="label-text text-xs text-gray-500">Visit #</span>
|
<span class="label-text text-xs font-medium text-gray-600">Visit #</span>
|
||||||
</label>
|
</label>
|
||||||
|
<label class="input input-sm input-bordered flex items-center gap-2 w-full focus-within:input-primary">
|
||||||
|
<ClipboardList class="w-4 h-4 text-gray-400" />
|
||||||
<input
|
<input
|
||||||
id="searchVisitNumber"
|
id="searchVisitNumber"
|
||||||
type="text"
|
type="text"
|
||||||
class="input input-sm input-bordered w-full"
|
class="grow bg-transparent outline-none"
|
||||||
placeholder="e.g. V12345"
|
placeholder="V12345"
|
||||||
bind:value={visitNumber}
|
bind:value={visitNumber}
|
||||||
onkeydown={handleKeydown}
|
onkeydown={handleKeydown}
|
||||||
/>
|
/>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Order Number -->
|
<!-- Order Number -->
|
||||||
<div class="flex-1 min-w-[120px]">
|
<div class="form-control col-span-1">
|
||||||
<label class="label py-0 mb-1" for="searchOrderNumber">
|
<label class="label py-0 mb-1" for="searchOrderNumber">
|
||||||
<span class="label-text text-xs text-gray-500">Order #</span>
|
<span class="label-text text-xs font-medium text-gray-600">Order #</span>
|
||||||
</label>
|
</label>
|
||||||
|
<label class="input input-sm input-bordered flex items-center gap-2 w-full focus-within:input-primary">
|
||||||
|
<FileText class="w-4 h-4 text-gray-400" />
|
||||||
<input
|
<input
|
||||||
id="searchOrderNumber"
|
id="searchOrderNumber"
|
||||||
type="text"
|
type="text"
|
||||||
class="input input-sm input-bordered w-full"
|
class="grow bg-transparent outline-none"
|
||||||
placeholder="e.g. O67890"
|
placeholder="O67890"
|
||||||
bind:value={orderNumber}
|
bind:value={orderNumber}
|
||||||
onkeydown={handleKeydown}
|
onkeydown={handleKeydown}
|
||||||
/>
|
/>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Actions -->
|
<!-- Date From -->
|
||||||
<div class="flex gap-1">
|
<div class="form-control col-span-1">
|
||||||
|
<label class="label py-0 mb-1" for="searchOrderDateFrom">
|
||||||
|
<span class="label-text text-xs font-medium text-gray-600">Order From</span>
|
||||||
|
</label>
|
||||||
|
<label class="input input-sm input-bordered flex items-center gap-2 w-full focus-within:input-primary">
|
||||||
|
<Calendar class="w-4 h-4 text-gray-400" />
|
||||||
|
<input
|
||||||
|
id="searchOrderDateFrom"
|
||||||
|
type="date"
|
||||||
|
class="grow bg-transparent outline-none text-xs"
|
||||||
|
bind:value={orderDateFrom}
|
||||||
|
onkeydown={handleKeydown}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Date To -->
|
||||||
|
<div class="form-control col-span-1">
|
||||||
|
<label class="label py-0 mb-1" for="searchOrderDateTo">
|
||||||
|
<span class="label-text text-xs font-medium text-gray-600">Order To</span>
|
||||||
|
</label>
|
||||||
|
<label class="input input-sm input-bordered flex items-center gap-2 w-full focus-within:input-primary">
|
||||||
|
<Calendar class="w-4 h-4 text-gray-400" />
|
||||||
|
<input
|
||||||
|
id="searchOrderDateTo"
|
||||||
|
type="date"
|
||||||
|
class="grow bg-transparent outline-none text-xs"
|
||||||
|
bind:value={orderDateTo}
|
||||||
|
onkeydown={handleKeydown}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Action Buttons -->
|
||||||
|
<div class="form-control col-span-2 flex flex-row items-end gap-2">
|
||||||
{#if hasFilters()}
|
{#if hasFilters()}
|
||||||
<button
|
<button
|
||||||
class="btn btn-sm btn-ghost"
|
class="btn btn-ghost btn-sm flex-1"
|
||||||
title="Clear filters"
|
title="Clear filters"
|
||||||
onclick={onClear}
|
onclick={onClear}
|
||||||
>
|
>
|
||||||
<X class="w-4 h-4" />
|
<X class="w-4 h-4" />
|
||||||
|
<span class="hidden sm:inline ml-1">Clear</span>
|
||||||
</button>
|
</button>
|
||||||
|
{:else}
|
||||||
|
<div class="flex-1"></div>
|
||||||
{/if}
|
{/if}
|
||||||
<button
|
<button
|
||||||
class="btn btn-primary btn-sm"
|
class="btn btn-primary btn-sm flex-[2]"
|
||||||
onclick={onSearch}
|
onclick={onSearch}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
>
|
>
|
||||||
@ -114,9 +171,10 @@
|
|||||||
<span class="loading loading-spinner loading-sm"></span>
|
<span class="loading loading-spinner loading-sm"></span>
|
||||||
{:else}
|
{:else}
|
||||||
<Search class="w-4 h-4 mr-1" />
|
<Search class="w-4 h-4 mr-1" />
|
||||||
{/if}
|
|
||||||
Search
|
Search
|
||||||
|
{/if}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user