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 persists data locally on the device using @react-native-async-storage/async-storage. Because the app currently has no real authentication backend, AsyncStorage serves as the sole user database: it stores all registered accounts, the active session, favourite doctor IDs, and a local appointment cache. All storage interactions are encapsulated in src/services/storage.js — no component or thunk calls AsyncStorage directly.

Storage Keys

KeyValuePurpose
@registered_usersJSON array of user objectsAll registered accounts on this device
@logged_in_userJSON user objectCurrent active session
@favourite_doctorsJSON array of doctor IDsPersisted favourite selections across app restarts
@appoinmentsJSON array of appointmentsLocal appointment cache

Storage Functions

All functions in src/services/storage.js return Promises and are designed to never throw — errors are caught internally and surfaced through return values or logged to the console.

User Account Management

// src/services/storage.js

// Push a new user object into the @registered_users array
export const saveUser = async (userData) => {
  const existingUsers = await getAllUsers();
  existingUsers.push(userData);
  await AsyncStorage.setItem(USERS_KEY, JSON.stringify(existingUsers));
  return { success: true };
  // returns { success: false, error: string } on failure
};

// Read all registered user objects
export const getAllUsers = async () => {
  const users = await AsyncStorage.getItem(USERS_KEY);
  return users ? JSON.parse(users) : [];
};

// Find a single user by email address or mobile number
export const getUser = async (emailOrPhone) => {
  const users = await getAllUsers();
  return users.find(
    (user) => user.email === emailOrPhone || user.mobile === emailOrPhone,
  );
};

// Validate credentials — returns { success, user } or { success: false, error }
export const validateUser = async (emailOrPhone, password) => {
  const user = await getUser(emailOrPhone);
  if (!user) {
    return { success: false, error: 'User not found. Please sign up first.' };
  }
  if (user.password !== password) {
    return { success: false, error: 'Incorrect password.' };
  }
  return { success: true, user };
};

Session Management

// Write the logged-in user object to @logged_in_user
export const saveLoggedInUser = async (userData) => {
  await AsyncStorage.setItem(SESSION_KEY, JSON.stringify(userData));
  return { success: true };
};

// Read the current session — returns null if no user is logged in
export const getLoggedInUser = async () => {
  const user = await AsyncStorage.getItem(SESSION_KEY);
  return user ? JSON.parse(user) : null;
};

// Remove the session key — effectively logs the user out
export const logoutUser = async () => {
  await AsyncStorage.removeItem(SESSION_KEY);
  return { success: true };
};

Favourite Doctors

// Overwrite the favourites list with a new array of doctor ID strings
export const saveFavourites = async (ids) => {
  await AsyncStorage.setItem(FAVOURITE_KEY, JSON.stringify(ids));
};

// Read the favourites list — returns [] if none saved
export const loadFavourites = async () => {
  const data = await AsyncStorage.getItem(FAVOURITE_KEY);
  return data ? JSON.parse(data) : [];
};

Appointment Cache

// Append a single appointment object to the local cache
export const saveAppointment = async (appointment) => {
  const appointments = await getAppoinments();
  appointments.push(appointment);
  await AsyncStorage.setItem(Appoinment_key, JSON.stringify(appointments));
};

// Read the full local appointment cache — returns [] if empty
export const getAppoinments = async () => {
  const data = await AsyncStorage.getItem(Appoinment_key);
  return data ? JSON.parse(data) : [];
};

Integration with Redux

Storage is never called directly from UI components. It is accessed through Redux thunks, which translate storage reads/writes into state changes.
1

App launch — session restore

AppNavigator dispatches checkAuthSession. The thunk calls getLoggedInUser(). If a user object is returned, the auth slice sets isAuthenticated = true and the user is taken straight to BottomTabs.
// src/redux/thunk/authThunk.js
export const checkAuthSession = createAsyncThunk(
  'auth/checkAuthSession',
  async (_, { rejectWithValue }) => {
    try {
      const user = await getLoggedInUser();
      return user; // null → not authenticated, object → authenticated
    } catch (error) {
      return rejectWithValue(error.message);
    }
  }
);
2

Sign up — saving a new account

signupUser thunk calls saveUser(userData) to append the account to @registered_users, then immediately calls saveLoggedInUser(userData) to create the session.
export const signupUser = createAsyncThunk(
  'auth/signupUser',
  async (userData, { rejectWithValue }) => {
    const result = await saveUser(userData);
    if (!result.success) return rejectWithValue(result.error);
    await saveLoggedInUser(userData);
    return userData;
  }
);
3

Login — validating credentials

loginUser thunk calls validateUser(emailOrPhone, password). On success it persists the session via saveLoggedInUser(result.user) and returns the user object to the slice.
4

Logout — clearing the session

logoutUser thunk calls logoutUser() (the storage function), which removes @logged_in_user. The auth slice then sets user = null and isAuthenticated = false.
5

Favourites — persisting across restarts

HomeScreen reads state.doctors.favouriteIds and, whenever it changes, calls saveFavourites(favouriteIds). On mount it calls loadFavourites() and dispatches setFavourite(ids) to pre-populate the Redux store.

Security Considerations

User passwords are stored in plaintext inside the @registered_users JSON array in AsyncStorage. AsyncStorage is not encrypted on either Android or iOS. Anyone with filesystem access to the device (jailbroken/rooted) or an unencrypted device backup can read all stored passwords. This implementation is acceptable only for development and demonstration purposes — it must not be deployed to production users.
For a production release, replace the local user database with a real authentication backend:
  1. Move registration and login to a server — send credentials over HTTPS, store only a hashed password (e.g. bcrypt) on the server side.
  2. Issue a JWT or opaque token on successful login and store it with react-native-keychain or expo-secure-store, both of which use the OS-level secure enclave / Keystore.
  3. Update checkAuthSession to read the secure token and validate it against the server (or decode and check its expiry locally).
  4. Remove @registered_users entirely — user accounts live on the server, not the device.

Build docs developers (and LLMs) love