/qoupe-react-native-template

Qoupe React Native Template

Primary LanguageTypeScript

react-native-template

Project is generated by

//TODO:

Please read High-level Architecture to see the context of a React Native App in the RTP landscape.

Overview

This repository is an example of React Native Application. Use this template when you start developing new app.

This repository is owned by RTP Enablement team

Fill in here your application purpose, and it's main functionalities. Also insert the link to your architecture from confluence.

Prerequisites

Please make sure that you have installed

How to start

  1. Follow React Native guidelines to configure your development environment for both iOS and Androd;
  2. Install dependencies with yarn;
  3. Launch metro server with yarn start;
  4. Choose platform you want to work with by running:
    1. yarn ios;
    2. yarn android (Android requires to launch an emulator or connected device beforehand);

Structure

react-native-template
├──android - android project;
├──ios - ios project;
├──e2e - E2E tests;
└──src - source code;
    ├──components - common components for all screens;
    ├──enums - common enums for all screens and components;
    ├──hooks - common hooks for all screens and components;
    ├──interfaces - common interfaces for all screens and components;
    ├──localization - common interfaces for all screens and components;
    │  ├──context - context that contains translations for the current language;
    │  └──locales - translations for different languages, grouped by namespace;
    ├──screens - all application screens;
    ├──store - redux store for the app;
    ├──test - setting up common mocks for tests;
    ├──app.tsx - entry point;
    └──routes.tsx - all navigation routes for the app;

Guidelines

Component Structure

component
├──component.tsx - component code;
├──component.styles.ts - component style sheet;
├──component.hooks.ts - component hooks;
├──component.hooks.spec.ts - hooks test;
├──component.spec.ts - component test (with snapshot and functional test);
└──component.story.ts - component story to showcase its features

Handling components growth

If a component gets big and complex consider:

  1. Decompose the component into smaller components
    1. If some parts are reusable across other components, extract them to the root components folder;
    2. If these parts are specific to this component, consider creating components folder inside and place those components there. They should also follow the component structure rules;
  2. Create dedicated hook file, to simplify render function. By moving state and functions that operate with state or redux, you can see how component file becomes more about its structure;
  3. Do we have a group of components that serve the same purpose, consider grouping them in a dedicated folder (e.g.: components/cards for all card components)

Testing

When testing components:

  1. Mock dependencies (don't retest other components/hooks);
  2. Make snapshots for props variations;
  3. Test firing events at your component (e.g.: press, type, scroll);

When testing hooks include testing not only functions and state, but also effects.

you can check test examples in src/screens/todo

Localization

You can store all text labels in src/localization/locales folder. common folder is mandatory to have. However, you can create more and register those files in src/localization/context/localization-data. This will help to reduce file size and manage translations more easily.

To use translations in a component or a hook call useLocalization.

Example:

const MyComponent = () => {
  const { t } = useLocalize();

  return <Text>{t('translation-key-from-json')}</Text>;
};

By default t('key') picks up translation from the common folder. If you want to use another folder, then prefix key with folder-name:. That allows you to use translations from different folders.

Example:

const MyComponent = () => {
  const { t } = useLocalize();

  return (
    <>
      <Text>{t('common-translation-key')}</Text>
      <Text>{t('folder-name:folder-specific-translation-key')}</Text>
    </>
  );
};

If you need to insert text inside your translation, use interpolation by wrapping text with {{parameter}}

Example translation file

{
  "key1": "Hello",
  "key2": "Hello {{name}}"
}

Code example

const MyComponent = () => {
  const { t } = useLocalize();

  return (
    <>
      <Text>{t('key1')}</Text>
      <Text>{t('key2', { params: { name: 'My Name' } })}</Text>
    </>
  );
};

If you need to insert JSX inside your translation, use interpolation by wrapping text with <parameter>Some text</parameter>

Example translation file

{
  "key1": "Hello",
  "key2": "Hello <name>My name</name>"
}

Code example

const MyComponent = () => {
  const { tJSX } = useLocalize();

  return (
    <>
      <Text>{t('key1')}</Text>
      <Text>
        {tJSX('key2', {
          components: { name: ({ children }) => <Text>{children}</Text> },
        })}
      </Text>
    </>
  );
};

ENV variables

Create a .env file in the root and fill like this:

MY_ENV=my-env

Then you need to declare your variables in the file src/types/env.d.ts:

declare module '@env' {
  //...
  export const MY_ENV: string;
}

Usage

Code example:

import { MY_ENV } from '@env';

console.log(MY_ENV); // my-env

Changing variables

Metro caches env variables. If you want to change a variable you will need to run the following command after changes:

yarn start --reset-cache

Then you can run yarn ios or yarn android with updated env variables.

Firebase Analytics and Crashlytics

Setup Android

Download google-services.json and replace it with the file with the same name in the folder android/app.

More info here.

Setup iOS

Download GoogleService-Info.plist. Using Xcode, open the projects /ios/{projectName}.xcodeproj file (or /ios/{projectName}.xcworkspace if using Pods).

Right click on the project name and "Add files" to the project.

Select the downloaded GoogleService-Info.plist file from your computer, and ensure the "Copy items if needed" checkbox is enabled.

More info here.

DebugView

To enable DebugView on Android you should launch an Android emulator and run the command adb shell setprop debug.firebase.analytics.app package_name. To disable you should run adb shell setprop debug.firebase.analytics.app .none..

To enable DebugView on iOS you should select the argument -FIRDebugEnabled and discard -FIRDebugDisabled in the Xcode (Choose the project -> Product -> Scheme -> Edit scheme -> Arguments). Then you need to build iOS project by yarn ios.

Troubleshooting

If you don't see your iOS device in DebugView you may need to start the project through yarn start --resetCache and build it in Xcode.

Usage

To send some analytics information to the Firebase Console you can use the method logEvent with an event name and additional information:

const TodosListItem: FC<TodosListItemProps> = ({ todo, onSelect }) => {
  const handlePress = async () => {
    await analytics().logEvent('todo_click', { id: todo.id });
    onSelect(todo.id);
  };

  return (
    <TouchableOpacity style={styles.root} onPress={handlePress}>
      <Text style={todo.isDone && styles.completedTodo}>{todo.text}</Text>
    </TouchableOpacity>
  );
};

To send crash reports to the Firebase Console you can use the method recordError:

const CrashAppButton = () => {
  const handleCrashApp = () => {
    crashlytics().recordError(new Error('Crash by click on the crush button'));
  };

  return (
    <View style={styles.container}>
      <Button title="Crash App" onPress={handleCrashApp} />
    </View>
  );
};

More methods of Firebase Analytics and Crashlytics you can find here.

E2E testing

We use Detox to run E2E tests.

Firstly, you should setup Environments:

Android

You need to create an emulator with the following parameters:

  • Device: Pixel 5
  • System image: Pie (Android 9.0)
  • AVD Name: Pixel 5 E2E

Then check the Kotlin version: Open Android Studio > More Actions > SDK Manager > in the left sidebar click on 'Kotlin' > click 'install' if this button exists.

iOS

You should have iPhone 13 from the xCode by default.

Running tests

Before running your tests you must compile the application. Run yarn e2e:ios:build for iOS and e2e:android:build for Android.

Then you can execute yarn e2e:ios:start to run tests on iOS and yarn e2e:android:start on Android.