/* * File: patientCareSlice.ts * Description: Patient care state management slice * Design & Developed by Tech4Biz Solutions * Copyright (c) Spurrin Innovations. All rights reserved. */ import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit'; import { Patient, PatientCareState } from '../../../shared/types'; // ============================================================================ // ASYNC THUNKS // ============================================================================ /** * Fetch Patients Async Thunk * * Purpose: Fetch patients list from API * * @returns Promise with patients data or error */ export const fetchPatients = createAsyncThunk( 'patientCare/fetchPatients', async (_, { rejectWithValue }) => { try { // TODO: Replace with actual API call await new Promise(resolve => setTimeout(resolve, 1500)); // Mock patients data const mockPatients: Patient[] = [ { id: '1', mrn: 'MRN001', firstName: 'John', lastName: 'Doe', dateOfBirth: new Date('1985-03-15'), gender: 'MALE', age: 38, bedNumber: 'A1', roomNumber: '101', admissionDate: new Date('2024-01-15'), status: 'ACTIVE', priority: 'CRITICAL', department: 'Emergency', attendingPhysician: 'Dr. Smith', allergies: [ { id: '1', name: 'Penicillin', severity: 'SEVERE', reaction: 'Anaphylaxis', }, ], medications: [ { id: '1', name: 'Morphine', dosage: '2mg', frequency: 'Every 4 hours', route: 'IV', startDate: new Date(), status: 'ACTIVE', prescribedBy: 'Dr. Smith', }, ], vitalSigns: { bloodPressure: { systolic: 140, diastolic: 90, timestamp: new Date() }, heartRate: { value: 95, timestamp: new Date() }, temperature: { value: 37.2, timestamp: new Date() }, respiratoryRate: { value: 18, timestamp: new Date() }, oxygenSaturation: { value: 98, timestamp: new Date() }, }, medicalHistory: [], currentDiagnosis: 'Chest pain, rule out MI', lastUpdated: new Date(), }, { id: '2', mrn: 'MRN002', firstName: 'Jane', lastName: 'Smith', dateOfBirth: new Date('1990-07-22'), gender: 'FEMALE', age: 33, bedNumber: 'B2', roomNumber: '102', admissionDate: new Date('2024-01-15'), status: 'ACTIVE', priority: 'HIGH', department: 'Trauma', attendingPhysician: 'Dr. Johnson', allergies: [], medications: [], vitalSigns: { bloodPressure: { systolic: 120, diastolic: 80, timestamp: new Date() }, heartRate: { value: 88, timestamp: new Date() }, temperature: { value: 36.8, timestamp: new Date() }, respiratoryRate: { value: 16, timestamp: new Date() }, oxygenSaturation: { value: 99, timestamp: new Date() }, }, medicalHistory: [], currentDiagnosis: 'Multiple trauma from MVA', lastUpdated: new Date(), }, ]; return mockPatients; } catch (error) { return rejectWithValue('Failed to fetch patients.'); } } ); /** * Fetch Patient Details Async Thunk * * Purpose: Fetch detailed patient information * * @param patientId - ID of the patient to fetch * @returns Promise with patient details or error */ export const fetchPatientDetails = createAsyncThunk( 'patientCare/fetchPatientDetails', async (patientId: string, { rejectWithValue }) => { try { // TODO: Replace with actual API call await new Promise(resolve => setTimeout(resolve, 1000)); // Mock patient details (same as above but with more detailed info) const mockPatient: Patient = { id: patientId, mrn: `MRN${patientId.padStart(3, '0')}`, firstName: 'John', lastName: 'Doe', dateOfBirth: new Date('1985-03-15'), gender: 'MALE', age: 38, bedNumber: 'A1', roomNumber: '101', admissionDate: new Date('2024-01-15'), status: 'ACTIVE', priority: 'CRITICAL', department: 'Emergency', attendingPhysician: 'Dr. Smith', allergies: [ { id: '1', name: 'Penicillin', severity: 'SEVERE', reaction: 'Anaphylaxis', }, ], medications: [ { id: '1', name: 'Morphine', dosage: '2mg', frequency: 'Every 4 hours', route: 'IV', startDate: new Date(), status: 'ACTIVE', prescribedBy: 'Dr. Smith', }, ], vitalSigns: { bloodPressure: { systolic: 140, diastolic: 90, timestamp: new Date() }, heartRate: { value: 95, timestamp: new Date() }, temperature: { value: 37.2, timestamp: new Date() }, respiratoryRate: { value: 18, timestamp: new Date() }, oxygenSaturation: { value: 98, timestamp: new Date() }, }, medicalHistory: [], currentDiagnosis: 'Chest pain, rule out MI', lastUpdated: new Date(), }; return mockPatient; } catch (error) { return rejectWithValue('Failed to fetch patient details.'); } } ); /** * Update Patient Async Thunk * * Purpose: Update patient information * * @param patientData - Updated patient data * @returns Promise with updated patient or error */ export const updatePatient = createAsyncThunk( 'patientCare/updatePatient', async (patientData: Partial & { id: string }, { rejectWithValue }) => { try { // TODO: Replace with actual API call await new Promise(resolve => setTimeout(resolve, 800)); return patientData; } catch (error) { return rejectWithValue('Failed to update patient.'); } } ); // ============================================================================ // INITIAL STATE // ============================================================================ /** * Initial Patient Care State * * Purpose: Define the initial state for patient care * * Features: * - Patients list and management * - Current patient details * - Loading states for async operations * - Error handling and messages * - Search and filtering */ const initialState: PatientCareState = { // Patients data patients: [], currentPatient: null, // Loading states isLoading: false, isRefreshing: false, isLoadingPatientDetails: false, // Error handling error: null, // Search and filtering searchQuery: '', selectedFilter: 'all', sortBy: 'priority', sortOrder: 'desc', // Pagination currentPage: 1, itemsPerPage: 20, totalItems: 0, // Cache lastUpdated: null, cacheExpiry: null, }; // ============================================================================ // PATIENT CARE SLICE // ============================================================================ /** * Patient Care Slice * * Purpose: Redux slice for patient care state management * * Features: * - Patient data management * - Search and filtering * - Pagination * - Caching * - Error handling * - Loading states */ const patientCareSlice = createSlice({ name: 'patientCare', initialState, reducers: { /** * Clear Error Action * * Purpose: Clear patient care errors */ clearError: (state) => { state.error = null; }, /** * Set Search Query Action * * Purpose: Set search query for patients */ setSearchQuery: (state, action: PayloadAction) => { state.searchQuery = action.payload; state.currentPage = 1; // Reset to first page when searching }, /** * Set Filter Action * * Purpose: Set patient filter */ setFilter: (state, action: PayloadAction<'all' | 'active' | 'discharged' | 'critical'>) => { state.selectedFilter = action.payload; state.currentPage = 1; // Reset to first page when filtering }, /** * Set Sort Action * * Purpose: Set patient sort options */ setSort: (state, action: PayloadAction<{ by: string; order: 'asc' | 'desc' }>) => { state.sortBy = action.payload.by; state.sortOrder = action.payload.order; }, /** * Set Current Page Action * * Purpose: Set current page for pagination */ setCurrentPage: (state, action: PayloadAction) => { state.currentPage = action.payload; }, /** * Set Items Per Page Action * * Purpose: Set items per page for pagination */ setItemsPerPage: (state, action: PayloadAction) => { state.itemsPerPage = action.payload; state.currentPage = 1; // Reset to first page when changing items per page }, /** * Set Current Patient Action * * Purpose: Set the currently selected patient */ setCurrentPatient: (state, action: PayloadAction) => { state.currentPatient = action.payload; }, /** * Update Patient in List Action * * Purpose: Update a patient in the patients list */ updatePatientInList: (state, action: PayloadAction) => { const index = state.patients.findIndex(patient => patient.id === action.payload.id); if (index !== -1) { state.patients[index] = action.payload; } // Update current patient if it's the same patient if (state.currentPatient && state.currentPatient.id === action.payload.id) { state.currentPatient = action.payload; } }, /** * Add Patient Action * * Purpose: Add a new patient to the list */ addPatient: (state, action: PayloadAction) => { state.patients.unshift(action.payload); state.totalItems += 1; }, /** * Remove Patient Action * * Purpose: Remove a patient from the list */ removePatient: (state, action: PayloadAction) => { const index = state.patients.findIndex(patient => patient.id === action.payload); if (index !== -1) { state.patients.splice(index, 1); state.totalItems -= 1; } // Clear current patient if it's the same patient if (state.currentPatient && state.currentPatient.id === action.payload) { state.currentPatient = null; } }, /** * Clear Cache Action * * Purpose: Clear patient data cache */ clearCache: (state) => { state.patients = []; state.currentPatient = null; state.lastUpdated = null; state.cacheExpiry = null; }, }, extraReducers: (builder) => { // Fetch Patients builder .addCase(fetchPatients.pending, (state) => { state.isLoading = true; state.error = null; }) .addCase(fetchPatients.fulfilled, (state, action) => { state.isLoading = false; state.patients = action.payload; state.totalItems = action.payload.length; state.lastUpdated = new Date(); state.cacheExpiry = new Date(Date.now() + 5 * 60 * 1000); // 5 minutes state.error = null; }) .addCase(fetchPatients.rejected, (state, action) => { state.isLoading = false; state.error = action.payload as string; }); // Fetch Patient Details builder .addCase(fetchPatientDetails.pending, (state) => { state.isLoadingPatientDetails = true; state.error = null; }) .addCase(fetchPatientDetails.fulfilled, (state, action) => { state.isLoadingPatientDetails = false; state.currentPatient = action.payload; state.error = null; }) .addCase(fetchPatientDetails.rejected, (state, action) => { state.isLoadingPatientDetails = false; state.error = action.payload as string; }); // Update Patient builder .addCase(updatePatient.fulfilled, (state, action) => { // Update patient in list const index = state.patients.findIndex(patient => patient.id === action.payload.id); if (index !== -1) { state.patients[index] = { ...state.patients[index], ...action.payload }; } // Update current patient if it's the same patient if (state.currentPatient && state.currentPatient.id === action.payload.id) { state.currentPatient = { ...state.currentPatient, ...action.payload }; } }) .addCase(updatePatient.rejected, (state, action) => { state.error = action.payload as string; }); }, }); // ============================================================================ // EXPORTS // ============================================================================ export const { clearError, setSearchQuery, setFilter, setSort, setCurrentPage, setItemsPerPage, setCurrentPatient, updatePatientInList, addPatient, removePatient, clearCache, } = patientCareSlice.actions; export default patientCareSlice.reducer; /* * End of File: patientCareSlice.ts * Design & Developed by Tech4Biz Solutions * Copyright (c) Spurrin Innovations. All rights reserved. */