feat: Implement Patient Management module (Phase 2a)
- Add patients API client with CRUD operations - Create patient list page with search and pagination - Implement multi-step patient form (4 steps): 1. Basic Info (PatientID, Name, Sex, Birthdate, etc.) 2. Address (Street, ZIP, Province/City dropdowns) 3. Contact & ID (Phone, Email, ID documents) 4. Additional (Demographics, Death Indicator, Comments) - Add province/city cascading dropdowns - Integrate ValueSets for dropdown options - Update implementation plan
This commit is contained in:
parent
f7cb3d50d4
commit
4accf7b6d6
@ -166,7 +166,7 @@ System ValueSets are pre-defined lookup values used throughout the application (
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Phase 2: Patient Management\n**Priority:** High | **Time Estimate:** 3-4 hours\n\n**Dependencies:** Master Data (locations, contacts, occupations, provinces/cities)\n\n#### 2a. Patient CRUD\n- [ ] Patients list page with pagination and search\n- [ ] Patient create form with validation\n- [ ] Patient edit form\n- [ ] Patient detail view\n- [ ] Patient delete with confirmation\n\n**API Endpoints:**\n- `GET /api/patient` - List patients (query: page, perPage, InternalPID, PatientID, Name, Birthdate)\n- `POST /api/patient` - Create patient\n- `PATCH /api/patient` - Update patient\n- `DELETE /api/patient` - Delete patient (soft delete, body: { InternalPID })\n- `GET /api/patient/{id}` - Get patient by ID\n- `GET /api/patient/check` - Check if patient exists (query: PatientID, EmailAddress1)
|
### Phase 2: Patient Management\n**Priority:** High | **Time Estimate:** 3-4 hours\n\n**Dependencies:** Master Data (locations, contacts, occupations, provinces/cities)\n\n#### 2a. Patient CRUD ✅ COMPLETED\n- [x] Patients list page with pagination and search\n- [x] Patient create form with validation (multi-step)\n- [x] Patient edit form (multi-step modal)\n- [x] Patient detail view (via edit modal)\n- [x] Patient delete with confirmation\n\n**API Endpoints:**\n- `GET /api/patient` - List patients (query: page, perPage, InternalPID, PatientID, Name, Birthdate)\n- `POST /api/patient` - Create patient\n- `PATCH /api/patient` - Update patient\n- `DELETE /api/patient` - Delete patient (soft delete, body: { InternalPID })\n- `GET /api/patient/{id}` - Get patient by ID\n- `GET /api/patient/check` - Check if patient exists (query: PatientID, EmailAddress1)
|
||||||
|
|
||||||
#### 2b. Advanced Patient Features
|
#### 2b. Advanced Patient Features
|
||||||
- [ ] Patient identifier management (KTP, PASS, SSN, etc.)
|
- [ ] Patient identifier management (KTP, PASS, SSN, etc.)
|
||||||
|
|||||||
98
src/lib/api/patients.js
Normal file
98
src/lib/api/patients.js
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import { get, post, patch, del } from './client.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch patients list with optional filters and pagination
|
||||||
|
* @param {Object} params - Query parameters
|
||||||
|
* @param {number} [params.page=1] - Page number
|
||||||
|
* @param {number} [params.perPage=20] - Items per page
|
||||||
|
* @param {number} [params.InternalPID] - Filter by internal patient ID
|
||||||
|
* @param {string} [params.PatientID] - Filter by patient ID
|
||||||
|
* @param {string} [params.Name] - Search by patient name
|
||||||
|
* @param {string} [params.Birthdate] - Filter by birthdate (YYYY-MM-DD)
|
||||||
|
* @returns {Promise<Object>} API response with patient data and pagination
|
||||||
|
*/
|
||||||
|
export async function fetchPatients(params = {}) {
|
||||||
|
const query = new URLSearchParams(params).toString();
|
||||||
|
return get(query ? `/api/patient?${query}` : '/api/patient');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch a single patient by ID
|
||||||
|
* @param {number} id - Internal patient ID
|
||||||
|
* @returns {Promise<Object>} API response with patient details
|
||||||
|
*/
|
||||||
|
export async function fetchPatient(id) {
|
||||||
|
return get(`/api/patient/${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a patient exists by PatientID or Email
|
||||||
|
* @param {Object} params - Check parameters
|
||||||
|
* @param {string} [params.PatientID] - Patient ID to check
|
||||||
|
* @param {string} [params.EmailAddress1] - Email to check
|
||||||
|
* @returns {Promise<Object>} API response with exists flag
|
||||||
|
*/
|
||||||
|
export async function checkPatientExists(params = {}) {
|
||||||
|
const query = new URLSearchParams(params).toString();
|
||||||
|
return get(query ? `/api/patient/check?${query}` : '/api/patient/check');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new patient
|
||||||
|
* @param {Object} data - Patient data
|
||||||
|
* @param {string} data.PatientID - Patient identifier (required)
|
||||||
|
* @param {string} data.NameFirst - First name (required)
|
||||||
|
* @param {string} data.Sex - Sex code: '1' (Female) or '2' (Male) (required)
|
||||||
|
* @param {string} data.Birthdate - Birthdate in ISO 8601 format (required)
|
||||||
|
* @param {string} [data.AlternatePID] - Alternate patient ID
|
||||||
|
* @param {string} [data.Prefix] - Title prefix (Mr, Mrs, Ms, Dr, Prof)
|
||||||
|
* @param {string} [data.NameMiddle] - Middle name
|
||||||
|
* @param {string} [data.NameLast] - Last name
|
||||||
|
* @param {string} [data.NameMaiden] - Maiden name
|
||||||
|
* @param {string} [data.Suffix] - Name suffix
|
||||||
|
* @param {string} [data.PlaceOfBirth] - Place of birth
|
||||||
|
* @param {string} [data.Citizenship] - Citizenship
|
||||||
|
* @param {string} [data.Street_1] - Street address line 1
|
||||||
|
* @param {string} [data.Street_2] - Street address line 2
|
||||||
|
* @param {string} [data.Street_3] - Street address line 3
|
||||||
|
* @param {string} [data.ZIP] - ZIP code
|
||||||
|
* @param {string} [data.Province] - Province area code
|
||||||
|
* @param {string} [data.City] - City area code
|
||||||
|
* @param {string} [data.Country] - Country
|
||||||
|
* @param {string} [data.Phone] - Phone number
|
||||||
|
* @param {string} [data.MobilePhone] - Mobile phone number
|
||||||
|
* @param {string} [data.EmailAddress1] - Primary email
|
||||||
|
* @param {string} [data.EmailAddress2] - Secondary email
|
||||||
|
* @param {Object} [data.PatIdt] - Patient identifier object
|
||||||
|
* @param {string} [data.PatIdt.IdentifierType] - Identifier type (KTP, PASS, SSN, SIM, KTAS)
|
||||||
|
* @param {string} [data.PatIdt.Identifier] - Identifier value
|
||||||
|
* @param {string} [data.Race] - Race
|
||||||
|
* @param {string} [data.MaritalStatus] - Marital status (A, B, D, M, S, W)
|
||||||
|
* @param {string} [data.Religion] - Religion
|
||||||
|
* @param {string} [data.Ethnic] - Ethnicity
|
||||||
|
* @param {string} [data.DeathIndicator] - Death indicator (Y/N)
|
||||||
|
* @param {string} [data.TimeOfDeath] - Time of death
|
||||||
|
* @param {string} [data.PatCom] - Patient comments
|
||||||
|
* @returns {Promise<Object>} API response
|
||||||
|
*/
|
||||||
|
export async function createPatient(data) {
|
||||||
|
return post('/api/patient', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update an existing patient
|
||||||
|
* @param {Object} data - Patient data (must include PatientID)
|
||||||
|
* @returns {Promise<Object>} API response
|
||||||
|
*/
|
||||||
|
export async function updatePatient(data) {
|
||||||
|
return patch('/api/patient', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a patient (soft delete)
|
||||||
|
* @param {number} internalPid - Internal patient ID
|
||||||
|
* @returns {Promise<Object>} API response
|
||||||
|
*/
|
||||||
|
export async function deletePatient(internalPid) {
|
||||||
|
return del('/api/patient', { body: JSON.stringify({ InternalPID: internalPid }) });
|
||||||
|
}
|
||||||
1007
src/routes/(app)/patients/+page.svelte
Normal file
1007
src/routes/(app)/patients/+page.svelte
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user