Common components for Ronas IT projects.
- Install the package:
npm i @ronas-it/react-native-common-modules - Import modules to your app and use as described below
At the moment this library contains the following components:
NOTE: Required dependencies:
react-native-safe-area-context
A component for granular control of safe area edges on each screen. The difference from SafeAreaView in react-native-safe-area-context is that the container adds padding to the elements inside it, rather than to the entire screen, making it more flexible for use.
Props:
edges: An array indicating which edges of the screen to respect. Possible values are 'top', 'right', 'bottom', 'left'. Defaults to all edges.style: Custom styles to apply to the view. Note that padding values will be adjusted to respect safe area insets.
Example:
import { AppSafeAreaView } from '@ronas-it/react-native-common-modules/safe-area-view';
<AppSafeAreaView edges={['top', 'bottom']} style={styles.container}>
<Text>Content goes here</Text>
</AppSafeAreaView>;NOTE: Required dependencies:
expo-notifications,expo-router,expo-constants,expo-device,expo-modules-core
Service for integrating Expo push notifications into apps. Requires setup and backend implementation for sending notifications.
PushNotificationsService public methods:
-
obtainPushNotificationsToken- get an Expo token that can be used to send a push notification to the device using Expo's push notifications service. -
pushToken- getter for retrieving the token if it was already obtained.
Hook, that automatically subscribes the device to receive push notifications when a user becomes authenticated, and unsubscribes when a user becomes non-authenticated. It supports custom subscription and unsubscription logic through provided functions or API configuration. Listens for responses to notifications and executes a callback, if provided, when a notification is interacted with.
Used in the root App component.
usePushNotifications hook arguments:
isAuthenticated(required) - flag, that indicates whether the user is authenticated or not.onNotificationResponse(optional) - callback when a notification is interacted with.subscribeDevice(optional) - function for subscribing the device.unsubscribeDevice(optional) - function for unsubscribing the device.apiConfig(optional) - API configuration for subscribing and unsubscribing the device (whensubscribeDeviceandunsubscribeDeviceare not provided).apiErrorHandler(optional) - API error handler for subscribe/unsubscribe functions.getTokenErrorHandler(optional) - handler for error that occur when attempting to obtain a push notifications token.
Example:
// Somewhere in a root component of your app:
import { usePushNotifications } from '@ronas-it/react-native-common-modules/push-notifications';
...
const authToken = useSelector(authSelectors.token);
...
usePushNotifications({
apiConfig: {
subscribeDeviceUrl: 'https://your-api.com/api/v1/push-notifications/subscribe',
unsubscribeDeviceUrl: 'https://your-api.com/api/v1/push-notifications/unsubscribe',
accessToken: authToken,
},
isAuthenticated: !!authToken,
})NOTE: By default, when using the
apiConfigoption, the hook sends the Expo push token to your server in the following format:JSON.stringify({ expo_token })
NOTE: Required dependencies:
expo-image-picker
ImagePickerService gives the application access to the camera and image gallery.
Public methods:
getImage- initializes the application (camera or gallery) and returns a result containing an image.launchGallery- launches the gallery application and returns a result containing the selected images.launchCamera- launches the camera application and returns the taken photo.requestGalleryAccess- requests the application access to the gallery.requestCameraAccess- requests the application access to the camera.getFormData- creates a FormData object with image.
Example
Pick image and send request:
import { imagePickerService, ImagePickerSource } from '@ronas-it/react-native-common-modules/image-picker';
const handlePickImage = async (source: ImagePickerSource) => {
const image = await imagePickerService.getImage(source);
const asset = image?.assets?.[0];
if (!asset) {
return;
}
const data = imagePickerService.getFormData(asset.uri);
// API call
createMedia(data);
};NOTE: Required dependencies:
@pusher/pusher-websocket-react-native,pusher-js
WebSocketService manages WebSocket connections using Pusher and can work in both web and mobile applications.
Doesn't support Expo Go.
It's necessary to install @pusher/pusher-websocket-react-native for a mobile app and pusher-js for a web app.
Options for WebSocketService constructor:
apiKey(required) -APP_KEYfrom Pusher Channels Dashboard.cluster(required) -APP_CLUSTERfrom Pusher Channels Dashboard.authURL(optional) - a URL that returns the authentication signature needed for private channels.useTLS(optional) - a flag that indicates whether TLS encrypted transport should be used. Default value istrue.activityTimeout(optional) - Time in ms before sending a ping when no messages have been sent. Default value is30000.pongTimeout(optional) - Time in ms to wait for the pong response.authorizerTimeoutInSeconds(optional) - Time in seconds to wait for the authorizer response. Default value is60.
WebSocketService public methods:
init(tokenGetter?, handlers?)- Initializes the Pusher client. Should be called only once before callingconnect. If an authorization token is provided, it will be used for secure connections.connect()- Connects the client to the Pusher server. Should be called after initializing the client usinginit.disconnect()- Disconnects the client from the Pusher server. Should be called when the client is no longer needed.subscribeToChannelsubscribes to a specified channel and registers an event listener for incoming messages on that channel.unsubscribeFromChannelremoves an event listener and, if there are no listeners for a specified channel, unsubscribes from it.
Example:
import { WebSocketService } from '@ronas-it/react-native-common-modules/websocket';
// Create a service instance
type ChannelName = `private-conversations.${number}` | `private-users.${number}`;
const webSocketService = new WebSocketService<ChannelName>({
apiKey: '1234567890qwertyuiop',
cluster: 'eu',
authURL: 'https://your-api.com/api/v1/broadcasting/auth',
});
// Callback to get your app auth token for private channels
const tokenGetter = () => authSelectors.token(getState());
// Initialize Pusher, e.g. after an app initialization or successful authorization
webSocketService.init(
tokenGetter, // Always get actual token
{
// Optional handlers
onConnectionStateChange: (currentState) => {
// Do something with the connection state
},
},
);
// Connect to Pusher instance
webSocketService.connect();
// Subscribe to a channel when it's necessary
webSocketService.subscribeToChannel('private-conversations.123', (event) => {
console.log('Received event:', event);
});
// Unsubscribe from a channel, e.g. before an app closing or logging out
webSocketService.unsubscribeFromChannel('private-conversations.123', (event) => {
console.log('Received event:', event);
});Hook that automatically manages WebSocket connection lifecycle on Android devices. It reconnects the service when the app comes to the foreground and disconnects when the app goes to the background.
NOTE: Android can silently lose WebSocket connection when the app is put to background. This hook addresses this issue. See GitHub issue #135 for more details.
Example:
import { usePusherReactNative } from '@ronas-it/react-native-common-modules/websocket';
import { webSocketService } from '@your-app/mobile/data-access/websocket';
// Use the hook in your root component
usePusherReactNative(webSocketService);NOTE: Required dependencies:
@reduxjs/toolkit,reactotron-react-native,reactotron-react-js,reactotron-redux
Configures and initializes Reactotron debugger with redux plugin for development purposes. Install the Reactotron app on your computer for use.
Example:
import { setupReactotron } from '@ronas-it/react-native-common-modules/reactotron';
import { createStoreInitializer } from '@ronas-it/rtkq-entity-api';
import Reactotron from 'reactotron-react-native';
import mmkvPlugin from 'reactotron-react-native-mmkv';
import type { ReactotronReactNative } from 'reactotron-react-native';
import { storage } from './mmkv/storage/instance/location'; // <--- update this to your mmkv instance.
const reactotron = setupReactotron('your-app', [
// You can add an array of Reactotron plugins here
(reactotron) => mmkvPlugin<ReactotronReactNative>({ storage }),
]);
const enhancers = reactotron ? [reactotron.createEnhancer()] : [];
const initStore = createStoreInitializer({
rootReducer: rootReducer as unknown as Reducer<AppState>,
middlewares,
enhancers,
});NOTE: Required dependencies:
i18n-js,expo-localization
Provides functions to set language and use translations using i18n-js
Example:
root layout:
import { setLanguage } from '@ronas-it/react-native-common-modules/i18n';
const translations = {
en: {
...require('i18n/example/en.json')
},
fr: {
...require('i18n/example/fr.json')
}
};
const useLanguage = setLanguage(translations, 'en');
interface LanguageContextProps {
language: string;
onLanguageChange?: (language: keyof typeof translations) => void;
}
export const LanguageContext = createContext<LanguageContextProps>({ language: 'en' });
function App(): ReactElement {
return (
<Stack>
<Stack.Screen name='index' />
</Stack>
);
}
export default function RootLayout(): ReactElement | null {
const [language, setLanguage] = useState<keyof typeof translations>('en');
useLanguage(language);
return (
<LanguageContext.Provider value={{ language, onLanguageChange: setLanguage }}>
<App />
</LanguageContext.Provider>
);
}screen:
import { AppSafeAreaView } from '@ronas-it/react-native-common-modules/safe-area-view';
import { useTranslation } from '@ronas-it/react-native-common-modules/i18n';
import { ReactElement, useContext } from 'react';
import { View, Text, Alert, Pressable } from 'react-native';
import { LanguageContext } from './_layout';
export default function RootScreen(): ReactElement {
const translate = useTranslation('EXAMPLE');
const { language, onLanguageChange } = useContext(LanguageContext);
const onPress = () => Alert.alert(translate('TEXT_PRESSED'));
const handleLanguageChange = (): void => {
onLanguageChange?.(language === 'en' ? 'fr' : 'en');
};
return (
<AppSafeAreaView edges={['bottom']} style={styles.safeAreaContainer}>
<View style={styles.container}>
<Pressable onPress={onPress} hitSlop={10}>
<Text>{translate('BUTTON_PRESS_ME')}</Text>
</Pressable>
<Pressable onPress={handleLanguageChange} hitSlop={10}>
<Text>{translate('BUTTON_LANGUAGE')}</Text>
</Pressable>
</View>
</AppSafeAreaView>
);
}NOTE: Required dependencies:
@clerk/clerk-expo,expo-web-browser,expo-auth-session
Hooks and helpers to create user authentication with Clerk Expo SDK.
Hook, that provides access to essential Clerk methods and objects.
Returned Object:
signUp- provides access to SignUp object.signIn- provides access to SignIn object.setActive- A function that sets the active session.signOut- A function that signs out the current user.
Hook, that provides functionality to handle user sign-up and sign-in processes using an identifier such as an email, phone number, or username. It supports both OTP (One Time Password) and password-based authentication methods.
Parameters:
method: Specifies the type of identifier used for authentication (e.g., 'emailAddress', 'phoneNumber', 'username').verifyBy: Specifies the verification method ('otp' for one-time passwords or 'password').
Returned Object:
startSignUp: Initiates a new user registration using the specified identifier and verification method.startSignIn: Initiates authentication of an existing user using the specified identifier and verification method.startAuthorization: Determines whether to initiate a sign-up or sign-in based on whether the user has been registered previously.verifyCode: Verifies an OTP code if the verification method is 'otp'.isLoading: Indicates whether an authentication request is in progress.isVerifying: Indicates whether an OTP verification is in progress.
Example:
import React, { useState } from 'react';
import { View, TextInput, Button } from 'react-native';
import { useAuthWithIdentifier } from '@ronas-it/react-native-common-modules/clerk';
export const AuthWithIdentifierComponent = () => {
const [identifier, setIdentifier] = useState('');
const [verificationCode, setVerificationCode] = useState('');
const { startSignUp, verifyCode, isLoading, isVerifying } = useAuthWithIdentifier('emailAddress', 'otp');
const handleSignUp = async () => {
await startSignUp({ identifier });
};
const handleVerifyCode = async () => {
const result = await verifyCode({ code: verificationCode });
console.log(result.sessionToken)
};
return (
<View>
<TextInput
placeholder="Enter your email"
value={identifier}
onChangeText={setIdentifier}
keyboardType="email-address"
/>
<TextInput
placeholder="Enter verification code"
value={verificationCode}
onChangeText={setVerificationCode}
/>
<Button onPress={handleSignUp} title="Sign Up" disabled={isLoading || isVerifying} />
<Button onPress={handleVerifyCode} title="Verify code" disabled={isLoading || isVerifying} />
</View>
);
};Hook provides functionality to handle SSO authentication flows.
Returned Object:
startSSOFlow: A function to initiate an SSO flow. It takes a strategy, redirectUrl, and optional tokenTemplate as parameters, starting the SSO authentication and returning session information or errors upon completion.isLoading: A boolean indicating whether an SSO process is currently ongoing.
This hook is a utility that facilitates user authentication using a ticket-based strategy (ticket is a token generated from the Backend API).
Returned Object:
startAuthorization: A function to initiate authentication with a ticket. It accepts an object with ticket and optional tokenTemplate parameters to kick off the authorization process and returns the session details.isLoading: A boolean indicating whether the ticket-based authorization process is ongoing.
This hook is a utility for getting session tokens.
Returned Object:
getSessionToken: A function to retrieve the session token. It takes an optional tokenTemplate parameter to specify a template for the token.
Hook provides functionality to add new email or phone number identifiers to a user's account and verify them using verification codes.
Returned Object:
createIdentifier: A function to add a new email or phone number identifier to the user's account and prepare it for verification.verifyCode: A function to verify a code sent to the identifier, completing the verification process.isCreating: A boolean indicating whether an identifier is currently being added.isVerifying: A boolean indicating whether a verification code is currently being processed.
Hook provides functionality for managing OTP (One Time Password) verification in user authentication workflows, supporting both sign-up and sign-in processes.
Returned Object:
sendOtpCode: Sends an OTP code to the user's identifier (email or phone number) based on the specified strategy.verifyCode: Verifies the OTP code provided by the user, completing the authentication process.isVerifying: A boolean indicating whether a verification attempt is currently in progress.
Hook provides methods to handle password reset functionality through email or phone-based OTP.
Returned Object:
startResetPassword: A function to initiate the password reset process by sending a verification code to the user's email or phone number.resetPassword: A function to reset the user's password by verifying the code and setting a new password.isCodeSending: A boolean indicating if the verification code is being sent.isResetting: A boolean indicating if the password is being reset.