# CLQMS Master Data - Test Management Frontend Development Prompt ## πŸ“‹ Project Overview Build a modern, responsive Svelte 5 frontend for CLQMS (Clinical Laboratory Quality Management System) Test Management module. The frontend will consume the existing REST API backend (`/api/tests`) and provide a comprehensive interface for managing laboratory test definitions across all test types. --- ## 🎯 Objective Create a user-friendly, type-safe frontend application that enables laboratory administrators to: - Browse and search all test definitions with filtering - Create new tests of any type (TEST, PARAM, CALC, GROUP, TITLE) - Edit existing tests with type-specific configurations - Manage reference ranges (numeric and text-based) - Configure test mappings for external systems - Organize tests into groups and panels - Manage calculated test formulas --- ## πŸ› οΈ Technology Stack (Svelte 5) ### Core Requirements - **Framework**: Svelte 5 with runes (`$state`, `$derived`, `$effect`) - **Meta-Framework**: SvelteKit (for routing and server-side features) - **Language**: TypeScript (strict mode enabled) - **Styling**: Tailwind CSS - **UI Components**: Skeleton UI (or Melt UI) - **Forms**: Headless form components with validation - **HTTP Client**: Axios (with request/response interceptors) - **State Management**: Svelte 5 runes (no external store library required) - **Build Tool**: Vite (comes with SvelteKit) ### Recommended Dependencies ```json { "dependencies": { "svelte": "^5.0.0", "@sveltejs/kit": "^2.0.0", "axios": "^1.6.0", "zod": "^3.22.0", "date-fns": "^3.0.0" }, "devDependencies": { "skeleton": "^2.8.0", "@skeletonlabs/tw-plugin": "^0.3.0", "tailwindcss": "^3.4.0", "autoprefixer": "^10.4.0", "postcss": "^8.4.0", "typescript": "^5.3.0" } } ``` --- ## πŸ“ Project Structure ``` src/ β”œβ”€β”€ lib/ β”‚ β”œβ”€β”€ components/ β”‚ β”‚ β”œβ”€β”€ test/ β”‚ β”‚ β”‚ β”œβ”€β”€ TestList.svelte # Main test listing page β”‚ β”‚ β”‚ β”œβ”€β”€ TestForm.svelte # Main form container with tabs β”‚ β”‚ β”‚ β”œβ”€β”€ TestCard.svelte # Single test card/row β”‚ β”‚ β”‚ β”œβ”€β”€ TestFilterPanel.svelte # Search/filter panel β”‚ β”‚ β”‚ β”œβ”€β”€ SidebarTabs.svelte # Left navigation tabs β”‚ β”‚ β”‚ β”œβ”€β”€ tabs/ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ BasicInfoTab.svelte # Basic test info β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ TechDetailsTab.svelte # Technical specifications β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ CalcDetailsTab.svelte # Calculated test formula β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ GroupMembersTab.svelte # Group member management β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ MappingsTab.svelte # System mappings β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ RefNumTab.svelte # Numeric reference ranges β”‚ β”‚ β”‚ β”‚ └── RefTxtTab.svelte # Text reference ranges β”‚ β”‚ β”‚ └── modals/ β”‚ β”‚ β”‚ β”œβ”€β”€ RefNumModal.svelte # Edit reference range modal β”‚ β”‚ β”‚ β”œβ”€β”€ RefTxtModal.svelte # Edit text reference modal β”‚ β”‚ β”‚ β”œβ”€β”€ MappingModal.svelte # Edit mapping modal β”‚ β”‚ β”‚ └── MemberModal.svelte # Add group member modal β”‚ β”‚ └── ui/ # Reusable UI components β”‚ β”‚ β”œβ”€β”€ Button.svelte β”‚ β”‚ β”œβ”€β”€ Input.svelte β”‚ β”‚ β”œβ”€β”€ Select.svelte β”‚ β”‚ β”œβ”€β”€ Checkbox.svelte β”‚ β”‚ β”œβ”€β”€ Table.svelte β”‚ β”‚ β”œβ”€β”€ Modal.svelte β”‚ β”‚ β”œβ”€β”€ Badge.svelte β”‚ β”‚ β”œβ”€β”€ Tabs.svelte β”‚ β”‚ β”œβ”€β”€ Alert.svelte β”‚ β”‚ └── Spinner.svelte β”‚ β”œβ”€β”€ stores/ β”‚ β”‚ β”œβ”€β”€ testStore.ts # Test form state with runes β”‚ β”‚ β”œβ”€β”€ valueSetStore.ts # ValueSet/dropdown data β”‚ β”‚ β”œβ”€β”€ authStore.ts # Authentication state β”‚ β”‚ └── uiStore.ts # UI state (modals, tabs) β”‚ β”œβ”€β”€ services/ β”‚ β”‚ β”œβ”€β”€ api.ts # Axios instance with interceptors β”‚ β”‚ β”œβ”€β”€ testService.ts # Test API operations β”‚ β”‚ β”œβ”€β”€ valueSetService.ts # ValueSet API calls β”‚ β”‚ └── validationService.ts # Frontend validation logic β”‚ β”œβ”€β”€ types/ β”‚ β”‚ β”œβ”€β”€ test.types.ts # All test-related types β”‚ β”‚ β”œβ”€β”€ api.types.ts # API response/request types β”‚ β”‚ β”œβ”€β”€ valueset.types.ts # ValueSet types β”‚ β”‚ └── index.ts # Type exports β”‚ └── utils/ β”‚ β”œβ”€β”€ validation.ts # Validation helpers β”‚ β”œβ”€β”€ format.ts # Formatters (dates, numbers) β”‚ β”œβ”€β”€ constants.ts # App constants β”‚ └── helpers.ts # Utility functions β”œβ”€β”€ routes/ β”‚ β”œβ”€β”€ +layout.svelte # Root layout with nav β”‚ β”œβ”€β”€ +page.svelte # Landing page β”‚ β”œβ”€β”€ tests/ β”‚ β”‚ β”œβ”€β”€ +page.svelte # Test list page β”‚ β”‚ └── [id]/ β”‚ β”‚ └── +page.svelte # Test detail/edit page β”‚ └── login/ β”‚ └── +page.svelte # Login page β”œβ”€β”€ app.html # HTML template └── app.css # Global styles ``` --- ## πŸ”Œ API Integration ### Base Configuration **API Base URL**: `http://localhost:8080/api` (configurable via environment variable) **Authentication**: JWT token via HTTP header ``` Authorization: Bearer {token} ``` ### Endpoints #### 1. List Tests ``` GET /api/tests Query Parameters: - SiteID (optional): Filter by site - TestType (optional): Filter by test type (TEST, PARAM, CALC, GROUP, TITLE) - VisibleScr (optional): Filter by screen visibility (0/1) - VisibleRpt (optional): Filter by report visibility (0/1) - TestSiteName (optional): Search by test name (partial match) ``` **Response**: ```typescript { status: "success"; message: string; data: TestSummary[]; } interface TestSummary { TestSiteID: number; TestSiteCode: string; TestSiteName: string; TestType: string; TestTypeLabel: string; SeqScr: number; SeqRpt: number; VisibleScr: number; VisibleRpt: number; CountStat: number; StartDate: string; DisciplineID?: number; DepartmentID?: number; DisciplineName?: string; DepartmentName?: string; } ``` #### 2. Get Single Test ``` GET /api/tests/:id ``` **Response**: ```typescript { status: "success"; message: string; data: TestDetail; } interface TestDetail { // Base fields TestSiteID: number; TestSiteCode: string; TestSiteName: string; TestType: string; TestTypeLabel: string; Description?: string; SiteID: number; SeqScr: number; SeqRpt: number; VisibleScr: number; VisibleRpt: number; CountStat: number; StartDate: string; EndDate?: string; // Technical details (TEST/PARAM/CALC) DisciplineID?: number; DepartmentID?: number; DisciplineName?: string; DepartmentName?: string; ResultType?: string; RefType?: string; VSet?: string; Unit1?: string; Factor?: number; Unit2?: string; Decimal?: number; ReqQty?: number; ReqQtyUnit?: string; CollReq?: string; Method?: string; ExpectedTAT?: number; // Nested data based on TestType testdefcal?: Calculation[]; // For CALC type testdefgrp?: GroupMember[]; // For GROUP type testmap?: TestMapping[]; // For all types testdeftech?: TechDetail[]; // For TEST/PARAM refnum?: RefNumRange[]; // For TEST/PARAM (numeric ref) reftxt?: RefTxtRange[]; // For TEST/PARAM (text ref) } interface RefNumRange { RefNumID: number; NumRefType: string; // REF, CRTC, VAL, RERUN NumRefTypeLabel: string; RangeType: string; // RANGE, THOLD RangeTypeLabel: string; Sex: string; // 0=All, 1=Female, 2=Male SexLabel: string; AgeStart: number; AgeEnd: number; LowSign?: string; // =, <, <= LowSignLabel?: string; Low?: number; HighSign?: string; // =, >, >= HighSignLabel?: string; High?: number; Flag?: string; // H, L, A, etc. Interpretation?: string; } interface RefTxtRange { RefTxtID: number; TxtRefType: string; // Normal, Abnormal, Critical TxtRefTypeLabel: string; Sex: string; SexLabel: string; AgeStart: number; AgeEnd: number; RefTxt: string; Flag?: string; } ``` #### 3. Create Test ``` POST /api/tests Content-Type: application/json Body: CreateTestPayload ``` **Request**: ```typescript interface CreateTestPayload { SiteID: number; TestSiteCode: string; TestSiteName: string; TestType: 'TEST' | 'PARAM' | 'CALC' | 'GROUP' | 'TITLE'; Description?: string; SeqScr?: number; SeqRpt?: number; VisibleScr?: number; VisibleRpt?: number; CountStat?: number; StartDate?: string; // Nested details (based on TestType) details?: { // Technical (TEST/PARAM/CALC) DisciplineID?: number; DepartmentID?: number; ResultType?: string; RefType?: string; VSet?: string; Unit1?: string; Factor?: number; Unit2?: string; Decimal?: number; ReqQty?: number; ReqQtyUnit?: string; CollReq?: string; Method?: string; ExpectedTAT?: number; // CALC only FormulaInput?: string; FormulaCode?: string; // GROUP only members?: number[]; // Array of TestSiteIDs }; // Reference ranges (TEST/PARAM) refnum?: Omit[]; reftxt?: Omit[]; // Mappings (all types) testmap?: TestMapping[]; } ``` **Response**: ```typescript { status: "created"; message: "Test created successfully"; data: { TestSiteId: number }; } ``` #### 4. Update Test ``` PATCH /api/tests Content-Type: application/json Body: CreateTestPayload & { TestSiteID: number } ``` **Response**: ```typescript { status: "success"; message: "Test updated successfully"; data: { TestSiteId: number }; } ``` #### 5. Delete Test (Soft Delete) ``` DELETE /api/tests Content-Type: application/json Body: { TestSiteID: number } ``` **Response**: ```typescript { status: "success"; message: "Test disabled successfully"; data: { TestSiteId: number; EndDate: string }; } ``` --- ## 🎨 UI/UX Design Specifications ### Layout Architecture **Page Layout**: Fixed sidebar + scrollable content area ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Header: CLQMS Test Management [User] [Logout] β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ β”‚ Sidebar β”‚ Main Content Area β”‚ β”‚ (Left) β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ Tab 1 β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ Tab 2 β”‚ β”‚ β”‚ β”‚ β”‚ Tab 3 β”‚ β”‚ Dynamic Content β”‚ β”‚ β”‚ ... β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ [Save] [Cancel] [Delete] β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Test List Page **Components**: 1. **Filter Panel** (top of page): - Site dropdown (multi-select) - Test Type dropdown (checkboxes) - Visibility toggles (Screen/Report) - Search input (debounced, 300ms) - Clear filters button 2. **Test Table/Card Grid**: - Columns: Code, Name, Type, Discipline, Department, SeqScr, SeqRpt, Visibility, Actions - Sortable headers (Code, Name, SeqScr, SeqRpt) - Row actions: View, Edit, Delete (with confirmation) - Row hover effect - Test type badge with color coding 3. **Pagination**: - Show 20 items per page - Page navigation buttons - Page size selector (10, 20, 50, 100) - Total count display **Table Design**: ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Code β”‚ Name β”‚ Type β”‚ Discipline β”‚ Dept β”‚ ScrVis β”‚ RptVis β”‚ Actions β”‚ β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ CBC β”‚ Complete Blood β”‚ TEST β”‚ Hematology β”‚ Hema β”‚ β˜‘ β”‚ β˜‘ β”‚ πŸ‘οΈ ✏️ πŸ—‘οΈ β”‚ β”‚ β”‚ β”‚ Count β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ HGB β”‚ Hemoglobin β”‚ PARAM β”‚ Hematology β”‚ Hema β”‚ β˜‘ β”‚ β˜‘ β”‚ πŸ‘οΈ ✏️ πŸ—‘οΈ β”‚ β”‚ β”‚ CALC_A1Cβ”‚ A1C Calculated β”‚ CALC β”‚ Chemistry β”‚ Chem β”‚ β˜‘ β”‚ β˜‘ β”‚ πŸ‘οΈ ✏️ πŸ—‘οΈ β”‚ β”‚ β”‚ CMP_GRP β”‚ Comprehensive β”‚ GROUP β”‚ - β”‚ - β”‚ β˜‘ β”‚ ☐ β”‚ πŸ‘οΈ ✏️ πŸ—‘οΈ β”‚ β”‚ β”‚ β”‚ Panel β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ HEADER1 β”‚ Chemistry Results β”‚ TITLE β”‚ - β”‚ - β”‚ ☐ β”‚ β˜‘ β”‚ πŸ‘οΈ ✏️ πŸ—‘οΈ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Test Form Page **Left Sidebar Tabs** (Navigation): ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Basic Info β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ Tech Details β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ Calculations β”‚ (CALC only) β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ Group Memb β”‚ (GROUP only) β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ Mappings β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ Ref Num β”‚ (TEST/PARAM/CALC) β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ Ref Txt β”‚ (TEST/PARAM) β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` **Tab Visibility Rules**: | Tab | TEST | PARAM | CALC | GROUP | TITLE | |-----|------|-------|------|-------|-------| | Basic Info | βœ… | βœ… | βœ… | βœ… | βœ… | | Tech Details | βœ… | βœ… | ❌ | ❌ | ❌ | | Calculations | ❌ | ❌ | βœ… | ❌ | ❌ | | Group Members | ❌ | ❌ | ❌ | βœ… | ❌ | | Mappings | βœ… | βœ… | βœ… | βœ… | βœ… | | Ref Num | βœ… | βœ… | βœ… | ❌ | ❌ | | Ref Txt | βœ… | βœ… | ❌ | ❌ | ❌ | **Active Tab Styling**: - Left border accent color (primary theme color) - Light background highlight - Bold text - Icon indicator ### Tab Content Specifications #### 1. Basic Info Tab **Form Layout** (Two-column grid): ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Test Code: [CBC_______] *Required β”‚ β”‚ Test Name: [Complete Blood Count________] *Required β”‚ β”‚ Test Type: [TEST β–Ό] (dropdown) β”‚ β”‚ Description: [Standard hematology test_______________] β”‚ β”‚ β”‚ β”‚ Site: [Main Lab β–Ό] β”‚ β”‚ β”‚ β”‚ Screen Seq: [1___] Report Seq: [1___] β”‚ β”‚ β”‚ β”‚ [β˜‘] Visible on Screen [β˜‘] Visible on Report β”‚ β”‚ β”‚ β”‚ [β˜‘] Count in Statistics β”‚ β”‚ β”‚ β”‚ Start Date: [2024-01-01_______] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` **Fields**: - TestSiteCode (required, 3-6 chars, uppercase, unique validation) - TestSiteName (required, 3-255 chars) - TestType (required, dropdown: TEST, PARAM, CALC, GROUP, TITLE) - Description (optional, textarea, max 500 chars) - SiteID (required, dropdown from sites API) - SeqScr (optional, number, default 0) - SeqRpt (optional, number, default 0) - VisibleScr (checkbox, default true) - VisibleRpt (checkbox, default true) - CountStat (checkbox, default true) - StartDate (optional, datetime, default current) **Dynamic Behavior**: - When TestType changes β†’ Show/hide relevant tabs - When TestType = CALC/PARAM/TEST β†’ Auto-populate defaults - TestType change triggers confirmation if form has unsaved changes #### 2. Tech Details Tab **Form Layout** (Three sections): **Section 1: Categorization** ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Discipline: [Hematology β–Ό] β”‚ β”‚ Department: [CBC Dept β–Ό] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` **Section 2: Result Configuration** ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Result Type: [Numeric β–Ό] (dynamic based on TestType) β”‚ β”‚ Ref Type: [Range β–Ό] (dynamic based on ResultType) β”‚ β”‚ Value Set: [____________] (if ResultType = VSET) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` **Section 3: Units & Conversion** ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Unit 1: [g/dL β–Ό] β”‚ β”‚ Factor: [1.0__] (conversion factor) β”‚ β”‚ Unit 2: [g/L β–Ό] β”‚ β”‚ Decimal: [2__] (decimal places) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` **Section 4: Sample Requirements** ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Required Qty: [5.0__] β”‚ β”‚ Qty Unit: [mL β–Ό] β”‚ β”‚ Collection Req: [Fasting required_______________] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` **Section 5: Method & TAT** ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Method: [Automated Analyzer_______________] β”‚ β”‚ Expected TAT: [60__] (minutes) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` **Fields**: - DisciplineID (dropdown, optional) - DepartmentID (dropdown, optional) - ResultType (dropdown, dynamic options based on TestType) - RefType (dropdown, dynamic options based on ResultType) - VSet (text input, shown only if ResultType = VSET) - Unit1 (dropdown from units valueset) - Factor (number, optional) - Unit2 (dropdown from units valueset) - Decimal (number, default 2, min 0, max 6) - ReqQty (number, optional) - ReqQtyUnit (dropdown) - CollReq (textarea, optional) - Method (text input, optional) - ExpectedTAT (number, optional) **Dynamic Dropdown Logic**: ```typescript // TestType β†’ ResultType mapping const getResultTypeOptions = (testType: string) => { switch (testType) { case 'CALC': return ['NMRIC']; case 'GROUP': case 'TITLE': return ['NORES']; default: return ['NMRIC', 'RANGE', 'TEXT', 'VSET']; } }; // ResultType β†’ RefType mapping const getRefTypeOptions = (resultType: string) => { switch (resultType) { case 'NMRIC': case 'RANGE': return ['RANGE', 'THOLD']; case 'VSET': return ['VSET']; case 'TEXT': return ['TEXT']; case 'NORES': return ['NOREF']; default: return []; } }; ``` #### 3. Calculations Tab (CALC only) **Form Layout**: ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Formula Input: [HGB + MCV + MCHC________] β”‚ β”‚ β”‚ β”‚ Formula Code: [{HGB} + {MCV} + {MCHC}_____________] β”‚ β”‚ β”‚ β”‚ Discipline: [Hematology β–Ό] β”‚ β”‚ Department: [CBC Dept β–Ό] β”‚ β”‚ β”‚ β”‚ Method: [Calculated from components_______] β”‚ β”‚ β”‚ β”‚ Unit 1: [g/dL β–Ό] β”‚ β”‚ Factor: [1.0__] β”‚ β”‚ Unit 2: [g/L β–Ό] β”‚ β”‚ Decimal: [2__] β”‚ β”‚ β”‚ β”‚ Ref Type: [Range β–Ό] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` **Fields**: - FormulaInput (text input, description of calculation) - FormulaCode (text input, actual formula with placeholders like {A}, {B}) - DisciplineID (dropdown) - DepartmentID (dropdown) - Method (text input) - Unit1, Factor, Unit2, Decimal (same as Tech Details) - RefType (dropdown: RANGE, THOLD) **Validation**: - FormulaCode must contain valid syntax - FormulaCode must reference valid test codes - Test codes in formula must exist in system #### 4. Group Members Tab (GROUP only) **Form Layout**: ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Group: CBC - Complete Blood Count β”‚ β”‚ β”‚ β”‚ Current Members: β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Code β”‚ Name β”‚ Type β”‚ Seq β”‚ Actions β”‚ β”‚ β”‚ β”œβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ HGB β”‚ Hemoglobin β”‚ PARAM β”‚ 1 β”‚ [↑] [↓] [βœ•] β”‚ β”‚ β”‚ β”‚ RBC β”‚ Red Blood Cells β”‚ TEST β”‚ 2 β”‚ [↑] [↓] [βœ•] β”‚ β”‚ β”‚ β”‚ WBC β”‚ White Blood Cellβ”‚ TEST β”‚ 3 β”‚ [↑] [↓] [βœ•] β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ Add Member: [HGB β–Ό] [Add Member +] β”‚ β”‚ β”‚ β”‚ Available Tests: (searchable dropdown) β”‚ β”‚ - HGB - Hemoglobin β”‚ β”‚ - RBC - Red Blood Cells β”‚ β”‚ - WBC - White Blood Cells β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` **Features**: - List current members with Code, Name, Type - Reorder members (drag-and-drop or ↑↓ buttons) - Remove member button (with confirmation) - Add member dropdown (searchable, excludes current group and members) - Prevent circular references (group cannot contain itself) - Prevent duplicate members **Member Selection**: - Dropdown with search - Group by TestType (TEST, PARAM, CALC) - Show TestSiteCode - TestSiteName format - Filter out already added members - Filter out current group itself #### 5. Mappings Tab (All test types) **Form Layout**: ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Test: CBC - Complete Blood Count β”‚ β”‚ β”‚ β”‚ Current Mappings: β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Host β”‚ Host Code β”‚ Client β”‚ Client Code β”‚ Actions β”‚ β”‚ β”‚ β”œβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ HIS β”‚ CBC β”‚ WST-1 β”‚ CBC01 β”‚ [✏️] [βœ•] β”‚ β”‚ β”‚ β”‚ SITE β”‚ CBC β”‚ INST-1 β”‚ CBC β”‚ [✏️] [βœ•] β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ [Add Mapping +] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` **Add/Edit Mapping Modal**: ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Add/Edit Mapping β”‚ β”‚ β”‚ β”‚ Host System: β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Type: [HIS β–Ό] β”‚ β”‚ β”‚ β”‚ ID: [1____] β”‚ β”‚ β”‚ β”‚ Data Src: [DB____] β”‚ β”‚ β”‚ β”‚ Test Code:[CBC____] β”‚ β”‚ β”‚ β”‚ Test Name:[Complete Blood Count___________] β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ Client System: β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Type: [WST β–Ό] β”‚ β”‚ β”‚ β”‚ ID: [1____] β”‚ β”‚ β”‚ β”‚ Data Src: [API____] β”‚ β”‚ β”‚ β”‚ Container: [Tube1 β–Ό] β”‚ β”‚ β”‚ β”‚ Test Code: [CBC01____] β”‚ β”‚ β”‚ β”‚ Test Name: [CBC_____________] β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ [Save] [Cancel] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` **Fields**: - HostType: dropdown (HIS, SITE, WST, INST) - HostID: text/number input - HostDataSource: text input - HostTestCode: text input - HostTestName: text input - ClientType: dropdown (HIS, SITE, WST, INST) - ClientID: text/number input - ClientDataSource: text input - ConDefID: dropdown (container definitions) - ClientTestCode: text input - ClientTestName: text input **Validation**: - At least one of Host or Client must be specified - Test codes must be unique per Host/Client combination #### 6. Ref Num Tab (Numeric Reference Ranges) **Form Layout**: ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Test: CBC - Complete Blood Count β”‚ β”‚ Numeric Reference Ranges β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚Type β”‚Range β”‚Sex β”‚ Age β”‚ Low β”‚High β”‚Flag β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚Bound β”‚Bound β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚Ref β”‚RANGE β”‚All β”‚0-150 β”‚[β‰₯ 4.0] β”‚[< 5.5] β”‚ N β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚Crtc β”‚THOLD β”‚All β”‚0-150 β”‚[< 3.5] β”‚[> 6.0] β”‚ H/L β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚Ref β”‚RANGE β”‚F β”‚18-150 β”‚[β‰₯ 4.5] β”‚[< 5.0] β”‚ N β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚Crtc β”‚THOLD β”‚M β”‚18-150 β”‚[< 3.8] β”‚[> 5.8] β”‚ H/L β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ [Add Range] [Delete Selected] [Copy from Similar Test] β”‚ β”‚ β”‚ β”‚ Selected Ranges: 0 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` **Add/Edit Reference Range Modal**: ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Numeric Reference Range β”‚ β”‚ β”‚ β”‚ Reference Type: [Reference β–Ό] β”‚ β”‚ (Reference, Critical, Validation, Rerun) β”‚ β”‚ β”‚ β”‚ Range Type: [Range β–Ό] β”‚ β”‚ (Range, Threshold) β”‚ β”‚ β”‚ β”‚ Sex: [All β–Ό] β”‚ β”‚ (All, Female, Male) β”‚ β”‚ β”‚ β”‚ Age Start: [0__] Age End: [150__] β”‚ β”‚ β”‚ β”‚ Low Bound: β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Sign: [β‰₯ β–Ό] Value: [4.0__] β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ High Bound: β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Sign: [< β–Ό] Value: [5.5__] β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ Flag: [H/L/A/N___] (High/Low/Abnormal/Normal) β”‚ β”‚ β”‚ β”‚ Interpretation:[Normal range for hemoglobin_______________] β”‚ β”‚ β”‚ β”‚ [Save] [Cancel] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` **Fields**: - NumRefType: dropdown (REF, CRTC, VAL, RERUN) - RangeType: dropdown (RANGE, THOLD) - Sex: dropdown (0=All, 1=Female, 2=Male) - AgeStart: number input (min 0, max 150) - AgeEnd: number input (min 0, max 150) - LowSign: dropdown (=, <, <=) - Low: number input (optional) - HighSign: dropdown (=, >, >=) - High: number input (optional) - Flag: text input (single char: H, L, A, N) - Interpretation: textarea (optional) **Validation**: - AgeStart must be less than AgeEnd - If both Low and High are present: Low must be less than High - LowSign must be appropriate for Low value (e.g., if Low = 4.0, LowSign should be >=) - HighSign must be appropriate for High value (e.g., if High = 5.5, HighSign should be <=) **Reference Range Logic**: - Reference (REF): Normal ranges for reporting - Critical (CRTC): Critical values requiring immediate notification - Validation (VAL): Validation checks for result entry - Rerun (RERUN): Conditions triggering automatic rerun **Range Type**: - RANGE: Standard range (Low to High) - THOLD: Threshold (single value with comparison) #### 7. Ref Txt Tab (Text Reference Ranges) **Form Layout**: ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Test: URINE - Urinalysis β”‚ β”‚ Text Reference Ranges β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚Type β”‚Sex β”‚ Age β”‚ Reference Text β”‚ Flag β”‚ β”‚ β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚Normal β”‚All β”‚0-150 β”‚Clear β”‚ N β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚Abnml β”‚All β”‚0-150 β”‚Cloudy β”‚ A β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚Crtc β”‚All β”‚0-150 β”‚Bloody β”‚ C β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ [Add Range] [Delete Selected] [Copy from Similar Test] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` **Add/Edit Text Reference Modal**: ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Text Reference Range β”‚ β”‚ β”‚ β”‚ Reference Type: [Normal β–Ό] β”‚ β”‚ (Normal, Abnormal, Critical) β”‚ β”‚ β”‚ β”‚ Sex: [All β–Ό] β”‚ β”‚ (All, Female, Male) β”‚ β”‚ β”‚ β”‚ Age Start: [0__] Age End: [150__] β”‚ β”‚ β”‚ β”‚ Reference Text: [Clear_______________] β”‚ β”‚ β”‚ β”‚ Flag: [N/A/C___] (Normal/Abnormal/Critical) β”‚ β”‚ β”‚ β”‚ [Save] [Cancel] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` **Fields**: - TxtRefType: dropdown (Normal, Abnormal, Critical) - Sex: dropdown (0=All, 1=Female, 2=Male) - AgeStart: number input - AgeEnd: number input - RefTxt: text input - Flag: text input (N, A, C) **Validation**: - AgeStart must be less than AgeEnd - RefTxt is required - Flag must match TxtRefType (Normal=N, Abnormal=A, Critical=C) --- ## πŸ—οΈ Component Implementation ### Core Component Requirements #### 1. State Management with Svelte 5 Runes **testStore.ts**: ```typescript import { writable } from 'svelte/store'; interface TestFormState { TestSiteID?: number; TestSiteCode: string; TestSiteName: string; TestType: 'TEST' | 'PARAM' | 'CALC' | 'GROUP' | 'TITLE'; Description?: string; SiteID: number; SeqScr: number; SeqRpt: number; VisibleScr: number; VisibleRpt: number; CountStat: number; StartDate?: string; details?: { DisciplineID?: number; DepartmentID?: number; ResultType?: string; RefType?: string; VSet?: string; Unit1?: string; Factor?: number; Unit2?: string; Decimal?: number; ReqQty?: number; ReqQtyUnit?: string; CollReq?: string; Method?: string; ExpectedTAT?: number; FormulaInput?: string; FormulaCode?: string; members?: number[]; }; refnum?: RefNumRange[]; reftxt?: RefTxtRange[]; testmap?: TestMapping[]; } export const testStore = writable({ TestSiteCode: '', TestSiteName: '', TestType: 'TEST', SiteID: 1, SeqScr: 0, SeqRpt: 0, VisibleScr: 1, VisibleRpt: 1, CountStat: 1, refnum: [], reftxt: [], testmap: [], }); ``` **Derived Stores**: ```typescript // Derive visible tabs based on TestType export const visibleTabs = derived(testStore, ($store) => { const type = $store.TestType; return allTabs.filter(tab => tab.isVisible(type)); }); // Derive valid ResultType options export const validResultTypes = derived(testStore, ($store) => { const type = $store.TestType; // Return options based on type }); // Derive valid RefType options export const validRefTypes = derived([testStore, validResultTypes], ([$store, $resultTypes]) => { const resultType = $store.details?.ResultType; // Return options based on resultType }); ``` #### 2. Reusable UI Components **Button.svelte**: ```svelte ``` **Input.svelte**: ```svelte
{#if label} {/if} {#if error} {error} {/if}
``` **Select.svelte**: ```svelte
{#if label} {/if}
``` #### 3. Test Form Component **TestForm.svelte** (Main container): ```svelte
{#if isLoading} {:else}

{$testStore.TestSiteID ? 'Edit Test' : 'New Test'}

{#if currentTab === 'basic'} {:else if currentTab === 'tech'} {:else if currentTab === 'calc'} {:else if currentTab === 'group'} {:else if currentTab === 'mappings'} {:else if currentTab === 'refnum'} {:else if currentTab === 'reftxt'} {/if}
{#if $testStore.TestSiteID} {/if}
{/if}
``` --- ## βœ… Validation Requirements ### Frontend Validation #### TestSiteCode - Required - 3-6 characters - Uppercase only - Alphanumeric only - Unique (check via API) - Regex: `^[A-Z0-9]{3,6}$` #### TestSiteName - Required - 3-255 characters - No special characters (except hyphen, space, parenthesis) - Regex: `^[a-zA-Z0-9\s\-\(\)]{3,255}$` #### TestType - Required - Must be one of: TEST, PARAM, CALC, GROUP, TITLE #### Type Combination Validation ```typescript const validateTypeCombination = (testType: string, resultType: string, refType: string) => { const valid = TestValidationService.validate(testType, resultType, refType); if (!valid.valid) { throw new Error(valid.error); } }; ``` #### Reference Range Validation **Numeric Ranges**: - AgeStart < AgeEnd (both 0-150) - If Low and High both present: Low < High - LowSign appropriate for Low value - HighSign appropriate for High value - Flag is single character (H, L, A, N) **Text Ranges**: - AgeStart < AgeEnd - RefTxt is required - Flag matches TxtRefType #### Group Validation - Group cannot contain itself - No circular references (Group A contains Group B, Group B contains Group A) - No duplicate members - Minimum 1 member for GROUP type --- ## 🎨 Styling & Design System ### Color Palette ```css :root { /* Primary */ --primary-50: #e0f2fe; --primary-100: #bae6fd; --primary-500: #0ea5e9; --primary-600: #0284c7; --primary-700: #0369a1; /* Secondary */ --secondary-500: #64748b; --secondary-600: #475569; /* Success */ --success-500: #22c55e; --success-600: #16a34a; /* Danger */ --danger-500: #ef4444; --danger-600: #dc2626; /* Warning */ --warning-500: #f59e0b; --warning-600: #d97706; /* Neutral */ --gray-50: #f9fafb; --gray-100: #f3f4f6; --gray-200: #e5e7eb; --gray-300: #d1d5db; --gray-500: #6b7280; --gray-700: #374151; --gray-900: #111827; } ``` ### Typography ```css /* Font sizes */ --text-xs: 0.75rem; /* 12px */ --text-sm: 0.875rem; /* 14px */ --text-base: 1rem; /* 16px */ --text-lg: 1.125rem; /* 18px */ --text-xl: 1.25rem; /* 20px */ --text-2xl: 1.5rem; /* 24px */ --text-3xl: 1.875rem; /* 30px */ ``` ### Spacing ```css --space-1: 0.25rem; /* 4px */ --space-2: 0.5rem; /* 8px */ --space-3: 0.75rem; /* 12px */ --space-4: 1rem; /* 16px */ --space-6: 1.5rem; /* 24px */ --space-8: 2rem; /* 32px */ ``` ### Components **Buttons**: ```css .btn { display: inline-flex; align-items: center; justify-content: center; padding: var(--space-2) var(--space-4); border-radius: 0.375rem; font-weight: 500; transition: all 0.2s; cursor: pointer; } .btn-primary { background-color: var(--primary-600); color: white; } .btn-primary:hover:not(:disabled) { background-color: var(--primary-700); } .btn-secondary { background-color: var(--gray-200); color: var(--gray-700); } .btn-danger { background-color: var(--danger-600); color: white; } .btn:disabled { opacity: 0.5; cursor: not-allowed; } ``` **Inputs**: ```css .input-field { width: 100%; padding: var(--space-2) var(--space-3); border: 1px solid var(--gray-300); border-radius: 0.375rem; font-size: var(--text-base); transition: border-color 0.2s; } .input-field:focus { outline: none; border-color: var(--primary-500); box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.1); } .input-field.has-error { border-color: var(--danger-500); } ``` **Sidebar Tabs**: ```css .sidebar-tab { padding: var(--space-3) var(--space-4); border-left: 3px solid transparent; cursor: pointer; transition: all 0.2s; } .sidebar-tab:hover { background-color: var(--gray-100); } .sidebar-tab.active { background-color: var(--primary-50); border-left-color: var(--primary-600); font-weight: 600; } ``` --- ## πŸ“± Responsive Design ### Breakpoints ```css --breakpoint-sm: 640px; --breakpoint-md: 768px; --breakpoint-lg: 1024px; --breakpoint-xl: 1280px; ``` ### Responsive Behavior **Desktop (> 1024px)**: - Sidebar: Fixed width, visible - Content: Full width - Form: 2-column grid layout **Tablet (768px - 1024px)**: - Sidebar: Collapsible (hamburger menu) - Content: Full width - Form: Single column layout - Table: Horizontal scroll **Mobile (< 768px)**: - Sidebar: Off-canvas drawer - Content: Full width - Form: Single column, stacked - Table: Card view instead of table --- ## πŸš€ Implementation Checklist ### Phase 1: Project Setup & Infrastructure - [ ] Initialize SvelteKit project with TypeScript - [ ] Install and configure Tailwind CSS - [ ] Set up Skeleton UI or Melt UI - [ ] Configure Axios with interceptors - [ ] Create type definitions (test.types.ts, api.types.ts) - [ ] Set up API service layer - [ ] Create auth store and testStore - [ ] Set up routing structure ### Phase 2: Reusable Components - [ ] Button component - [ ] Input component - [ ] Select component - [ ] Checkbox component - [ ] Table component - [ ] Modal component - [ ] Badge component - [ ] Alert component - [ ] Spinner component - [ ] Tabs component ### Phase 3: Test List Page - [ ] Test list page layout - [ ] Filter panel component - [ ] Test table component - [ ] Pagination component - [ ] Search functionality - [ ] Filter functionality - [ ] Sort functionality - [ ] Load test data from API ### Phase 4: Test Form - Basic & Tech - [ ] Test form container with sidebar tabs - [ ] Basic Info tab - [ ] Tech Details tab - [ ] Dynamic dropdown logic - [ ] Form validation - [ ] Save functionality - [ ] Update functionality ### Phase 5: Type-Specific Tabs - [ ] Calculations tab (CALC) - [ ] Group Members tab (GROUP) - [ ] Mappings tab (all types) - [ ] Member selection dropdown - [ ] Mapping add/edit modal ### Phase 6: Reference Ranges - [ ] RefNum tab with table - [ ] RefTxt tab with table - [ ] Reference range modal - [ ] Reference range validation - [ ] Add/Edit/Delete operations ### Phase 7: Polish & Testing - [ ] Responsive design - [ ] Loading states - [ ] Error handling - [ ] Form dirty state tracking - [ ] Confirmation dialogs - [ ] Toast notifications - [ ] Accessibility (ARIA labels) - [ ] Keyboard navigation - [ ] Cross-browser testing ### Phase 8: Documentation - [ ] Component documentation - [ ] API integration guide - [ ] User guide - [ ] Deployment instructions --- ## πŸ“š Additional Notes ### ValueSet Integration - Use backend API `/api/valueset` to fetch dropdown options - Cache valuesets locally to reduce API calls - Transform labels: API returns both code and label (e.g., `TestType` and `TestTypeLabel`) - Display labels in UI, use codes for API calls ### Authentication - JWT token stored in localStorage - Include token in Authorization header for all API calls - Handle token expiration and refresh - Redirect to login if unauthorized ### Error Handling - Display user-friendly error messages - Log technical errors to console - Retry logic for failed requests (with backoff) - Show appropriate feedback for network errors ### Performance - Implement debounced search (300ms) - Lazy load test data (pagination) - Optimize re-renders with Svelte 5 runes - Memoize expensive computations ### Accessibility - ARIA labels for form inputs - Keyboard navigation support - Screen reader compatibility - Focus management in modals - Color contrast compliance (WCAG AA) --- ## πŸ”— References ### Backend Documentation - API Endpoints: `/api/tests` - Models: `TestDefSiteModel`, `TestDefCalModel`, `TestDefGrpModel`, `TestMapModel` - Validation: `TestValidationService` ### Type System - Test types: TEST, PARAM, CALC, GROUP, TITLE - Result types: NMRIC, RANGE, TEXT, VSET, NORES - Reference types: RANGE, THOLD, TEXT, VSET, NOREF ### Business Rules - Soft deletes only (set EndDate) - Test type + ResultType + RefType must be valid combination - Reference ranges are type-specific (numeric vs text) - Calculations use formula placeholders like {A}, {B} --- ## 🎯 Success Criteria The frontend is considered complete when: 1. **Functional Requirements** - All CRUD operations work for all test types - Reference ranges can be managed (add/edit/delete) - Group members can be added/removed/reordered - Mappings can be configured for external systems - Form validation prevents invalid data submission 2. **User Experience** - Intuitive navigation with sidebar tabs - Clear visual feedback for actions - Responsive design works on all devices - Loading states indicate progress - Error messages are helpful and actionable 3. **Code Quality** - TypeScript strict mode with no errors - Component reusability and modularity - Proper error handling throughout - Clean, readable code with comments - Efficient state management with Svelte 5 runes 4. **Performance** - Page load time < 2 seconds - Search results appear within 300ms - Form submissions complete within 1 second - No memory leaks or performance degradation 5. **Testing** - Unit tests for components - Integration tests for API calls - E2E tests for critical user flows - Cross-browser compatibility verified --- ## πŸ“ž Support For questions or issues during development: 1. Review backend API documentation in `README.md` 2. Check model definitions in `app/Models/Test/` 3. Refer to validation service in `app/Libraries/TestValidationService.php` 4. Test API endpoints directly using tools like Postman --- **Last Updated**: February 2025 **Version**: 1.0