Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/BhushanBadhe39/SkinFirts/llms.txt

Use this file to discover all available pages before exploring further.

SkinFirts manages the full authentication lifecycle — from splash screen session rehydration through registration, login, profile editing, and logout — using a thin authService layer that coordinates between the MockAPI backend, React Native’s AsyncStorage, and a Redux UserSlice. All screens consume these service functions so no screen ever touches storage or Redux directly.

Authentication flow

When the app launches, SplashScreen runs immediately. It dispatches loadDoctors to pre-fetch the doctor roster and reads the persisted user from AsyncStorage. If a saved session is found, it hydrates the Redux store before the 3-second splash timer fires. The navigation destination is decided by the Redux isLoggedIn flag.
SplashScreen (mounts)

  ├─ dispatch(loadDoctors())          → pre-fetch doctor data into Redux

  ├─ AsyncStorage.getItem('@user_account_details')
  │     ├─ Found  → dispatch(setUser(parsedUser))  →  isLoggedIn = true
  │     └─ Not found                               →  isLoggedIn = false

  └─ setTimeout 3 000 ms
        ├─ isLoggedIn === true  → navigation.replace('MainTabs')
        └─ isLoggedIn === false → navigation.replace('Register')
The Register screen is the landing page for unauthenticated users. It presents two buttons — Log In and Sign Up — that navigate to their respective flows.

Registration flow

1

Open the Sign Up screen

The user taps Sign Up on the Register screen. The app navigates to SignUp.
2

Fill in the registration form

The SignUp screen collects five fields that are tracked in a single formData state object:
FieldPlaceholder
Full NameYour Full Name
Password
Email
Mobile Number+91 XXXXXXXXXX
Date Of BirthDD/MM/YYYY
The Sign Up button stays disabled until every field has a non-empty value (Object.values(formData).every(v => v.trim() !== '')).
3

Call signUpUser

On submit, handleSubmit calls signUpUser(formData, dispatch) from authService.
4

POST to /users and persist session

Inside signUpUser, createUser(formData) POSTs to /users. The API merges pre-defined appointment arrays onto the payload before persisting. The resolved user object is then saved to AsyncStorage under the key @user_account_details and dispatched as setUser.
5

Navigate to MainTabs

After signUpUser resolves, SignUp calls navigation.navigate('MainTabs').
// src/services/authService.js
export const signUpUser = async (formData, dispatch) => {
  const newUser = await createUser(formData)
  await AsyncStorage.setItem('@user_account_details', JSON.stringify(newUser))
  dispatch(setUser(newUser))
  return true
}

Login flow

1

Open the Login screen

The user taps Log In on the Register screen. The app navigates to Login1.
2

Enter credentials

Login1 collects an email address and a password. The Log In button is disabled until both fields are non-empty. A Forgot Password link navigates to the SetPassword screen, which is the forgot-password flow where the user can enter and confirm a new password.
3

Call loginUser

On submit, handleSubmit calls loginUser(email, password, dispatch) from authService.
4

Fetch and match user

loginUser calls fetchUsers(), which GETs /users to retrieve the full user list. It then searches for a user whose email matches (case-insensitive, trimmed) and whose password matches exactly.
5

Persist session and navigate

If a matching user is found, the user object is saved to AsyncStorage and dispatched as setUser. loginUser returns true and Login1 navigates to MainTabs. If no match is found, loginUser returns false and the screen shows an Invalid Email or Password alert.
// src/services/authService.js
export const loginUser = async (email, password, dispatch) => {
  try {
    const users = await fetchUsers()
    const authUser = users.find(
      user =>
        user.email.toLowerCase() === email.trim().toLowerCase() &&
        user.password === password
    )
    if (!authUser) return false
    await AsyncStorage.setItem('@user_account_details', JSON.stringify(authUser))
    dispatch(setUser(authUser))
    return true
  } catch (error) {
    console.log('Error fetching data' + error)
    return false
  }
}

Forgot password

The SetPassword screen is reached via the Forgot Password link on the Login1 screen. It presents a Password field and a Confirm Password field, with a Create New Password button to submit the new credentials.

Logout

logoutUser(dispatch) removes the persisted session from AsyncStorage and dispatches clearUser(), which resets both state.user and state.isLoggedIn in the Redux store. The calling screen is responsible for resetting navigation to Register after the call resolves.
// src/services/authService.js
export const logoutUser = async (dispatch) => {
  await AsyncStorage.removeItem('@user_account_details')
  dispatch(clearUser())
}

Editing user details

Profile updates go through editUserDetails, which PATCHes the user record on the server by ID and then re-persists the updated object to both AsyncStorage and the Redux store.
// src/services/authService.js
export const editUserDetails = async (id, updates, dispatch) => {
  try {
    const newUser = await updateUser(id, updates)
    if (!newUser) return false
    await AsyncStorage.setItem('@user_account_details', JSON.stringify(newUser))
    dispatch(setUser(newUser))
    return true
  } catch (error) {
    console.log('Error')
  }
}
The underlying API function sends a PATCH request to /users/${id}:
// src/api/usersApi.js
export async function updateUser(id, updates) {
  const { data } = await apiClient.patch(`./users/${id}`, updates)
  return data
}

Redux state shape — UserSlice

The UserSlice holds two fields. Every piece of the app that needs to know whether a user is signed in reads from this slice via useSelector.
// src/redux/Slices/UserSlice.js
const initialState = {
  user: null,
  isLoggedIn: false,
}

setUser(payload)

Sets state.user to the dispatched payload and flips state.isLoggedIn to true. Called after a successful sign-up, login, or profile edit.

clearUser()

Resets state.user to null and state.isLoggedIn to false. Called by logoutUser.
// src/redux/Slices/UserSlice.js
const userSlice = createSlice({
  name: 'user',
  initialState,
  reducers: {
    setUser(state, action) {
      state.user = action.payload
      state.isLoggedIn = true
    },
    clearUser(state) {
      state.user = null
      state.isLoggedIn = false
    },
  },
})

export const { setUser, clearUser } = userSlice.actions
export default userSlice.reducer

AsyncStorage key

All session persistence uses a single key:
@user_account_details
The value stored is the full JSON-stringified user object as returned by the MockAPI.
Passwords are stored and compared as plain strings on MockAPI. This is intentional for the development environment only. Before shipping to production, replace the credential-matching logic in loginUser with a proper hashed-password or token-based authentication scheme.

Build docs developers (and LLMs) love