/* * 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 { MedicalCase, PatientCareState } from '../../../shared/types'; import { patientAPI } from '../services/patientAPI'; // ============================================================================ // 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 (token: string, { rejectWithValue }) => { try { // Make actual API call to fetch medical cases const response :any = await patientAPI.getPatients(token); if (response.ok && response.data&&response.data.success) { // Add random case types to each patient record const caseTypes: Array<'Critical' | 'Emergency' | 'Routine'> = ['Critical', 'Emergency', 'Routine']; const patientsWithTypes = response.data.data.map((patient: any) => ({ ...patient, type: caseTypes[Math.floor(Math.random() * caseTypes.length)] })); return patientsWithTypes as MedicalCase[]; } else { // Fallback to mock data for development const mockPatients: MedicalCase[] = [ { id: 1, patientdetails: JSON.stringify({ patientdetails: { Date: '2024-01-15', Name: 'John Doe', PatID: 'MRN001', PatAge: '38', PatSex: 'M', Status: 'Active', InstName: 'City General Hospital', Modality: 'CT', ReportStatus: 'Pending' } }), series: JSON.stringify([ { Path: ['/dicom/series1'], SerDes: 'Chest CT', ViePos: 'Supine', pngpath: '/images/ct_chest_1.png', SeriesNum: '1', ImgTotalinSeries: '50' } ]), created_at: '2024-01-15T10:30:00Z', updated_at: '2024-01-15T11:45:00Z', series_id: 'series_001', type: 'Critical' }, { id: 2, patientdetails: JSON.stringify({ patientdetails: { Date: '2024-01-15', Name: 'Jane Smith', PatID: 'MRN002', PatAge: '33', PatSex: 'F', Status: 'Active', InstName: 'Memorial Medical Center', Modality: 'MR', ReportStatus: 'Completed' } }), series: JSON.stringify([ { Path: ['/dicom/series2'], SerDes: 'Brain MRI', ViePos: 'Supine', pngpath: '/images/mri_brain_1.png', SeriesNum: '2', ImgTotalinSeries: '120' } ]), created_at: '2024-01-15T09:15:00Z', updated_at: '2024-01-15T10:30:00Z', series_id: 'series_002', type: 'Routine' }, ]; return mockPatients; } } catch (error: any) { console.error('Fetch patients error:', error); return rejectWithValue(error.message || '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 as any, 1000)); // Mock patient details for specific patient const mockPatient: MedicalCase = { id: parseInt(patientId), patientdetails: JSON.stringify({ patientdetails: { Date: '2024-01-15', Name: 'John Doe', PatID: `MRN${patientId.padStart(3, '0')}`, PatAge: '38', PatSex: 'M', Status: 'Active', InstName: 'City General Hospital', Modality: 'CT', ReportStatus: 'Pending' } }), series: JSON.stringify([ { Path: [`/dicom/series${patientId}`], SerDes: 'Chest CT', ViePos: 'Supine', pngpath: `/images/ct_chest_${patientId}.png`, SeriesNum: patientId, ImgTotalinSeries: '50' } ]), created_at: '2024-01-15T10:30:00Z', updated_at: '2024-01-15T11:45:00Z', series_id: `series_${patientId.padStart(3, '0')}`, type: 'Critical' }; 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: number }, { rejectWithValue }) => { try { // TODO: Replace with actual API call await new Promise((resolve) => setTimeout(resolve as any, 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: 'date', 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' | 'Critical' | 'Routine' | 'Emergency'>) => { 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: 'date' | 'name' | 'age'; 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().toLocaleDateString(); state.cacheExpiry = new Date(Date.now() + 5 * 60 * 1000).toLocaleDateString(); // 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. */