Skip to content

React native client #349

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,10 @@ We no longer recommend using an express server with Rails. It's simply not neces
2. Open a browser tab to http://localhost:4000 for the Hot Module Replacement Example just using an express server (no Rails involved). This is good for fast prototyping of React components. However, this setup is not as useful now that we have hot reloading working for Rails!
3. Try Hot Reloading steps below!

## React Native

See React Native mobile app that works for both iOS and Android under the `mobile` folder.

## Contributors
[The Shaka Code team!](http://www.shakacode.com/about/), led by [Justin Gordon](https://github.com/justin808/), along with with many others. See [contributors.md](docs/contributors.md)

Expand Down
3 changes: 3 additions & 0 deletions mobile/ReactNativeTutorial/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": ["react-native"]
}
6 changes: 6 additions & 0 deletions mobile/ReactNativeTutorial/.buckconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

[android]
target = Google Inc.:Google APIs:23

[maven_repositories]
central = https://repo1.maven.org/maven2
2 changes: 2 additions & 0 deletions mobile/ReactNativeTutorial/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ios
android
45 changes: 45 additions & 0 deletions mobile/ReactNativeTutorial/.eslintrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
extends:
- "eslint-config-shakacode"
- "plugin:lodash-fp/recommended"
- "plugin:flowtype/recommended"
plugins:
- "react-native"
- "flowtype"
- "babel"
- "lodash-fp"

env:
node: true
settings:
import/resolver:
node:
extensions:
- ".js"
- ".android.js"
- ".ios.js"
moduleDirectory:
- "."
- "node_modules"
flowtype:
onlyFilesWithFlowAnnotation: true
globals:
__DEV__: true
fetch: true
rules:
new-cap: 0
react/sort-comp: 2
no-console: 2

babel/no-await-in-loop: 1

generator-star-spacing: 0

react-native/no-unused-styles: 2
react-native/split-platform-components: 2
react-native/no-inline-styles: 2
react-native/no-color-literals: 2

react/jsx-filename-extension:
- 1
- extensions: [".js", ".jsx"]
67 changes: 67 additions & 0 deletions mobile/ReactNativeTutorial/.flowconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
[ignore]

# We fork some components by platform.
.*/*[.]android.js

# Ignore templates with `@flow` in header
.*/local-cli/generator.*

# Ignore malformed json
.*/node_modules/y18n/test/.*\.json

# Ignore the website subdir
<PROJECT_ROOT>/website/.*

# Ignore BUCK generated dirs
<PROJECT_ROOT>/\.buckd/

# Ignore unexpected extra @providesModule
.*/node_modules/commoner/test/source/widget/share.js

# Ignore duplicate module providers
# For RN Apps installed via npm, "Libraries" folder is inside node_modules/react-native but in the source repo it is in the root
.*/Libraries/react-native/React.js
.*/Libraries/react-native/ReactNative.js
.*/node_modules/jest-runtime/build/__tests__/.*
.*/node_modules/react/node_modules/.*
.*/node_modules/react-native-experimental-navigation/.*
.*/node_modules/react-native/Libraries/Components/StaticContainer.js

# Json lint doesn't pass flow
.*/node_modules/jsonlint/.*

[include]

[libs]
node_modules/react-native/Libraries/react-native/react-native-interface.js
node_modules/react-native/flow
flow/

[options]
module.system=haste

esproposal.class_static_fields=enable
esproposal.class_instance_fields=enable

experimental.strict_type_args=true

munge_underscores=true

module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub'
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'

suppress_type=$FlowIssue
suppress_type=$FlowFixMe
suppress_type=$FixMe

suppress_type=$FlowIgnore
suppress_comment=\\(.\\|\n\\)*\\$FlowIgnore

suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(3[0-2]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(3[0-2]\\|1[0-9]\\|[1-2][0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy

unsafe.enable_getters_and_setters=true

[version]
^0.33.0
41 changes: 41 additions & 0 deletions mobile/ReactNativeTutorial/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# OSX
#
.DS_Store

# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate
project.xcworkspace

# Android/IJ
#
*.iml
.idea
.gradle
local.properties

# node.js
#
node_modules/
npm-debug.log

# BUCK
buck-out/
\.buckd/
android/app/libs
android/keystores/debug.keystore
19 changes: 19 additions & 0 deletions mobile/ReactNativeTutorial/.jest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Mocking the global.fetch included in React Native
global.fetch = jest.fn();

// Helper to mock a success response (only once)
fetch.mockResponseSuccess = (body) => {
fetch.mockImplementationOnce (
() => Promise.resolve({
json: () => Promise.resolve(body),
text: () => Promise.resolve(JSON.stringify(body)),
})
);
};

// Helper to mock a failure response (only once)
fetch.mockResponseFailure = (error) => {
fetch.mockImplementationOnce(
() => Promise.reject(error)
);
};
1 change: 1 addition & 0 deletions mobile/ReactNativeTutorial/.watchmanconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
77 changes: 77 additions & 0 deletions mobile/ReactNativeTutorial/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
## React Native Tutorial
This is a simple mobile app for posting comments in React Native.
This tutorial shows how to connect to the the https://www.reactrails.com API for a sample microblog.

### Setup
1. Install the latest version of Xcode from AppStore or https://developer.apple.com/download/ (Apple ID required)
2. Install the latest version of Android Studio from https://developer.android.com/studio/index.html
3. Install nvm (Node Version Manager)

```
curl -o- https://github.com/raw/creationix/nvm/v0.32.1/install.sh | bash
```

4. Install NodeJS stable

```
nvm install node
```

5. Install React Native and recommended packages

```
npm install -g react-native-cli
brew install watchman
brew install flow
```

6. Install npm dependencies

```
npm i
```

### Backend API

* Currently connecting by default to https://www.reactrails.com/. Be aware of that!
* The url can be changed app/api/index.js. Keep in mind, that Android emulator is
a separate Virtual Machine with its own localhost binding. To make the api available under emulator,
you have to use ip address of your computer, that could be seen by running `ifconfig` in the shell

### Running IOS
```
react-native run-ios
```

### Running Android
1. Check that installed build tools match gradle config of android project:
- In gradle config (app > android > build.gradle), search `buildToolsVersion`
- Run `android sdk` from bash and find installed build tools version there
2. Run emulator from Android studio or `emulator @<version>` from bash (you can find installed version by running `emulator -list-avds` from bash)
3. From project folder run
```
react-native run-android
```

### Testing
Testing framework uses mocha + enzyme, to run tests type
```
npm test
```

### Linters
This projects uses Eslint with React and React Native rules. To run linters type
```
npm run lint
```


### Flow
This projects uses Eslint with React and React Native rules. To run linters type
```
npm run flow
```

### Detailed docs

Can be found in `docs` folder. See [Introduction](docs/Introduction.md) to start.
8 changes: 8 additions & 0 deletions mobile/ReactNativeTutorial/__mocks__/mock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React from 'react';
import _ from 'lodash/fp';

export default (props) => React.createElement(
'Mock',
_.omit('store', props),
props.children,
);
39 changes: 39 additions & 0 deletions mobile/ReactNativeTutorial/__mocks__/mockCall.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
class MockCall {
constructor() {
this.queue = [];
}

setMocks(mocks) {
this.queue = mocks;
}

getNextMock() {
if (!this.queue || !this.queue.length) return undefined;
return this.queue.shift();
}

reset() {
this.queue = [];
}
}

const mockCall = new MockCall();

// Mocks calls inside a function under test. This function takes several args and
// stubs the return from call in order of occurence. If no mock were specified
// it returns underfined
export const mockCalls = (...args) => mockCall.setMocks(args);

// Clears all mocks for calls
export const resetMockCalls = () => mockCall.reset();

// The mock call dispatches a fake action to the store with type: 'CALL' and
// function name and args as parameters.
const call = ({ dispatch }) => (f, ...args) => {
dispatch({ type: 'CALL', name: f.name, args });
const mock = mockCall.getNextMock();
const result = typeof mock === 'function' ? mock() : mock;
return f.then ? Promise.resolve(result) : result;
};

export default call;
11 changes: 11 additions & 0 deletions mobile/ReactNativeTutorial/__mocks__/mockThunkMiddleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import call from './mockCall';

export const thunkMiddlewareCreator = (callEffect) =>
({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, callEffect({ dispatch }));
}
return next(action);
};

export default thunkMiddlewareCreator(call);
9 changes: 9 additions & 0 deletions mobile/ReactNativeTutorial/__mocks__/redux-mock-store.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import configureMockStore from 'redux-mock-store';
import { initialState as reduxInitialState } from 'ReactNativeTutorial/app/reducers';

import mockThunkMiddleware from './mockThunkMiddleware';

export const createStoreFromState = configureMockStore([mockThunkMiddleware]);
export const initialState = reduxInitialState;

export default () => createStoreFromState(initialState);
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from 'react';
import Add from 'ReactNativeTutorial/app/bundles/comments/components/Add/Add';

import renderer from 'react-test-renderer';

const actions = {
fetch: jest.fn(),
updateForm: jest.fn(),
createComment: jest.fn(),
};

describe('Add', () => {
it('renders correctly', () => {
const props = {
author: 'Alexey',
text: 'Some random comment',
actions,
};
const tree = renderer.create(
<Add {...props} />
);
expect(tree).toMatchSnapshot();
});
});
Loading