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
| Key | Value | Purpose |
|---|
@registered_users | JSON array of user objects | All registered accounts on this device |
@logged_in_user | JSON user object | Current active session |
@favourite_doctors | JSON array of doctor IDs | Persisted favourite selections across app restarts |
@appoinments | JSON array of appointments | Local 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.
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);
}
}
);
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;
}
);
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.
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.
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:
- Move registration and login to a server — send credentials over HTTPS, store only a hashed password (e.g. bcrypt) on the server side.
- 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.
- Update
checkAuthSession to read the secure token and validate it against the server (or decode and check its expiry locally).
- Remove
@registered_users entirely — user accounts live on the server, not the device.