Skip to main content

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
ActionEffect
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
ActionPayloadEffect
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 objectStores 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
.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;
})
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' }));
  }
};

Build docs developers (and LLMs) love