React Native Flow

App helper utilities

Reference for a conventional `helper.tsx` (or `utils/helpers`) module in a React Native CLI app—based on React Navigation, AsyncStorage, i18next, dayjs, toasts, and @notifee/react-native. Names like `saveToSecureStorage` map to AsyncStorage in the sample; swap for secure storage if you handle secrets. Imports such as `@/src/language-config/i18n` are examples—point them at your project.

Packages to install

Install these npm packages in your React Native CLI app. Use `npm install` (or your package manager) and make sure required native setup is done for navigation/notifications.

  • @react-native-async-storage/async-storage
  • dayjs
  • @notifee/react-native
  • react-native-toast-message
  • @react-navigation/native

Recommended

npm install @react-native-async-storage/async-storage dayjs @notifee/react-native react-native-toast-message @react-navigation/native

npm

npm install @react-native-async-storage/async-storage dayjs @notifee/react-native react-native-toast-message @react-navigation/native

Peers react and react-native are provided by your app setup.

Wire in your project

Adjust paths for i18n (`@/src/language-config/...`), `../constants/routes`, `../context/ThemeContext`, and your `../navigation/NavigationService` (`navigationRef`). Optional: set GOOGLE_API_KEY for static maps.

Includes a dependency header, import block, and per-export /** … */ notes (npm / React Native / your modules / built-ins).

Language & theme

`changeLanguage`

src/utils/helper.tsx

Async: persists the selected language key (e.g. `@language`) then calls `i18n.changeLanguage` so UI strings update immediately.

Uses

  • npm: @react-native-async-storage/async-storage
  • Your modules: @/src/language-config/i18n
export const changeLanguage = async (lang: string) => {
  await saveToSecureStorage("@language", lang);
  i18n.changeLanguage(lang);
};
`getTheme`

src/utils/helper.tsx

Resolves the effective theme: if the user chose `default`, follows system `ColorSchemeName` (`light` / `dark`); otherwise returns the explicit `Theme` from your context.

Uses

  • React Native: ColorSchemeName
  • Your modules: ../context/ThemeContext (`Theme`)
export const getTheme = (theme: Theme, systemTheme: ColorSchemeName) => {
  if (theme === "default" && systemTheme === "dark") {
    return "dark";
  } else if (theme === "default" && systemTheme === "light") {
    return "light";
  } else {
    return theme;
  }
};

Logging & toasts

`devLog`

src/utils/helper.tsx

Wraps `console.log` so logs run only when `__DEV__` is true—keeps release builds quiet.

Uses

  • Built-in: __DEV__ (Metro / React Native)
export const devLog = (...args: any[]) => {
  if (__DEV__) {
    console.log(...args);
  }
};
`ShowToastOptions`

src/utils/helper.tsx

Optional `text1`, `text2`, and `type` (`success` | `error`) passed into `showError` / `showSuccess` when you don’t use a plain string message.

Uses

  • Built-in: Type-only — pair with react-native-toast-message in showError / showSuccess
export interface ShowToastOptions {
  text1?: string;
  text2?: string;
  type?: "success" | "error";
}
`showError`

src/utils/helper.tsx

Shows a `react-native-toast-message` toast. Accepts a string or `ShowToastOptions`; merges with `getTextList().somethingWentWrong` when lines are missing.

Uses

  • npm: react-native-toast-message
  • Your modules: @/src/language-config/TextList (`getTextList`)
export const showError = (messageOrOptions: string | ShowToastOptions) => {
  let type = "error";
  let text1 = "";
  let text2 = getTextList().somethingWentWrong;

  if (typeof messageOrOptions === "string") {
    text2 = messageOrOptions || text2;
  } else {
    type = messageOrOptions.type || type;
    text1 = messageOrOptions.text1 || text1;
    text2 = messageOrOptions.text2 || text2;
  }

  Toast.show({
    type,
    text1: `${text1}`,
    text2,
  });
};
`showSuccess`

src/utils/helper.tsx

Same shape as `showError` but defaults to success styling—use for confirmations and happy paths.

Uses

  • npm: react-native-toast-message
  • Your modules: @/src/language-config/TextList (`getTextList`)
export const showSuccess = (messageOrOptions: string | ShowToastOptions) => {
  let type = "success";
  let text1 = "";
  let text2 = getTextList().somethingWentWrong;

  if (typeof messageOrOptions === "string") {
    text2 = messageOrOptions || text2;
  } else {
    type = messageOrOptions.type || type;
    text1 = messageOrOptions.text1 || text1;
    text2 = messageOrOptions.text2 || text2;
  }

  Toast.show({
    type,
    text1: `${text1}`,
    text2,
  });
};

Persistence (AsyncStorage)

`saveToSecureStorage`

src/utils/helper.tsx

`AsyncStorage.setItem` wrapped in try/catch with `devLog` on failure. Despite the name, this sample uses AsyncStorage (not hardware-backed secure storage).

Uses

  • npm: @react-native-async-storage/async-storage
export async function saveToSecureStorage(
  key: string,
  value: string
): Promise<void> {
  try {
    await AsyncStorage.setItem(key, value);
  } catch (error) {
    devLog("[AsyncStorage] Error saving data:", error);
  }
}
`getFromSecureStorage`

src/utils/helper.tsx

Reads a string by key; returns `null` if missing or on error.

Uses

  • npm: @react-native-async-storage/async-storage
export async function getFromSecureStorage(
  key: string
): Promise<string | null> {
  try {
    const value = await AsyncStorage.getItem(key);
    return value;
  } catch (error) {
    devLog("[AsyncStorage] Error retrieving data:", error);
    return null;
  }
}
`removeKeysFromSecureStorage`

src/utils/helper.tsx

`AsyncStorage.multiRemove` for batch cleanup (logout, toggle remember-me off, etc.).

Uses

  • npm: @react-native-async-storage/async-storage
export async function removeKeysFromSecureStorage(key: string[]) {
  try {
    await AsyncStorage.multiRemove(key);
  } catch (error) {
    devLog("[AsyncStorage] Error removing data:", error);
    return null;
  }
}
`removeAllKeysFromSecureStorage`

src/utils/helper.tsx

Clears the entire AsyncStorage database—use sparingly (full sign-out / reset).

Uses

  • npm: @react-native-async-storage/async-storage
export async function removeAllKeysFromSecureStorage() {
  try {
    await AsyncStorage.clear();
  } catch (error) {
    devLog("[AsyncStorage] Error removing all data:", error);
    return null;
  }
}

Remember me

`RememberMeCredentials`

src/utils/helper.tsx

Shape: `email`, `password`, `rememberMe`. Used with the helpers below. Storing passwords in AsyncStorage is convenient for demos but insecure for production—prefer tokens or a secure vault.

Uses

  • Built-in: Type-only — no runtime imports
export interface RememberMeCredentials {
  email: string;
  password: string;
  rememberMe: boolean;
}
`saveRememberMeCredentials`

src/utils/helper.tsx

If `rememberMe` is true, writes email/password/`@remember_me` keys; otherwise removes those keys.

Uses

  • npm: @react-native-async-storage/async-storage
  • Note: Uses saveToSecureStorage / removeKeysFromSecureStorage
export const saveRememberMeCredentials = async (credentials: RememberMeCredentials): Promise<void> => {
  try {
    if (credentials.rememberMe) {
      await saveToSecureStorage("@remembered_email", credentials.email);
      await saveToSecureStorage("@remembered_password", credentials.password);
      await saveToSecureStorage("@remember_me", "true");
    } else {
      await removeKeysFromSecureStorage([
        "@remembered_email",
        "@remembered_password",
        "@remember_me",
      ]);
    }
  } catch (error) {
    devLog("[Remember Me] Error saving credentials:", error);
  }
};
`loadRememberMeCredentials`

src/utils/helper.tsx

Reads saved credentials when `@remember_me` equals the string true; otherwise returns empty strings and rememberMe: false.

Uses

  • npm: @react-native-async-storage/async-storage
export const loadRememberMeCredentials = async (): Promise<RememberMeCredentials> => {
  try {
    const savedEmail = await getFromSecureStorage("@remembered_email");
    const savedPassword = await getFromSecureStorage("@remembered_password");
    const rememberMe = await getFromSecureStorage("@remember_me");

    if (savedEmail && savedPassword && rememberMe === "true") {
      return {
        email: savedEmail,
        password: savedPassword,
        rememberMe: true,
      };
    }

    return {
      email: "",
      password: "",
      rememberMe: false,
    };
  } catch (error) {
    devLog("[Remember Me] Error loading credentials:", error);
    return {
      email: "",
      password: "",
      rememberMe: false,
    };
  }
};
`clearRememberMeCredentials`

src/utils/helper.tsx

Removes the three remember-me keys without wiping all storage.

Uses

  • npm: @react-native-async-storage/async-storage
export const clearRememberMeCredentials = async (): Promise<void> => {
  try {
    await removeKeysFromSecureStorage([
      "@remembered_email",
      "@remembered_password",
      "@remember_me",
    ]);
  } catch (error) {
    devLog("[Remember Me] Error clearing credentials:", error);
  }
};

Strings, dates & currency

`capitalizeFirstLetter`

src/utils/helper.tsx

Returns empty string for falsy input; otherwise uppercases the first character and leaves the rest untouched.

Uses

  • Built-in: No packages
export const capitalizeFirstLetter = (text: string): string => {
  if (!text) return "";
  return text.charAt(0).toUpperCase() + text.slice(1);
};
`getTimeOfDay`

src/utils/helper.tsx

Bucketed greeting by hour (5–12 morning, 12–17 afternoon, 17–21 evening, else night) using localized strings from `getTextList()`.

Uses

  • Your modules: @/src/language-config/TextList (`getTextList`)
export const getTimeOfDay = () => {
  const currentHour = new Date().getHours();

  if (currentHour >= 5 && currentHour < 12) {
    return getTextList().morning;
  } else if (currentHour >= 12 && currentHour < 17) {
    return getTextList().afternoon;
  } else if (currentHour >= 17 && currentHour < 21) {
    return getTextList().evening;
  } else {
    return getTextList().night;
  }
};
`formatDate`

src/utils/helper.tsx

Formats a `Date` or date string with **dayjs** (`format` argument, e.g. `YYYY-MM-DD`).

Uses

  • npm: dayjs
export const formatDate = (date: string | Date, format: string): string => {
  return dayjs(date).format(format);
};
`formatCurrency`

src/utils/helper.tsx

`Intl.NumberFormat` with `style: "currency"`, fixed 2 fraction digits, defaulting currency to `GBP` when omitted.

Uses

  • Built-in: Intl.NumberFormat
export const formatCurrency = (amount: number, currency: string) => {
  return new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: currency || "GBP",
    minimumFractionDigits: 2,
    maximumFractionDigits: 2,
  }).format(amount);
};
`getCurrencySymbol`

src/utils/helper.tsx

Maps ISO codes (USD, EUR, INR, …) to symbols; falls back to `£` when code is empty or unknown.

Uses

  • Built-in: Intl (standard JS)
export const getCurrencySymbol = (currencyCode: string | null | undefined): string => {
  const normalizedCurrencyCode = currencyCode?.trim().toUpperCase();

  if (!normalizedCurrencyCode) {
    return "£";
  }

  const currencyMap: Record<string, string> = {
    USD: "$",
    GBP: "£",
    EUR: "€",
    INR: "₹",
    JPY: "¥",
    CNY: "¥",
    AUD: "A$",
    CAD: "C$",
    CHF: "CHF",
    SEK: "kr",
    NOK: "kr",
    DKK: "kr",
    PLN: "zł",
    RUB: "₽",
    BRL: "R$",
    MXN: "$",
    ZAR: "R",
    SGD: "S$",
    HKD: "HK$",
    NZD: "NZ$",
    KRW: "₩",
    TRY: "₺",
    AED: "د.إ",
    SAR: "﷼",
    PKR: "₨",
    BDT: "৳",
    THB: "฿",
    MYR: "RM",
    IDR: "Rp",
    PHP: "₱",
    VND: "₫",
  };

  return currencyMap[normalizedCurrencyCode] || "£";
};

Linking & settings

`openAppSettings`

src/utils/helper.tsx

iOS: opens `app-settings:`; Android: `Linking.openSettings()` for app details—use after permission denials.

Uses

  • React Native: Linking, Platform
export const openAppSettings = () => {
  if (Platform.OS === "ios") {
    Linking.openURL("app-settings:");
  } else {
    Linking.openSettings();
  }
};
`openWebUrl`

src/utils/helper.tsx

Thin wrapper around `Linking.openURL` for https links and deep links.

Uses

  • React Native: Linking
export const openWebUrl = (url: string) => {
  Linking.openURL(url);
};

React Navigation navigation

`navigate`

src/utils/helper.tsx

React Navigation `navigate` wrapper using a global `navigationRef`. Passes `params` (and merges `search` into the same params object for convenience).

Uses

  • npm: @react-navigation/native
  • Your modules: ../navigation/NavigationService (`navigationRef`)
type NavigateOptions = {
  params?: Record<string, string>;
  search?: Record<string, string | number | boolean | undefined>;
};

export const navigate = (
  route: string | any,
  options?: NavigateOptions
) => {
  const nav = navigationRef?.current;
  if (!nav) {
    devLog("Navigation not ready");
    return;
  }

  nav.navigate(route as never, {
    ...(options?.params ?? {}),
    // React Navigation doesn't have an exact "search" concept like Expo Router.
    ...(options?.search ?? {}),
  } as never);
};
`navigateBack`

src/utils/helper.tsx

Calls `navigationRef.current.goBack()` to pop the navigation stack.

Uses

  • npm: @react-navigation/native
  • Your modules: ../navigation/NavigationService (`navigationRef`)
export const navigateBack = () => {
  navigationRef?.current?.goBack();
};
`updateUser`

src/utils/helper.tsx

Persists access/refresh tokens from an API payload, updates user state via `setUser`, then navigates to a route (or default tab root).

Uses

  • npm: @react-native-async-storage/async-storage, @react-navigation/native
  • Your modules: ../constants/routes · `navigate` in same file
  • Note: Expects API shape with data.access_token, data.refresh_token, data.user
export const updateUser = async (
  data: any,
  setUser: (user: any) => void,
  route?: any
) => {
  await saveToSecureStorage("@access_token", data?.data?.access_token);
  await saveToSecureStorage("@refresh_token", data?.data?.refresh_token);
  setUser(data?.data?.user);
  if (route) {
    navigate(route);
  } else {
    navigate(Routes.TABS.ROOT);
  }
};

UI data helpers

`getConsistentColor`

src/utils/helper.tsx

Deterministic pastel color from a string id (e.g. review id) using a simple hash into a fixed palette—good for avatars or tags.

Uses

  • Built-in: No packages
export const getConsistentColor = (reviewId: string) => {
  const colors = [
    "#FF6B6B",
    "#4ECDC4",
    "#45B7D1",
    "#96CEB4",
    "#FFEAA7",
    "#DDA0DD",
    "#98D8C8",
    "#F7DC6F",
    "#BB8FCE",
    "#85C1E9",
    "#F8C471",
    "#82E0AA",
    "#F1948A",
    "#85C1E9",
    "#D7BDE2",
  ];

  let hash = 0;
  for (let i = 0; i < reviewId.length; i++) {
    hash = reviewId.charCodeAt(i) + ((hash << 5) - hash);
  }
  return colors[Math.abs(hash) % colors.length];
};

Google Static Maps

`MapMarker`

src/utils/helper.tsx

Marker shape: required `lat`/`lng`, optional `name`, `color`, `label` for Static Maps marker parameters.

Uses

  • Built-in: Type-only
export interface MapMarker {
  name?: string;
  lat: number;
  lng: number;
  color?: string;
  label?: string;
}
`StaticMapOptions`

src/utils/helper.tsx

Options for the Static Maps URL: `center`, `zoom`, `size`, `maptype`, `markers`, `scale`, `format`.

Uses

  • Built-in: Type-only
export interface StaticMapOptions {
  center?: { lat: number; lng: number };
  zoom?: number;
  size?: string;
  maptype?: "roadmap" | "satellite" | "terrain" | "hybrid";
  markers?: MapMarker[];
  scale?: 1 | 2;
  format?: "png" | "jpg" | "gif";
}
`generateStaticMapUrl`

src/utils/helper.tsx

Builds a Google Maps Static API URL from options; reads `process.env.GOOGLE_API_KEY`, logs and returns `""` if missing; encodes marker pipes per Google’s format.

Uses

  • Built-in: GOOGLE_API_KEY (env), global URL / encodeURIComponent
  • Note: Uses Google Maps Static API
export const generateStaticMapUrl = (options: StaticMapOptions): string => {
  const {
    center,
    zoom = 13,
    size = "600x200",
    maptype = "roadmap",
    markers = [],
    scale = 1,
    format = "png",
  } = options;

  const apiKey = process.env.GOOGLE_API_KEY;

  if (!apiKey) {
    devLog("Warning: Google Maps API key not found");
    return "";
  }

  const baseUrl = "https://maps.googleapis.com/maps/api/staticmap";
  const params: string[] = [];

  if (center) {
    params.push(`center=${center.lat},${center.lng}`);
  } else if (markers.length > 0) {
    params.push(`center=${markers[0].lat},${markers[0].lng}`);
  }

  params.push(`zoom=${zoom}`);
  params.push(`size=${size}`);
  params.push(`maptype=${maptype}`);
  params.push(`scale=${scale}`);
  params.push(`format=${format}`);

  if (markers.length > 0) {
    markers.forEach((marker) => {
      const markerParams: string[] = [];
      if (marker.color) {
        markerParams.push(`color:${marker.color}`);
      }
      if (marker.label) {
        markerParams.push(`label:${marker.label}`);
      }
      markerParams.push(`${marker.lat},${marker.lng}`);
      const markerString = markerParams.join("|");
      params.push(`markers=${encodeURIComponent(markerString)}`);
    });
  }

  params.push(`key=${apiKey}`);

  const finalUrl = `${baseUrl}?${params.join("&")}`;
  devLog("Generated Static Map URL:", finalUrl);
  return finalUrl;
};
`generateStaticMapUrlWithMarker`

src/utils/helper.tsx

Convenience wrapper: centers on one point, adds a red marker, spreads extra `StaticMapOptions` except conflicting fields.

Uses

  • Built-in: Builds on generateStaticMapUrl
export const generateStaticMapUrlWithMarker = (
  name: string,
  lat: number,
  lng: number,
  options?: Omit<StaticMapOptions, "markers" | "center">
): string => {
  return generateStaticMapUrl({
    center: { lat, lng },
    markers: [{ name, lat, lng, color: "red" }],
    ...options,
  });
};

Local notifications

`initializeNotifications`

src/utils/helper.tsx

On real devices, requests notification permission; on Android creates a `default` channel using **@notifee/react-native**.

Uses

  • npm: @notifee/react-native
  • React Native: Platform
export const initializeNotifications = async () => {
  const settings = await notifee.requestPermission();
  if (settings.authorizationStatus < 1) {
    devLog("Permission for notifications not granted!");
    return;
  }

  if (Platform.OS === "android") {
    await notifee.createChannel({
      id: "default",
      name: "default",
      importance: AndroidImportance.HIGH,
    });
  }
};
`showNotification`

src/utils/helper.tsx

Schedules an immediate local notification (`trigger: null`) with title and body.

Uses

  • npm: @notifee/react-native
export const showNotification = async (title: string, body: string) => {
  await notifee.displayNotification({
    title,
    body,
    android: { channelId: "default" },
  });
};

Sponsored

Quick promo