npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@ronas-it/react-native-common-modules

v0.5.0

Published

Common modules for React Native apps at Ronas IT

Downloads

127

Readme

React Native Common Modules

Common components for Ronas IT projects.

Usage

  1. Install the package: npm i @ronas-it/react-native-common-modules
  2. Import modules to your app and use as described below

UI-components

At the moment this library contains the following components:

1. AppPressable

This component can be used in the same way as the built-in Pressable component, but it also includes opacity control.

Props:

  • pressedOpacity: Opacity value. Default is 0.4.

Example:

import { AppPressable } from '@ronas-it/react-native-common-modules';

<AppPressable style={styles.button} pressedOpacity={0.5}>
  <Text>Press Me</Text>
</AppPressable>

2. AppSafeAreaView

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';

<AppSafeAreaView edges={['top', 'bottom']} style={styles.container}>
  <Text>Content goes here</Text>
</AppSafeAreaView>

3. VirtualizedList

A component-wrapper for FlashList, that includes onScrollUp and onScrollDown props.

Props:

  • onScrollUp: Called when user scrolls up.
  • onScrollDown: Called when user scrolls down.

NOTE: onScrollUp and onScrollDown are synced with onScroll

Example:

import { VirtualizedList, VirtualizedListProps } from '@ronas-it/react-native-common-modules';

export function App(): ReactElement {
  const [direction, setDirection] = useState<'UP' | 'DOWN'>();

  const handleScrollUp = (): void => {
    setDirection('UP');
  };

  const handleScrollDown = (): void => {
    setDirection('DOWN');
  };

  const handleScrollEnd = (): void => {
    setDirection(undefined);
  };

  const renderItem: VirtualizedListProps<Book>['renderItem'] = ({ item }) => {
    return (
      <View>
        <Text>{item.isbn}</Text>
        <Text>{item.title}</Text>
      </View>
    );
  };

  const keyExtractor: VirtualizedListProps<Book>['keyExtractor'] = (item) => item.isbn;

  return (
    <View>
      <Text>Direction: {direction}</Text>
      <VirtualizedList
        estimatedItemSize={86}
        data={books}
        renderItem={renderItem}
        onScrollUp={handleScrollUp}
        onScrollDown={handleScrollDown}
        onScrollEndDrag={handleScrollEnd}
        onMomentumScrollEnd={handleScrollEnd}
        keyExtractor={keyExtractor}
      />
    </View>
  );
}

Services

1. Push notifications

PushNotificationsService

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.

usePushNotifications

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 (when subscribeDevice and unsubscribeDevice are 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';

...
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,
})

2. Storage

A library that provides two types of key-value storage API: AsyncStorage and SecuredStorage (IOS, Android).

Example

Implement storage service:

import { AsyncStorageItem, SecureStorageItem } from '@ronas-it/react-native-common-modules';

class AppStorageService {
  public token = new SecureStorageItem('token');
  public tokenExpiryDate = new SecureStorageItem('tokenExpiryDate');
  public language = new AsyncStorageItem('language');
}

export const appStorageService = new AppStorageService();

Usage:

// Get storage item
const token = await appStorageService.token.get();
// Set storage item
appStorageService.token.set('new_token');
// Delete storage item
appStorageService.token.remove();

3. 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';

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);
};

4. WebSocket

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_KEY from Pusher Channels Dashboard.
  • cluster (required) - APP_CLUSTER from 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 is true.
  • activityTimeout (optional) - time in milliseconds to ping a server after last message.
  • pongTimeout (optional) - time in milliseconds to wait a response after a pinging request.

WebSocketService public methods:

  • connect initializes and connects the Pusher client. Optional authorization token is used for secure connections.
  • subscribeToChannel subscribes to a specified channel and registers an event listener for incoming messages on that channel.
  • unsubscribeFromChannel removes an event listener and, if there is no listeners for a specified channel, unsubscribes from it.

Example:

import { WebSocketService } from '@ronas-it/react-native-common-modules';

// 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'
});

// Initialize Pusher, e.g. after an app initialization or successful authorization
await webSocketService.connect('your-auth-token');

// 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);
});

Utils

1. setupReactotron(projectName: string)

Configures and initializes Reactotron debugger with redux plugin for development purposes. Install the Reactotron app on your computer for use.

Example:

import { createStoreInitializer } from '@ronas-it/rtkq-entity-api';
import { setupReactotron } from '@ronas-it/react-native-common-modules';

const reactotron = setupReactotron('your-app');
const enhancers = reactotron ? [reactotron.createEnhancer()] : [];

const initStore = createStoreInitializer({
  rootReducer: rootReducer as unknown as Reducer<AppState>,
  middlewares,
  enhancers,
});

2. i18n

Provides functions to set language and use translations using i18n-js

Example:

root layout:

import { setLanguage } from '@ronas-it/react-native-common-modules';

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 { AppPressable, AppSafeAreaView, useTranslation } from '@ronas-it/react-native-common-modules';
import { ReactElement, useContext } from 'react';
import { View, Text, Alert } 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}>
        <AppPressable onPress={onPress} hitSlop={10}>
        <Text>{translate('BUTTON_PRESS_ME')}</Text>
        </AppPressable>
        <AppPressable onPress={handleLanguageChange} hitSlop={10}>
          <Text>{translate('BUTTON_LANGUAGE')}</Text>
        </AppPressable>
      </View>
    </AppSafeAreaView>
  );
}