• This repository has been archived on 02/Sep/2021
  • Stars
    star
    140
  • Rank 261,473 (Top 6 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created about 7 years ago
  • Updated about 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

📲 Kiwi.com mobile app written in React Native

CircleCI

This is not an actual mobile application. This repository contains only React Native (RN) parts of the project. These parts are being used in the original (private) native code. However, you can still run this application to see these parts in the pure React Native.

Table of Contents

Installation and Run

Note: we currently support only macOS. It is however possible to run the Android application under Linux by tweaking the file android/app/build.gradle like in this commit.

All necessary information are described in the official React Native documentation. Basically you need to install macOS dependencies:

brew install node watchman yarn
gem install cocoapods

Install Xcode and Android Studio. After that clone this repository and install all the necessary dependencies:

git clone [email protected]:kiwicom/mobile.git
cd mobile
yarn install
cd ios; pod install

And if you have Xcode already installed - just run yarn ios. It should open iPhone emulator with our application.

It's also possible to open other devices from command line to test tablets for example:

xcrun simctl list devices
yarn ios --simulator="iPad Pro (10.5-inch)"

Similarly for Android (yarn android) but you have to open Android emulator first.

You need to make sure that your Android emulator image supports Google Play Store. Look for this symbol:

Moreover, make sure you have a valid personal Gitlab token and set it as your environment variable:

export RNKIWIMOBILE_DEPLOYMENT_TOKEN="YOUR_TOKEN_HERE"

also you should add two files android/app/src/main/res/values/secrets.xml

<resources>
    <string name="facebook_app_id">Your Facebook App ID Here</string>
    <string name="google_maps_key">Your Google maps API Key Here</string>
</resources>

and android/playground/src/main/res/values/secrets.xml

<resources>
    <string name="facebook_app_id">Your Facebook App ID Here</string>
    <string name="google_maps_key">Your Google maps API Key Here</string>
</resources>

and you have to create the debug.keystore file:

  • cd android/app
  • keytool -genkeypair -v -keystore debug.keystore -alias androiddebugkey -keyalg RSA -keysize 2048 -validity 1000
    • You will be asked for a password, use android, you will be prompted for another password, just hit enter to use same password.

Testing

You will usually need only this during development:

yarn test
yarn test --watch

You can also run tests without all the verbose messages produced by console.(log|warn|error) as such:

yarn test --silent

It's good idea to run the whole test-set using this command:

yarn test-ci

It basically consists of code linting, type checking, complete testing and GraphQL schema validation. You can find more possibilities by running yarn run.

Building

We use Fastlane as a tool for building, codesigning and uploading to App Store, Google Play and beta testing environments. If you want to build just a JS bundle files simply run following command:

yarn build

You'll then find output files in the .build directory (for Android and iOS).

Fastlane installation

You need to do several steps in order to be able to deploy and build this application:

  • install Fastlane
  • setup environment variables: create ios/fastline/.env file with [email protected]
  • clone private react-native-app-certificates repository with all necessary keys (ask Trond Bergquist or Martin Zlamal for access)
  • copy the kiwi-rn-hotels.keystore file into android/app directory
  • create a new password in the Keychain Access app (macOS) with name android_keystore and account name rn_hotels (the password is stored in the Vault - see Environment)
  • double click the dist_cert.p12 file (password can be found in the Vault)

Fastlane run instructions

In order to build and deploy this project to the TestFlight just navigate to the ios folder and run fastlane beta. Alternatively from root directory:

( cd ios ; fastlane beta )

This new build has to be distributed to the (external) testers. To do so just go to iTunes Connect, select the right application > TestFlight > iOS builds > select build number > Groups (+) > select the group of testers > next, next, next...

On android, navigate to the android folder and run fastlane beta. Alternatively from root directory:

( cd android ; fastlane beta )

The newly build apk will be found in android/app/build/outputs/apk/app-release.apk

Environment

All sensitive environment variables are stored in .env file. You should setup these variables if you want 100% of all functions.

Information for Kiwi.com employees: all environment variables are shared using Vault. Ask your colleagues how to get them. You'll first need VPN, secret key (token) and Vault namespace.

Project structure

This project uses Yarn workspaces so the root directory is actually so called "workspace root". Workspace root is responsible for handling this repository (especially testing). You can find all sources inside of the app directory. Each directory inside app should be treated as separate NPM package and you should not reuse code from each other via import statements. If you need to use one package inside of other package (this should be very common use-case) please require it in package.json file (see app/core/package.json).

.
├── .circleci/                  - CI configuration
├── .github/                    - GitHub templates (for PR, issues, contributing)
├── android/                    - native code for Android
├── app/
│   │── core/                   - core application (not distributed)
│   ├── hotels/                 - Hotels application (distributed)
│   ├── MMB/                    - Manage My Booking application (distributed)
├── ios/                        - native code for iOS
├── packages/                   - Yarn workspaces
│   ├── accessibility/          - @kiwicom/mobile-accessibility
│   ├── config/                 - @kiwicom/mobile-config
│   ├── navigation/             - @kiwicom/mobile-navigation
│   ├── relay/                  - @kiwicom/mobile-relay
│   ├──  ...
│   └── shared/                 - @kiwicom/mobile-shared
├── scripts/                    - support scripts for the whole monorepo
└── schema.graphql              - GraphQL schema of the backend server

In case you need additional dependency for the package, you should add it to the package.json of the workspace (for example app/hotels/package.json). Root package.json is only for global dependencies related to the whole monorepo (testing tools, linters and so on).

Native modules

The native developers have prepared some native modules that we can use in our code. They are available through an npm package called @kiwicom/react-native-native-modules

Adding a new native module

  • Navigate to app/shared/package.json and bump the version to latest version.
  • Navigate to ios/Podfile and add the new package like this:
    • pod 'RNLogging', :path => '../node_modules/@kiwicom/react-native-native-modules'
  • Run yarn pod-install
  • Navigate to android/app/src/main/java/com/reactnativeapp/MainApplication.java and add the new package to the getPackages method, new RNLoggingPackage()

Logging module

It exposes two methods

  • ancillaryDisplayed
  • ancillaryPurchased

And 4 types:

const Type = {
  ANCILLARY_STEP_DETAILS,
  ANCILLARY_STEP_PAYMENT,
  ANCILLARY_STEP_RESULTS,
  ANCILLARY_STEP_SEARCH_FORM,
};

Usage:

import { Logger } from '@kiwicom/mobile-shared';

Logger.ancillaryDisplayed(
  Logger.type.ANCILLARY_STEP_DETAILS,
  Logger.Provider.ANCILLARY_PROVIDER_BOOKINGCOM
  );
Logger.ancillaryPurchased(
  Logger.type.ANCILLARY_STEP_RESULTS,
  Logger.Provider.ANCILLARY_PROVIDER_BOOKINGCOM
  );

Translation module

It exposes one method

  • translate

Usage:

import { Translate } from '@kiwicom/mobile-shared';

const someString = Translate('translation.key.to.translate');

Currency module

It exposes one method

  • formatAmount

Usage:

import { CurrencyFormatter } from '@kiwicom/mobile-shared';

const priceInEuros = 500.34;
const currencyCode = 'NOK';
const priceInNOK = CurrencyFormatter(priceInEuros, currencyCode);

Note that in development, it uses a "dummy" currency formatter, so it is possible that some decimals appear as 12.99999999999999. In production, however, the native module picks the formatter provided by the native host. (See the iOS code here for example)

Best practices

Accessing arbitrarily nested, possibly nullable properties on a JavaScript object

Sometimes (especially in GraphQL environment with nullable results) it's necessary to access deeply nested objects in order to get the value. However the path may contain nullable fields and therefore it's necessary to do checks like this:

props.user &&
props.user.friends &&
props.user.friends[0] &&
props.user.friends[0].friends

But that's not very friendly and this is why we have optional chaining . You can use it like this:

const friends = props.user?.friends?.[0]?.friends;

Do not use _.get(...) from Lodash!

Error handling

Error handling is complicated in general - especially in GraphQL environment. There are several scenarios that may occur:

  1. GraphQL API returns data field and no errors

This should be considered as a valid full response and there should not be any errors. There may be nullable fields, however.

  1. GraphQL API returns data = null and errors field

This is fatal error. Server was not able to get data and it's probably not operating correctly. It's like equivalent of total GraphQL server error (500). We should display full page error (GeneralError component).

  1. GraphQL API returns data but also errors field

Most common scenario (somewhere between). In this case we are able to fetch at least something but it failed partially so there are errors and we can expect some nullable fields. This may be just missing prices but also completely missing data. It's very different to point 2.

We are showing little warning in this case. How to handle nullable fields really depends on the situation. Sometimes it's OK to leave it empty instead of for example hotel rating (★★★), sometimes it's necessary to display error message or sad picture in case of completely missing hotels. It depends. We are always trying to render as much as possible.

Working with Playground

There is so called Playground for easier development. It's our custom WIP replacement for Storybook. The idea is to write regular component tests with ability to see them in the Playground. Therefore you need to write only the tests and you don't have to maintain additional stories. Example of simple test:

it('Works!', () => {
  PlaygroundRenderer.render(<AdaptableBadge text="default badge" />);
  PlaygroundRenderer.render(<AdaptableBadge text="badge with color" color="red" />);
});

The PlaygroundRenderer allows you to see the tests in the Playground and it automatically creates shallow snapshots of the component.

To start the Playground, you need to switch which App is imported in the index.js file at the root of this repository. Comment the line importing the file app/App and uncomment the following line, which imports packages/playground/src/Navigation. That means you should now see

//import App from './app/App';
import App from './packages/playground/src/Navigation';

in index.js. Start the app like you would normally do, i.e. by running yarn ios, and you should see the following screen:

Working with GraphQL API

This application uses GraphQL API as a data source. You can find GraphQL schema in schema.graphql file. This schema is used by Relay Compiler and Relay Babel plugin to generate and validate queries for backend server. GraphQL API itself is evolving over time so you may need to update our snapshot. You can do it easily using this command:

yarn graphql

Additional useful tools:

Working with translations

Current implementation is little bit dodgy because we have to use native code (requirement from native team). The underlying implementation is basically this:

- (NSString *)translate:(NSString *)key {
    return key;
}

So it returns key back. However, this happens only in development environment and it should return real translation in production (we cannot test or use it in development). For this reason we have custom fallback vocabulary and we touch this repository if underlying code returns unchanged key.

You always have to use the following component:

<Translation id="Core.Authentication.Login" />

These components should be enforced everywhere we need to use translations (button titles, children of the Text component). However, there are situations where we need to use the translation (because of the enforcement) but there is nothing to translate. In this case just use the passThrough property instead of id:

<Translation passThrough="★★★★★" />

It comply with the translations interface but it returns the property value directly back without even trying to translate it.

There are also situations where we need to return multiple translations but this is little bit more tricky because it's not possible to nest (or concat) multiple translations. You can use TranslationFragment component for this:

<TranslationFragment>
  <Translation passThrough="★★★★★" />
  <Translation id="SingleHotel.Rating.Stars" />
</TranslationFragment>

This fragment also comply with Flow types and it has similar behaviour with React.Fragment from React 16.2+...

PhraseApp

We use PhraseApp for managing translations. All keys and relevant screenshots are deployed automatically (the deployment script must be executed manually though):

yarn deploy-translations

PHRASE_APP_PROJECT_ID and PHRASE_APP_TOKEN should be added to ~/.bash_profile

(we need to improve it - this is just PoC)

How to create screenshots? Open iOS simulator and press Ctrl+S (save). It will save the screenshot of current page so you can work with it later. It's usually good idea to mark where is the translated string on the screen. You should convert your new screenshots to JPG to make them smaller before commiting them to the Git (macOS):

mkdir jpegs
sips --resampleHeightWidthMax 640 --setProperty format jpeg ./*.png --out jpegs

Upgrading dependencies

Check all dependencies with outdated Yarn command. This will tell you how behind we actually are. Try not to upgrade everything at once since there may be breaking changes (even though it's non-breaking upgrade). The second command will help you significantly with upgrading these dependencies across our workspace repository:

yarn outdated
yarn upgrade-interactive --latest

E2e testing

We use detox for e2e testing. Note: One of our tests imageGallery.spec.js might fail depending on device. See comment in that file.

Android

Detox is currently stable for android on RN-versions <=0.56. It runs on android, but there might be some quirks. To run, first create an emulator in Android Studio with the name e2e_emulator. Then you can run yarn e2e-aphone. Because we have an absolutely positioned close button on the bottom of the detail view, android will click this button when trying to scroll. You might want to comment line 34 in BookingSummary.js

ios

ios should work just fine. Just do e2e-iphone or e2e-ipad to run the tests

Upgrade react-native

Since we upload our dependencies to maven, and these depends on the current version of react-native, there are no maven packages whenever we upgrade react-native version. In order to test it locally, you need to replace all occurrences of packageFromUnpkg(it, "react-native", reactNativeVersion) with packageFromNodeModules(it, "react-native") and you need to comment include ':rnkiwimobile' and include ':playground' in settings.gradle.

Remember to undo this changes before commiting. This is just to be able to test after upgrade

More Repositories

1

orbit

React components of open-source Orbit design system by Kiwi.com
TypeScript
1,388
star
2

pytest-recording

A pytest plugin that allows recording network interactions via VCR.py
Python
418
star
3

navigation-compose-typed

Type-safe arguments for Jetpack Navigation Compose using Kotlinx.Serialization
Kotlin
217
star
4

margarita

[not actively maintained] Mobile and Web application implementing Kiwi.com Tequila API
JavaScript
208
star
5

orbit-compose

Android Jetpack Compose components of open-source Orbit design system by Kiwi.com.
Kotlin
144
star
6

orbit-swiftui

Kiwi.com Orbit design system library
Swift
131
star
7

structlog-sentry

Sentry integration for structlog
Python
99
star
8

crane

⬆ A GitLab CI ready image to upgrade services in Rancher
Python
96
star
9

the-zoo

🐒 A service registry for humans
Python
93
star
10

gitlab-unfurly

Serverless Slack bot for unfurling GitLab URLs.
Python
39
star
11

refined-gitlab

🛠 WIP 🛠 Chrome extension that enhances GitLab
JavaScript
32
star
12

orbit-design-tokens-archived

Design tokens store visual design attributes. They help us make our UI more consistent and consistent and support custom theming.
HTML
28
star
13

konfetti

Python configuration management system with an intuitive API
Python
27
star
14

dockerfiles

🐳 Collection of dockerfiles and automated docker hub builds
Dockerfile
27
star
15

monorepo-utils

🔧 Helpful functions to manage monorepos (using Yarn Workspaces)
JavaScript
26
star
16

react-native-reverse-geocode

Kotlin
25
star
17

contessa

Easy way to define, execute and store quality rules for your data.
Python
18
star
18

pg2avro

Utility generating avro files from postgres
Python
17
star
19

universal-components

Component Library for React Native, Expo and React applications
JavaScript
16
star
20

travelling-salesman

Rules for Kiwi.com travelling salesman competition
Python
15
star
21

python-weekend-entry-task

Entry task assignment for python weekend | https://pythonweekend.cz/
15
star
22

flask-ninja

Python
14
star
23

nitrolib

This is a mirror of https://gitlab.skypicker.com/frontend/nitrolib where y'all have no access 😽
JavaScript
13
star
24

fetch

🍒 Production ready fetch function with advanced capabilities like retries with delay and request cancellation after timeout
JavaScript
13
star
25

monorepo-shipit

Monorepo 👉 many repos Git exporter
JavaScript
12
star
26

smart-faq

Smart FAQ ⚠️INACTIVE → moved to internal GitLab ⚠️
JavaScript
11
star
27

easycql

Generate code for faster unmarshalling with gocql
Go
10
star
28

request-session

Python HTTP requests on steroids 💪
Python
10
star
29

relay

🚄 Opinionated Relay wrapper used at Kiwi.com
JavaScript
9
star
30

phoenix

Outage announcement integration with slack
Python
9
star
31

terraform-aws-nfs

🔧 NFS on AWS using ZFS, using ephemeral NVMe disks for L2ARC and RAID1 EBS storage
Shell
9
star
32

xssable

A vulnerable blogging platform used to demonstrate XSS vulnerabilities.
HTML
9
star
33

terraform-provider-montecarlo

This open-source Terraform provider enables users to seamlessly integrate the Monte Carlo data reliabillity platform into their infrastructure as a code (IaC) workflows.
Go
9
star
34

terraform-google-cloudfunctions

Terraform module for Google Cloud Functions
HCL
8
star
35

weekendfe

JS Weekend frontend site exercise
JavaScript
7
star
36

k8s-vault-operator

Go
7
star
37

kiwicom-python

🛠 WIP Internship project. Kiwi.com API wrapper
Python
7
star
38

starpicker

A tool that periodically checks sites for feedback about an entity and posts the findings to Slack.
Python
6
star
39

requests-iap

Python requests AuthClass authenticating HTTP requests to OIDC-authenticated resources (Cloud Identity-Aware Proxy)
Python
6
star
40

docsify-lunr-search

Search plugin for docsify.js which uses https://lunrjs.com/
JavaScript
5
star
41

stranger-strings

Web app for localisation analysing
Vue
5
star
42

catboost-cxx

OSS implementation of Yandex CatBoost model applier
C++
5
star
43

httpenv

📞 A service serving environment variables over HTTP
Python
5
star
44

Paper-Plane

TypeScript
5
star
45

eslint-plugin-relay-imports

JavaScript
4
star
46

eslint-plugin-kiwicom

JavaScript
4
star
47

wkshp-bucket-list-travel-app

Workshop in Budapest on 23/05/2019
JavaScript
4
star
48

graphql-bc-checker

🚦 Detect breaking changes in GraphQL schema with ability to log these changes.
JavaScript
4
star
49

pytest-catch-server

Pytest plugin with server fixture for catching HTTP requests.
Python
3
star
50

iwant-bot

🛠 WIP Internship project
Python
3
star
51

glenv

With direnv it will automatically export env. variables directly from GitLab
Go
3
star
52

kiwi-cache

Python
3
star
53

terraform-aws-rds-alarms

HCL
3
star
54

jsweekend

Project for attendees of https://jsweekend.cz
JavaScript
3
star
55

terraform-aws-rds-core

HCL
3
star
56

graphql-resolve-wrapper

Utility which enables to wrap GraphQL resolvers with your custom functions
JavaScript
3
star
57

fakesimdjson

Fallback to build simdjson-go tape using only encoding/json
Go
2
star
58

kiwi-json

Python
2
star
59

kiwi-structlog-config

Structlog configuration
Python
2
star
60

kiwi-platform-py

Company standards as code for Kiwi.com. Intended for use in Kiwi.com's internal Python projects.
Python
2
star
61

faqstorer

Python
2
star
62

terraform-vault-project

Vault resources for Gitlab project.
HCL
2
star
63

email-on-acid-sdk

Php sdk for email testing service Email on Acid
PHP
2
star
64

graphql-optics

📡 Monitoring tool for GraphQL servers and proxies
JavaScript
2
star
65

mlweekend

materials and entry task for intensive weekend course of machine learning
2
star
66

orbit-landing

JavaScript
2
star
67

orbit-playroom

Playroom allows you to design in the browser with orbit-components and support of JSX. You can easily share your code with anyone through a link, or open an example from orbit.kiwi.
JavaScript
2
star
68

gcp-api-enabler

Google Cloud Function that enables stated API's for newly created projects.
Python
2
star
69

vault2env-js

🔐 Utility to help us fetching ENV variables from Vault automatically
JavaScript
2
star
70

stopovers

Landing pages for stopover cities
JavaScript
2
star
71

terraform-kubernetes-elasticsearch

Elasticsearch module for Kubernetes based on elastic Helm charts
Python
2
star
72

eslint-config-kiwicom

💅 Eslint configuration for JS used at Kiwi.com.
JavaScript
2
star
73

terraform-kubernetes-namespace

HCL
2
star
74

summer-camp-live-map

JavaScript
1
star
75

graphql-global-id

Utility to manage ID fields in GraphQL correctly.
JavaScript
1
star
76

eslint-plugin-relay-fragments

ESLint plugin to keep your relay fragment components simple.
JavaScript
1
star
77

eslint-plugin-graphql-fragments

ESLint plugin to keep your GraphQL fragment components simple.
JavaScript
1
star
78

terraform-google-firestore

terraform module for the firestore projects
HCL
1
star
79

python-weekend-xmas-task

Entry task assignment for python weekend in Prague, 10 – 12 December 2021 | https://pythonweekend.cz/
1
star
80

orbit-swiftui-testing

Tests for the orbit-swiftui repository
Swift
1
star
81

travel-hack

A starter for hacking with @kiwicom/orbit-components and @kiwicom/relay
JavaScript
1
star
82

eslint-config-kiwicom-cypress

JavaScript
1
star
83

calendar-ux-test

New Calendar prototype for UX testing
JavaScript
1
star
84

hypothesis-jsonschema-unfit

Generate JSON data that does NOT match the given JSON schema
Python
1
star
85

terraform-google-cloudsql-core-postgresql

HCL
1
star
86

js-iam-middleware

Middleware to validate IAP JWT.
TypeScript
1
star
87

terraform-datadog-aws-lb-alarms

HCL
1
star
88

eslint-config-nitro

(DEPRECATED) ESlint config 🔥
JavaScript
1
star
89

terraform-gitlab-project-cluster

HCL
1
star
90

terraform-provider-scylla

Go
1
star
91

babel-preset-kiwicom

💈 Babel preset for JS used at Kiwi.com
JavaScript
1
star
92

terraform-aws-ftp-transfer-user

HCL
1
star
93

stranger-strings-sample-data

Sample data for https://github.com/kiwicom/stranger-strings
1
star
94

sourcelift

🏋 The source code powering kiwi.com/sourcelift
JavaScript
1
star
95

loopbind

🛠️ CLI tool to easily bind localhost network interface with additional IP and ensure matching record in /etc/hosts.
PHP
1
star
96

eslint-plugin-orbit-components

Linting rules for the best usage of @kiwicom/orbit-components
JavaScript
1
star