Skip to content

Commit b3b55f7

Browse files
author
Alex Alexeev
committed
Fetch and store data
1 parent 497280d commit b3b55f7

11 files changed

Lines changed: 372 additions & 186 deletions

App.js

Lines changed: 76 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,41 +5,90 @@
55
*/
66

77
import React, { Component } from 'react';
8-
import {
9-
Platform,
10-
StyleSheet,
11-
Text,
12-
View
13-
} from 'react-native';
14-
15-
import surveys from './survey/default_surveys';
16-
import Survey from './survey';
8+
import { Platform, StyleSheet, Text, View, AsyncStorage } from 'react-native';
9+
import uuid from 'react-native-uuid';
10+
import { Toast, Root } from 'native-base';
1711

12+
import surveys from './src/default_surveys';
13+
import Survey from './src/Survey';
1814

1915
const instructions = Platform.select({
20-
ios: 'Press Cmd+R to reload,\n' +
21-
'Cmd+D or shake for dev menu',
22-
android: 'Double tap R on your keyboard to reload,\n' +
23-
'Shake or press menu button for dev menu',
16+
ios: 'Press Cmd+R to reload,\n' + 'Cmd+D or shake for dev menu',
17+
android:
18+
'Double tap R on your keyboard to reload,\n' +
19+
'Shake or press menu button for dev menu'
2420
});
2521

26-
export default class App extends Component<{}> {
22+
// @TODO: add specific types
23+
type State = {
24+
survey: ?Object,
25+
error: ?Object
26+
};
27+
28+
export default class App extends Component<{}, State> {
29+
state: State = {
30+
survey: null,
31+
error: null
32+
};
33+
34+
async componentDidMount() {
35+
await this.getSurveyData();
36+
}
37+
38+
getSurveyData = async () => {
39+
const remoteJSON = await fetch(
40+
'https://surveyjs-data-3cv0xvjbs.now.sh/questions-paged.json',
41+
{}
42+
)
43+
.then(response => response.json())
44+
.catch(error => {
45+
throw new Error('Error fetching a survey', error);
46+
});
47+
if (remoteJSON) {
48+
await this.storeData(remoteJSON.data);
49+
}
50+
};
51+
52+
storeData = async survey => {
53+
try {
54+
const id = uuid.v1();
55+
const key = `@Surveys:${id}`;
56+
await AsyncStorage.setItem(key, JSON.stringify({ ...survey, id }));
57+
const storedSurvey = await AsyncStorage.getItem(key);
58+
const surveyJSON = JSON.parse(storedSurvey);
59+
Toast.show({
60+
text: `Successfully stored the survey with id ${
61+
surveyJSON.id
62+
} and title "${surveyJSON.title}"`,
63+
buttonText: 'Okay'
64+
});
65+
this.setState({ survey: surveyJSON });
66+
} catch (error) {
67+
throw new Error('Error storing a survey', error);
68+
}
69+
};
2770

2871
onSurveyCompleted(ownProps, nextProps) {
2972
//TODO: Readers hooks go here.
30-
alert("Nested Survey was completed!");
73+
alert('Nested Survey was completed!');
3174
}
3275

33-
3476
render() {
3577
return (
36-
<Survey
37-
surveyJSON={surveys.example3PagePatientSatisfactionSurvey}
38-
title="My Custom Survey Title"
39-
navigation={this.props.navigation}
40-
surveyResponseDateString={''}
41-
onSurveyComplete={this.onSurveyCompleted}
42-
data={{}}/>
78+
<Root>
79+
{this.state.survey ? (
80+
<Survey
81+
surveyJSON={this.state.survey}
82+
title={this.state.survey.title}
83+
navigation={this.props.navigation}
84+
surveyResponseDateString={''}
85+
onSurveyComplete={this.onSurveyCompleted}
86+
data={{}}
87+
/>
88+
) : (
89+
<Text>Loading survey...</Text>
90+
)}
91+
</Root>
4392
);
4493
}
4594
}
@@ -49,16 +98,16 @@ const styles = StyleSheet.create({
4998
flex: 1,
5099
justifyContent: 'center',
51100
alignItems: 'center',
52-
backgroundColor: '#F5FCFF',
101+
backgroundColor: '#F5FCFF'
53102
},
54103
welcome: {
55104
fontSize: 20,
56105
textAlign: 'center',
57-
margin: 10,
106+
margin: 10
58107
},
59108
instructions: {
60109
textAlign: 'center',
61110
color: '#333333',
62-
marginBottom: 5,
63-
},
111+
marginBottom: 5
112+
}
64113
});

index.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import { AppRegistry } from 'react-native';
22
import App from './App';
33

4-
AppRegistry.registerComponent('SurveyJSInWebViewWithReactAndReactNative', () => App);
4+
AppRegistry.registerComponent(
5+
'SurveyJSInWebViewWithReactAndReactNative',
6+
() => App
7+
);

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@
77
"test": "jest"
88
},
99
"dependencies": {
10+
"buffer": "^5.2.1",
1011
"lodash": "4.17.11",
1112
"moment": "^2.23.0",
1213
"native-base": "^2.10.0",
1314
"prop-types": "15.6.2",
1415
"react": "16.6.3",
1516
"react-native": "0.57.8",
17+
"react-native-uuid": "^1.4.9",
1618
"react-native-webview-bridge": "^0.40.1",
1719
"react-navigation": "3.0.9",
1820
"react-redux": "6.0.0",

src/Survey.js

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
import React, { Component } from 'react';
2+
import { Dimensions, AsyncStorage } from 'react-native';
3+
import WebViewBridge from 'react-native-webview-bridge';
4+
import {
5+
StyleProvider,
6+
Container,
7+
Text,
8+
Button,
9+
Footer,
10+
Toast
11+
} from 'native-base';
12+
import { SourceCode } from 'NativeModules';
13+
import PropTypes from 'prop-types';
14+
import { bindActionCreators } from 'redux';
15+
import { connect } from 'react-redux';
16+
import moment from 'moment';
17+
import _ from 'lodash';
18+
import uuid from 'react-native-uuid';
19+
20+
function prepareForBridge(message) {
21+
//Replaces the singlequote character with symbol we can fix on the other side.
22+
return JSON.stringify(message).replace(/'/g, '__@@__');
23+
}
24+
25+
//Android/iOS specific file loading our html assets:
26+
let VIEW;
27+
const scriptURL = SourceCode.scriptURL;
28+
if (scriptURL.indexOf('file://') > -1) {
29+
const _bundleSourcePath = scriptURL.substring(
30+
7,
31+
scriptURL.lastIndexOf('/') + 1
32+
);
33+
const name = require('./prodViewUri');
34+
const fileURI = `${_bundleSourcePath}${name}`;
35+
VIEW = { uri: fileURI };
36+
} else {
37+
VIEW = require('../webviews/surveyIndex.html');
38+
}
39+
40+
export default class Survey extends Component {
41+
static propTypes = {
42+
navigation: PropTypes.object,
43+
actions: PropTypes.object,
44+
data: PropTypes.object.isRequired,
45+
errorMessage: PropTypes.string,
46+
surveyJSON: PropTypes.object.isRequired,
47+
title: PropTypes.string,
48+
onSurveyComplete: PropTypes.func,
49+
surveyResponseDateString: PropTypes.string.isRequired //Pass in existing response data if you want survey to show existing data.
50+
};
51+
52+
constructor(props) {
53+
super(props);
54+
this.onLoad = this.onLoad.bind(this);
55+
}
56+
57+
onLoad() {
58+
//Replace \n with <br/> to keep survey library happy:
59+
var surveyString1 = JSON.stringify(this.props.surveyJSON)
60+
.split('\\n')
61+
.join('<br/>');
62+
var surveyObj = JSON.parse(surveyString1);
63+
64+
//Load response data for specified survey date if it exists:
65+
var surveyResponseObj = this.getResponseForDate(
66+
this.props.surveyResponseDateString
67+
);
68+
69+
setTimeout(
70+
() =>
71+
this.refs.webviewbridge.sendToBridge(
72+
prepareForBridge({
73+
action: 'LOAD',
74+
survey: surveyObj,
75+
surveydata: surveyResponseObj
76+
})
77+
),
78+
500
79+
);
80+
}
81+
82+
onBridgeMessage = async msg => {
83+
const message = JSON.parse(msg);
84+
85+
if (message.action && message.action === 'COMPLETESURVEY') {
86+
var singleSurveyMap = {};
87+
singleSurveyMap[this.props.title] = [message.surveydata];
88+
message.surveydata.CompletionDate = moment().toISOString();
89+
90+
if (!message.surveydata.DataDate) {
91+
message.surveydata.DataDate = message.surveydata.CompletionDate;
92+
}
93+
try {
94+
const id = uuid.v1();
95+
96+
// TODO: use optional chaining propsal to check for nulls
97+
const key = `@Responses:${id}${(message.surveydata &&
98+
message.surveydata.email) ||
99+
''}`;
100+
Toast.show({
101+
text: `before set, ${key}`,
102+
buttonText: 'Okay'
103+
});
104+
await AsyncStorage.setItem(
105+
key,
106+
JSON.stringify({ ...message.surveydata, id })
107+
);
108+
Toast.show({
109+
text: `after set`,
110+
buttonText: 'Okay'
111+
});
112+
const storedResponses = await AsyncStorage.getItem(key);
113+
114+
if (storedResponses) {
115+
const responsesJSON = JSON.parse(storedResponses);
116+
Toast.show({
117+
text: `Successfully stored responsn with id ${
118+
responsesJSON.id
119+
} and user email ${responsesJSON.email}`,
120+
buttonText: 'Okay'
121+
});
122+
}
123+
} catch (error) {
124+
throw new Error('Error storing responses', error);
125+
}
126+
//TODO: Exercise left to the reader :)
127+
}
128+
};
129+
130+
//Get saved survey response from user data if it exists already and survey versions are the same.
131+
getResponseForDate(dateString) {
132+
//TODO: If you want the survey to start auto filled out, a SurveyJS JSON response can be placed here.
133+
134+
return {};
135+
}
136+
137+
render() {
138+
const { height: screenHeight } = Dimensions.get('window');
139+
140+
return (
141+
<WebViewBridge
142+
ref="webviewbridge"
143+
style={{ flex: 1, height: 500, justifyContent: 'center' }}
144+
source={VIEW}
145+
scalesPageToFit={false}
146+
scrollEnabled
147+
javaScriptEnabled
148+
onLoad={this.onLoad}
149+
onBridgeMessage={this.onBridgeMessage}
150+
/>
151+
);
152+
}
153+
}

0 commit comments

Comments
 (0)