Documentation Index Fetch the complete documentation index at: https://mintlify.com/Jay-byte389/AMS/llms.txt
Use this file to discover all available pages before exploring further.
AMS manages all application state with Redux Toolkit . The store is composed of four slices — auth, doctors, appointments, and snackbar — each owning a clearly scoped piece of state. All async work (network calls, AsyncStorage reads/writes) is handled by createAsyncThunk functions in dedicated thunk files, keeping slice reducers pure and predictable. Components interact with the store exclusively through useSelector (reads) and useDispatch (writes).
Store Configuration
// src/redux/store.js
import { configureStore } from '@reduxjs/toolkit' ;
import authReducer from './slices/authSlice' ;
import doctorsReducer from './slices/doctorSlice' ;
import snackBarReducer from './slices/snackBarSlice' ;
import appointmentReducer from './slices/appointmentSlice' ;
export const store = configureStore ({
reducer: {
auth: authReducer ,
doctors: doctorsReducer ,
snackbar: snackBarReducer ,
appointments: appointmentReducer ,
},
});
auth Current user object, authentication flag, loading state, and error message.
doctors Full doctor list, the currently selected doctor, and persisted favourite IDs.
appointments List of all appointments fetched from the API, with loading and error states.
snackbar Global toast visibility, message text, and type (success / error).
Slices
Auth Slice
The auth slice owns everything related to the current user session.
Initial state
{
user : null ,
isAuthenticated : false ,
loading : true , // true on startup so AppNavigator waits for the session check
error : null ,
}
Synchronous actions
Action Effect clearAuthError()Sets error back to null — call before re-submitting a login/signup form
Thunk lifecycle reducers
// src/redux/slices/authSlice.js (extra reducers excerpt)
builder
// ── checkAuthSession ──────────────────────────────────────
. addCase ( checkAuthSession . pending , ( state ) => { state . loading = true ; })
. addCase ( checkAuthSession . fulfilled , ( state , action ) => {
state . loading = false ;
if ( action . payload ) {
state . user = action . payload ;
state . isAuthenticated = true ;
} else {
state . user = null ;
state . isAuthenticated = false ;
}
})
. addCase ( checkAuthSession . rejected , ( state ) => { state . loading = false ; })
// ── signupUser ────────────────────────────────────────────
. addCase ( signupUser . pending , ( state ) => { state . loading = true ; state . error = null ; })
. addCase ( signupUser . fulfilled , ( state , action ) => {
state . loading = false ;
state . user = action . payload ;
state . isAuthenticated = true ;
})
. addCase ( signupUser . rejected , ( state , action ) => {
state . loading = false ;
state . error = action . payload ;
})
// ── loginUser ─────────────────────────────────────────────
. addCase ( loginUser . pending , ( state ) => { state . loading = true ; state . error = null ; })
. addCase ( loginUser . fulfilled , ( state , action ) => {
state . loading = false ;
state . user = action . payload ;
state . isAuthenticated = true ;
})
. addCase ( loginUser . rejected , ( state , action ) => {
state . loading = false ;
state . error = action . payload ;
})
// ── logoutUser ────────────────────────────────────────────
. addCase ( logoutUser . fulfilled , ( state ) => {
state . user = null ;
state . isAuthenticated = false ;
state . loading = false ;
});
loading starts as true (not false) in the initial state. This prevents AppNavigator from briefly flashing the Auth stack before the session check completes — the navigator renders null while isReady is false.
Doctors Slice
The doctors slice manages the browsable list of doctors, the currently viewed profile, and the user’s persisted favourite selections.
Initial state
{
doctorsList : [],
selectedDoctor : null ,
favouriteIds : [],
loading : false ,
error : null ,
}
Synchronous actions
Action Payload Effect setFavourite(ids)string[]Replaces the entire favouriteIds array (used when loading persisted favourites from AsyncStorage on app start) toggleFavourtie(doctorId)stringAdds doctorId if not present, removes it if already favourited setSelectedDoctor(doctor)doctor object Stores the doctor whose profile screen is about to open clearSelectedDoctor()— Resets selectedDoctor to null on back-navigation
// src/redux/slices/doctorSlice.js (reducers excerpt)
toggleFavourtie : ( state , action ) => {
const doctorId = action . payload ;
if ( state . favouriteIds . includes ( doctorId )) {
state . favouriteIds = state . favouriteIds . filter (( id ) => id !== doctorId );
} else {
state . favouriteIds . push ( doctorId );
}
},
Thunk lifecycle reducers
fetchDoctors is the only async thunk for this slice. On pending it sets loading = true and clears any previous error; on fulfilled it replaces doctorsList with the API payload; on rejected it stores the error message.
Appointments Slice
The appointments slice tracks every appointment record in a flat list array.
Initial state
{
list : [],
loading : false ,
error : null ,
}
The slice has no synchronous actions — all mutations go through async thunks.
Thunk lifecycle reducers
fetchAppointments
addAppointment
cancelAppointment
. addCase ( fetchAppointments . pending , ( state ) => {
state . loading = true ;
state . error = null ;
})
. addCase ( fetchAppointments . fulfilled , ( state , action ) => {
state . loading = false ;
state . list = action . payload ; // replaces entire list
})
. addCase ( fetchAppointments . rejected , ( state , action ) => {
state . loading = false ;
state . error = action . payload ;
})
. addCase ( addAppointment . pending , ( state ) => {
state . loading = true ;
})
. addCase ( addAppointment . fulfilled , ( state , action ) => {
state . loading = false ;
state . list . push ( action . payload ); // append new record
})
. addCase ( addAppointment . rejected , ( state , action ) => {
state . loading = false ;
state . error = action . payload ;
})
. addCase ( cancelAppointment . pending , ( state ) => {
state . loading = true ;
})
. addCase ( cancelAppointment . fulfilled , ( state , action ) => {
state . loading = false ;
// Find the item and update it in-place to keep the list intact
const index = state . list . findIndex (
( item ) => item . id === action . payload . id ,
);
if ( index !== - 1 ) {
state . list [ index ] = action . payload ; // status is now 'Cancelled'
} else {
state . list . push ( action . payload );
}
})
. addCase ( cancelAppointment . rejected , ( state , action ) => {
state . loading = false ;
state . error = action . payload ;
})
cancelAppointment.fulfilled updates the appointment in place rather than removing it from the list. This means cancelled appointments remain visible in the UI with a status: 'Cancelled' badge, which is the intended UX.
Snackbar Slice
snackBarSlice provides a lightweight global toast system. Any screen or thunk can trigger a snackbar without prop-drilling.
Initial state
{
visible : false ,
message : "" ,
type : "success" ,
}
Actions
// src/redux/slices/snackBarSlice.js
showSnackbar : ( state , action ) => {
state . visible = true ;
state . message = action . payload . message ;
state . type = action . payload . type || 'success' ; // 'success' | 'error'
},
hideSnackbar : ( state ) => {
state . visible = false ;
state . message = '' ;
},
GlobalSnackbar (rendered in App.tsx outside the navigator) subscribes to this slice and renders the toast whenever visible is true.
Using the Store in Components
Reading State with useSelector
import { useSelector } from 'react-redux' ;
// Read the authenticated user
const user = useSelector (( state ) => state . auth . user );
// Read the doctors list and loading flag
const { doctorsList , loading } = useSelector (( state ) => state . doctors );
// Read favourite IDs
const favouriteIds = useSelector (( state ) => state . doctors . favouriteIds );
Dispatching Actions and Thunks with useDispatch
import { useDispatch } from 'react-redux' ;
import { fetchDoctors } from '../redux/thunk/doctorThunk' ;
import { toggleFavourtie } from '../redux/slices/doctorSlice' ;
import { showSnackbar } from '../redux/slices/snackBarSlice' ;
const dispatch = useDispatch ();
// Fetch all doctors on mount
useEffect (() => {
dispatch ( fetchDoctors ());
}, [ dispatch ]);
// Toggle a favourite and show feedback
const handleFavourite = ( doctorId ) => {
dispatch ( toggleFavourtie ( doctorId ));
dispatch ( showSnackbar ({ message: 'Favourites updated' , type: 'success' }));
};
Handling Async Thunk Results
// Dispatch loginUser and respond to the outcome
const handleLogin = async () => {
const result = await dispatch ( loginUser ({ emailOrPhone , password }));
if ( loginUser . fulfilled . match ( result )) {
// navigation is handled by AppNavigator reacting to isAuthenticated
} else {
dispatch ( showSnackbar ({ message: result . payload , type: 'error' }));
}
};