Regression: Resend messages with error (#532)

This commit is contained in:
Diego Mello 2018-11-16 09:06:29 -02:00 committed by GitHub
parent c6fcfb63fd
commit e9deb577e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 691 additions and 147 deletions

View File

@ -1,3 +1,4 @@
export const RectButton = () => 'View';
export const State = () => 'View';
export const LongPressGestureHandler = () => 'View';
export const BorderlessButton = () => 'View';

View File

@ -228,7 +228,15 @@ exports[`Storyshots Message list 1`] = `
}
>
<View>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -252,7 +260,15 @@ exports[`Storyshots Message list 1`] = `
>
Simple
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -276,11 +292,51 @@ exports[`Storyshots Message list 1`] = `
>
Long message
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -304,7 +360,15 @@ exports[`Storyshots Message list 1`] = `
>
Grouped messages
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -328,7 +392,15 @@ exports[`Storyshots Message list 1`] = `
>
Without header
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -352,7 +424,15 @@ exports[`Storyshots Message list 1`] = `
>
With alias
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -376,7 +456,15 @@ exports[`Storyshots Message list 1`] = `
>
Edited
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -400,7 +488,15 @@ exports[`Storyshots Message list 1`] = `
>
Static avatar
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -424,7 +520,15 @@ exports[`Storyshots Message list 1`] = `
>
Full name
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -448,7 +552,15 @@ exports[`Storyshots Message list 1`] = `
>
Mentions
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -472,7 +584,15 @@ exports[`Storyshots Message list 1`] = `
>
Emojis
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -496,7 +616,15 @@ exports[`Storyshots Message list 1`] = `
>
Custom Emojis
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -520,7 +648,15 @@ exports[`Storyshots Message list 1`] = `
>
Time format
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -544,7 +680,15 @@ exports[`Storyshots Message list 1`] = `
>
Reactions
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -568,10 +712,42 @@ exports[`Storyshots Message list 1`] = `
>
Multiple reactions
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -595,7 +771,15 @@ exports[`Storyshots Message list 1`] = `
>
Intercalated users
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<View
style={
Object {
@ -668,7 +852,15 @@ exports[`Storyshots Message list 1`] = `
unread messages
</Text>
</View>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<View
style={
Object {
@ -739,8 +931,24 @@ exports[`Storyshots Message list 1`] = `
}
/>
</View>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<View
style={
Object {
@ -802,7 +1010,15 @@ exports[`Storyshots Message list 1`] = `
}
/>
</View>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -826,8 +1042,24 @@ exports[`Storyshots Message list 1`] = `
>
Date and Unread separators
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -851,7 +1083,15 @@ exports[`Storyshots Message list 1`] = `
>
With image
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -875,7 +1115,15 @@ exports[`Storyshots Message list 1`] = `
>
With video
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -899,7 +1147,15 @@ exports[`Storyshots Message list 1`] = `
>
With audio
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -923,7 +1179,15 @@ exports[`Storyshots Message list 1`] = `
>
URL
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -947,7 +1211,15 @@ exports[`Storyshots Message list 1`] = `
>
Custom fields
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -971,7 +1243,15 @@ exports[`Storyshots Message list 1`] = `
>
Two short custom fields
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -995,7 +1275,15 @@ exports[`Storyshots Message list 1`] = `
>
Broadcast
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -1019,8 +1307,26 @@ exports[`Storyshots Message list 1`] = `
>
Archived
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
View
</View>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
View
</View>
<Text
style={
Array [
@ -1044,7 +1350,15 @@ exports[`Storyshots Message list 1`] = `
>
Error
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -1068,7 +1382,15 @@ exports[`Storyshots Message list 1`] = `
>
Temp
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -1092,7 +1414,15 @@ exports[`Storyshots Message list 1`] = `
>
Editing
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -1116,7 +1446,15 @@ exports[`Storyshots Message list 1`] = `
>
Removed
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -1140,7 +1478,15 @@ exports[`Storyshots Message list 1`] = `
>
Joined
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -1164,7 +1510,15 @@ exports[`Storyshots Message list 1`] = `
>
Room name changed
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -1188,7 +1542,15 @@ exports[`Storyshots Message list 1`] = `
>
Message pinned
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -1212,7 +1574,15 @@ exports[`Storyshots Message list 1`] = `
>
Has left the channel
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -1236,7 +1606,15 @@ exports[`Storyshots Message list 1`] = `
>
User removed
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -1260,7 +1638,15 @@ exports[`Storyshots Message list 1`] = `
>
User added
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -1284,7 +1670,15 @@ exports[`Storyshots Message list 1`] = `
>
User muted
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -1308,7 +1702,15 @@ exports[`Storyshots Message list 1`] = `
>
User unmuted
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -1332,7 +1734,15 @@ exports[`Storyshots Message list 1`] = `
>
Role added
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -1356,7 +1766,15 @@ exports[`Storyshots Message list 1`] = `
>
Role removed
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -1380,7 +1798,15 @@ exports[`Storyshots Message list 1`] = `
>
Changed description
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -1404,7 +1830,15 @@ exports[`Storyshots Message list 1`] = `
>
Changed announcement
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -1428,7 +1862,15 @@ exports[`Storyshots Message list 1`] = `
>
Changed topic
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -1452,7 +1894,15 @@ exports[`Storyshots Message list 1`] = `
>
Changed type
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -1476,7 +1926,15 @@ exports[`Storyshots Message list 1`] = `
>
Custom style
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -1500,7 +1958,15 @@ exports[`Storyshots Message list 1`] = `
>
Markdown emphasis
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -1524,7 +1990,15 @@ exports[`Storyshots Message list 1`] = `
>
Markdown headers
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -1548,7 +2022,15 @@ exports[`Storyshots Message list 1`] = `
>
Markdown links
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -1572,7 +2054,15 @@ exports[`Storyshots Message list 1`] = `
>
Markdown image
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -1596,7 +2086,15 @@ exports[`Storyshots Message list 1`] = `
>
Markdown code
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [
@ -1620,7 +2118,15 @@ exports[`Storyshots Message list 1`] = `
>
Markdown quote
</Text>
<View
style={
Object {
"flexDirection": "row",
}
}
>
View
</View>
<Text
style={
Array [

View File

@ -31,9 +31,11 @@ export default class MessageErrorActions extends React.Component {
this.CANCEL_INDEX = 0;
this.DELETE_INDEX = 1;
this.RESEND_INDEX = 2;
setTimeout(() => {
if (this.actionSheet && this.actionSheet.show) {
this.actionSheet.show();
}
});
}
handleResend = protectedFunction(() => {

View File

@ -6,7 +6,9 @@ import {
import Icon from 'react-native-vector-icons/MaterialIcons';
import moment from 'moment';
import { KeyboardUtils } from 'react-native-keyboard-input';
import { State, RectButton, LongPressGestureHandler } from 'react-native-gesture-handler';
import {
State, RectButton, LongPressGestureHandler, BorderlessButton
} from 'react-native-gesture-handler';
import Image from './Image';
import User from './User';
@ -252,7 +254,11 @@ export default class Message extends PureComponent {
return null;
}
const { onErrorPress } = this.props;
return <Icon name='error-outline' color='red' size={20} style={styles.errorIcon} onPress={onErrorPress} />;
return (
<BorderlessButton onPress={onErrorPress} style={styles.errorButton}>
<Icon name='error-outline' color='red' size={20} />
</BorderlessButton>
);
}
renderReaction = (reaction) => {
@ -337,12 +343,14 @@ export default class Message extends PureComponent {
const accessibilityLabel = I18n.t('Message_accessibility', { user: author.username, time: moment(ts).format(timeFormat), message: msg });
return (
<View style={styles.root}>
{this.renderError()}
<LongPressGestureHandler
onHandlerStateChange={({ nativeEvent }) => nativeEvent.state === State.ACTIVE && onLongPress()}
>
<RectButton
enabled={!(this.isInfoMessage() || this.hasError() || archived)}
style={[styles.container, header && { marginBottom: 10 }]}
style={[styles.container, header && styles.marginBottom]}
onPress={this.onPress}
activeOpacity={0.8}
underlayColor='#e1e5e8'
@ -352,9 +360,16 @@ export default class Message extends PureComponent {
accessibilityLabel={accessibilityLabel}
>
<View style={styles.flex}>
{this.renderError()}
{this.renderAvatar()}
<View style={[styles.messageContent, header && styles.hasHeader, this.isTemp() && styles.temp]}>
<View
style={[
styles.messageContent,
header && styles.messageContentWithHeader,
this.hasError() && header && styles.messageContentWithHeader,
this.hasError() && !header && styles.messageContentWithError,
this.isTemp() && styles.temp
]}
>
{this.renderUsername()}
{this.renderContent()}
{this.renderAttachment()}
@ -379,6 +394,7 @@ export default class Message extends PureComponent {
</View>
</RectButton>
</LongPressGestureHandler>
</View>
);
}
}

View File

@ -1,16 +1,24 @@
import { StyleSheet, Platform } from 'react-native';
export default StyleSheet.create({
root: {
flexDirection: 'row'
},
container: {
paddingVertical: 5
paddingVertical: 5,
flexDirection: 'row',
width: '100%'
},
messageContent: {
flex: 1,
marginLeft: 51
},
hasHeader: {
messageContentWithHeader: {
marginLeft: 15
},
messageContentWithError: {
marginLeft: 0
},
flex: {
flexDirection: 'row',
flex: 1
@ -35,6 +43,9 @@ export default StyleSheet.create({
height: 20
},
temp: { opacity: 0.3 },
marginBottom: {
marginBottom: 10
},
codeStyle: {
...Platform.select({
ios: { fontFamily: 'Courier New' },
@ -92,10 +103,9 @@ export default StyleSheet.create({
width: 17,
height: 17
},
errorIcon: {
paddingRight: 12,
paddingLeft: 0,
alignSelf: 'center'
errorButton: {
paddingHorizontal: 15,
paddingVertical: 5
},
broadcastButton: {
width: 107,

View File

@ -48,7 +48,7 @@ export default async function canOpenRoom({ rid, path }) {
const [type, name] = path.split('/');
try {
const data = await (SDK.driver.ddp ? canOpenRoomDDP.call(this, { rid, type, name }) : canOpenRoomREST.call(this, { type, rid }));
const data = await (this.connected() ? canOpenRoomDDP.call(this, { rid, type, name }) : canOpenRoomREST.call(this, { type, rid }));
return data;
} catch (e) {
log('canOpenRoom', e);

View File

@ -36,7 +36,7 @@ export default function() {
return new Promise(async(resolve, reject) => {
try {
const { subscriptions, rooms } = await (SDK.driver.ddp ? getRoomDpp.apply(this) : getRoomRest.apply(this));
const { subscriptions, rooms } = await (this.connected() ? getRoomDpp.apply(this) : getRoomRest.apply(this));
const data = rooms.map(room => ({ room, sub: database.objects('subscriptions').filtered('rid == $0', room._id) }));

View File

@ -38,7 +38,7 @@ export default function loadMessagesForRoom(...args) {
const { database: db } = database;
return new Promise(async(resolve, reject) => {
try {
const data = (await (SDK.driver.ddp
const data = (await (this.connected()
? loadMessagesForRoomDDP.call(this, ...args)
: loadMessagesForRoomRest.call(this, ...args))).map(buildMessage);

View File

@ -9,6 +9,8 @@ async function loadMissedMessagesRest({ rid: roomId, lastOpen }) {
let lastUpdate;
if (lastOpen) {
lastUpdate = new Date(lastOpen).toISOString();
} else {
return [];
}
const { result } = await SDK.api.get('chat.syncMessages', { roomId, lastUpdate, count: 50 });
return result;
@ -29,7 +31,7 @@ export default function loadMissedMessages(...args) {
const { database: db } = database;
return new Promise(async(resolve, reject) => {
try {
const data = (await (SDK.driver.ddp ? loadMissedMessagesDDP.call(this, ...args) : loadMissedMessagesRest.call(this, ...args)));
const data = (await (this.connected() ? loadMissedMessagesDDP.call(this, ...args) : loadMissedMessagesRest.call(this, ...args)));
if (data) {
if (data.updated && data.updated.length) {

View File

@ -19,7 +19,7 @@ export default async function readMessages(rid) {
const ls = new Date();
const { database: db } = database;
try {
const data = await (SDK.driver.ddp ? readMessagesDDP.call(this, rid) : readMessagesREST.call(this, rid));
const data = await (this.connected() ? readMessagesDDP.call(this, rid) : readMessagesREST.call(this, rid));
const [subscription] = db.objects('subscriptions').filtered('rid = $0', rid);
db.write(() => {
subscription.open = true;

View File

@ -31,26 +31,22 @@ export const getMessage = (rid, msg = {}) => {
return message;
};
function sendMessageByRest(message) {
const { _id, rid, msg } = message;
return SDK.api.post('chat.sendMessage', { message: { _id, rid, msg } });
function sendMessageByRest(args) {
return SDK.api.post('chat.sendMessage', { message: args });
}
function sendMessageByDDP(message) {
const { _id, rid, msg } = message;
return SDK.driver.asyncCall('sendMessage', { _id, rid, msg });
function sendMessageByDDP(...args) {
try {
return SDK.driver.asyncCall('sendMessage', ...args);
} catch (error) {
return sendMessageByRest.call(this, ...args);
}
}
export async function _sendMessageCall(message) {
try {
const data = await (SDK.driver.ddp ? sendMessageByDDP.call(this, message) : sendMessageByRest.call(this, message));
const { _id, rid, msg } = message;
const data = await (this.connected() ? sendMessageByDDP.call(this, { _id, rid, msg }) : sendMessageByRest.call(this, { _id, rid, msg }));
return data;
} catch (e) {
database.write(() => {
message.status = messagesStatus.ERROR;
database.create('messages', message, true);
});
}
}
export default async function(rid, msg) {
@ -63,11 +59,17 @@ export default async function(rid, msg) {
room.lastMessage = message;
});
try {
const ret = await _sendMessageCall.call(this, message);
// TODO: maybe I have created a bug in the future here <3
db.write(() => {
db.create('messages', buildMessage({ ...message, ...ret }), true);
});
} catch (e) {
database.write(() => {
message.status = messagesStatus.ERROR;
database.create('messages', message, true);
});
}
} catch (e) {
log('sendMessage', e);
}

View File

@ -43,7 +43,7 @@ export default function subscribeRoom({ rid, t }) {
}, 5000);
};
if (!SDK.driver.ddp && SDK.driver.userId) {
if (!this.connected()) {
loop();
} else {
SDK.driver.on('logged', () => {

View File

@ -30,7 +30,7 @@ export default async function subscribeRooms(id) {
}, 5000);
};
if (!SDK.driver.ddp && SDK.driver.userId) {
if (!this.connected()) {
loop();
} else {
SDK.driver.on('logged', () => {
@ -44,13 +44,13 @@ export default async function subscribeRooms(id) {
});
SDK.driver.on('disconnected', () => {
if (this._login) {
if (SDK.driver.userId) {
loop();
}
});
SDK.driver.on('stream-notify-user', protectedFunction((e, ddpMessage) => {
if (ddpMessage.msg === 'added') {
if (!this.ddp || ddpMessage.msg === 'added') {
return;
}
const [type, data] = ddpMessage.fields.args;

View File

@ -421,6 +421,9 @@ const RocketChat = {
log('SDK.connect catch', e);
});
},
connected() {
return SDK.driver.ddp && SDK.driver.ddp._logged;
},
register({ credentials }) {
return call('registerUser', credentials);
@ -534,7 +537,7 @@ const RocketChat = {
message.status = messagesStatus.TEMP;
database.create('messages', message, true);
});
return _sendMessageCall(JSON.parse(JSON.stringify(message)));
return _sendMessageCall.call(this, JSON.parse(JSON.stringify(message)));
},
async search({ text, filterUsers = true, filterRooms = true }) {

View File

@ -20,6 +20,7 @@ let LoginView = null;
const handleSelectServer = function* handleSelectServer({ server }) {
try {
yield database.setActiveDB(server);
yield put(connectRequest());
yield call([AsyncStorage, 'setItem'], 'currentServer', server);
const token = yield AsyncStorage.getItem(`${ RocketChat.TOKEN_KEY }-${ server }`);
if (token) {
@ -36,7 +37,6 @@ const handleSelectServer = function* handleSelectServer({ server }) {
return result;
}, {})));
yield put(connectRequest());
yield put(selectServerSuccess(server));
} catch (e) {
log('handleSelectServer', e);

View File

@ -116,7 +116,7 @@ export default class RoomView extends LoggedView {
const {
room, loaded, joined, end
} = this.state;
const { showActions } = this.props;
const { showActions, showErrorActions } = this.props;
if (room.ro !== nextState.room.ro) {
return true;
@ -130,6 +130,8 @@ export default class RoomView extends LoggedView {
return true;
} else if (showActions !== nextProps.showActions) {
return true;
} else if (showErrorActions !== nextProps.showErrorActions) {
return true;
}
return false;
}

6
package-lock.json generated
View File

@ -2578,9 +2578,9 @@
"integrity": "sha512-FWR7QB7EqBRq1s9BMk0ccOSOuRLfVEWYpHQYpFPaXtCoqN6dJx2ttdsdQbUxLLnAlKpYeVjveGGhQ3583TTa7g=="
},
"@types/node": {
"version": "9.6.35",
"resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.35.tgz",
"integrity": "sha512-h5zvHS8wXHGa+Gcqs9K8vqCgOtqjr0+NqG/DDJmQIX1wpR9HivAfgV8bjcD3mGM4bPfQw5Aneb2Pn8355L83jA=="
"version": "9.6.36",
"resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.36.tgz",
"integrity": "sha512-Fbw+AdRLL01vv7Rk7bYaNPecqmKoinJHGbpKnDpbUZmUj/0vj3nLqPQ4CNBzr3q2zso6Cq/4jHoCAdH78fvJrw=="
},
"@types/react": {
"version": "16.4.6",