(~ 2 min)
2 |
3 | ## Owner: Arthur Levoyer
4 |
5 | ## Prerequisites
6 |
7 | - Have git-cli installed
8 |
9 | ## Context
10 |
11 | Let's say, you are currently working on your own `my-feature` branch and someone from your team is merging new commits into the `master` branch which you would like to use. You have two different possibilities to incorporate them to your `my-feature` branch.
12 |
13 | 
14 |
15 | ## Steps
16 | 1. First approach: Merge a branch
17 |
18 | Merge the `master` branch into the `feature` branch by entering following:
19 | - `git checkout my-feature`
20 | - `git merge master`
21 | It gives you a new “merge commit” in the feature branch that ties together the histories of both branches.
22 |
23 | It's nice because it is a non-destructive operation but if your `master` branch is very active, you might quickly have a new commits including a lot of changes and this will pollute your history quite a lot.
24 |
25 | 
26 |
27 |
28 | 2. Second approach: Rebase a branch
29 | - `git checkout my-feature`
30 | - `git rebase master`
31 |
32 | The difference with the merge solution above, it that it will create new commits into your `my-feature` for each commits in `master` and give you a much cleaner project history.
33 |
34 | On the other hand, a very unwanted situation might occur if you do not follow the [Golden Rules of Rebasing](https://www.atlassian.com/git/tutorials/merging-vs-rebasing#the-golden-rule-of-rebasing)
35 |
36 | 
37 |
38 | Source: [atlassian.com](https://www.atlassian.com/git/tutorials/merging-vs-rebasing)
39 |
40 |
--------------------------------------------------------------------------------
/intro.tpl:
--------------------------------------------------------------------------------
1 | ---
2 | post_title: '%TITLE%'
3 | layout: layout
4 | published: true
5 | categories:
6 | - '%CATEGORY%'
7 | ---
8 |
--------------------------------------------------------------------------------
/javascript/promisify-a-callback.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Promisify a callback _(~5 min)_
2 |
3 | ## Owner: Arthur Levoyer
4 |
5 | ## Why
6 |
7 | When an asynchronous action is performed, if you want to wait for its success or failure and avoid several chains of callbacks. See [callback hell](http://callbackhell.com/).
8 |
9 | ## Steps
10 |
11 | - I identified the asynchronous call I want to wait for
12 | - I included the function into a callback, the executor of the Promise will handle an asynchronous work (in the examples below the describeTable). Once the work is done, if it went well, we are calling the resolve function, if not we are calling the reject one.
13 |
14 | ## Examples
15 |
16 | ### Example 1: Bad example
17 |
18 | ```jsx
19 | export const waitForCallbackToBeSolved = () => {
20 | asynchronousAction(params, (error, data) => {
21 | // We create a Promise with the function using a callback in second arguments
22 | if (error) throw error;
23 | else console.log(data);
24 | });
25 | };
26 |
27 | export const getResponse = async () => {
28 | try {
29 | await waitForCallbackToBeSolved();
30 | doStuff();
31 | } catch (error) {
32 | log(error);
33 | throw error;
34 | }
35 | };
36 | ```
37 |
38 | -> [ ] Neither `Promise` nor `promisify` had been used hence we are sending a 200 status in all cases
39 |
40 | ### Example 2: Good example
41 |
42 | ```jsx
43 | export const waitForCallbackToBeSolved = () => {
44 | return new Promise((resolve, reject) => {
45 | // We create a Promise with the function using a callback in second argument
46 | asynchronousAction(params, (error, data) => {
47 | if (error) {
48 | return reject(error);
49 | }
50 | resolve(data);
51 | });
52 | });
53 | };
54 |
55 | export const getResponse = async () => {
56 | try {
57 | await waitForCallbackToBeSolved();
58 | doStuff();
59 | } catch (error) {
60 | log(error);
61 | throw error;
62 | }
63 | };
64 | ```
65 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {}
2 |
--------------------------------------------------------------------------------
/ops/docker/deploy-with-https.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Setup HTTPS on your docker environment (~15 min)
2 |
3 | ## Owner: [Sammy Teillet](https://github.com/samox)
4 |
5 | ## Control points
6 |
7 | {% hint style='success' %}
8 |
9 | If, _as an expert of docker_, you want to adapt the standard to the context of your project, you have to check that:
10 |
11 | {% endhint %}
12 |
13 | * [ ] server listen port `80` and `443`
14 | * [ ] server redirect port `80` to `443` with `301: Moved Permanently`
15 | * [ ] proxy should renew certificates automatically before they expire (letsencrypt certificates have 90 days of validity)
16 | * [ ] you should get at least `A` when checking https://www.ssllabs.com/ssltest/
17 | * [ ] you should check in the report of https://www.ssllabs.com/ssltest/ that the server devices range cover your definition of DONE: eg, if you need to support old IE or old android, you have to lower the security enough for compatibility
18 |
19 | ## Prerequisites
20 |
21 | * [ ] You have a staging environment with docker
22 | * [ ] You can ssh to the server
23 | * [ ] Make sure you have the docker rights `sudo usermod -aG docker $YOUR_USER_NAME`
24 |
25 | ## Steps (~15 min)
26 |
27 | ### Install the nginx-proxy companion (~5 min)
28 |
29 | - Connect to your server `ssh user@your.domain`
30 | - Clone the nginx-proxy-companion [project](https://github.com/evertramos/docker-compose-letsencrypt-nginx-proxy-companion) on the server at the root of the server.
31 |
32 | ```bash
33 | git clone git@github.com:evertramos/docker-compose-letsencrypt-nginx-proxy-companion.git
34 | ```
35 |
36 | - Create a `.env` file
37 |
38 | ```bash
39 | cd docker-compose-letsencrypt-nginx-proxy-companion
40 | cp ./.env.sample .env
41 | ```
42 |
43 | - Set the `NGINX_FILES_PATH=/srv/nginx/data` in the `.env`
44 | - `vim ./.env`
45 | - line 41 replace `NGINX_FILES_PATH=/srv/nginx/data`(or a different path if you prefer)
46 |
47 | {% hint style='success' %} **CHECK**
48 |
49 | Try to launch the companion by running:
50 |
51 | ```bash
52 | ./start.sh
53 | ```
54 |
55 | You should have the following error because the port 80 is already used by your app docker:
56 |
57 | ```
58 | ERROR: for nginx-web Cannot start service nginx-web: driver failed programming external connectivity on endpoint nginx-web (4c0105fe57d370c99c0a143c967d1b8737006a4138618e1defebc4bab4e42d11): Bind for 0.0.0.0:80 failed: port is already allocated
59 | ```
60 |
61 | 
62 |
63 | {% endhint %}
64 |
65 | ### Configure your project to use the companion (~5 min)
66 |
67 | - Remove the binding 80 port command, but expose it
68 |
69 | ```diff
70 | version: '3'
71 | services:
72 | your-web-app: #It should contain port: "80:80"
73 | # ...
74 | - ports:
75 | - - "80:80"
76 | + expose:
77 | + - 80
78 | ```
79 |
80 | - Configure the app to use the network created by the companion (`webproxy` is the default name)
81 |
82 | ```diff
83 | version: '3'
84 | services:
85 | # ...
86 |
87 | +networks:
88 | + default:
89 | + external:
90 | + name: webproxy
91 | ```
92 |
93 | {% hint style='info' %} **GO FURTHER**
94 |
95 | https://blog.docker.com/2016/12/understanding-docker-networking-drivers-use-cases/
96 |
97 | {% endhint %}
98 |
99 | - In your project set 3 environment variable: `VIRTUAL_HOST`, `LETSENCRYPT_HOST`, `LETSENCRYPT_EMAIL`. The email will be used by _Letsencrypt_ to notify you if the certificate expire.There are 2 ways:
100 | - In the docker-compose file
101 | - In your prod.env file that is read by your Dockerfile.
102 |
103 |
104 | {% hint style='info' %} **RECOMENDED WAY**
105 |
106 | Update the .env file of your web-app docker
107 |
108 | {% endhint %}
109 |
110 | - In the `./env/prod.env` add the following:
111 |
112 | ```diff
113 | #... other env variable
114 | + VIRTUAL_HOST=my.domain.cloud.bam.tech
115 | + LETSENCRYPT_HOST=my.domain.cloud.bam.tech
116 | + LETSENCRYPT_EMAIL=your@email.com
117 | ```
118 |
119 | {% hint style='warning' %} **OTHER solution**
120 |
121 | If you have no .env file you an also Update the docker-compose-prod file
122 |
123 |
124 | ```diff
125 | version: '3'
126 | services:
127 | your-web-app: #It should contain port: "80:80"
128 | # ...
129 | environment:
130 | + - VIRTUAL_HOST=my.domain.cloud.bam.tech
131 | + - LETSENCRYPT_HOST=my.domain.cloud.bam.tech
132 | + - LETSENCRYPT_EMAIL=your@email.com
133 | ```
134 |
135 | {% endhint %}
136 |
137 |
138 | ### Make the switch (~5 min)
139 |
140 | {% hint style='danger' %} **BUSINESS INTERRUPTION**
141 |
142 | You will have to shut down your docker (so the port 80 is available), so during this step your domain won't be accessible.
143 |
144 | {% endhint %}
145 |
146 | - Cut your app docker:
147 |
148 | ```bash
149 | cd your-project-directory
150 | docker-compose -f docker-compose-prod.yml down
151 | ```
152 |
153 | - Start the companion (go to the companion directory):
154 |
155 | ```bash
156 | cd ../docker-compose-letsencrypt-nginx-proxy-companion
157 | ./start.sh
158 | ```
159 |
160 | - Launch your project docker again:
161 |
162 | ```bash
163 | cd -
164 | docker-compose -f docker-compose-prod.yml up -d
165 | ```
166 |
167 | {% hint style='success' %} **CHECK**
168 |
169 | - Check the validity of your domain, go to https://your.domain
170 | - Go [there](https://www.ssllabs.com/ssltest/) and check your domain. Useful tip: go to the __Handshake Simulation__ section and check the supported devices.
171 |
172 | {% endhint %}
173 |
--------------------------------------------------------------------------------
/ops/docker/docker-nginx-companion-error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bamlab/dev-standards/f07fee937df828f63daa6d0dffc36ac9c4e78bbc/ops/docker/docker-nginx-companion-error.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dev-standards",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "repository": "git@github.com:bamlab/dev-standards.git",
6 | "author": "Yann Leflour ",
7 | "license": "MIT",
8 | "scripts": {
9 | "test": "echo 'No other tests'",
10 | "contributors:add": "all-contributors add",
11 | "contributors:generate": "all-contributors generate"
12 | },
13 | "devDependencies": {
14 | "danger": "^1.0.0",
15 | "lodash": "^4.17.4",
16 | "minimatch": "^3.0.4"
17 | },
18 | "dependencies": {
19 | "all-contributors-cli": "^4.4.0",
20 | "gitbook-plugin-ga": "^2.0.0"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/performance/backend/cache-routes-using-varnish.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Cache your routes using varnish (~45 min)
2 |
3 | ## Owner: [Xavier Lefevre](https://github.com/xavierlefevre)
4 |
5 | ## Control points
6 |
7 | {% hint style='success' %}
8 |
9 | If, _as an expert of caching_, you want to adapt the standard to the context of your project, you have to check that:
10 |
11 | {% endhint %}
12 |
13 | * [ ] if the data is not in cache, you redirect to the backend
14 | * [ ] you don't cache authenticated requests
15 | * [ ] you don't cache requests that mutate data on the server (POST/PUT/DELETE in REST)
16 | * [ ] the cache duration is respecting business needs
17 | * example: a football game score can't be cached more than 1 min for a live match but can be cached forever for a finished game
18 | * [ ] you respect cache headers, like [Cache-Control](https://developer.mozilla.org/fr/docs/Web/HTTP/Headers/Cache-Control)
19 |
20 | ## Why
21 |
22 | Using a tool like Varnish to cache routes in order to optimize the response performance below 0.1s.
23 |
24 | ## Steps
25 |
26 | {% hint style='warning' %}
27 |
28 | **TODO**
29 |
30 | If you fall on this method of operation and want to fill it don't hesitate! It will help others.
31 | You ca for instance, look at this article https://medium.com/about-developer-blog/varnish-58c5d8269269 and convert it to a M33 like steps (short steps and check after after each steps) when you use it.
32 |
33 | A good MO example: [Setup HTTPS on your docker environment](../../ops/docker/deploy-with-https.mo.md)
34 |
35 | {% endhint %}
36 |
--------------------------------------------------------------------------------
/performance/backend/how-to-investigate-performance.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] How to investigate back-end performance
2 |
3 | ## Owner: [Xavier Lefevre](https://github.com/xavierlefevre)
4 |
5 | ## Why
6 | - You don't know from which end investigate the performance issue. Follow those steps to make sure you know how to investigate in an efficient way. Also in a way that you'll be able to share and explain your learnings easily with others.
7 |
8 | ## Steps
9 | - [ ] Define the context of the problem, and how to reproduce it
10 | - Ex: We want a performing player ranking query from a 3G network
11 | - [ ] Check the [performance tools and technics](./backend-performance-tools.md) before anything
12 | - [ ] Make sure you note every steps of your investigation, take screenshots and draw schemas
13 | - Ex: I requested the ranking route from Postman with the ID of a user => I changed the network in order to see the impact of bad internet on the request time => etc.
14 | - [ ] Start from the main broad problem, take screenshots and note your exact findings
15 | - Ex: The request takes 12,235s on an iPhone 4S on 3G network
16 | - [ ] Cut your problem in pieces as soon as you start going into details, and continue noting
17 | - Ex: The ranking request fetches data from the portfolio API in 10,123s and the user API in 1,856s
18 | - [ ] Make hypotheses: from 10,123s, you expect with your fix to reach below 1s because of a potential SQL query mis-performance
19 | - [ ] Fix it, and then compare the result with your initial state
20 | - If the issue is not fixed, write down that your hypotheses is invalid, it still is a learning and worth sharing
21 | - [ ] Update your product owner and team mates: by saving and sharing your final report, like in a Gist or Trello Ticket
22 | - [ ] Iterate...
23 | - [ ] Finally share what you learned with your team to be challenged and move forward!
24 |
--------------------------------------------------------------------------------
/performance/backend/minimize-number-sql-queries.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Minimize your number of SQL queries
2 |
3 | ## Owner: [Xavier Lefevre](https://github.com/xavierlefevre)
4 |
5 | ## Control points
6 |
7 | * [ ] you don't lazy load data that you need to access directly
8 |
9 | ## Why
10 |
11 | SQL is extremely powerful to retrieve and manipulate big chunks of data, but not powerful if you want to access data 1000 times in a row
12 |
13 | ## Steps
14 |
15 | - By default some ORMs lazy load relations: meaning that it will load the model you want but keep references of the relations
16 | - If you want to access those relations, it will only re-query the database later, in a loop for instance, it might send thousants of queries to retrieve relations
17 | - By join-loading the main SQL query, you make sure that you retrieve the relation directly, the ORM will join the model and its relations from the main first query
18 | - Then if you access one of the relation, it will already be available in the response object
19 | - See an example with SQL Alchemy: http://docs.sqlalchemy.org/en/latest/orm/loading_relationships.html
20 |
21 | {% hint style='warning' %}
22 |
23 | **TODO**
24 |
25 | If you fall on this method of operation and want to fill it don't hesitate! It will help others.
26 | You ca for instance, look at this article https://medium.com/about-developer-blog/varnish-58c5d8269269 and convert it to a M33 like steps (short steps and check after after each steps) when you use it.
27 |
28 | A good MO example: [Setup HTTPS on your docker environment](../../ops/docker/deploy-with-https.mo.md)
29 |
30 | {% endhint %}
31 |
--------------------------------------------------------------------------------
/performance/backend/output-sql-alchemy-orm-query.mo.md:
--------------------------------------------------------------------------------
1 | # Output SQL Alchemy ORM query
2 |
3 | ## Owner: [Xavier Lefevre](https://github.com/xavierlefevre)
4 |
5 | ## Steps
6 |
7 | If your performance issues seem to come from your SQL queries, you should take a look at the output of SQL Alchemy:
8 | - Log/print the SQL Alchemy query:
9 | ```python
10 | logging.info(self.session.query(
11 | Revision.portfolio_id,
12 | func.max(Revision.valuation_date).label('max_date')
13 | ))
14 | ```
15 | - Retrieve what's printed in your logs and format it: https://sqlformat.org/
16 | - Test the query against the database to see how to optimize it
17 |
--------------------------------------------------------------------------------
/performance/backend/python-investigation-tools.mo.md:
--------------------------------------------------------------------------------
1 | # Python investigation tools
2 |
3 | ## Owner: [Xavier Lefevre](https://github.com/xavierlefevre)
4 |
5 | ## Steps
6 |
7 | ### Python: Simple and quick investigation of a function execution time
8 |
9 | By using timer functions you can see how long takes the execution:
10 | ```python
11 | import time
12 | import logging
13 |
14 | def retrieve_data(self, ids):
15 | # Start your time recording
16 | start_time = time.time()
17 |
18 | datas = Repository().get_data(ids).all()
19 |
20 | # First stop, to see how long took "get_data"
21 | first_record_time = time.time()
22 | logging.info('After getting datas: %s' %
23 | str(first_record_time - start_time))
24 |
25 | answer = [{
26 | 'id': str(data.id),
27 | 'related_data': data.relation.to_dict() if data.relation else {}
28 | } for data in datas]
29 |
30 | # Second stop, to see how long took the answer construction
31 | second_record_time = time.time()
32 | logging.info('After building the final answer: %s' % str(second_record_time - first_record_time))
33 |
34 | return answer
35 | ```
36 |
37 | ### Python: More advanced solution to profile the execution of a function and its children
38 | - https://blog.sicara.com/profile-surgical-time-tracking-python-db1e0a5c06b6
39 |
40 | ### Python: Further performance analysis tools
41 | You can also profile with the below tool:
42 | - https://docs.python.org/3/library/profile.html
43 |
--------------------------------------------------------------------------------
/performance/backend/serve-images-as-static-files.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Save and serve your images as static files
2 |
3 | ## Owner: [Xavier Lefevre](https://github.com/xavierlefevre)
4 |
5 | ## Control points
6 |
7 | * [ ] you don't save images in a database
8 |
9 | ## Why
10 |
11 | Save and serve the image file from the server in a specific folder, or an Amazon S3, instead of having it in the database in Base64 is much more performing for progressively displaying a page.
12 |
13 | ## Steps
14 |
15 | {% hint style='warning' %}
16 |
17 | **TODO**
18 |
19 | If you fall on this method of operation and want to fill it don't hesitate! It will help others.
20 | You ca for instance, look at this article https://medium.com/about-developer-blog/varnish-58c5d8269269 and convert it to a M33 like steps (short steps and check after after each steps) when you use it.
21 |
22 | A good MO example: [Setup HTTPS on your docker environment](../../ops/docker/deploy-with-https.mo.md)
23 |
24 | {% endhint %}
25 |
--------------------------------------------------------------------------------
/performance/front/how-to-investigate-performance.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] How to investigate front-end performance
2 |
3 | ## Owner: [Louis Lagrange](https://github.com/Minishlink)
4 |
5 | ## Why
6 |
7 | Sometimes, standards are not enough, or you're not applying them, resulting in performance bottlenecks.
8 |
9 | ## Steps
10 |
11 | Proceed by dichotomy: cut your app in multiple pieces in order to find out where the problem comes from. For example, literally remove some components or pages!
12 |
13 | ### Profile
14 |
15 | Measure the performance with the following tools. They're ordered by `simplicity` \* `perspectives of learnings`.
16 |
17 | - Put some `console.count('my component')` in your components' render methods in order to measure the number of renders
18 | - In app Performance monitor (CMD+D on iOS, CTRL+M on Android; and select Performance monitor)
19 | - Network profiler => if some calls are too long, investigate backend performance (TODO link to backend performance standard)
20 | - [React.unstable_Profiler](https://medium.com/@dave_lunny/how-to-use-reacts-experimental-new-profiler-feature-c340674e5d0e)
21 | - Close React Native Debugger and open the Chrome debugger. Click on the performance tab and hit record to start profiling the performance of your application. See [this article](https://building.calibreapp.com/debugging-react-performance-with-react-16-and-chrome-devtools-c90698a522ad) to learn how to read the output.
22 | - Native tools (Android Studio, XCode)
23 | - https://facebook.github.io/react-native/docs/performance.html#profiling
24 | - Inspect the JS<->native bridge with [RN-Snoopy](https://github.com/jondot/rn-snoopy)
25 |
26 | ## Useful links
27 |
28 | - React Native doc: https://facebook.github.io/react-native/docs/performance.html
29 | - Example commit: https://github.com/Minishlink/DailyScrum/commit/3c6d5f70a638a146f1a2158b94292010eb12186a
30 |
--------------------------------------------------------------------------------
/performance/front/react-native-maps-performance.s.md:
--------------------------------------------------------------------------------
1 | # [Standard] React Native Maps performance
2 |
3 | ## Owner: [Alban Depretz](https://github.com/chdeps)
4 |
5 | ## Why
6 |
7 | A lot of apps seem to be struggling with performance when it comes to maps & displaying pins. So I put together a REX that goes hand in hand with Louis Lagrange's standard on performance. You'll see that some generic tips given by Louis are applied here. It could be considered as an application of the standard by taking into account the specifics of maps' rendering.
8 |
9 | ## What
10 |
11 | Here are a few tips I suggest using to improve your maps' performance:
12 |
13 | 1. Use `onRegionChangeComplete` instead of onRegionChange. You will wait until you're done changing the region.
14 | 2. Use `debounce` when making HTTP calls to fetch new pins.
15 |
16 | > ⚠️ If a call takes longer than your wait time. Another call might triggered in the mean time & go through the callback before the first call. It might cause a laggy feeling & incoherent data. Cancelling debounce will not cancel async callback. You can do something like below :
17 |
18 | ```javascript
19 | //Generate a unique id to identify a query
20 | const queryId = shortid.generate();
21 | this.queryId = queryId;
22 | this.setState({ isLoading: true }, () =>
23 | this.props
24 | .callForPins(..args)
25 | .then(({ data: { pins } }) => {
26 | //There is a newest callback no need to update the state
27 | if (this.queryId !== queryId) return;
28 | return this.setState({
29 | pins,
30 | });
31 | })
32 | .catch(console.warn)
33 | .finally(() => this.setState({ isLoading: false }))
34 | );
35 | ```
36 |
37 | 3. Use a `caching technique` to reduce the number of queries
38 |
39 | When calling for new pins, you need to consider what your inputs are. Given that you query pins on the map with the following arguments:
40 | * Region on which the user is (eg. You're located over Paris. You don't want to load a pin in New York)
41 | * Types of pins (eg. On a map, you just want the restaurants but you don't want to see the shops)
42 | * Search field (eg. If you're searching for bistrots you don't want to get Mc Donalds' pins)
43 |
44 | You can create a hash key with the type of pins & the search field :
45 |
46 | ```javascript
47 | //callForPins callback
48 | const key = extractKey({ pinTypes, search });
49 | this.setState({
50 | queriedRegion: {
51 | [key]: boundaries(region),
52 | },
53 | pins,
54 | });
55 | ```
56 |
57 | Before querying for new pins on the map check whether the last query's hash key is the same & whether the region of your query is within the previous query's region. If so we already have the pins & there is no need for querying new pins.
58 |
59 | ```javascript
60 | _getPins = (region, pinTypes, search) => {
61 | //Create a uniq key out of the pinTypes & search parameters
62 | const key = extractKey({ pinTypes, search });
63 | if (this.state.queriedRegion[key]
64 | && isRegionWithIn(boundaries(region), this.state.queriedRegion[key])) return;
65 | //Call for new pins with debounce if the pinTypes or search parameters have changed since last time
66 | //Or if the region queried is larger than the previous one
67 | return this._callForPinsDebounce(region, pinTypes, search);
68 | };
69 | ```
70 |
71 | > As regards to caching, there still things that need to be done. At the time, I was doing that Apollo did not provide any caching per parameter. It would allow us to have a greater history of calls in cache & only the last one. Also, ideally you could think of caching when zooming out. This involves some dev on the back-end, as it means that you are capable of fetching pins in a ring & only inside a cercle.
72 |
73 | 4. `shouldComponentUpdate` is your friend. Don't re-render the map if your pins haven't updated for instance.
74 | 5. Clustering of pins on the front end ([Clustering with react-native-maps](https://github.com/bamlab/react-native-components-collection/tree/master/packages/react-native-component-map-clustering))
75 |
76 |
--------------------------------------------------------------------------------
/performance/front/react-native-performance.s.md:
--------------------------------------------------------------------------------
1 | # [Standard] React Native performance
2 |
3 | ## Owner: [Louis Lagrange](https://github.com/Minishlink)
4 |
5 | ## Checks
6 |
7 | In order to have an efficient application from the get-go, respect the following standards.
8 |
9 | ## Why
10 |
11 | Because a few seconds of page render, a laggy chart display or a buggy animation makes you lose customers, those tips will help you avoid that before it even happens.
12 | In order to have an efficient application from the get-go, respect the following standards.
13 |
14 | ### General
15 |
16 | > Side note: You don't need to apply every of these standards right away (that would be premature optimization), but as your technical experience grows, you should adopt them along the way. These best practices are ordered by potential impact on performance.
17 |
18 | - Use an up-to-date version of your dependencies, and first and foremost:
19 | - [React Native](https://github.com/facebook/react-native/releases)
20 | - [React Navigation](https://github.com/react-navigation/react-navigation/releases)
21 | - Don't use images that are unnecessary big. Dynamic resizing is very inefficient on Android. Resize them to 1x 2x 3x flavors (`img.png`, `img@2x.png`, `img@3x.png`) and use them normally (`require('img.png')`). UX designers can export images easily this way with Sketch.
22 | - Use animations in order to make things more fluid (`animationEnabled` in `TabNavigator`; `LayoutAnimation`)
23 | - Use `shouldComponentUpdate` / `PureComponent`. Test thoroughly your component when using `shouldComponentUpdate` because this is error-prone. It will massively improve your app's performance though.
24 | - Don't create new functions on every render, [bind your functions efficiently](https://github.com/bamlab/dev-standards/blob/master/react-native/react/binding-functions-in-react-component.s.md). Similarly, avoid creating inline styles.
25 | - When using `Animated`, use [`useNativeDriver`](https://facebook.github.io/react-native/docs/animations.html#using-the-native-driver)
26 | - If you have a big view that has a lot of subviews, and these are not always shown to the user, use [`removeClippedSubviews`](https://facebook.github.io/react-native/docs/view.html#removeclippedsubviews)
27 | - When triggering a function after clicking on a button, or at `componentDidMount`, use [`InteractionManager.runAfterInteractions`](https://facebook.github.io/react-native/docs/interactionmanager.html)
28 | - Remove console logs from your production builds, use the [`transform-remove-console`](https://facebook.github.io/react-native/docs/performance.html#using-consolelog-statements) Babel plugin
29 | - When possible, use `Fragment` instead of `View`
30 | - Try to limit the number of data you display in charts, maps and tables. To investigate the potential impact, try to divide this number by 10 and measure the impact with the tools presented in the profiling section
31 | - Do not request your data to often: if it changes every hour, do not perform the same request every minutes, it will trigger useless renders and waste ressources.
32 |
33 | ### Useless renders
34 |
35 | - Use `shouldComponentUpdate` / `PureComponent`. Test thoroughly your component when using `shouldComponentUpdate` because this is error-prone. It will massively improve your app's performance though.
36 | - Don't create new functions on every render, [bind your functions efficiently](https://github.com/bamlab/dev-standards/blob/master/react-native/react/binding-functions-in-react-component.s.md).
37 | - Do not request your data to often: if it changes every hour, do not perform the same request every minutes, it will trigger useless renders and waste ressources.
38 |
39 | ### Displaying large list of elements
40 |
41 | - Try to limit the number of data you display in charts, maps and tables. To investigate the potential impact, try to divide this number by 10 and measure the impact with the tools presented in the profiling section
42 | - If you have a big view that has a lot of subviews, and these are not always shown to the user, use [`removeClippedSubviews`](https://facebook.github.io/react-native/docs/view.html#removeclippedsubviews)
43 |
44 | ### Technical debt
45 |
46 | - Use an up-to-date version of your dependencies, and first and foremost:
47 | - [React Native](https://github.com/facebook/react-native/releases)
48 | - [React Navigation](https://github.com/react-navigation/react-navigation/releases)
49 | - Remove console logs from your production builds, use the [`transform-remove-console`](https://facebook.github.io/react-native/docs/performance.html#using-consolelog-statements) Babel plugin
50 | - When possible, use `Fragment` instead of `View`
51 |
52 | ### Start-up times
53 |
54 | If your app takes too much time to initialize, solve the problem incrementally:
55 |
56 | 1. Add a splashscreen that [closes when the app is ready](https://github.com/Minishlink/DailyScrum/commit/811cfd57304dbb6f08386bce7b1d9d0b7c7388ae) with [`react-native-splash-screen`](https://github.com/crazycodeboy/react-native-splash-screen)
57 | 2. If the startup time is > 2 seconds, show a full page modal with an animation (in the continuity of your splashscreen)
58 | 3. If the startup time is consistently > 5 seconds (or 7 seconds with an animated splashscreen): if you have a very big app, implement [dynamic imports](https://facebook.github.io/react-native/docs/performance.html#unbundling-inline-requires); if not, look for other clues: aren't you doing some long API calls at startup?
59 |
60 | ## Exemple with maps in react-native
61 |
62 | You can take a look the following standard : [React native maps performance](https://github.com/bamlab/dev-standards/blob/master/performance/front/react-native-maps-performance.s.md)
63 |
64 | ## Good examples
65 |
66 | > Please andon and/or create an issue if you need one!
67 |
68 | ## Bad examples
69 |
70 | > Please andon and/or create an issue if you need one!
71 |
--------------------------------------------------------------------------------
/performance/front/simulate-network-iphone.mo.md:
--------------------------------------------------------------------------------
1 |
2 | # iPhone: Simulate a network like LTE, 3G or Edge
3 |
4 | ## Owner: [Xavier Lefevre](https://github.com/xavierlefevre)
5 |
6 | ## Steps
7 |
8 | - Make sure you iPhone is connected to the Wifi network
9 | - Connect your computer to your iPhone via hotspot
10 | - Go to the iPhone settings
11 | - Then select: Developer > Network Link Conditioner
12 | - Enable
13 | - Select your desired network quality: LTE, 3G or Edge for instance
14 | - Test your requests in Postman and see the result on the performance
15 | > source: https://www.natashatherobot.com/simulate-bad-network-ios-simulator/
16 |
--------------------------------------------------------------------------------
/performance/front/table-and-chart-with-good-performance.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Optimize the render time of lists, tables and charts
2 |
3 | ## Owner: [Justine Mignot](https://github.com/justinemignot)
4 |
5 | ## Steps
6 |
7 | - [ ] Find how many lines or data points are displayed on your page
8 | - [ ] Decide if your end user should see them all
9 | - [ ] If it does not need all this data, try reducing its amount
10 | - [ ] If it does need all the data, see how to optimize render
11 | - Find solutions per components, "Charts, Maps, Tables and Lists" below
12 |
13 | ### Chart/Maps data optimization
14 |
15 | > Why: On a project like Investo for BNP, we reduced by 50% the data points of a chart, we saved 2s on the page render time!
16 |
17 | - Open your page with the chart
18 | - Reduce by half the quantity of data displayed
19 | - If the result is still clear enough for the end user, check how long it took to render (link to Thibaut's [article](https://blog.bam.tech/developper-news/5-tips-to-improve-performance-react-native-application) on how to investigate)
20 | - If the improvement is enough and the information clear for the user, perfect, you improved your performance and still helped your end user
21 | - If it's not enough, reproduce the previous step
22 | - If you can't manage to improve the performance and/or that you are now displaying too few points, you should investigate the render performance of your components, it means that the code is too heavy, not that you display too much data
23 |
24 | ### Tables/Lists render optimization
25 |
26 | > Why: On a project like Galaxy for BNP, they displayed 50 lines instead of ~500, and users never clicked on the 'see more' button!
27 |
28 | #### It does not need all this data, try reducing its amount
29 |
30 | - Open your page with the table
31 | - Reduce by half the quantity of lines displayed (or more if it makes more sense to display less on your project)
32 | - Add a 'See more' button to allow your user to display all lines
33 | - If the improvement is enough, perfect, you improved your performance
34 | - If it's not enough, reproduce the previous step
35 | - If you can't manage to improve the performance and/or that you are now displaying too few points, you should investigate the render performance of your components, it means that the code is too heavy, not that you display too much data
36 |
37 | #### If it does need all the data, see how to optimize render
38 |
39 | - Pagination:
40 |
41 | - Back: only if the cause of slowness is the time of backend request (more than 2s)
42 | - paginate,
43 | - use lazy loading.
44 | - Front: if you want to minize elements to display and so gain on rendering time.
45 |
46 | - React Native Components:
47 |
48 | - use [FlatList](https://facebook.github.io/react-native/docs/flatlist), [SectionList](https://facebook.github.io/react-native/docs/sectionlist), [VirtualizedList](https://facebook.github.io/react-native/docs/virtualizedlist)
49 | because it render items lazily, just when they are about to appear, and removes items that scroll way off screen to save memory and processing time
50 | - DO NOT USE `ScrollView`: it simply renders all its react child components at once, so it has a big performance downside!
51 |
52 | - React library:
53 | - [react-virtualized](https://bvaughn.github.io/react-virtualized/#/components/List):
54 | great tool to display a big list with React.
55 | But implementing it add a not negligible complexity on your tickets. Take it into consideration.
56 |
--------------------------------------------------------------------------------
/performance/performance-decision-flow.s.md:
--------------------------------------------------------------------------------
1 | # [Standard] Performance Decision Flow
2 |
3 | ## Owner: [Thibaut Guedou](https://github.com/thibautguedou3)
4 |
5 | ## Checks
6 |
7 | - Back-end:
8 | - Your requests take less than 500ms to complete
9 | - Front-end:
10 |
11 | - Your pages take less than 2s to display
12 | - No visible lags
13 | - Every action has instant visual feedback
14 |
15 | ## Do you know how to investigate your performance issues?
16 |
17 | ### General
18 |
19 | 1. [Simulate a network like LTE, 3G or Edge with an iPhone in hotstop](/performance/front/simulate-network-iphone.mo.md)
20 |
21 | ### Backend
22 |
23 | 1. [How to investigate a general backend performance issue](/performance/backend/how-to-investigate-performance.mo.md)
24 | 2. [Python investigation tools](/performance/backend/python-investigation-tools.mo.md)
25 | 3. [Output SQL Alchemy ORM query](/performance/backend/output-sql-alchemy-orm-query.mo.md)
26 |
27 | ## Now that you investigated, can we help you?
28 |
29 | ### Backend
30 |
31 | 1. [Cache your routes using varnish](/performance/backend/cache-routes-using-varnish.mo.md)
32 | 2. [Serve images as static files](/performance/backend/serve-images-as-static-files.mo)
33 | 3. [Minimize your number of SQL queries](/performance/backend/minimize-number-sql-queries.mo.md)
34 |
35 | ### Front
36 |
37 | 1. [Build performant application](/performance/front/react-native-performance.s.md)
38 | 2. [Investigate performance issues](/performance/front/how-to-investigate-performance.mo.md)
39 | 3. Pure components **-> [To do]**
40 | 4. [Optimize the render time of lists, tables and charts](/performance/front/table-and-chart-with-good-performance.mo.md)
41 |
42 | ## Have you a mean of keeping the performance under control?
43 |
44 | ### Backend
45 |
46 | - [Monitor your backend performance with K6](https://github.com/bamlab/performance-monitoring)
47 |
48 | ## Good examples
49 |
50 | > Please andon and/or create an issue if you need one!
51 |
52 | ## Bad examples
53 |
54 | > Please andon and/or create an issue if you need one!
55 |
--------------------------------------------------------------------------------
/project-standards/project-success/index.md:
--------------------------------------------------------------------------------
1 | # Project Success
2 |
3 | ### Objective
4 | > Succeeding to accompany our client, by making this project a success for them and for BAM
5 |
6 | ### Standards
7 | - Critère de succès connus, BAMED et mesurés (fixé avec le payeur)
8 | - Projet réussi sur le questionnaire BAM
9 | - Sponsor présent à la review ou à la précédente
10 | - Sprint réussi (Sprint Goal atteint et nombre de points >= forecast)
11 | - [Launch in production (each plateform) or Apple agreement asked (if sprint >= 2)](/project-standards/project-success/production.s.md)
12 | - Aucune dépendance extérieure
13 | - PO valide sur plateforme ISO prod (provisioning + data synchronisée hebdomadairement)
14 | - Aucune régression ou bug découvert lors du dernier sprint (si oui, créer un bac rouge)
15 | - Aucun ticket "à valider" revenu en doing (si oui, créer un bac rouge)
16 |
17 | ### Todo
18 | 1. Translate the standards
19 |
--------------------------------------------------------------------------------
/project-standards/project-success/production.s.md:
--------------------------------------------------------------------------------
1 | # [Standard] Launch in production (each platform) or Apple agreement asked (if sprint >= 2)
2 |
3 | ## Owner: [Xavier Lefèvre](https://github.com/xavierlefevre)
4 |
5 | ## Description
6 | - The project needs to be placed in front of its end users as fast as possible, the team needs to do the necessary for this as soon as the second sprint starts.
7 |
8 | ## Impact
9 | - Showing a MVP as soon as possible to end users is a mean to avoid as much as possible waste and un-necessary developments (hence spendings) for un-wanted features. The risk to waste a lot of money in developments is much higher than the risk to be repelled by your customer base for a small clean feature.
10 |
11 | ## Checks
12 | - [ ] Every week, take a "Launch in production" ticket.
13 | - [ ] Create a "In production" ticket in your "Done" columns in order to specify which dev has been launched or not, and keep a trace of it for future "LIP".
14 | - [ ] For micro-services, check each and every API when you launch in production.
15 | - [ ] When developing, always think about the retro-compatibility of your changes in the back-end (versioning) to make sure that people who do not have the last version of the app don't get un-wanted bugs.
16 |
17 | ## Bad Examples
18 | *TBD*
19 |
20 | ## Good Examples
21 | *TBD*
22 |
--------------------------------------------------------------------------------
/project-standards/taking-over-project/index.md:
--------------------------------------------------------------------------------
1 | # Taking over an existing project
2 |
3 | ### Objective
4 |
5 | > Minimize malfunction risks when starting to work on a project that had been started outside of BAM
6 |
7 |
8 | ### Steps
9 |
10 | - [Migrate certificates to BAM's repository](/project-standards/taking-over-project/migrate-to-new-ios-certificates.mo.md)
11 |
--------------------------------------------------------------------------------
/project-standards/taking-over-project/migrate-to-new-ios-certificates.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Migrate project to BAM's certificates
2 |
3 | ## Owner: [Yassine Chbani](https://www.github.com/yassinecc)
4 |
5 | ## Description
6 | - A project started by a third party should use your organisation's iOS certificates once a team starts working on it
7 |
8 | ## Impact
9 | - If the original Apple developer account is not an entreprise one, the certificates for the staging app will expire and renewing them will include a dependency to the original owner of the project
10 |
11 | ## Prerequisites
12 | - [ ] You have access to the previous Apple Developer account
13 | - [ ] Your project uses fastlane
14 |
15 | ## Steps
16 | ### Removing the old app ID
17 | - Log in to the original Apple Developer account on developer.apple.com
18 | - Go to the certificates, Identifiers and Profiles page
19 | - In the Identifiers section, locate the staging app's ID and select it
20 | - In the menu you opened, browse to the bottom and delete the app ID
21 |
22 | ### Generating a new provisiong profile
23 | - In your fastlane folder, open the .env file for the staging app
24 | - Change the `MATCH_GIT_URL` and `IOS_TEAM_ID` fields to the ones used by you organisation
25 | - If not already the case, set `MATCH_TYPE` to 'enterprise' and `MATCH_FORCE_ENTERPRISE` to '1' in the `IOS_MATCH` section of the env file
26 | - Change the `FL_HOCKEY_API_TOKEN` to you organisation's token
27 | - Run `bundle exec fastlane ios setup --env=staging`
28 | - Deploy to HockeyApp
29 | - Download and test the app
30 | - Share with your product owner and relevant people the new link to download the staging app
31 |
--------------------------------------------------------------------------------
/project-standards/technical-agility/code-vocabulary-identical-business-vocabulary.s.md:
--------------------------------------------------------------------------------
1 | # [Standard] Code's vocabulary identical to business' vocabulary
2 |
3 | ## Owner: TBD
4 |
5 | ## Description
6 | - The name of your code variables and DB entities should represent as much as possible the language used by the client/business side.
7 |
8 | ## Impact
9 | - The communication between the PO and the technical team as much as the arrival of a new developer on the project are made easier.
10 |
11 | ## Checks
12 | *TBD*
13 |
14 | ## Bad Examples
15 | *TBD*
16 |
17 | ## Good Examples
18 | *TBD*
19 |
--------------------------------------------------------------------------------
/project-standards/technical-agility/index.md:
--------------------------------------------------------------------------------
1 | # Technical Agility
2 |
3 | ### Objective
4 | > Ensuring a sustainable and easy to takeover technical project
5 |
6 | ### Standards
7 | - [Code's vocabulary identical to business' vocabulary](/project-standards/technical-agility/code-vocabulary-identical-business-vocabulary.s.md)
8 | - [Stable and up-to-date dependencies](/project-standards/technical-agility/up-to-date-dependencies.s.md)
9 | - [This week, a member of the technical team destroyed their project environment and re-installed everything under 15minutes](/project-standards/technical-agility/under-15-minutes-project-installation.s.md)
10 | - At least one re-factoring per day
11 | - [The tests' standards of my framework are respected](/project-standards/technical-agility/react-native-test.s.md)
12 | - Build and deployment in one command (staging and production)
13 | - Green continuous integration on every deployed branches
14 |
--------------------------------------------------------------------------------
/project-standards/technical-agility/under-15-minutes-project-installation.s.md:
--------------------------------------------------------------------------------
1 | # [Standard] This week, a member of the technical team destroyed their project environment and re-installed everything under 15minutes
2 |
3 | ## Owner: *TBD*
4 |
5 | ## Description
6 | - In order to make sure that a new BAMer or even an external team could easily without too much waste install the project and start creating value under 15 minutes.
7 |
8 | ## Impact
9 | - If the team does not regularly kill and re-install the project, in order to update the install process documentation, there is a high risk that a new developer arriving on the project spends several hours to try to launch the project on its machine.
10 |
11 | ## Checks
12 | *TBD*
13 |
14 | ## Bad Examples
15 | *TBD*
16 |
17 | ## Good Examples
18 | *TBD*
19 |
--------------------------------------------------------------------------------
/project-standards/technical-agility/up-to-date-dependencies.s.md:
--------------------------------------------------------------------------------
1 | # [Standard] Stable and up-to-date dependencies
2 |
3 | ## Owner: [Xavier Lefèvre](https://github.com/xavierlefevre)
4 |
5 | ## Description
6 | - The project code dependencies such as NPM packages need to be very regularly updated, the team should check once per sprint.
7 |
8 | ## Impact
9 | - An old dependency, can become deprecated and not adapt well with new operating systems, browsers, development tools, etc.
10 |
11 | ## Checks
12 | *TBD*
13 |
14 | ## Bad Examples
15 |
16 | ### redacted project
17 | - Problem: Cordova has not been updated for several months on the project and one day a developer could not launch the app on an iOS emulator because their new Xcode version had an emulator list discrepancy not handled by this old Cordova version, but handled by the new one.
18 | - Loss: 1h30 of debugging + 1h30 of problem solving
19 |
20 | ## Good Examples
21 | *TBD*
22 |
23 | ## Upgrading React Native
24 |
25 | React Native is very probably the dependency you'll have to upgrade the more often so we felt it was worth dedicating a [whole article](../../react-native/update/upgrade-react-native.mo.md) to it.
26 |
--------------------------------------------------------------------------------
/react-native/animations/react-native-animations.s.md:
--------------------------------------------------------------------------------
1 | # [Standard] React Native animations
2 |
3 | ## Owner: [Louis Lagrange](https://github.com/Minishlink)
4 |
5 | ## Why
6 |
7 | Animations are a great way to improve the User Experience by :
8 |
9 | - easing the interactions, so that they may seem more natural
10 | - giving a clear visual feedback on an action's success or failure, and on its nature (tap / long press / slide / pinch)
11 | - educating the user on possible interactions on an element
12 | - helping the user wait while content is loading
13 | - giving a sensation of speed and minimizing small performance problems
14 | - show more content on the page in a fluid manner
15 |
16 | ## Checks
17 |
18 | - In order to improve how we create animations, I send a quick message to the owner "Hey it's , I'm going to make an animation on "
19 | - Creating an animation should not take more than half a day of design and development time. If it takes more time, I andon the owner who will help me or find someone to help me.
20 | - I know of the resources that can help me:
21 | - similar animations that BAM made previously with the [catalog](link available on M33 standard): this can help me showcase examples for my PO, estimate the time needed for the design and the development, and find a technical strategy for my animation
22 | - the tools that are available in order to create a React Native animation with [this table](https://github.com/bamlab/animations/blob/master/matrix.md)
23 | - the [official guide](https://facebook.github.io/react-native/docs/animations) on animations
24 | - If I use `Animated`:
25 | - I make sure to use the parameter `useNativeDriver` in `Animated.timing`, `Animated.spring`, `Animated.decay` and `Animated.event` (see [React Native performance](../../performance/front/react-native-performance.s.md))
26 | - I only use `Animated.interpolate` on styles of type `opacity` or `transform` (otherwise `useNativeDriver` won't work)
27 | - If I use any third party library, I look at the documentation and/or code, and if a `useNativeDriver` prop exists, I use it
28 | - When my animation is finished, I make a GIF of it (with [Kap](https://getkap.co/): `brew cask install kap`) and add it to the catalog [here](https://github.com/bamlab/animations/blob/master/catalog.md) (10 min)
29 |
30 | ## Good examples
31 |
32 | > Please andon and/or create an issue if you need one!
33 |
34 | ### `useNativeDriver`
35 |
36 | ```js
37 |
45 | ```
46 |
47 | ### Style interpolation
48 |
49 | ```js
50 |
60 | ```
61 |
62 | ## Bad examples
63 |
64 | > Please andon and/or create an issue if you need one!
65 |
66 | ### `useNativeDriver`
67 |
68 | ```js
69 |
75 | ```
76 |
77 | ### Style interpolation
78 |
79 | ```js
80 |
89 | ```
--------------------------------------------------------------------------------
/react-native/architecture/default-stack.s.md:
--------------------------------------------------------------------------------
1 | # [Standard] React Native stack
2 |
3 | ## Owner: Florian Rival
4 |
5 | ## Why
6 |
7 | Having a set of common tools/libraries allow us to quickly move from one project to another, be more efficient and get a deep knowledege of each tool, including the advantages **and** drawbacks of these tools.
8 |
9 | ## I need a navigation solution to start my app
10 |
11 | | Library/tool | What | Why |
12 | | ------------- |-------------| -----|
13 | | `react-navigation` | Navigation library for React Native | Recommended solution on [React Native documentation](https://facebook.github.io/react-native/docs/navigation.html), very customizable and with performant good enough for +90% of apps |
14 | | `react-native-navigation` | Navigation implemented using native navigation components | If you need to use the native navigation components so that your navigation is 100% equivalent to a native app. |
15 |
16 | ## I need to display icons
17 |
18 | | Library/tool | What | Why |
19 | | ------------- |-------------| -----|
20 | | `react-native-vector-icons` | Customizable Icons for React Native | Most comprehensive library of icons |
21 |
22 | ## I want to store the state of the app
23 |
24 | | Library/tool | What | Why |
25 | | ------------- |-------------| -----|
26 | | `redux` | State container | Widely used in the React community, lots of dev tooling |
27 | | `redux-persist` | Persistence of the data of the app | Simple to integrate with Redux and flexible |
28 | | `redux-saga` | Handling of asynchronous processes in the app | Simple to integrate with Redux, testable, make complex business flow easy to read |
29 |
30 | ## I want to handle forms
31 |
32 | | Library/tool | What | Why |
33 | | ------------- |-------------| -----|
34 | | `formik` | Forms handling library | |
35 | | `date-fns`, `moment` | Date handling library | Widely used libraries. |
36 |
37 | ## I want to handle animations
38 |
39 | | Library/tool | What | Why |
40 | | ------------- |-------------| -----|
41 | | Lottie (`react-native-lottie`) | Animation library | Good looking, performant animations. Easy to integrate in React Native. |
42 |
43 | ## I need to add testing to my app
44 |
45 | | Library/tool | What | Why |
46 | | ------------- |-------------| -----|
47 | | jest | Testing framework | Already integrated with React Native by default, allow to do snapshot testing |
48 | | redux-saga-test-plan | Testing utilities for `redux-saga` | Allow to test redux-saga |
49 | | Detox | End to end testing | Alternatives (Calabash) are not reliable enough and slow |
50 |
51 | ## I want static type checking
52 |
53 | | Library/tool | What | Why |
54 | | ------------- |-------------| -----|
55 | | Flowtype | Static typing | Improve developer experience, help to avoid errors when dealing with complex objects |
56 | | Typescript | Static typing | More stable and mature than Flowtype. Never used on a React Native project at BAM yet |
57 |
58 | ## I want to ensure the quality of my codebase
59 |
60 | | Library/tool | What | Why |
61 | | ------------- |-------------| -----|
62 | | Prettier | Automatic formattting of source code | Avoid all discussions/loss of time on styling Integration/plugin for editors |
63 | | eslint with `eslint-config-universe` | Linter | |
64 |
65 | ## I want to be able to push on-the-fly updates to my app
66 |
67 | | Library/tool | What | Why |
68 | | ------------- |-------------| -----|
69 | | AppCenter Code Push | Deploy mobile app updates without a full release | Speed up the deployment during development, allow for bug fixes and new features releases on the fly |
70 |
71 | ## I need to have crash/bugs reporting
72 |
73 | | Library/tool | What | Why |
74 | | ------------- |-------------| -----|
75 | | Sentry | Native crashes and JS exceptions reports | Easy integration and good React Native support with `react-native-sentry` |
76 |
77 | ## I need to add analytics/tracking to my app
78 |
79 | | Library/tool | What | Why |
80 | | ------------- |-------------| -----|
81 | | Firebase Analytics | Analytics for mobile applications | The recommended solution by Google for applications, with a good quality native module for React Native ([react-native-firebase](https://github.com/invertase/react-native-firebase)) |
82 |
83 | ## I need to have automated deployment
84 |
85 | | Library/tool | What | Why |
86 | | ------------- |-------------| -----|
87 | | fastlane | Automation of deployment tasks | Most widely used deployment tool for iOS/Android + existing actions for HockeyApp/App Center/App Store/Play Store |
88 | | match | Automation of certificate/provisioning profile generation | Avoid dealing with certificates, one place storage for all certificates |
89 |
90 | ## I need a continuous integration service for launching tests
91 |
92 | | Library/tool | What | Why |
93 | | ------------- |-------------| -----|
94 | | Bitrise | Automation of applications builds | Ensure reproducible builds, avoid spending time building apps on developer computers |
95 | | Travis CI | Automation of unit tests | |
96 |
97 |
--------------------------------------------------------------------------------
/react-native/architecture/file-naming.s.md:
--------------------------------------------------------------------------------
1 | # [Standard] File Naming
2 |
3 | ## Checks
4 |
5 | - File names use [camelCase](https://en.wikipedia.org/wiki/Camel_case)
6 | - Component File names use [PascalCase](https://en.wikipedia.org/wiki/PascalCase) and use the component name
7 | - When containers are next to their component
8 | - The component name should be `.component.js`
9 | - The container name should be `.container.js`
10 |
--------------------------------------------------------------------------------
/react-native/architecture/project-architecture.s.md:
--------------------------------------------------------------------------------
1 | # [Standard] Project Architecture
2 |
3 | ## Checks
4 | - Entire code except `index.ios.js` and `index.android.js` should be in `src`
5 | - The structure should be as follow
6 | - `index.ios.js`
7 | - `index.android.js`
8 | - `/src`
9 | - `modules`
10 | - `components`
11 | - `pages`
12 | - `style`
13 |
--------------------------------------------------------------------------------
/react-native/debugging/analyse-bug.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bamlab/dev-standards/f07fee937df828f63daa6d0dffc36ac9c4e78bbc/react-native/debugging/analyse-bug.jpg
--------------------------------------------------------------------------------
/react-native/debugging/debug-javascript-ios-device.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Debug Javascript on an iOS Device
2 |
3 | ## Prerequisites
4 | - [ ] Have [React Native Debugger](https://github.com/jhen0409/react-native-debugger) installed
5 | - [ ] Have a certificate + provisioning profile for debug
6 |
7 | ## Steps
8 |
9 | > :warning: The Ip mentioned is the one from your local network and not your router's ip on the internet
10 |
11 | > :warning: Make sure you have reverted the changes after debugging to avoid build issues
12 |
13 | - Make sure both the device and computer are on the same network
14 | - Open your project in Xcode
15 | - In `Libraries/React.xcodeproj/React/Base/RCTBundleURLPRovider.m`
16 | - Replace `NSString *host = ipGuess ?: @"localhost";`
17 | - With your computer IP address (remove ipGuess if it poses problems): `NSString *host = @"";`
18 | - In `Libraries/RCTWebSocket.xcodeproj/RCTWebSocketExecutor.m`
19 | - Replace: `host = @"localhost";`
20 | - With your computer IP address: `host = @"";`
21 | - Verify signing by making sure you have obtained the signing certificate for debug first
22 | - Run the app
23 | - Shake to open the menu
24 | - Hit *Debug Remotely*
25 |
--------------------------------------------------------------------------------
/react-native/debugging/debug-javascript.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Debug Javascript Code *(~3 min)*
2 |
3 | ## Owner: Yann Leflour
4 |
5 | ## Prerequisites *(~5 min)*
6 | - [ ] Have [React Native Debugger](https://github.com/jhen0409/react-native-debugger) installed
7 |
8 | ## Steps *(~3min)*
9 |
10 | - Have your app running on a simulator or device *(2min)*
11 | - ***Check:*** The simulator opens
12 | - Connect debugging *(~1min)*
13 | - Open **React Native Debugger**
14 | - Shake your device to open the development menu
15 | - Press `Debug JS Remotely`
16 | - Your app should now be connected to your debugger
17 | - ***Check:*** You can see the source code in React Native Debugger's *sources* pane
18 |
19 |
--------------------------------------------------------------------------------
/react-native/debugging/debug-native-android.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Debug on Android
2 |
3 | ## Owner: [Yann Leflour](https://github.com/yleflour)
4 | ## Debug Android code
5 | ### Prerequisites
6 |
7 | - [ ] Have [Android Studio](https://developer.android.com/studio/index.html) installed
8 | ## Steps
9 |
10 | - Open **Android Studio**
11 | - Click on *File > Open*
12 | - Navigate to and open */android*
13 | - Run in debug mode from **Android Studio**
14 |
15 | ## Log Android Errors
16 |
17 | ### Prerequisites
18 |
19 | - [ ] Have [Pidcat](https://github.com/JakeWharton/pidcat) installed
20 |
21 | ## Steps
22 |
23 | - Connect the Android phone to your computer
24 | - Make sure that the phone is available from your computer: `adb devices`
25 | - Run: `pidcat `
26 | - See all the logs related to your app, requests, native and javascript logs and errors, etc.
27 |
--------------------------------------------------------------------------------
/react-native/debugging/debug-native-ios.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Debug Native iOS Code
2 |
3 | ## Prerequisites
4 |
5 | - [ ] Have [XCode installed](https://developer.apple.com/xcode/) installed
6 |
7 | ## Steps
8 |
9 | 1. From your project root run `open ios/.xcworkspace` if the file exists or `open ios/.xcodeproj`
10 | 2. In Xcode press the play button to run in debug mode
11 |
--------------------------------------------------------------------------------
/react-native/debugging/debug-network-calls.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Debug Network calls in React Native debuggers *(~1 min)*
2 |
3 | ## Owner: Alexandre Moureaux
4 |
5 | ## Prerequisites *(~5 min)*
6 | - [ ] You know how to [debug javascript](/react-native/debugging/debug-javascript.mo.md)
7 |
8 | ## Steps *(~1min)*
9 |
10 | - Follow https://github.com/bamlab/react-native-debugger-utils#installation
11 | - Add this code in your app: https://github.com/bamlab/react-native-debugger-utils#debug-network-calls
12 | - Refresh your page with the React Native debugger open and go the network tab
13 | - [Star the repo](https://github.com/bamlab/react-native-debugger-utils) if it works ;)
14 |
--------------------------------------------------------------------------------
/react-native/debugging/debug-two-ios-apps-simultaneously.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Debug two iOS apps simultaneously
2 |
3 | ## Owner: [Xavier Lefèvre](https://www.github.com/xavierlefevre)
4 |
5 | ## Last update date: 29th of January 2018
6 |
7 | ### Prerequisites
8 |
9 | * Having already installed and launched each app before
10 | * Using [React Native Debugger](https://github.com/jhen0409/react-native-debugger)
11 |
12 | ### Steps
13 |
14 | * For the first application, you can launch it as you would normally:
15 |
16 | * Open it with xcode `xcode ./ios/your-first-app.xcworkspace`
17 | * Open React Native Debugger
18 | * Launch the simulator from xcode with the play button on the top left
19 |
20 | {% hint style='success' %} **CHECK**
21 | In RN debugger, you can see logs from the first app.
22 | {% endhint %}
23 |
24 | * For the second application:
25 |
26 | * Open it with xcode `xcode ./ios/your-second-app.xcworkspace`
27 | * Modify the port used by the packager in the native code:
28 | * Do a full project search with "Maj + Cmd + F"
29 | * Look for "8081"
30 | * Replace "8081" by a new port, like "9980"
31 | * Save each change
32 | * In React Native Debugger:
33 | * Open a new window "Cmd + T"
34 | * Enter your new port "9980"
35 | * Launch the simulator from xcode with the play button
36 | * Launch a new packager from your project directory: `react-native start --port 9980`
37 | * Close and re-open the app from within the simulator
38 |
39 | {% hint style='success' %} **CHECK**
40 | In the other RN debugger, you can see logs from the second app.
41 | {% endhint %}
42 |
43 | * You are good to go! Both apps are now running with separate packagers and separate debuggers.
44 |
--------------------------------------------------------------------------------
/react-native/debugging/debug-webviews.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Debug a React Native WebView *(~5 min)*
2 |
3 | ## Owner: [Louis Zawadzki](https://github.com/louiszawadzki)
4 |
5 | ## Prerequisites
6 | - [ ] A React Native application with a WebView
7 | - [ ] Safari if you want to debug on an iOS device
8 |
9 | ## Steps iOS *(~2min)*
10 |
11 | - Run your app on your iOS simulator
12 | - Open Safari
13 | - Enable the "Develop" menu:
14 | - Pull down the "Safari" menu and choose "Preferences"
15 | - Click on the "Advanced" tab
16 | - Check the box next to "Show Develop menu in menu bar"
17 | - Pull down the "Develop" menu
18 | - Click on "Simulator" that should be right below your computer
19 | - Select your WebView in the menu
20 |
21 | ## Steps Android *(~3min)*
22 |
23 | - In your `android/app/src/main/java/com/applilabchatbot/MainApplication.java` add `import android.webkit.WebView;` in the imports and the following line in your `onCreate` method:
24 |
25 | ```java
26 | @Override
27 | public void onCreate() {
28 | super.onCreate();
29 | SoLoader.init(this, /* native exopackage */ false);
30 | + WebView.setWebContentsDebuggingEnabled(true);
31 | }
32 | ```
33 |
34 | - Launch your app
35 | - Open Chrome
36 | - Go to [chrome://inspect](chrome://inspect)
37 | - Select your WebView under your device name
38 |
39 | ### Common WebViews pitfalls
40 |
41 | - To inject Javascript you have to set your WebView's `javaScriptEnabled` prop to `true`
42 | - On Android, you can't use arrow functions in the injected javascript
43 | - `window.postMessage` might not be available straight away in your injected Javascript, to make sure it's the case you can wrap your injected code by a setTimeout like this:
44 |
45 | ```js
46 | setTimeout(function() {
47 | /* your injected js goes here */
48 | }, 0)
49 | ```
50 |
--------------------------------------------------------------------------------
/react-native/debugging/get-ios-logs.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Get iOS Logs
2 |
3 | ## Owner: [Julien Nassar](https://github.com/juliennassar)
4 |
5 | ## Why / context
6 |
7 | If you want to debug native modules (crash, production app...) it is important to have logs. This standard is a way to get them.
8 |
9 | ### Prerequisites
10 |
11 | - [ ] Have Xcode installed
12 |
13 | ## Steps
14 |
15 | - Open **Xcode**
16 | - Click on *window > Devices and simulators*
17 | - Select your device and open logs in the window
18 |
19 | {% hint style='success' %} **CHECK**
20 |
21 | 
22 |
23 | {% endhint %}
24 |
--------------------------------------------------------------------------------
/react-native/debugging/handle-gradle-dependencies-clash.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Handle version conflicts between Gradle dependencies
2 |
3 | ## Owner: [Louis Zawadzki](https://github.com/louiszawadzki)
4 |
5 | ## Prerequisites:
6 |
7 | You have 2 dependencies that depend on different versions of the same package, so your Android build will fail with an error like:
8 |
9 | ```
10 | com.android.dex.DexException: Multiple dex files define google/android/play-services/iid/R$anim;
11 | ```
12 |
13 | If you're having an issue with Google Maps and Firebase you can have a look at [this article](https://medium.com/@suchydan/how-to-solve-google-play-services-version-collision-in-gradle-dependencies-ef086ae5c75f).
14 |
15 | ## Steps:
16 |
17 | ### 1. Find out which dependencies is causing the issue *(~2min)*
18 |
19 | First, you need to figure out which package is causing the dependency issue.
20 |
21 | Versions conflicts break your build when one method is present in one version and not in another.
22 |
23 | **N.B.**: You can potentially have versions conflicts without any issue. Similarly your build can pass but you can still have issues if the logic inside a function has been changed.
24 |
25 | Look at your error to know exactly which package is causing the issue (in the previous example it's probably `com.google.android.gms:play-services-iid`)
26 |
27 | Then you must find out which version should be set.
28 |
29 | To do so, run `cd android && ./gradlew app:dependencies && cd ..`.
30 | This will print out your tree of dependencies.
31 |
32 | In there, you must look for two instances of the dependency but with different versions.
33 | For example if it returns:
34 |
35 | ```
36 | _debugCompile - ## Internal use, do not manually configure ##
37 | +--- project :react-native-maps
38 | | +--- com.google.android.gms:play-services-base:11.1.6
39 | | \--- com.google.android.gms:play-services-basement:11.1.6
40 | +--- com.salesforce.marketingcloud:marketingcloudsdk:5.3.+ -> 5.3.1
41 | | +--- com.google.android.gms:play-services-gcm:11.0.1 -> 11.1.6
42 | | | \--- com.google.android.gms:play-services-iid:11.0.1 -> 11.1.6
43 | | | +--- com.google.android.gms:play-services-base:11.0.1 -> 11.1.6 (*)
44 | | | \--- com.google.android.gms:play-services-basement:11.0.1 -> 11.1.6 (*)
45 | ```
46 |
47 | A quick note on how to read this tree:
48 |
49 | - `(*)` indicates that this lib is already installed higher in the tree
50 | - `->` indicates that a different version of the library was installed
51 |
52 | You can see here for example that `com.google.android.gms:play-services-base` version is 11.1.6 for `react-native-maps` and version 11.0.1 for `com.salesforce.marketingcloud:marketingcloudsdk`, therefore forcing `com.google.android.gms:play-services-iid` to be at version 11.1.6.
53 |
54 |
55 | ### 2. Force dependency to use a specific version
56 |
57 | If the highest version of the dependency does not work, your next guess has to be the lowest one required by your dependencies.
58 |
59 | So now in your `android/app/build.gradle` you need to:
60 |
61 | - Tell `react-native-maps` not to compile `com.google.android.gms:play-services-base`:
62 | ```
63 | compile(project(':react-native-maps')){
64 | exclude group: 'com.google.android.gms', module: 'play-services-base'
65 | }
66 | ```
67 |
68 | - Tell `com.salesforce.marketingcloud:marketingcloudsdk` not to compile `com.google.android.gms:play-services-base`:
69 | ```
70 | compile('com.salesforce.marketingcloud:marketingcloudsdk:5.3.+') {
71 | exclude group: 'com.google.android.gms', module: 'play-services-base'
72 | }
73 | ```
74 |
75 | - Force the version of `com.google.android.gms:play-services-base` to be the lowest one, i.e. 11.0.1:
76 | ```
77 | compile ("com.google.android.gms:play-services-base:11.0.1") {
78 | force = true;
79 | }
80 | ```
81 |
82 | - **Run `cd android && ./gradlew clean && cd ..`** to update the dependencies
83 |
84 |
85 | > **Check:** your dependency tree should look like this:
86 |
87 | ```
88 | _debugCompile - ## Internal use, do not manually configure ##
89 | +--- project :react-native-maps
90 | +--- com.salesforce.marketingcloud:marketingcloudsdk:5.3.+ -> 5.3.1
91 | | +--- com.google.android.gms:play-services-gcm:11.0.1
92 | | | \--- com.google.android.gms:play-services-iid:11.0.1
93 | | | +--- com.google.android.gms:play-services-base:11.0.1 (*)
94 | | | \--- com.google.android.gms:play-services-basement:11.0.1 (*)
95 | +--- com.google.android.gms:play-services-maps:11.0.1
96 | | +--- com.google.android.gms:play-services-base:11.0.1 (*)
97 | | \--- com.google.android.gms:play-services-basement:11.0.1 (*)
98 | +--- com.google.android.gms:play-services-base:11.0.1 (*)
99 | ```
100 |
101 | Note that now `com.google.android.gms:play-services-base`'s version is 11.0.1
102 |
103 | > **Check:** when you launch your build it either passes or error with a different error
104 |
105 |
106 | ### 3. Repeat if you have a different error
107 |
108 | It's possible that the lib you've downgraded relies on a version of another lib that conflicts with another dependency so you will have to repeat this with this new dependency until your build passes :)
109 |
110 | It's also possible that the lowest version does not have a method required by the highest version.
111 | In this case you can try a version between the two that works.
112 | It's possible that there is no version that works.
113 |
--------------------------------------------------------------------------------
/react-native/features/clean-logout.s.md:
--------------------------------------------------------------------------------
1 | # [Standard] Implementing a clean logout
2 |
3 | ## Owner: [Louis Lagrange](https://github.com/Minishlink)
4 |
5 | ## Checks
6 |
7 | You should remove all persisted and in-memory user content after a logout.
8 | You should logout from every external services silently.
9 |
10 | * If my project uses `react-apollo`
11 | * the cache is cleared with [client.resetStore](https://www.apollographql.com/docs/react/advanced/caching.html#reset-store)
12 | * If my project uses `redux`
13 | * there is a `LOGOUT` or `RESET_CUSTOMER_DATA` action that replaces the user reducers' states with the initial states
14 | * If my project uses React-Native `AsyncStorage`
15 | * the cache is cleared with [AsyncStorage.clear](https://facebook.github.io/react-native/docs/asyncstorage.html#clear), or [AsyncStorage.multiRemove](https://facebook.github.io/react-native/docs/asyncstorage.html#multiremove) if you need to target only some keys.
16 | * Errors should be caught and handled
17 |
18 | ## Good examples
19 |
20 | ```js
21 | // pseudo code
22 | const logout = async () => {
23 | try {
24 | await fetch('ZENDESK_LOGOUT_URL', { method: 'GET' });
25 | await firebase.auth().signOut();
26 | await AsyncStorage.clear();
27 | ReduxStore.dispatch(resetCustomerData());
28 | apolloClient.resetStore();
29 | Navigation.navigate('login');
30 | } catch (e) {
31 | HandleErrorService.handleError(e);
32 | // eventually show an error or retry
33 | }
34 | }
35 | ```
36 |
37 | ## Bad examples
38 |
39 | ### Example 1
40 |
41 | Without cleaning the user data, you will have state and data inconsistencies with the new user.
42 |
43 | ```js
44 | // pseudo code
45 | const logout = async () => {
46 | Navigation.navigate('login');
47 | }
48 | ```
49 |
50 | ### Example 2
51 |
52 | Without the `try catch`, the app will crash if the user has no connection, or if another error happens.
53 |
54 | ```js
55 | // pseudo code
56 | const logout = async () => {
57 | await fetch('ZENDESK_LOGOUT_URL', { method: 'GET' });
58 | await firebase.auth().signOut();
59 | await AsyncStorage.clear();
60 | ReduxStore.dispatch(resetCustomerData());
61 | apolloClient.resetStore();
62 | Navigation.navigate('login');
63 | }
64 | ```
--------------------------------------------------------------------------------
/react-native/features/deep-linking.md:
--------------------------------------------------------------------------------
1 | # [MO] How to implement deep linking with react-navigation
2 |
3 | ## Owner : [Nicolas Ngomai](https://github.com/lechinoix)
4 |
5 | * What is deep linking?
6 |
7 | Deeplinking permits you to register a custom URL Scheme in your phone so that when calling a url as `myapp://mypath?param=value` the phone will open the app with the `mypath?param=value`.
8 | In React Native, you can use the `Linking Module` that handle the external links in your app.
9 | When calling a deeplink in your app, a 'url' event will be dispatch with the url associated.
10 |
11 | ## How to implement?
12 |
13 | - Follow this guide from react navigation: https://reactnavigation.org/docs/en/deep-linking.html
14 | - For complementary information, you can consult Linking documentation : https://facebook.github.io/react-native/docs/linking.html
15 |
16 | ## Troubleshooting
17 |
18 | ### iOS
19 |
20 | If you have Facebook SDK installed, a "application" function will already be implemented in your AppDelegate.m
21 | You will need to refactor the two methods as is:
22 |
23 | ```objectivec
24 | - (BOOL)application:(UIApplication *)application
25 | openURL:(NSURL *)url
26 | options:(NSDictionary *)options {
27 |
28 | if([[FBSDKApplicationDelegate sharedInstance] application:application
29 | openURL:url
30 | sourceApplication:options[UIApplicationOpenURLOptionsSourceApplicationKey]
31 | annotation:options[UIApplicationOpenURLOptionsAnnotationKey]
32 | ]){
33 | return YES;
34 | }
35 | else if([RCTLinkingManager application:application openURL:url options:options]){
36 | return YES;
37 | }
38 |
39 | return NO;
40 | }
41 |
42 | ```
43 |
44 | ### Android
45 |
46 | If you already have an intent-filter in your MainApplication, had a different one just beside
47 |
48 | ```xml
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | ```
61 |
62 |
--------------------------------------------------------------------------------
/react-native/features/icomoon.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Add new icons to the application
2 |
3 | ## Owner: [Amaury Liet](http://github.com/AmauryLiet/)
4 |
5 | ## Prerequisites
6 |
7 | - A running React Native app, preferably started with the generator
8 |
9 |
10 | ## Intro
11 |
12 | To add new icons to the app, you need to update 3 files in the project.
13 |
14 | These 3 files are in the `icomoon.zip` archive: but if you only have the `*.svg` file of the icon, you need to generate the icomoon archive first.
15 |
16 | ## Prerequisites
17 |
18 | - Have the icons available (either in an `icomoon` file or a `svg` file)
19 |
20 |
21 | ## Steps
22 |
23 | ### 1. [If necessary] Generate to `icomoon.zip` file:
24 |
25 | 1. Go to [Icomoon.io](https://icomoon.io/app/#/select)
26 |
27 | 2. Click on `+ Import icons`
28 |
29 | 3. Import the `selection.json` file of the icons currently in the app, located in `src/components/Icon/selection.json`
30 |
31 | 4. Add icons on the set you just imported by clicking on the burger (on the right) then `Import to set`
32 |
33 | 5. If wanted, rename the icon by passing in `edit` mode (click on the pencil on top of the screen) then click on the icons to rename
34 |
35 | 6. Select the icons you want to export (by default select all of them)
36 |
37 | 7. On the bottom of the screen, click `Generate font` then `Download`
38 |
39 |
40 | ## 2. Add the icons to the application
41 |
42 | 1. Open the `icomoon.zip` file
43 |
44 | 2. Overwrite the following files:
45 | - `android/app/src/main/assets/fonts/icomoon.ttf`
46 | - `src/components/Icon/selection.json`
47 | - `resources/icons/icomoon.ttf`
48 |
49 |
50 | > :warning: **If you are using code-push, don't forget to hard deploy**
51 | >
52 | > Deploying with CodePush will **not** update the icons of the app
53 |
54 |
--------------------------------------------------------------------------------
/react-native/features/lock-device-orientation.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Lock the device screen
2 |
3 | ## Owner: [Kévin Jean](https://github.com/Miniplop)
4 |
5 | ## Prerequisites
6 | - A running React Native app, preferably started with the generator
7 |
8 | ## Steps
9 |
10 | - Follow [this](https://github.com/yamill/react-native-orientation/blob/master/README.md) to install react-native-orientation
11 |
12 | > :warning: Do not forget to rebuild your app
13 |
14 | ### Lock all the app pages
15 |
16 | > :warning: Do not lock the screen rotation on react-native-camera or other native modules which needs screen rotation
17 |
18 | We need to lock all the app pages, to do so import react-native-orientation in our top component:
19 |
20 | `import Orientation from 'react-native-orientation`
21 |
22 | Add those lines to lock the orientation:
23 |
24 | ```
25 | componentWillMount () {
26 | Orientation.lockToPortrait()
27 | }
28 | ```
29 |
30 | - Refresh your app, and try to rotate your screen
31 |
32 | - [Star the repo](https://github.com/yamill/react-native-orientation) if it works ;)
33 |
--------------------------------------------------------------------------------
/react-native/features/offline-redux.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Implementing offline read and write feature
2 |
3 | ## Owner: [Maxime Sraïki](https://github.com/sraikimaxime)
4 |
5 | ## Control Points
6 |
7 | {% hint style='success' %}
8 |
9 | If you want to make your application work offline, you'll need to check that
10 |
11 | {% endhint %}
12 |
13 | * [ ] Data are persisted accross application restart
14 | * [ ] Your user is aware of its connectivity state
15 | * [ ] When you're offline, you gracefully handle the network interraction for the user
16 |
17 | ## Motivation
18 |
19 | Your application has to be used in a low connectivity context (abroad, far from towns, in the subway, in Darius's house, ...)
20 |
21 | ## Prerequisites
22 |
23 | * [ ] Working with React-Native app
24 | * [ ] Using Redux as an application state manager
25 |
26 | {% hint style='info' %} MobX User ?
27 |
28 | If you're using Mobx, [check this out](./offline-mobx.mo.md)
29 |
30 | {% endhint %}
31 |
32 | ## Steps
33 |
34 | ## Knowing wether or not you're offline (~20min)
35 |
36 | ## Reading data offline (~15m)
37 |
38 | {% hint style='success' %} **Control points**
39 |
40 | * [ ] Persist some data
41 | * [ ] Kill your app
42 | * [ ] Turn it to plane mode
43 | * [ ] Open your app
44 | * [ ] See your data
45 |
46 | {% endhint %}
47 |
48 | Use [`redux-persist`](https://github.com/rt2zz/redux-persist).
49 |
50 | ## Writing data offline (~30m)
51 |
52 | ### With Redux-Offline
53 |
54 | You can use [`redux-offline`](https://github.com/redux-offline/redux-offline), basically it provides you with all the ACTION, COMMIT, ROLLBACK logic that let you implement optimistic or defensive offline design.
55 |
56 | To build something optimistic, do the state change on the ACTION, leave the COMMIT empty and rewind the application state on the ROLLBACK.
57 |
58 | To build something defensive, change to a pending state on the ACTION and do the definitive state modification on the COMMIT only, the ROLLBACK is still a rewind of the application state.
59 |
60 | If you are also implementing sagas, take a look at [this issue](https://github.com/redux-offline/redux-offline/issues/173)
61 |
62 | ### Without Redux Offline
63 |
64 | We also implemented writing feature without redux offline on a project @BAM, let me know if you want to know more !
65 |
66 | ## Tips & TroubleShoot
67 |
68 | * In order to be able to detect this, you can use the react-native's [`NetInfo.isConnected`](https://facebook.github.io/react-native/docs/netinfo.html#docsNav) function to get the connectivity status your phone thinks it has.
69 |
70 | * There are ways to check user's connectivity by pinging one of your own server routes instead of basing it on the phone self awareness of its connectivity.
71 |
72 | * We did not implement offline calls that would need conflict management (several users able to access the same data at the same time) yet.
73 |
--------------------------------------------------------------------------------
/react-native/firebase/assets/example-tickets.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bamlab/dev-standards/f07fee937df828f63daa6d0dffc36ac9c4e78bbc/react-native/firebase/assets/example-tickets.png
--------------------------------------------------------------------------------
/react-native/firebase/assets/firebase-debug-view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bamlab/dev-standards/f07fee937df828f63daa6d0dffc36ac9c4e78bbc/react-native/firebase/assets/firebase-debug-view.png
--------------------------------------------------------------------------------
/react-native/firebase/assets/xcode-firebase-debug-setup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bamlab/dev-standards/f07fee937df828f63daa6d0dffc36ac9c4e78bbc/react-native/firebase/assets/xcode-firebase-debug-setup.png
--------------------------------------------------------------------------------
/react-native/firebase/debug-events.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Good practices to debug events in Firebase
2 |
3 | ## Owner: [Thomas Pucci](https://github.com/tpucci)
4 |
5 | ## Prerequisites
6 |
7 | * [React Native Firebase](https://github.com/invertase/react-native-firebase) is installed on your project
8 | * You want to track one event
9 |
10 | ## Scrum
11 |
12 | Validating events tracking with Firebase should be done with two tickets:
13 |
14 | 1. You should have one ticket to send the event to Firebase which your PO will validate with a screenshot.
15 | 2. You should have a second ticket to track your event and its parameters on Firebase and save it (this ticket is dependant of the previous one and **can be treated one day after the first ticket is completed**).
16 |
17 | _Example:_
18 |
19 | 
20 |
21 | ## Steps
22 |
23 | ### Set up your device in debug mode (10min)
24 |
25 | Choose to start with either Android or iOS. Once you've finished with an OS, switch to the other.
26 |
27 | #### iOS
28 |
29 | 1. in Xcode, edit the product's scheme.
30 |
31 | {% hint style='info' %}
32 |
33 | Go in **Product**, **Scheme ▶**, **Edit Scheme... ⌘<** or use the shortcut **⌘<**.
34 |
35 | {% endhint %}
36 |
37 | 2. In the left menu, select **Run**. Select the **Arguments** tab.
38 | 3. In the **Arguments passed on launch** section, click the **+** icon (_Add items_).
39 | 4. Type in `-FIRDebugEnabled` and hit enter.
40 | 5. Close the modal.
41 | 6. Build your application and run it on your simulator or device.
42 |
43 | 
44 |
45 | {% hint style='success' %} **CHECK**
46 |
47 | 1. In Firebase, in the left menu, go in **Analytics**, **Debug View**.
48 | 2. Select your application in the top menu.
49 | 3. Your debug devices count should print: **APPAREIL DE DÉBOGAGE: 1**
50 |
51 | {% endhint %}
52 |
53 | #### Android
54 |
55 | 1. Run your simulator or connect your device.
56 |
57 | {% hint style='success' %} **CHECK**
58 |
59 | Running the command `adb devices` in your shell should display your device ID.
60 |
61 | ```bash
62 | List of devices attached
63 | emulator-5554 device
64 | ```
65 |
66 | {% endhint %}
67 |
68 | 2. Run the following command: `adb shell setprop debug.firebase.analytics.app `
69 |
70 | {% hint style='success' %} **CHECK**
71 |
72 | 1. In Firebase, in the left menu, go in **Analytics**, **Debug View**.
73 | 2. Select your application in the top menu.
74 | 3. Your debug devices count should print: **APPAREIL DE DÉBOGAGE: 1**
75 |
76 | {% endhint %}
77 |
78 | ### Use react-native-firebase API to track events (10min)
79 |
80 | 1. Use `logEvent` method.
81 |
82 | _Exemple:_
83 |
84 | ```js
85 | import firebase from "react-native-firebase";
86 |
87 | const firebaseAnalytics = firebase.analytics();
88 |
89 | export default class Analytics {
90 | static trackEvent(eventName, params) {
91 | firebaseAnalytics.logEvent(eventName, params);
92 | }
93 | }
94 | ```
95 |
96 | 2. In your simulator or on your device, do the action which rises the event.
97 |
98 | {% hint style='success' %} **CHECK**:
99 |
100 | 1. In Firebase, in the left menu, go in **Analytics**, **Debug View**.
101 | 2. Select your application in the top menu.
102 | 3. You should see your events with their parameters
103 | 
104 |
105 | {% endhint %}
106 |
107 | 2. (bis) Do the same for Android and iOS.
108 |
109 | ### Complete your task (10min)
110 |
111 | 3. Take a screenshot of the event(s) **with their parameters** your ticket aims to implement. (To see the parameters received by Firebase, click on one event)
112 |
113 | 4. Commit your work **except all modifications to `.xcodeproj`**
114 |
115 | 5. Create your pull request
116 |
117 | 6. Once merged, attach your screenshot to your first ticket which aims to track the event.
118 |
119 | 7. Deploy your changes, and do the action which rises the event on your Staging Application.
120 |
121 | 8. Put your first ticket to validation and add a due date to the second ticket to tomorrow.
122 |
123 | ### Check that your event is tracked and track your event parameters (1 day waiting + 10min)
124 |
125 | 9. In Firebase, in the left menu, go in **Analytics**, **Events**.
126 |
127 | 10. Check that your event is in the list. If not, either something went wrong in the previous steps either Google has not reported any events yet (or Google is down).
128 |
129 | 11. To track parameter, click on your event then on the 'Add parameters' button.
130 |
131 | ## (Optionnal) remove debug mode (10min)
132 |
133 | #### iOS
134 |
135 | Either stash your changes on `.xcodeproj` or do the following:
136 |
137 | 1. in Xcode, edit the product's scheme.
138 |
139 | {% hint style='info' %}
140 |
141 | Go in **Product**, **Scheme ▶**, **Edit Scheme... ⌘<** or use the shortcut **⌘<**.
142 |
143 | {% endhint %}
144 |
145 | 2. In the left menu, select **Run**. Select the **Arguments** tab.
146 | 3. In the **Arguments passed on launch** section, remove `-FIRDebugEnabled` click the **+** icon (_Add items_).
147 | 4. Type in `-FIRDebugDisabled` and hit enter.
148 | 5. Close the modal.
149 | 6. Build your application and run it on your simulator or device.
150 |
151 | 
152 |
153 | {% hint style='success' %} **CHECK**
154 |
155 | 1. In Firebase, in the left menu, go in **Analytics**, **Debug View**.
156 | 2. Select your application in the top menu.
157 | 3. Your debug devices count should print: **APPAREIL DE DÉBOGAGE: 0**
158 |
159 | {% endhint %}
160 |
161 | #### Android
162 |
163 | 1. Reload the app in your simulator or your device.
164 |
165 | {% hint style='success' %} **CHECK**
166 |
167 | Running the command `adb devices` in your shell should display your device ID.
168 |
169 | ```bash
170 | List of devices attached
171 | emulator-5554 device
172 | ```
173 |
174 | {% endhint %}
175 |
176 | 2. Run the following command: `adb shell setprop debug.firebase.analytics.app .none.`
177 |
178 | {% hint style='success' %} **CHECK**:
179 |
180 | 1. In Firebase, in the left menu, go in **Analytics**, **Debug View**.
181 | 2. Select your application in the top menu.
182 | 3. Your debug devices count should print: **APPAREIL DE DÉBOGAGE: 0**
183 |
184 | {% endhint %}
185 |
--------------------------------------------------------------------------------
/react-native/package-dependencies/handle-dependencies-with-yarn-override.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Handle dependencies with Yarn override
2 |
3 | ## Owner: [Justine Mignot](https://github.com/justinemignot)
4 |
5 | > **Note**: Please create an [issue](https://github.com/bamlab/dev-standards/issues/new) or even a Pull Request with your feedback, typo correction.
6 |
7 | ## Context
8 |
9 | During this standard, we will go through how to handle versions dependencies of different packages to a same package.
10 |
11 | If some package doesn't use same versions of a package, depending of the order it will be called, it won't be the same version of package used.
12 | We want to ensure that the same version is used everywhere in the app.
13 |
14 | Normally this would require to manually edit `yarn.lock` file, but it is really bad because this file is deleted each time you install a new package or run a yarn command.
15 |
16 | By chance, yarn has a feature override, which allows us to fix those versions dependencies.
17 |
18 | ## Prerequisites
19 |
20 | * Have a react native app installed
21 | * Install `moment-timezone` (version "0.5.13")
22 | * Install `react-native-datepicker` (version "1.6.0")
23 |
24 | ## Steps
25 |
26 | ### Figure out a problem
27 |
28 | * Identify the case:
29 | * you just installed a new package (I just installed `react-native-datepicker`) and there is a regression in the app (in my case `moment.locale()` was not working anymore)
30 | * you're trying to set a parameter of a package (e.g. the default locale of `moment`) but it's not taken into account by another package
31 | * Then open `yarn.lock`:
32 | * look for your newly installed package
33 | \* look for this package dependencies:
34 |
35 | ```
36 | react-native-datepicker@^1.6.0:
37 | react-native-datepicker@^1.6.0:
38 | version "1.6.0"
39 | resolved "https://registry.yarnpkg.com/react-native-datepicker/-/react-native-datepicker-1.6.0.tgz#3a40dc9b112023c49d60ba2a0789d440b7e3d97c"
40 | dependencies:
41 | moment "2.x.x"
42 | ```
43 |
44 | * try to find other packages which depends on another version of `moment`
45 | * search for `moment` in `yarn.lock`
46 | * if another package depends on it but in another version, several lines for `moment` will appear:
47 |
48 | ```
49 | "moment@2.x.x":
50 | version "2.20.1"
51 | resolved "https://registry.yarnpkg.com/moment/-/moment-2.20.1.tgz#d6eb1a46cbcc14a2b2f9434112c1ff8907f313fd"
52 |
53 | "moment@>= 2.9.0":
54 | version "2.18.1"
55 | resolved "https://registry.yarnpkg.com/moment/-/moment-2.18.1.tgz#c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f"
56 |
57 | moment@^2.19.0:
58 | version "2.19.1"
59 | resolved "https://registry.yarnpkg.com/moment/-/moment-2.19.1.tgz#56da1a2d1cbf01d38b7e1afc31c10bcfa1929167"
60 | ```
61 |
62 | * find which other package it is by searching for `moment` in dependencies section of packages:
63 |
64 | ```
65 | moment-timezone@^0.5.13:
66 | version "0.5.14"
67 | resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.14.tgz#4eb38ff9538b80108ba467a458f3ed4268ccfcb1"
68 | dependencies:
69 | moment ">= 2.9.0"
70 | ```
71 |
72 | ### Solve the problem
73 |
74 | * In `package.json` file, add a section 'resolutions' at the same level as the 'dependencies' section.
75 | * Specify to which version of `moment` depend the two packages, choose same version number for both:
76 |
77 | ```json
78 | "dependencies": {
79 | ...
80 | },
81 | "resolutions": {
82 | "react-native-datepicker/moment": "2.19.1",
83 | "moment-timezone/moment": "2.19.1"
84 | },
85 | ```
86 |
87 | * If the package is a dependency of your app, you'll need to set its version in the `package.json`:
88 |
89 | ```json
90 | "dependencies": {
91 | "moment": "2.19.1"
92 | },
93 | "resolutions": {
94 | "react-native-datepicker/moment": "2.19.1",
95 | "moment-timezone/moment": "2.19.1"
96 | }
97 | ```
98 |
99 | * Run `yarn install`.
100 |
101 | {% hint style='success' %} **CHECK 1**
102 |
103 | Check your yarn.lock file, `moment` should appears in only one line:
104 |
105 | ```txt
106 | moment@2.19.1, moment@2.x.x, "moment@>= 2.9.0", moment@^2.19.0:
107 | version "2.19.1"
108 | resolved "https://registry.yarnpkg.com/moment/-/moment-2.19.1.tgz#56da1a2d1cbf01d38b7e1afc31c10bcfa1929167"
109 | ```
110 |
111 | which means that every package depending on `moment` is resolved to a same version (here 2.19.1).
112 |
113 | {% endhint %}
114 |
115 | {% hint style='success' %} **CHECK 2**
116 |
117 | Your app should works correctly now, regression should be solved. `moment` dependencies are solved.
118 |
119 | {% endhint %}
120 |
121 | ## Troubleshooting
122 |
123 | * Yarn documentation : https://yarnpkg.com/en/docs/selective-version-resolutions
124 |
--------------------------------------------------------------------------------
/react-native/react-navigation/unmount-compoenent-on-page-change.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Unmount a component on page change *(~14 min)*
2 |
3 | ## Owner: Nicolas Djambazian
4 |
5 | ## Motivation
6 |
7 | React-navigation doesn't unmount your page when you go on the next one. That allow fast transition when you go back.
8 |
9 | But if you are using a Camera component, a WebView or every component which use a lot of resources and can have side effect if it continue to run background, you need to unmount them when you leave the page.
10 |
11 | For that, you can use the [`getPathAndParamsForState` of a Router](https://reactnavigation.org/docs/routers/api).
12 |
13 | ## Prerequisites *(~5min)*
14 | - The page have a container.
15 | -You must have a main stack navigation exported in `src/Routing.js`
16 |
17 |
18 | ## Steps *(~5min)*
19 |
20 | - Add a props `myFeatureIsActivated` on the component with default value at `true`
21 | - In the render method, display you component only if `myFeatureIsActivated` is at true:
22 |
23 | ```jsx
24 | return (
25 |
26 | {this.props.cameraIsActivated && }
27 |
28 | );
29 |
30 | ```
31 |
32 | - Test is your component still work (nothing should have change)
33 | - Import your main stack navigation
34 | - In the mapDispatchToProps, compare the path given by the getPathAndParamsForState to the path of your page, you should have something like:
35 |
36 | ```jsx
37 | import { RootNavigator } from '../../../Routing';
38 |
39 | const mapStateToProps = state => ({
40 | cameraActivated: RootNavigator.router.getPathAndParamsForState(state.navigation).path === 'path/of/the/page/in/navigation/stacks',
41 | });
42 | ```
43 |
44 | The path is given by your navigation stacks. In the following example, the path of `SIMCardScan` is `activate/simCardScan`
45 |
46 | ```jsx
47 | const ActivateStack = StackNavigator(
48 | {
49 | welcome: {
50 | screen: Pages.SignUp.RequiredToActivateSim,
51 | },
52 | simCardScan: {
53 | screen: Pages.SignUp.SIMCardScan,
54 | },
55 | },
56 | {
57 | initialRouteName: 'welcome,
58 | }
59 | );
60 |
61 | export const RootNavigator = StackNavigator(
62 | {
63 | landing: {
64 | screen: LandingPage,
65 | },
66 | activate: {
67 | screen: ActivateStack,
68 | },
69 | },
70 | {
71 | initialRouteName: 'landing',
72 | navigationOptions: {
73 | headerStyle: styles.header,
74 | headerTintColor: theme.headerTextColor,
75 | },
76 | headerMode: 'screen',
77 | }
78 | );
79 | ```
80 |
81 | - Test a last time, your component should disappear at the beginning of the page transition.
82 |
83 |
--------------------------------------------------------------------------------
/react-native/react/assets/withUncle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bamlab/dev-standards/f07fee937df828f63daa6d0dffc36ac9c4e78bbc/react-native/react/assets/withUncle.png
--------------------------------------------------------------------------------
/react-native/react/assets/withoutUncle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bamlab/dev-standards/f07fee937df828f63daa6d0dffc36ac9c4e78bbc/react-native/react/assets/withoutUncle.png
--------------------------------------------------------------------------------
/react-native/react/binding-functions-in-react-component.s.md:
--------------------------------------------------------------------------------
1 | # [Standard] Binding functions in react components
2 |
3 | ## Owner: [Jean Faverie](https://github.com/jfaverie)
4 |
5 | > **Note**: Please create an [issue](https://github.com/bamlab/dev-standards/issues/new) or even a Pull Request with your feedback, typo correction.
6 |
7 | ## Context
8 |
9 | During this standard, we will take an example from the egghead react native tutorial when launching an event with a submit button.
10 |
11 | The tutorial does it the old ES5 way when we should better use the ES6 way (with arrow functions).
12 |
13 | ## Prerequisites (~4 min)
14 |
15 | - Have **react-native** installed (`npm i -g react-native-cli`) (~2 min)
16 | - Have a react-native project (`react-native init
37 | )
38 | }
39 | }
40 | ```
41 |
42 | - This is bad in two ways: performance and syntax.
43 |
44 | 1. Performance: the first problem here is we use `bind` at every `onChange` event, which is very costly. What we could do is (still not optimal):
45 |
46 | ```javascript
47 | class Test extends Component {
48 | // ...
49 | handleChange(event) {
50 | this.setState({
51 | username: event.nativeEvent.text,
52 | }).bind(this);
53 | }
54 | // ...
55 | render() {
56 | return (
57 |
60 | )
61 | }
62 | }
63 | ```
64 | we improve our performance, as we only bind at the creation of the class. This is not ideal though.
65 |
66 | 2. The `bind` function is used to be sure to use the good context (the `this` of the class, not the one of the handleChange function).
67 |
68 | ### Good Examples:
69 | We can improve the syntax by using an arrow function, which has no proper context and uses the context of the class (you can use tis example).
70 |
71 | ```javascript
72 | class Test extends Component {
73 | // ...
74 | handleChange = event => {
75 | this.setState({
76 | username: event.nativeEvent.text,
77 | });
78 | };
79 | // ...
80 | render() {
81 | return (
82 |
85 | )
86 | }
87 | }
88 | ```
89 |
90 | The `this` inside the arrow function `handleChange` now refers to the `Test` class.
91 |
--------------------------------------------------------------------------------
/react-native/react/enable-overflow-android.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Enable component overflow on MapView
2 |
3 | ## Owner: [Yassine Chbani](https://github.com/yassinecc)
4 |
5 | ## Motivation
6 |
7 | It is usual to position React components in such a way that every child is rendered on top of its parent. Sometimes you want to do something out of the ordinary and let one component overflow on another that is outside its parent. It turns out that Android is quite picky with this and will not render the overflowing part on MapViews. But fear not, there is a way to get around this!
8 |
9 | ## Prerequisites
10 |
11 | Our setup will include one child view that we want rendered on top of its MapView neighbour:
12 |
13 | 
14 |
15 |
16 | ## Steps (~10 minutes)
17 |
18 | - We start writing our basic views:
19 |
20 | ```jsx
21 | render () {
22 | return (
23 |
24 |
25 |
26 |
27 |
28 | // Your code goes here
29 |
30 |
31 |
32 | )
33 | }
34 | ```
35 |
36 | - The trick here is to introduce `uncle`, a fourth component which will host the child outside the parent. The uncle will have a negative `marginTop` value so that it overlaps with the previously rendered `neighbour` component:
37 |
38 | ```jsx
39 | const OVERLAP_HEIGHT = 50
40 |
41 | const styles = {
42 | uncle: {
43 | backgroundColor: 'transparent',
44 | marginTop: -OVERLAP_HEIGHT
45 | },
46 | child: {
47 | marginTop: 0
48 | },
49 | parent: {
50 | marginTop: OVERLAP_HEIGHT
51 | }
52 | neighbour: {
53 | // Another style
54 | }
55 | }
56 | ```
57 |
58 | The new layout idea is the following:
59 |
60 | 
61 |
62 | Notice how the `child` if positioned right at the top of its `uncle`. We didn't want to hide the part of `neighbour` that is at the same level as the top of the `child`, so the background color of the `uncle` is set to transparent. In `parent`'s style, we added `marginTop: OVERLAP_HEIGHT` to preserve the original vertical layout of this component with respect to `neighbour`.
63 |
64 | - The last step is to make sure that the child will be rendered on top of the parent. The easiest way it to call the child just before the end of the `uncle`. That way you don't have to deal with `zIndex` properties:
65 |
66 | ```jsx
67 | render () {
68 | return (
69 |
70 |
71 |
72 |
73 |
74 | // Parent code
75 |
76 |
77 | // Code of the child
78 |
79 |
80 |
81 | )
82 | }
83 | ```
84 |
85 |
--------------------------------------------------------------------------------
/react-native/react/get-element-size-or-position-with-onLayout.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Get the size or position of a component with onLayout
2 |
3 | ## Owner: [Julien Nassar, Gaspard Denis](https://github.com/juliennassar)
4 |
5 | ## Control Points
6 |
7 | - Hide your dynamically sized (or positioned) component with a `style={{ opacity: 0 }}` during the first rendering of your component to avoid glitches.
8 |
9 | ## Motivation
10 |
11 | If you need :
12 | - to display a list of views without previous knowlegde of their size but want them to be all the same
13 | - to know the size or position of an element on your screen dynamically (whithout explicitly describing it in the object's style)
14 |
15 | To do this, React offers a onLayout props ([see official docs](https://facebook.github.io/react-native/docs/view.html#onlayout)) in which you can pass a callback that will be executed after the rendering of a component.
16 |
17 | ## Prerequisites
18 |
19 | A React-Native app. We will take here the example of a loading bar like this one :
20 | 
21 |
22 | Your goal is to calculate the number of green pixels rows you have to display for a given loading status from 0 (0%) to 1 (100%) without previous knowledge of the loader width :
23 |
24 | ```jsx
25 | import React from 'react';
26 | import { View } from 'react-native';
27 |
28 | export default class Display extends React.Component {
29 | render() {
30 |
31 |
32 | {/* Some react component to display whatever */}
33 |
34 |
35 |
36 | }
37 | }
38 | ```
39 |
40 | We do not know the size of `LoadingBar` component but we want to display a 33% progress in the `LoadingBar`.
41 |
42 | ## Steps (~5 minutes)
43 |
44 | First add a function to your `LoadingBar` component to get its width, and pass it in the `onLayout` props of your `LoadingBar` Component, and store it in your component's state :
45 |
46 | ```jsx
47 | import React from 'react';
48 | import { View } from 'react-native';
49 |
50 | export default class LoadingBar extends React.Component {
51 | constructor(props) {
52 | super(props)
53 | this.state = {
54 | loaderWidth: 0
55 | }
56 | }
57 |
58 | measureLoadingBar = ({nativeEvent}) => this.setState({ loaderWidth: nativeEvent.layout.width });
59 |
60 | render() {
61 |
62 | {/* Here you want to display x% of your bar, x being the props 'status' passed by the component above */}
63 |
64 | }
65 | }
66 | ```
67 |
68 | The `onLayout` will generate an event when the LoadingBar is displayed. You can access any layout info with :
69 | ```
70 | const {posX, posY, width, height} = event.nativeEvent.layout
71 | ```
72 |
73 | You can now compute the number of green pixels rows with the width we just got with `onLayout` :
74 | ```
75 | const numbersOfGreenPixelsRows = this.props.status * this.state.loaderWidth
76 | ```
77 |
--------------------------------------------------------------------------------
/react-native/setup/add-cocoapods.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Add Cocoapods to your project (~10min)
2 |
3 | ## Owner: [Yann Leflour](https://github.com/yleflour)
4 |
5 | ## Prerequisites:
6 |
7 | - Have [bundler](http://bundler.io) installed
8 | - Have a *Gemfile* at the root of your project
9 |
10 | ## Steps:
11 |
12 | ### 1. Add cocoapods (~5min)
13 |
14 | - In your *Gemfile* add the line `cocoapods`
15 | - Run `bundle install`
16 | - Go into the iOS project folder (`cd ios`)
17 | - Initialize pods with `bundle exec pod init`
18 | - Add `pods` to *.gitignore*
19 | - Open the `Podfile`
20 | - Remove every *[name]Tests* target
21 | - (Optional) Remove the *[name]-tvOS* target
22 | - Run `bundle exec pod install`
23 |
24 | > **Checks:**
25 | > - You now have a *projectName.xcworkspace* file in the `ios` folder
26 | > - You can run your project by opening *projectName.xcworkspace* with XCode or `react-native run-ios`
27 | > The *pods* folder shouldn't show up in the git diffs
28 |
29 | ### 2. Add your first Pod (~2min)
30 |
31 | - Open the `Podfile`
32 | - Add `pod '', '~> '` inside the target
33 | - Run `bundle exec pod install`
34 |
35 | > **Checks:**
36 | > - The exposed *.h* file from the pod can be imported in *AppDelegate.m*
37 | > - You can run your project by opening *projectName.xcworkspace* with XCode or `react-native run-ios`
38 |
--------------------------------------------------------------------------------
/react-native/setup/assets/firebase_android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bamlab/dev-standards/f07fee937df828f63daa6d0dffc36ac9c4e78bbc/react-native/setup/assets/firebase_android.png
--------------------------------------------------------------------------------
/react-native/setup/assets/ios_steps.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bamlab/dev-standards/f07fee937df828f63daa6d0dffc36ac9c4e78bbc/react-native/setup/assets/ios_steps.png
--------------------------------------------------------------------------------
/react-native/setup/assets/stripe_basic_payment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bamlab/dev-standards/f07fee937df828f63daa6d0dffc36ac9c4e78bbc/react-native/setup/assets/stripe_basic_payment.png
--------------------------------------------------------------------------------
/react-native/setup/deploy-project-to-production.md:
--------------------------------------------------------------------------------
1 | # [MO] Setup & Deploy Project to Production - Only iOS Testflight
2 |
3 | ## Owner: [Xavier Lefèvre](github.com/xavierlefevre)
4 |
5 | ## Prerequisites
6 | - [ ] [React Native Toolbox](https://github.com/bamlab/generator-rn-toolbox)
7 | - [ ] Your client admin account on Apple Developer
8 | - [ ] Your client admin account on iTunes Connect
9 |
10 | ## Steps
11 |
12 | ### 1. Setup Production Env
13 | > Creates the necessary fastlane and JS environments files
14 | ```bash
15 | yo rn-toolbox:fastlane-env
16 | ```
17 |
18 | ***Answers***
19 | - Please confirm the project name: `` => The same as for the staging/hockeyapp setup
20 | - The name for this new environment (lowercase, no space): `production`
21 | - The name of your repository Git branch for the environment just set: `production` => Or master...
22 | - The name of the company which will be publishing this application: `Bam` => Or your client name
23 | - The app name for this environment: `` => The final App name
24 | - The App Id for this environment: `com...production`
25 | - Which platform will you use for deployment?: `AppStore`
26 | - Your git repo for match: `git@github.com:/certificates.git`
27 | - The branch you want to use for match: `` => The same as for the staging/hockeyapp setup, one Apple account means one branch usually
28 | - The developer.apple.com team id for the certificates: `**redacted**` => Can be found in Membership (on the website https://developer.apple.com)
29 | - The itunesconnect.apple.com team name: `**redacted**` => Can be found at the bottom top right
30 | - Your apple id: `**redacted**` => The username of the apple account
31 | - Your keystore password: `` => You can directly accept the generated password from the generator
32 |
33 | ### 2. Test your JS Production environment in your emulator
34 | > To make sure that your app is ready to be pushed in production, not showing or using dev tools and calling the right back-end
35 |
36 | ### 3. Generate a certificate and a provisioning profile with setup
37 | ```bash
38 | bundle exec fastlane ios setup --env=production
39 | ```
40 |
41 | ### 4. Create the app on iTunes Connect
42 | - My apps > Top Left '+' > New App
43 | - Platform: `iOS`
44 | - Name: ``
45 | - Language: ``
46 | - Bundle ID: ``
47 | - SKU: ``
48 | - Create!
49 |
50 | ### 5. Launch the build process
51 | > It will sign and build your app and upload it to iTunes Connect.
52 |
53 | ```bash
54 | bundle exec fastlane ios deploy --env=production
55 | ```
56 |
57 | If there is an error due to icons, [check this doc](https://github.com/bamlab/generator-rn-toolbox/blob/master/generators/assets/README.md#generate-icons)
58 |
59 | ### 6. See your app available on Testflight internal testing
60 | - Wait: processing from Apple (can see the status in iTunes Connect > Your App > Activity)
61 | - Your app should be "green" for iTunes Connect Users: iTunes Connect > Your App > Testflight
62 | - Click: iTunes Connect Users to invite testers > '+'
63 | - Add someone that was already invited to manage this account
64 |
65 | ### 7. iTunes status
66 | This is the flow you will go through once you've uploaded your app:
67 |
68 | 
69 |
70 | Here is a website that gives the current waiting time for the review step: http://appreviewtimes.com/.
71 | The longest step is 'Waiting for Review' that can last several days.
72 |
73 | ## ToDo
74 | - Add compliance issues detail after the app arrived on iTunes Connect
75 | - Detail how to add a new user to an iTunes Connect account
76 | - Detail how to use match with an [already existing certificate](http://macoscope.com/blog/simplify-your-life-with-fastlane-match/#migration)
77 |
--------------------------------------------------------------------------------
/react-native/setup/deploy-script.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Add a deploy script to your app *(~20min)*
2 |
3 | ## Owner: [Xavier Lefèvre](https://github.com/xavierlefevre)
4 |
5 | ## Description
6 | - With one command, deploy with codepush or fastlane, android and/or ios, on the specified environment!
7 |
8 | ## Steps
9 | - Copy paste [deploy.sh](/react-native/setup/deploy.sh) to your project
10 | - Add a deploy command to your `package.json`:
11 | ```json
12 | {
13 | "scripts": {
14 | "deploy": ".//deploy.sh",
15 | ...
16 | }
17 | }
18 | ```
19 | - Adapt the script to your fastlane and codepush implementation
20 | - Deploy (depending on your implementation):
21 | ```bash
22 | yarn deploy -- -t -o -e
23 | ```
24 |
--------------------------------------------------------------------------------
/react-native/setup/deploy-to-production-android.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Deploy Project to Production on the Google Play Store
2 |
3 | ## Owner: [Yassine Chbani](github.com/yassinecc)
4 |
5 | ## Prerequisites
6 |
7 | * [ ] Your client admin account on Google Play Console
8 | * [ ] You have tested your app's critical features in its production environment
9 |
10 | ## Steps
11 |
12 | ### 1. Bump version
13 |
14 | Bump version code and version name in `fastlane/.env.prod`.
15 |
16 | ### 2. Launch the build process
17 |
18 | This will build your app and upload it to the Google Play Console.
19 |
20 | ```bash
21 | bundle exec fastlane android deploy --env=production
22 | ```
23 |
24 | ### 3. Make your app available for beta testing
25 |
26 | * Log in to [the developer console](https://play.google.com/apps/publish/) with your project's account and select your app
27 | * Go to `Release Management/App releases` in the left panel
28 | * Click on `Manage Beta` then `Create release` and upload the APK generated from the build process. This file is located at `android/app/build/outputs/apk/app-release.apk`
29 | * Rollout the beta testing and share the download link to your PO
30 |
31 | ⚠️ WARNING ⚠️ Once rolled out into production, it is not possible to directly roll back to APKs that have a lower version code. You'll have to bump the version code and rebuild your app, basically telling the Google Play console you have a new version of the app.
32 |
33 | ## 4. Update the Play Store assets
34 |
35 | If the app's icon or one of its graphics changed, you have to update them separately from the APK:
36 |
37 | * On the left panel, go to `Store presence/Store listing`
38 | * Upload your new graphics then submit your update
39 |
40 |
41 |
--------------------------------------------------------------------------------
/react-native/setup/deploy.sh:
--------------------------------------------------------------------------------
1 | #! /bin/sh
2 |
3 | RED='\033[0;31m'
4 | BLUE='\033[0;34m'
5 | CYAN='\033[0;36m'
6 | GREEN='\033[0;32m'
7 | YELLOW='\033[0;33m'
8 | NO_COLOR='\033[0m'
9 |
10 | APP_ENV="staging"
11 | APP_OS="ios and android"
12 | DEPLOY_TYPE="soft"
13 |
14 | while getopts ":e:o:t:" opt; do
15 | case $opt in
16 | e) APP_ENV="$OPTARG"
17 | ;;
18 | o) APP_OS="$OPTARG"
19 | ;;
20 | t) DEPLOY_TYPE="$OPTARG"
21 | ;;
22 | \?) echo "${RED}Invalid option -$OPTARG${NO_COLOR}" >&2
23 | ;;
24 | esac
25 | done
26 |
27 | if [ $DEPLOY_TYPE == "hard" ]; then
28 | echo "${BLUE}* * * * *"
29 | echo "👷 Hard-Deploy"
30 | echo "* * * * *${NO_COLOR}"
31 | if [[ $APP_OS != "android" ]]; then
32 | echo "${GREEN}- - - - -"
33 | echo "Fastlane 🍎 iOS $APP_ENV"
34 | echo "- - - - -${NO_COLOR}"
35 | bundle exec fastlane ios deploy --env=$APP_ENV
36 | fi
37 | if [[ $APP_OS != "ios" ]]; then
38 | echo "${YELLOW}- - - - -"
39 | echo "Fastlane 🤖 Android $APP_ENV"
40 | echo "- - - - -${NO_COLOR}"
41 | bundle exec fastlane android deploy --env=$APP_ENV
42 | fi
43 | fi
44 |
45 | if [ $DEPLOY_TYPE == "soft" ]; then
46 | echo "${CYAN}* * * * *"
47 | echo "🍦 Soft-Deploy"
48 | echo "* * * * *${NO_COLOR}"
49 |
50 | git stash
51 | git checkout integration
52 | git pull
53 |
54 | source fastlane/.env.$APP_ENV
55 | mv src/environment/index.js src/environment/index.js.bak
56 | cp src/environment/index.$APP_ENV.js src/environment/index.js
57 |
58 | LAST_GIT_COMMIT=$(git log HEAD --pretty=format:"%h : %s" -1)
59 | read -e -p "What's the changelog? (leave empty for \"$LAST_GIT_COMMIT\") " INPUT_CHANGELOG
60 | MESSAGE="${INPUT_CHANGELOG:-$LAST_GIT_COMMIT}"
61 | echo "${CYAN}Deploying Commit : $MESSAGE${NO_COLOR}"
62 |
63 | yarn
64 |
65 | if [ $APP_ENV == "production" ]; then
66 | echo "- - - - -"
67 | echo "️️️⚠️ No Codepush for Production yet"
68 | echo "- - - - -"
69 | else
70 | if [[ $APP_OS != "android" ]]; then
71 | echo "${GREEN}- - - - -"
72 | echo "Codepush 🍎 iOS Staging"
73 | echo "- - - - -${NO_COLOR}"
74 | appcenter codepush release-react -d Staging -a /-iOS -m --target-binary-version $IOS_VERSION --description "$MESSAGE"
75 | fi
76 | if [[ $APP_OS != "ios" ]]; then
77 | echo "${YELLOW}- - - - -"
78 | echo "Codepush 🤖 Android Staging"
79 | echo "- - - - -${NO_COLOR}"
80 | appcenter codepush release-react -d Staging -a /-Android -m --target-binary-version $ANDROID_VERSION_NAME --description "$MESSAGE"
81 | fi
82 | fi
83 |
84 | mv src/environment/index.js.bak src/environment/index.js
85 |
86 | fi
87 |
--------------------------------------------------------------------------------
/react-native/setup/overriding-existing-app.s.md:
--------------------------------------------------------------------------------
1 | # [Standard] When the final goal is to override an existing app
2 |
3 | ## Owner: [Alexandre Moureaux](https://github.com/almouro)
4 |
5 | ## Context
6 |
7 | You're starting a version 2 of an existing app from scratch.
8 | Replacing the existing app in the stores might be done later in the project, but there are still things to check beforehand:
9 |
10 | ## Checks
11 |
12 | ### - [ ] Check the `targetSdkVersion` of the existing version
13 |
14 | You cannot downgrade the `targetSdkVersion`, so your new project needs to have at least the same `targetSdkVersion` as the old one.
15 |
16 | :warning: **N.B.:** By default, a React Native project has `22` as its `targetSdkVersion`.
17 |
18 | `targetSdkVersion` 23 is for Android 6+ where [permissions are now asked at runtime](http://developer.android.com/training/permissions/requesting.html) and not at installation.
19 |
20 | #### Good examples
21 |
22 | So if the app you're replacing has set 23 or above as the `targetSdkVersion`, your new app needs to have at least that, and should implement permissions at runtime.
23 |
24 | You can use [react-native-permissions](https://github.com/yonahforst/react-native-permissions) to that effect.
25 |
26 | #### Bad Examples (Real story)
27 |
28 | On a project, I had not checked that. Last day on the project, we finally were overriding the existing app,but upon publishing in the Play Store, we couldn't because we were downgrading the `targetSdkVersion`.
29 |
30 | We had to spend more time on the project to use `react-native-permissions` and ask for permissions at runtime. This time would have been saved, had we checked this beforehand.
31 |
32 | ### - [ ] Use the existing app keystore
33 |
34 | Use the previous app's keystore for production builds, even if you're not replacing the app just yet.
35 |
36 | #### Bad examples (Real story)
37 |
38 | On a project, I had not used the production keystore, before the last day. The previous app's keystore had been created with an old java version and we weren't able to sign the app with it.
39 |
40 | We had to spend more time on the project to solve this issue (by updating Java).
41 |
--------------------------------------------------------------------------------
/react-native/setup/patch-react-native-android.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Patch React Native for Android (~60min)
2 |
3 | ## Owner: [Louis Zawadzki](https://github.com/louiszawadzki)
4 |
5 | ## Prerequisites:
6 |
7 | - A React Native application
8 |
9 | ## Steps:
10 |
11 | ### 1. Start downloading the Android NDK (2 minutes)
12 |
13 | - Download the NDK [here](https://facebook.github.io/react-native/docs/android-building-from-source.html#download-links-for-android-ndk) (it can take 20 to 30 minutes)
14 | - Once the download has started you can move on to the next steps
15 |
16 | ### 2. Apply your patch at deployment time (15 minutes)
17 |
18 | - Copy the files that contain the fixes inside a `fix-rn` directory at the root of the project
19 | - Create a `scripts/fix-rn.sh` file at the root of your project, looking like:
20 |
21 | ```bash
22 | #!/bin/bash
23 |
24 | cp fix-rn/rn-file.java node_modules/react-native/ReactAndroid/path/to/the/faulty/file.java
25 | cp fix-rn/rn-file2.java node_modules/react-native/ReactAndroid/path/to/the/faulty/file2.java
26 | ```
27 |
28 | for example:
29 |
30 | ```bash
31 | #!/bin/bash
32 |
33 | cp fix-rn/UIImplementation.java node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java
34 | ```
35 |
36 | - Make the file executable by running `$ chmod +x scripts/fix-rn.sh`
37 |
38 | > **Checks:**
39 | >
40 | > - when you run `$ scripts/fix-rn.sh` your files have been changed in your node modules
41 |
42 | - Add `scripts/fix-rn.sh` in the `postInstall` of your `package.json`
43 | - Make sure your run `yarn` after you've pulled the latest changes in your deployment script
44 |
45 | > **Checks:**
46 | >
47 | > - when you run your deploy script your files have been changed in your node modules
48 |
49 | ### 3. Configure your app to take the patched version of React Native (5 minutes)
50 |
51 | (This part comes from the [official React Native documentation](https://facebook.github.io/react-native/docs/android-building-from-source.html))
52 |
53 | #### Adding gradle dependencies
54 |
55 | Add gradle-download-task as dependency in `android/build.gradle`:
56 |
57 | ```groovy
58 | dependencies {
59 | classpath 'com.android.tools.build:gradle:1.3.1'
60 | classpath 'de.undercouch:gradle-download-task:3.1.2'
61 |
62 | // NOTE: Do not place your application dependencies here; they belong
63 | // in the individual module build.gradle files
64 | }
65 | ```
66 |
67 | #### Adding the :ReactAndroid project
68 |
69 | Add the :ReactAndroid project in `android/settings.gradle`:
70 |
71 | ```groovy
72 | include ':ReactAndroid'
73 |
74 | project(':ReactAndroid').projectDir = new File(
75 | rootProject.projectDir, '../node_modules/react-native/ReactAndroid')
76 | ```
77 |
78 | Modify your `android/app/build.gradle` to use the :ReactAndroid project instead of the pre-compiled library, e.g. - replace `compile 'com.facebook.react:react-native:+'` with `compile project(':ReactAndroid')`:
79 |
80 | ```groovy
81 | dependencies {
82 | compile fileTree(dir: 'libs', include: ['*.jar'])
83 | compile 'com.android.support:appcompat-v7:23.0.1'
84 |
85 | compile project(':ReactAndroid')
86 |
87 | ...
88 | }
89 | ```
90 |
91 | #### Making 3rd-party modules use your fork
92 |
93 | If you use 3rd-party React Native modules, you need to override their dependencies so that they don't bundle the pre-compiled library.
94 | Otherwise you'll get an error while compiling - `Error: more than one library with package name 'com.facebook.react'`.
95 |
96 | You don't need to change the code of all your modules.
97 | Modify your `android/app/build.gradle`, and add at the same level that `dependencies` and `android`:
98 |
99 | ```groovy
100 | configurations.all {
101 | exclude group: 'com.facebook.react', module: 'react-native'
102 | }
103 | ```
104 |
105 | ### 4. Finish NDK installation (5 minutes)
106 |
107 | - Once the NDK has been downloaded unzip it under `/Users/your_unix_name/android-ndk/` (create `android-ndk` if necessary)
108 | - Set `ANDROID_SDK` and `ANDROID_NDK` through you local shell (`.zshrc` or `.bashrc`), for example:
109 |
110 | ```bash
111 | export ANDROID_SDK=/Users/your_unix_name/android-sdk-macosx
112 | export ANDROID_NDK=/Users/your_unix_name/android-ndk/android-ndk-r10e
113 | ```
114 |
115 | - Don't forget to run `source ~/.zshrc` (or .bashrc) to get the environment variables in your current shell session
116 |
117 | > **Checks:**
118 | >
119 | > - when you run `react-native run-android` your app compiles and you can see that `:ReactAndroid` is built in the logs
120 |
--------------------------------------------------------------------------------
/react-native/setup/setup-and-deploy-new-project-to-staging-with-hockeyapp.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Setup & Deploy New Project to Staging with HockeyApp
2 |
3 | {% hint style='danger' %} **DEPRECATION**
4 |
5 | This standard has been deprecated by [@felixmeziere](https://github.com/felixmeziere) on January 28 in favour of [[MO] Deploy to staging](./setup-and-deploy-new-project-to-staging.mo.md).
6 |
7 | **Reason**: HockeyApp is meant to be deprecated by AppCenter. AppCenter is the new HockeyApp and there is [no loss of functionality](http://blog.m33.network/2017/09/react-native-devops-2-0-overview-of-mobile-center-next-generation-of-hockeyapp/).
8 |
9 | {% endhint %}
10 |
11 | ## Owner: [Yann Leflour](https://github.com/yleflour)
12 |
13 | ## Prerequisites
14 |
15 | * [ ] Have you entire environment setup
16 | * [ ] Generating a new SSH key and adding it to the ssh-agent: (https://help.github.com/articles/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent/)
17 |
18 | ## Steps
19 |
20 | {% hint style='warning %} **FRIENDLY ADVICE**
21 |
22 | Remember to commit after each step
23 |
24 | {% endhint %}
25 |
26 | ### 1. Setup your React Native App
27 |
28 | ```bash
29 | react-native init
30 | cd
31 | # First Commit
32 | ```
33 |
34 | ### 2. Setup Fastlane
35 |
36 | ```bash
37 | yo rn-toolbox:fastlane-setup
38 | # Second Commit
39 | ```
40 |
41 | **_Answers_**
42 |
43 | * Please confirm the project name: ``
44 | * Commit keystore files?: `Y`
45 | * Overwrite : ``
46 |
47 | ### 3. Setup Staging Env
48 |
49 | ```bash
50 | yo rn-toolbox:fastlane-env
51 | # Third Commit
52 | ```
53 |
54 | **_Answers_**
55 |
56 | * Please confirm the project name: ``
57 | * The name for this new environment (lowercase, no space): `staging`
58 | * The name of your repository Git branch for the environment just set: ``
59 | * The name of the company which will be publishing this application: `Bam`
60 | * The app name for this environment: ` S`
61 | * The App Id for this environment: `tech.bam..staging`
62 | * Which platform will you use for deployment?: `HockeyApp`
63 | * The type of certificate you will be using: `In House (Enterprise only)`
64 | * Your git repo for match: `git@github.com:/certificates.git`
65 | * The branch you want to use for match: ``
66 | * The developer.apple.com team id for the certificates: `**redacted**`
67 | * Your apple id: `**redacted**`
68 | * Your keystore password: ``
69 | * A valid HockeyApp token: `**redacted**`
70 |
71 | ### 4. Deploy Staging
72 |
73 | ```bash
74 | bundle exec fastlane ios deploy --env=staging
75 | bundle exec fastlane android deploy --env=staging
76 | ```
77 |
78 | ### 5. Create the download link
79 |
80 | * Go to [smarturl.it](https://manage.smarturl.it)
81 | * Go to Hockey App with `**redacted**`
82 | * For each app (Android + iOS)
83 | * Go to `Manage app`
84 | * Go to `Distribution`
85 | * Select `Download Page` > `Public`
86 | * Hit `Save`
87 | * Create a new link
88 | * Default URl: `Trello url`
89 | * Device Destination:
90 | * iPhone: The Hockey App iOS Download & Feedback `Public Page url`
91 | * iPad: The Hockey App iOS Download & Feedback `Public Page url`
92 | * Android: The Hockey App iOS Download & Feedback `Public Page url`
93 | * Organize
94 | * Custom Alias: `smarturl.it/`
95 |
96 | ## Troubleshooting
97 |
98 | If 'Cloning GitHub repo' takes more than 2 minutes: the github servers may be untrusted Trigering a `git clone git@github.com:bamlab/certificates.git` will fix it.
99 |
--------------------------------------------------------------------------------
/react-native/setup/setup-and-deploy-new-project-to-staging.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Setup & Deploy New Project to Staging
2 |
3 | {% hint style='info' %} **NOTE**
4 |
5 | This standard replaces [[MO] Deploy to staging with HockeyApp](setup-and-deploy-new-project-to-staging-with-hockeyapp.mo.md), deprecated by [@felixmeziere](https://github.com/felixmeziere) on January 28.
6 |
7 | **Reason**: HockeyApp is meant to be deprecated by AppCenter. AppCenter is the new HockeyApp and there is [no loss of functionality](http://blog.m33.network/2017/09/react-native-devops-2-0-overview-of-mobile-center-next-generation-of-hockeyapp/).
8 |
9 | {% endhint %}
10 |
11 | ## Owner: [Felix Meziere](https://github.com/felixmeziere)
12 |
13 | ## Prerequisites
14 |
15 | * [ ] Have you entire environment setup
16 | * [ ] Generating a new SSH key and adding it to the ssh-agent: (https://help.github.com/articles/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent/)
17 |
18 | ## Steps
19 |
20 | {% hint style='warning' %} **FRIENDLY ADVICE**
21 |
22 | Remember to commit after each step
23 |
24 | {% endhint %}
25 |
26 | ### 1. Setup your React Native App
27 |
28 | ```bash
29 | react-native init
30 | cd
31 | # First Commit
32 | ```
33 |
34 | ### 2. Setup Fastlane
35 |
36 | ```bash
37 | yo rn-toolbox:fastlane-setup
38 | # Second Commit
39 | ```
40 |
41 | **_Answers_**
42 |
43 | * Please confirm the project name: ``
44 | * Commit keystore files?: `Y`
45 | * Overwrite : ``
46 |
47 | ### 3. Setup Staging Env
48 |
49 | ```bash
50 | yo rn-toolbox:fastlane-env
51 | # Third Commit
52 | ```
53 |
54 | **_Answers_**
55 |
56 | * Please confirm the project name: ``
57 | * The name for this new environment (lowercase, no space): `staging`
58 | * The name of your repository Git branch for the environment just set: ``
59 | * The name of the company which will be
60 | publishing this application: `Bam`
61 | * Which platform will you use for deployment?: `AppCenter`
62 | * The iOS app name for this environment. Name should be different from the Android app and not contain spaces: `-ios-S`
63 | * The Android app name for this environment. Name should be different from the Android app and not contain spaces: `-android-S`
64 | * The App Id for this environment: `tech.bam..staging`
65 | * The type of certificate you will be using: `In House (Enterprise only)`
66 | * Your git repo for match: `git@github.com:/certificates.git`
67 | * The branch you want to use for match: ``
68 | * The developer.apple.com team id for the certificates: `**redacted**`
69 | * Your apple id: `**redacted**`
70 | * Your keystore password: ``
71 | * A valid App Center API token: `**redacted**`
72 | * A valid App Center Username: `**redacted**`
73 | * (After some npm installation...) Should fastlane modify the Gemfile at path 'xxx' for you? (y/n): `y`
74 |
75 | _Note:_ The AppCenter username is at the bottom-left of the AppCenter interface for a person or is the name of the organization for an organization.
76 |
77 | ### 4. Deployment setup
78 |
79 | ```bash
80 | bundle exec fastlane ios setup --env=staging
81 | # Fourth Commit
82 | ```
83 |
84 | ### 5. Deploy Staging
85 |
86 | ```bash
87 | bundle exec fastlane ios deploy --env=staging
88 | bundle exec fastlane android deploy --env=staging
89 | ```
90 |
91 | **_Answers_**
92 |
93 | * OS: `iOS/Android` depending on which you are deploying
94 | * Platform: `React Native`
95 | * Do you want to create a New App?: `yes`
96 |
97 | ### 6. Get the download link
98 |
99 | * For each app (Android + iOS)
100 | * Go to the emails you just got for the two deployments
101 | * Copy the url that the _Install_ button points to and remove the end bit so that it finishes
102 | with `/releases/`
103 | * Go to [smarturl.it](https://manage.smarturl.it)
104 | * Create a new link
105 | * Default URl: `Trello url`
106 | * Device Destination:
107 | * iPhone: The AppCenter iOS Download & Feedback `Public Page url`
108 | * iPad: The AppCenter iOS Download & Feedback `Public Page url`
109 | * Android: The The AppCenter Android Download & Feedback `Public Page url`
110 | * Organize
111 | * Custom Alias: `smarturl.it/`
112 |
113 | ## Troubleshooting
114 |
115 | If 'Cloning GitHub repo' takes more than 2 minutes: the github servers may be untrusted. Triggering a `git clone git@github.com:bamlab/certificates.git` will fix it.
116 |
--------------------------------------------------------------------------------
/react-native/setup/setup-facebook-login.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Install Fb React Native Login (v0.47) (~35 min)
2 |
3 | ## Owner: [Guillaume Renouvin](http://github.com/GuillaumeRenouvin/)
4 |
5 | ## Prerequisites (~15 min)
6 | * Have Yarn installed (~2 min)
7 | * Have an application created on Facebook and its id (https://developers.facebook.com/apps) (~10 min)
8 | * Have an account added as developer on your application facebook
9 | * Have cocoapods in your project (~5 min)
10 |
11 | ## Context
12 | When I had to install a facebook login on my React Native project, I thought it would be easy and that I would only have to follow the tutorial of the github repo. But, by simply following the tutorial, I found myself with many problems of versions on both iOS and Android.
13 |
14 | I hope that thanks to this article which summarizes the tips that I could find online, you will be able to install a facebook login in less than an hour.
15 |
16 | ## Steps (~20 min)
17 | Install react-native-fbsdk package (https://github.com/facebook/react-native-fbsdk): `yarn add react-native-fbsdk@0.6.0` (last release 0.6.1 bug on react native link)
18 |
19 | #### iOS (~10 min)
20 | * Link it `react-native link react-native-fbsdk`
21 | * Add in your podfile the library's dependencies:
22 | ```
23 | target 'accorlocal' do
24 | inherit! :search_paths
25 | pod 'FBSDKCoreKit', '~> 4.25.0'
26 | pod 'FBSDKShareKit', '~> 4.25.0'
27 | pod 'FBSDKLoginKit', '~> 4.25.0'
28 | end
29 | ```
30 | `cd ios && bundle exec pod install --repo-update`
31 | * Then follow the [documentation](https://developers.facebook.com/quickstarts/?platform=ios) -> Fill your app id -> Configure your info.plist -> connect the App Delegate
32 |
33 | **check:** `console.log(NativeModules)` should show the FacebookLoginManager module on iOS build
34 |
35 | #### Android (~10 min)
36 | * Then follow the [documentation](https://github.com/facebook/react-native-fbsdk#31-android-project) -> "If your react-native version is 0.29 or above"
37 | * Go to [Facebook developer](https://developers.facebook.com/quickstarts/?platform=android) -> Fill your app id -> And follow "Add Facebook App ID"
38 | * There are versions issues on the nodes_modules. To fix them, add a script in /bin/patch-fb-sdk.sh and add it in your package.json as a post install command:
39 | ```
40 | #!/bin/sh
41 | if [[ $CI ]]; then
42 | sed -i.bak '' 's/@Override//' ./node_modules/react-native-fbsdk/android/src/main/java/com/facebook/reactnative/androidsdk/FBSDKPackage.java
43 | sed -i.bak '' 's/4\.+/4.22.1/' ./node_modules/react-native-fbsdk/android/build.gradle
44 | else
45 | sed -i.bak 's/@Override//' ./node_modules/react-native-fbsdk/android/src/main/java/com/facebook/reactnative/androidsdk/FBSDKPackage.java
46 | sed -i.bak 's/4\.+/4.22.1/' ./node_modules/react-native-fbsdk/android/build.gradle
47 | fi
48 | ```
49 | * To debug with android, on you terminal generate a key: `keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64` and add it to [your facebook app](https://developers.facebook.com/apps/1806939376263478/settings/) -> `Key hashings`
50 |
51 | **check 1:** `console.log(NativeModules)` should show the FacebookLoginManager module on Android build
52 | **check 2:** You should be able to log on Facebook on your application on Android on development
53 |
54 | #### Add the Facebook login button
55 | Now, you should be able to add the login button on your app working on both Android and iOS. You just have to import `react-native-fbsdk` and add your Facebook button
56 | ```
57 | import { TouchableOpacity, Text } from 'react-native';
58 | import { LoginManager } from 'react-native-fbsdk';
59 |
60 | class Login extends Component {
61 | tryFacebookLogin() {
62 | // Attempt a login using the Facebook login dialog asking for default permissions.
63 | LoginManager.logInWithReadPermissions(['public_profile', 'email']).then(
64 | function(result) {
65 | if (result.isCancelled) {
66 | alert('Login cancelled');
67 | } else {
68 | alert('Login success with permissions: ' + result.grantedPermissions.toString());
69 | }
70 | },
71 | function(error) {
72 | alert('Login fail with error: ' + error);
73 | }
74 | );
75 | }
76 |
77 | render() {
78 | return (
79 |
80 | Facebook button
81 |
82 | );
83 | }
84 | }
85 | ```
86 |
87 | You can find more configuration [here](https://github.com/facebook/react-native-fbsdk#login)
88 |
--------------------------------------------------------------------------------
/react-native/setup/setup-stripe-dev-standard.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Setup Stripe in app payment form with tipsi-stripe (~2 hours)
2 |
3 | ## Owner: [Guillaume Renouvin](https://github.com/GuillaumeRenouvin)
4 |
5 | ## Prerequisites
6 | - Have a Stripe account and its publishable/secret key duet that you can find on [your Stripe account](https://dashboard.stripe.com/login)
7 |
8 | ## Context
9 | On a project, I had to let my user pay within my React Native app. My client wanted to use Stripe services.
10 |
11 | First I tried to develop a browser solution with [stripe element](https://stripe.com/docs/stripe-js/elements/quickstart). I had two problems:
12 | - It was really time consuming to develop a web page for the payment;
13 | - It made the user navigate back and forth from the app to their web browser, resulting in a really poor user experience.
14 |
15 | I then found out [tipsi-stripe](https://github.com/tipsi/tipsi-stripe) which is a React Native library that wraps the Stripe native SDK for iOS and Android. It only took me 2 hours to set it up and granted a far better user experience, satisfying our client ;).
16 |
17 | ## However your client should be aware of
18 | - [tipsi-stripe](https://github.com/tipsi/tipsi-stripe) only supports english;
19 | - [tipsi-stripe](https://github.com/tipsi/tipsi-stripe) has not been audited by Stripe yet. The PCI DSS (Payment Card Industry Data Security Standard) regulation committee recently forced Stripe to stop accepting credit card data from direct calls to their API. Therefore, they enforced the usage of "Stripe-controlled" libraries like Elements and their own SDKs.
20 | **It means, Stripe could actually ask you to stop using tipsi in order to fit new PCI DSS requirements anytime.**
21 | So far, tipsi-stripe uses direct calls to Stripe SDKs and therefore, we did not receive any warning from them, still you should keep it in mind.
22 |
23 | However, even if Stripe asked you to stop using tipsi, the time loss would be light as it only takes around 2 hours to install the lib. Setting up browser payment would take more than a day and offers a poorer UX.
24 |
25 | ## Steps (~1 hour)
26 | - Install tipsi-stripe package following its [installation documentation](https://github.com/tipsi/tipsi-stripe#installation)
27 | **check:**
28 | - Break point in iOS in the code;
29 | - Break point in Android in the code;
30 | - `console.log(NativeModules)` (where NativeModules is a react native import) should show the tipsi-stripe module
31 | - I recommend to use the basic add card form to be Stripe friendly
32 | [Documentation](https://github.com/tipsi/tipsi-stripe#request-with-card-form)
33 |
34 | ```js
35 | import React, { PureComponent } from 'react';
36 | import { View, Text } from 'react-native';
37 | import stripe from 'tipsi-stripe';
38 |
39 | const ENV = "staging";
40 | export default class Payment extends PureComponent {
41 | props: PropsType;
42 | states: StatesType;
43 |
44 | static title = 'Card Form';
45 |
46 | state = {
47 | token: null,
48 | };
49 |
50 | componentDidMount() {
51 | stripe.init({ // Place this in the App.js file
52 | publishableKey: "fake token",
53 | androidPayMode: ENV === "production" ? "production" : "test"
54 | });
55 | }
56 |
57 | handleCardPayPress = async () => {
58 | try {
59 | this.setState({
60 | token: null,
61 | });
62 | const token = await stripe.paymentRequestWithCardForm({
63 | smsAutofillDisabled: true,
64 | });
65 |
66 | this.setState({
67 | token,
68 | });
69 | this.props.addCard(token.tokenId);
70 | } catch (error) {}
71 | };
72 |
73 | render() {
74 | return (
75 |
78 | Payment
79 |
80 | );
81 | }
82 | }
83 | ```
84 |
85 | ### Plug it with your back
86 | With Stripe, you have a publishable key that you can store on you application and a private key that should never appear in any distributed binary. The publishable key can only be used to create tokens from card informations. Then, you have to combine them with the private key to post it to Stripe through their API.
87 | **Therefore the private key should only be used server side.**
88 | You can find more information [here](https://stripe.com/docs/dashboard#api-keys).
89 |
90 | Here is the most basic example of the relations between your app, your server and Stripe for a payment:
91 | 
92 |
--------------------------------------------------------------------------------
/react-native/setup/setup_firebase_multiple_envs.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Setup Firebase on iOS/Android with multiple environments *(~1h)*
2 |
3 | ## Owner: [Louis Lagrange](https://github.com/Minishlink)
4 |
5 | Correcter: Thomas Pucci
6 |
7 | ## Prerequisites *(~30min)*
8 |
9 | - [ ] An Android or iOS app with the Firebase SDK installed
10 |
11 | - For React Native apps, you can use [`react-native-firebase`](https://github.com/invertase/react-native-firebase):
12 | - [iOS](https://rnfirebase.io/docs/v3.2.x/installation/ios)
13 | - [Android](https://rnfirebase.io/docs/v3.1.*/installation/android)
14 | - Be careful, when you're using specific modules of firebase, like analytics, you may have to add some `compile` to the `gradle` and some external pods
15 |
16 |
17 | ## Foreword
18 |
19 | You can install and setup Firebase with two different ways:
20 |
21 | | | Javascript asynchronous setup | Native synchronous setup |
22 | |---|---|---|
23 | | Pros | - 👍 No Native code is required
- ⏩ Setup is quick | - 🚀 In your application, you do not need to wait for firebase to instantiate each time you need it
- ✅ You can use Firebase Phone Authentication |
24 | | Cons | ⚠️ You **cannot** use this setup if you aim to use Firebase Phone Authentication as it requires the default Firebase app to be setup (meaning the native synchronous setup to be done: see the paragraph ℹ️ *Important note* [here](https://rnfirebase.io/docs/v3.2.x/core/initialize-apps)) | 📲 You need install native libraries |
25 |
26 | This MO aims to setup Firebase with the **Native synchronous setup**. For the **Javascript asynchronous setup** read the [docs here](https://rnfirebase.io/docs/v3.2.x/core/initialize-apps); and each time you need to call Firebase in your JS code, wait for the Firebase app initialization with `onReady()` method.
27 |
28 | ## Steps *(~30min)*
29 |
30 | It's pretty straightforward to install Firebase when you have only one environment.
31 | But what if you have multiple environments, such as `dev`, `staging` and `production`?
32 | Here's a step-by-step guide.
33 |
34 | ### Android *(~10min)*
35 | On Android, Firebase groups the different configurations in one file.
36 |
37 | 1. Go to the [Firebase console](https://console.firebase.google.com/)
38 | 2. Select your project
39 | 3. Click "Add an application", choose Android
40 | 4. Fill in the form (giving a name like `Staging`), click save, and close the window
41 | 5. Repeat steps 3 to 4 for all your environments
42 | 5. Download the `google-services.json` file
43 | 1. Select one of the Android applications
44 | 2. Click on "google-services.json"
45 | 6. Put `google-services.json` in your `app` folder (`android/app` in React-Native)
46 | 7. You might want to add `google-services.json` in your `.gitignore`
47 |
48 | 
49 |
50 | ### iOS *(~20min)*
51 | On iOS, there is one Firebase configuration file per environment.
52 |
53 | 1. Go to the [Firebase console](https://console.firebase.google.com/)
54 | 2. Select your project
55 | 3. Click "Add an application", choose iOS
56 | 4. Fill in the form (giving a name like `Staging`), click save
57 | 5. Download the configuration file `GoogleService-Info.plist` and rename it like `GoogleService-Info.{APP_IDENTIFIER}.plist`
58 | * Example: for `tech.bam.myApp.staging`, `GoogleService-Info.tech.bam.myApp.staging.plist`
59 | 6. Repeat steps 3 to 5 for all your environments
60 | 7. Duplicate your configuration file for dev environment two times and rename them like so:
61 | * `GoogleService-Info.plist`
62 | * `GoogleService-Info..plist`
63 | 8. Put all your configuration files in the root of your iOS app folder (`ios` in React-Native)
64 | 9. Make sure that your app identifier is injected in your `.pbxproj`. For example, if you're using Fastlane, add a `update_app_identifier` step like:
65 | ```ruby
66 | update_app_identifier(
67 | xcodeproj: xcodeproj_full_path,
68 | plist_path: plist_full_path,
69 | app_identifier: ENV['APP_IDENTIFIER']
70 | )
71 | ```
72 | If you bootstrapped your project with BAM generator, use the following in the iOS build lane:
73 | ```ruby
74 | update_app_identifier(
75 | xcodeproj: xcodeproj,
76 | plist_path: ENV['IOS_PLIST_PATH'],
77 | app_identifier: ENV['IOS_APP_ID']
78 | )
79 | ```
80 | 10. In XCode, in `Build phases`, add a `Select GoogleService-Info.plist` build step before the `Copy Bundle Resources` step that contains:
81 | ```bash
82 | cp "GoogleService-Info.plist" "GoogleService-Info.plist.bak"
83 | cp "GoogleService-Info."$IOS_APP_ID".plist" "GoogleService-Info.plist"
84 | ```
85 | 11. In XCode, in `Build phases`, add a `Clean GoogleService-Info.plist` build step after the `Copy Bundle Resources` step that contains:
86 | ```bash
87 | cp "GoogleService-Info.plist.bak" "GoogleService-Info.plist"
88 | rm "GoogleService-Info.plist.bak"
89 | ```
90 | 12. Make sure that the `GoogleService-Info.plist` is listed in the resources of the `Copy Bundle Resources` step
91 | 13. You might want to add `GoogleService-Info.*.plist` in your `.gitignore`
92 |
93 | 
94 |
95 | ## Troubleshooting
96 |
97 | You can take a look at the commit that adds crash reporting and analytics in DailyScrum: [8005ce3](https://github.com/Minishlink/DailyScrum/commit/8005ce348cc61e9ad4550392fc08ae8a1bad8033)
98 |
--------------------------------------------------------------------------------
/react-native/update/upgrade-react-native.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Upgrade react native
2 |
3 | ## Owner: [Tycho Tatitscheff](https://github.com/tychota)
4 |
5 | ## Prerequisites
6 |
7 | - Be sure that all the react native warnings have been fixed by looking at the native logs in the React Native Debugger console.
8 | - Have [react-native-git-upgrade](https://github.com/facebook/react-native/tree/master/react-native-git-upgrade) installed
9 |
10 | ## Warning
11 |
12 | If you are late by several versions do them one at a time. Upgrading several version at a time (like from 0.42 to 0.46) can create a lot of complication, because React Native changes many javascript and native dependencies that also impact your code and its structure. If you do one version at a time, you are sure to be able to more quickly give a working version with a slightly newer version (like from 0.42 to 0.43, etc.) that you tested on both Android and iOS.
13 |
14 |
15 | ## Steps (~12min)
16 |
17 | ### Create a new branch (~1 min)
18 |
19 | - Stash the existing modifications by running `git stash`
20 | - Create a new branch by running `git checkout -b upgrade/react-native-0-XX-0`
21 |
22 | > **Checks**: when running `git status`, you have no untracked or no modified files
23 |
24 | ### Look at the breaking changes of your new release
25 |
26 | - Look at your actual version of React Native
27 |
28 | > Lets say it is `0.45.1`
29 |
30 | - Find the changelog here: https://github.com/facebook/react-native/releases/tag/v0.X.0 where X is the minor of your react native version, note down the major breaking changes you'll have to consider later.
31 |
32 | > **Check**: I have a clear list of deprecated items to check.
33 |
34 | ### Launch the automatic upgrade (~10 mins)
35 |
36 | - Look at this table: https://github.com/ncuillery/rn-diff
37 |
38 | > You want to upgrade one version at the time of react native, but include the patches that are bug fixes for the new version
39 | - In this case, you want to go to `0.46.4` and not `0.46.0` since for the version `0.46`, react-native releases 4 bug fixes that you would have to fix yourself later if you had stay to `0.46.0`
40 |
41 | - Run `react-native-git-upgrade 0.46.4`
42 |
43 | - Fix the potential conflict: see https://facebook.github.io/react-native/docs/upgrading.html#4-resolve-the-conflicts
44 |
45 | - If other modules or libraries have to be updated for compatibility reasons, update them following the upgrade native module steps.
46 |
47 | - Once the React Native upgrade is completed, follow the tests steps (simulator and device) to perform one upgrade at a time.
48 |
49 | ### Upgrade native modules (~10 mins per native module)
50 |
51 | > Note: React Native may cause major breaking changes:
52 | - [v0.40.0](https://github.com/facebook/react-native/releases/v0.40.0)
53 |
54 | - If react native cause a breaking changes in native side (you would see that in the changelog):
55 |
56 | - Open your `android/settings.gradle` and list all module imported
57 | - Compare this list to your `podfile` if you use cocoapods, and the linked framework (in Xcode, the library directory that contains both react-native and react-native plugins framework) @TODO @tycho insert photo
58 | - For each package found, look at the github repo to see if it has been updated, or has pending issues that may jeopardize the upgrade process
59 | - Upgrade the module in `package.json` and run `yarn`.
60 |
61 | > There are also some modules that always require an update for a RN upgrade (example: `react-native-svg`)
62 |
63 | > **Check**: you can now build android and iOS.
64 |
65 | ### Upgrade your own code to fit react new syntax (~10 mins)
66 |
67 | - Identify the breaking change by running the app and googling for the issues
68 | - Run [`react-codemod`](https://github.com/reactjs/react-codemod) to fix all the issues on the codebase.
69 | - [Example props-types](https://github.com/reactjs/react-codemod#react-proptypes-to-prop-types): `jscodeshift -t react-codemod/transforms/ReactNative-View-propTypes.js myproject/src`
70 |
71 | ### Upgrade javascript modules
72 |
73 | > **Note**: For javascript, the overall process is similar than for native module: try to run the app and upgrade all the modules that fail.
74 |
75 | #### React-based changes (~10 mins per module)
76 |
77 | > **Example**: PropTypes gets moved to another package.
78 |
79 | - Try to see if the failing module has an existing fix (then upgrade)
80 | - Otherwise, fork it, and apply the same principle you did on your code to your newly created package.
81 |
82 | #### Packager incompatibilities
83 |
84 | > **Example**: `moment.js`
85 |
86 | - Try to look for github issues on Google
87 | - Use another better architected package (see [this amazing package](https://github.com/date-fns/date-fns)) or create your own.
88 |
89 | ### Fix flow
90 |
91 | // @todo: Tycho
92 |
93 | ### Fix tests
94 |
95 | // @todo: Tycho
96 |
97 | ### Deploy and test on device
98 |
99 | - Once you have tested that everything is working fine on both iOS and Android, deploy on device (do not merge your branch)
100 | - Run the command to hard deploy from your branch to hockeyapp
101 | - Test that everything is working fine on devices
102 | - If everything is correct, merge and soft deploy
103 |
104 | ## Troubleshooting
105 |
106 |
107 | If this is taking too long you can create a new React Native project from scratch with `react-native init` and import and re-install all your javascript and native parts (CocoaPods, linking, etc.).
108 |
109 | There can also be cache issues (with yarn or gradle for instance) so if your project doesn't take long to be cloned you can clone a new instance of your project if you're stuck.
110 |
--------------------------------------------------------------------------------
/react-native/use_http_links_in_react_native.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Use HTTP links with RN Components/API Calls on iOS
2 | ## Owner: [Julien Nassar](https://github.com/juliennassar)
3 | ## Sponsor: [Alexandre Moureaux](https://github.com/almouro)
4 |
5 | ## Prerequisites (~ 2 minutes)
6 | - [ ] Have a React Native application [using yo generator](https://github.com/bamlab/generator-rn-toolbox)
7 |
8 | ## Context
9 |
10 | Using HTTP links (in image sources for example) will not work on iOS devices/emulators. By default, the HTTP protocol is disabled. API calls and Image sources using HTTP protocol will not work on iOS, and no errors will be displayed.
11 |
12 | ## Steps (~ 2 minutes)
13 |
14 | Using the default configuration, the images in this page will not be displayed:
15 |
16 | ```javascript
17 | import React, { Component } from 'react'
18 | import { View, Text, Image, TouchableOpacity } from 'react-native'
19 |
20 |
21 | export default class Workspace extends Component {
22 | render () {
23 | return (
24 |
25 |
26 |
31 |
32 |
33 | )
34 | }
35 | }
36 | ```
37 | The source uri uses the HTTP protocol
38 |
39 | the result is this:
40 |
41 |
42 |
43 | No image displayed :(
44 |
45 |
46 | ### how to display these images:
47 |
48 | By default iOS forbids calls using http protocol. Normally you should use secured http protocol (https), if you don't have that opportunity, you have to allow the domain using http protocol by modifying the `/ios//info.plist`:
49 |
50 | in the NSExceptionDomains section, add your domain name and permission
51 |
52 | ```xml
53 | NSExceptionDomains
54 |
55 | localhost
56 |
57 | NSExceptionAllowsInsecureHTTPLoads
58 |
59 |
60 | YOUR_DOMAIN.com
61 |
62 | NSExceptionAllowsInsecureHTTPLoads
63 |
64 |
65 |
66 | ```
67 |
68 | **- [ ] Rebuild your app**
69 | If you reloading your app it will not work, you modified Native code, so you need to rebuild the native part as well
70 | And it works :)
71 |
72 |
73 |
74 | and it works!
75 |
--------------------------------------------------------------------------------
/react/component.s.md:
--------------------------------------------------------------------------------
1 | # [Standard] Writing a Component
2 |
3 | ## Owner: Nicolas Djambazian
4 |
5 | ## Standards
6 |
7 | **A react component begins than a `// @flow`**
8 |
9 | Why ? Flow typings will be used to check the Props and the State
10 |
11 |
12 |
13 | **A react component should import React with the following syntax**
14 | ```
15 | import * as React from 'react';
16 | ```
17 | Why ? To be able o access to the flow defined properties : https://flow.org/en/docs/react/types/
18 |
19 |
20 | **The props and the state must be checked by flow**
21 |
22 | Why ? It allows to :
23 |
24 | - Check the props are valid when you use the component
25 | - Be sure to have done all checks for nullable props
26 | - Give a good updated documentation of the props
27 |
28 |
29 | Ex :
30 | ```
31 | type Props = {
32 | title?: ?string
33 | id: number,
34 | cards: Array<{
35 | title: string,
36 | }>,
37 | }
38 | type State = { isOpenend: boolean };
39 | class MyComponent extends React.PureComponent {
40 | // ...
41 | }
42 | ```
43 |
44 | **When we open a component file, we should see elements in that orders : props and state typings, class definition, style, hoc and then the final export**
45 |
46 | Why ? The first thing you want to know when you open a component is his API. So the typing should be as first.
47 |
48 | Then You want to know how it works and/or what it contains. So the class should be in seconds.
49 |
50 | Styling is the last thing you want to know.
51 |
52 |
53 | **The styling of a component should be in the same file at the end**
54 |
55 | The style of a component is highlty coupled with his implementation. When you want to change the DOM, you often have to change the style and vice-versa.
56 |
57 | If you want to use the same DOM with different styles, add a `style` props on your component.
58 |
59 | If another component need a part of your style, you have several choices :
60 | - Create a third component with that style, used by both of them
61 | - Add this part of the style in a theme
62 |
63 |
64 | **The Component should be exported as `default`**
65 |
66 | To not have to think of the name of the export.
67 |
68 | **The `render` function should come last**
69 |
70 | To immediately know where to look for the `render` function.
71 |
72 | **Instance methods should not be prefixed with `_`**
73 |
74 | It is common practice to add `_` in front of the private methods of your components.
75 | It turns out that *most* component methods are private. It would mean that most of our methods would need a `_`.
76 |
77 | To not forget any `_`, we simply choose to not put any.
78 |
79 | ## Bad Example
80 |
81 |
82 | ```jsx
83 | // No @flow
84 | import React from 'react'; // Bad React import
85 | import { Text, View } from 'react-native';
86 |
87 | // style in an other file.
88 | import centeredStyle from '../../../style';
89 |
90 | // Style at the begining of the file
91 | const styles = {
92 | centeredStyle,
93 | text: {
94 | color: '#bbbbbb'
95 | },
96 | };
97 |
98 | // No flow Props typing and no default export
99 | export class Page extends React.PureComponent {
100 | render() {
101 | return (
102 |
103 | {this.props.text}
104 |
105 | );
106 | }
107 | }
108 |
109 | ```
110 |
111 |
112 | ## Good Example
113 | ```jsx
114 | // @flow
115 | import * as React from 'react';
116 | import { Text } from 'react-native';
117 | import { CenteredPageContent } from '../components';
118 |
119 | type Props = {
120 | text: string,
121 | }
122 |
123 | class Page extends React.PureComponent {
124 | render() {
125 | return (
126 |
127 | {this.props.text}
128 |
129 | );
130 | }
131 | }
132 |
133 | const styles = {
134 | text: {
135 | color: '#bbbbbb'
136 | },
137 | };
138 |
139 | export default Page;
140 | ```
141 |
142 |
--------------------------------------------------------------------------------
/react/lifecycle/trigger-action-on-props-update.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] Trigger action on props update with componentWillReceiveProps
2 |
3 | ## Owner: Yassine Chbani
4 |
5 | ## Motivation
6 |
7 | If you have ever worked with React, you will have probably used Redux at some point and found it great as your components can
8 | subscribe to any changes to the store state and react accordingly. But what happens if you want to similarly handle the update
9 | of one of your component's props? For example, call a certain method for a given change of the props?
10 |
11 | Well you're in luck, because Facebook provides a set of methods that get called at different points of the lifecycle of a component 1. We are going to look at the `ComponentWillReceiveProps`method in the following article.
12 |
13 |
14 | ## Prerequisites
15 |
16 | Your page has a set of props that can change after it has been mounted and before it gets unmounted. The props change can be
17 | triggered from within or outside the page.
18 |
19 | ## Steps (~10 minutes)
20 |
21 | - Add to your prop a component that gets updated from outside the page e.g. from a Redux store:
22 |
23 | ```jsx
24 | import { Connectivity } from '../../../Connectivity';
25 |
26 | const mapStateToProps = state => ({
27 | isConnected: Connectivity.isConnected(state),
28 | });
29 | ```
30 |
31 | Let’s also add a component which is rendered at a certain `isTextVisible` condition:
32 |
33 | ```jsx
34 | class MyClass extends Component {
35 | state = {
36 | isConnected: false
37 | isTextVisible: false
38 | }
39 |
40 | render () {
41 | return (
42 | if( this.isTextVisible ) {
43 |
44 | Connexion successful!
45 |
46 | }
47 | )
48 | }
49 | }
50 | ```
51 |
52 | Let’s say you want to have a special behaviour for this Text component, such that it appears for 3 seconds when `isConnected` changes from `false` to `true`.
53 |
54 | ```jsx
55 | componentWillReceiveProps (nextProps) {
56 | if (!this.props.isConnected && nextProps.isConnected) {
57 | this.setState(isActivated, () => this.makeTextDisappear())
58 | }
59 | }
60 |
61 | makeTextDisappear = () => {
62 | setTimeout(() => this.setState({isTextVisible: false}), 3000)
63 | }
64 | ```
65 |
66 | The critical point here is the `if (!this.props.isConnected && nextProps.isConnected)` condition (also called hook). It is necessary to be specific about what prop change triggers the desired action, because `componentWillReceiveProps` is called at every prop update and the code inside is executed each time then. Our code now looks like this:
67 |
68 | ```jsx
69 | import { Connectivity } from '../../../Connectivity';
70 |
71 | class MyClass extends Component {
72 | state = {
73 | isConnected: false
74 | isTextVisible: false
75 | }
76 |
77 | componentWillReceiveProps (nextProps) {
78 | if (!this.props.isConnected && nextProps.isConnected) {
79 | this.setState(isActivated, () => this.makeTextDisappear())
80 | }
81 | }
82 |
83 | makeTextDisappear = () => {
84 | setTimeout(() => this.setState({isTextVisible: false}), 3000)
85 | }
86 |
87 | render () {
88 | return (
89 | if( this.isTextVisible ) {
90 |
91 | Connexion successful!
92 |
93 | }
94 | )
95 | }
96 | }
97 |
98 | const mapStateToProps = state => ({
99 | isConnected: Connectivity.isConnected(state),
100 | });
101 | ```
102 |
103 | A couple of interesting notes2:
104 | - `componentWillReceiveProps` can be called even if the props did not change
105 | - If done before `render()`is called, then calling `setState` will not trigger an additional render
106 |
107 | 1: See [this](https://engineering.musefind.com/react-lifecycle-methods-how-and-when-to-use-them-2111a1b692b1) or
108 | [that article](https://reactjs.org/docs/react-component.html) about the full lifecycle of a React component.
109 |
110 | 2: https://developmentarc.gitbooks.io/react-indepth/content/life_cycle/update/component_will_receive_props.html
111 |
--------------------------------------------------------------------------------
/react/redux/custom-redux-form-field.mo.md:
--------------------------------------------------------------------------------
1 | # [MO] How to use redux-form with custom fields (~10min)
2 |
3 | ## Owner: [Darius Afchar](https://github.com/DariusAf)
4 |
5 | * What is **redux-form**?
6 |
7 | Redux-form is a higher-order component decorator that enables you to efficiently manage your form by automating a lot of things as form-validation, focus events, storage synchronisation...
8 |
9 | * The point of this article?
10 |
11 | With redux-form, a lot of things are done under the hood, so it may be tricky to add a custom component and have it work as expected. For instance, you might want to use a external component as a date-picker, or a super-component composed with different inputs that should return an aggregated answer. In those cases, you have to get your hands dirty to customise how redux-form connect to your component. Here is one way to do so.
12 |
13 | ## Prerequisities
14 |
15 | A react project with a redux store, obviously.
16 |
17 | * a react project: create one with [create-react-app](https://github.com/facebookincubator/create-react-app)
18 | * [redux installed](http://redux.js.org/docs/basics/UsageWithReact.html), make sure to install **redux** and **react-redux**
19 | * create a store and a reducer
20 |
21 | ## Steps
22 |
23 | 1. Add **redux-form** to your project, run
24 |
25 | ```bash
26 | npm install redux-form
27 | ```
28 |
29 | 2. Connect redux-form to your store by adding it to your reducers
30 |
31 | It depends on how you did organize your code, but if you have several reducers it might be similar to the following code:
32 |
33 | ```javascript
34 | import { combineReducers } from 'redux';
35 | import { reducer as formReducer } from 'redux-form';
36 | // your imports ...
37 |
38 | const appReducer = combineReducers({
39 | // ... your project reducers
40 | form: formReducer,
41 | });
42 |
43 | const initialState = {};
44 | const rootReducer = (state = initialState, action) => (appReducer(state, action));
45 |
46 | export default rootReducer;
47 |
48 | ```
49 |
50 | 3. Add a form field component to the front
51 |
52 | Let's say we have a custom component called *MySuperNiceInput* we want to connect.
53 |
54 | ```javascript
55 | import { Field, reduxForm } from 'redux-form'
56 | import { MySuperNiceInput } from 'path/to/MySuperNiceInput'
57 | // your imports ...
58 |
59 | const MyForm = ({ handleSubmit }) => (
60 |
72 | );
73 |
74 | export default reduxForm(
75 | form: 'myformnamethatwillappearinthestore'
76 | )(MyForm);
77 | ```
78 |
79 | 4. Control how things change with *this.props.input.onChange()*
80 |
81 | Redux-form automatically pass some props to the component you pass through the *component* prop of *\*.
82 |
83 | ```javascript
84 | import { connect } from 'react-redux';
85 | // your imports ...
86 |
87 | class MySuperNiceInput extends Component {
88 | handleChange(callbackValue) {
89 | // ...
90 | this.props.input.onChange(valueToSendToStore);
91 | }
92 |
93 | render() {
94 | return (
95 |
96 | this.handleChange(m)}
99 | />
100 |
101 | );
102 | }
103 | }
104 | ```
105 |
106 | This will dispatch actions to the form reducers whenever onChange is triggered.
107 |
108 | You can find all the props you can pass [on the official documentation](http://redux-form.com/6.0.0-alpha.4/docs/api/Field.md/).
109 |
110 | 6. Manage the submit event
111 |
112 | Time to use what we gave to redux-form. There is a high chance you would like your form data to be sent to a specific store of redux, so that's how to do it.
113 |
114 | Something you have to know about redux-form that can be a bit confusing is that if you want to pass a prop to the form, you have to use the syntax **onNameOfProp** and you receive it as **handleNameOfProp**.
115 |
116 | It means that the wording *handleSubmit* we have used previously is mandatory. We did write
117 | ```const MyForm = ({handleSubmit}) => (