Skip to content

Commit

Permalink
Merge pull request #37 from AndrewGable/tgolen-add-comment
Browse files Browse the repository at this point in the history
Have the ability to add comments now
  • Loading branch information
AndrewGable authored Aug 10, 2020
2 parents c46bcc0 + cfc2829 commit 55ae09e
Show file tree
Hide file tree
Showing 8 changed files with 202 additions and 55 deletions.
61 changes: 36 additions & 25 deletions src/lib/Network.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,13 @@ function request(command, data, type = 'post') {
console.info('[API] Error', responseData);
})
// eslint-disable-next-line no-unused-vars
.catch(() => isAppOffline = true);
.catch(() => {
isAppOffline = true;

// Throw a new error to prevent any other `then()` in the promise chain from being triggered (until another
// catch() happens
throw new Error('API is offline');
});
}

// Holds a queue of all the write requests that need to happen
Expand All @@ -61,30 +67,35 @@ function delayedWrite(command, data) {
/**
* Process the write queue by looping through the queue and attempting to make the requests
*/
// function processWriteQueue() {
// if (isAppOffline) {
// // Make a simple request to see if we're online again
// request('Get', null, 'get')
// .then(() => isAppOffline = false);
// return;
// }
//
// if (delayedWriteQueue.length === 0) {
// return;
// }
//
// _.each(delayedWriteQueue, (delayedWriteRequest) => {
// request(delayedWriteRequest.command, delayedWriteRequest.data)
// .then(delayedWriteRequest.callback)
// .catch(() => {
// // If the request failed, we need to put the request object back into the queue
// delayedWriteQueue.push(delayedWriteRequest);
// });
// });
// }
function processWriteQueue() {
if (isAppOffline) {
// Make a simple request to see if we're online again
request('Get', null)
.then(() => isAppOffline = false);
return;
}

if (delayedWriteQueue.length === 0) {
return;
}

for (let i = 0; i < delayedWriteQueue.length; i++) {
// Take the request object out of the queue and make the request
const delayedWriteRequest = delayedWriteQueue.shift();

request(delayedWriteRequest.command, delayedWriteRequest.data)
.then(delayedWriteRequest.callback)
.catch(() => {
// If the request failed, we need to put the request object back into the queue
delayedWriteQueue.push(delayedWriteRequest);
});
}
}

// TODO: Figure out setInterval
// Process our write queue very often
// setInterval(processWriteQueue, 1000);
setInterval(processWriteQueue, 1000);

export {request, delayedWrite};
export {
request,
delayedWrite,
};
33 changes: 23 additions & 10 deletions src/lib/Pusher/pusher.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ function init(appKey, params) {
});

// If we want to pass params in our requests to api.php we'll need to add it to socket.config.auth.params
// as per the documentation (https://pusher.com/docs/channels/using_channels/connection#channels-options-parameter).
// as per the documentation
// (https://pusher.com/docs/channels/using_channels/connection#channels-options-parameter).
// Any param mentioned here will show up in $_REQUEST when we call "Push_Authenticate". Params passed here need
// to pass our inputRules to show up in the request.
if (params) {
Expand Down Expand Up @@ -92,8 +93,9 @@ function bindEventToChannel(channel, eventName, eventCallback = () => {}, isChun
return;
}

// If we are chunking the requests, we need to construct a rolling list of all packets that have come through Pusher.
// If we've completed one of these full packets, we'll combine the data and act on the event that it's assigned to.
// If we are chunking the requests, we need to construct a rolling list of all packets that have come through
// Pusher. If we've completed one of these full packets, we'll combine the data and act on the event that it's
// assigned to.

// If we haven't seen this eventID yet, initialize it into our rolling list of packets.
if (!chunkedDataEvents[eventData.id]) {
Expand All @@ -109,13 +111,17 @@ function bindEventToChannel(channel, eventName, eventCallback = () => {}, isChun
chunkedEvent.receivedFinal = true;
}

// Only call the event callback if we've received the last packet and we don't have any holes in the complete packet.
// Only call the event callback if we've received the last packet and we don't have any holes in the complete
// packet.
if (chunkedEvent.receivedFinal && chunkedEvent.chunks.length === Object.keys(chunkedEvent.chunks).length) {
eventCallback(JSON.parse(chunkedEvent.chunks.join('')));
try {
eventCallback(JSON.parse(chunkedEvent.chunks.join('')));
} catch (err) {
console.error('[Pusher] Unable to parse chunked JSON response from Pusher', 0, {error: err, eventData: chunkedEvent.chunks.join('')});
console.error('[Pusher] Unable to parse chunked JSON response from Pusher', 0, {
error: err,
eventData: chunkedEvent.chunks.join('')
});
}

delete chunkedDataEvents[eventData.id];
Expand All @@ -131,7 +137,8 @@ function bindEventToChannel(channel, eventName, eventCallback = () => {}, isChun
* @param {String} channelName
* @param {String} eventName
* @param {Function} [eventCallback]
* @param {Boolean} [isChunked] This parameters tells us whether or not we expect the result to come in individual pieces/chunks (because it exceeds
* @param {Boolean} [isChunked] This parameters tells us whether or not we expect the result to come in individual
* pieces/chunks (because it exceeds
* the 10kB limit that pusher has).
*
* @return {Promise}
Expand All @@ -142,7 +149,8 @@ function subscribe(channelName, eventName, eventCallback = () => {}, isChunked =
return new Promise((resolve, reject) => {
// We cannot call subscribe() before init(). Prevent any attempt to do this on dev.
if (!socket) {
throw new Error('[Pusher] instance not found. Pusher.subscribe() most likely has been called before Pusher.init()');
throw new Error(`[Pusher] instance not found. Pusher.subscribe()
most likely has been called before Pusher.init()`);
}

console.debug('[Pusher] Attempting to subscribe to channel', true, {channelName, eventName});
Expand All @@ -157,7 +165,10 @@ function subscribe(channelName, eventName, eventCallback = () => {}, isChunked =

channel.bind('pusher:subscription_error', (status) => {
if (status === 403) {
console.debug('[Pusher] Issue authenticating with Pusher during subscribe attempt.', 0, {channelName, status});
console.debug('[Pusher] Issue authenticating with Pusher during subscribe attempt.', 0, {
channelName,
status
});
}

reject(status);
Expand Down Expand Up @@ -200,7 +211,8 @@ function unsubscribe(channelName, eventName = '') {
const channel = getChannel(channelName);

if (!channel) {
console.debug('[Pusher] Attempted to unsubscribe or unbind from a channel, but Pusher-JS has no knowledge of it', 0, {channelName, eventName});
console.debug(`[Pusher] Attempted to unsubscribe or unbind from a channel,
but Pusher-JS has no knowledge of it`, 0, {channelName, eventName});
return;
}

Expand All @@ -210,7 +222,8 @@ function unsubscribe(channelName, eventName = '') {
} else {
if (!channel.subscribed) {
// eslint-disable-next-line no-console
console.warn('[Pusher] Attempted to unsubscribe from channel, but we are not subscribed to begin with', 0, {channelName});
console.warn(`[Pusher] Attempted to unsubscribe from channel,
but we are not subscribed to begin with`, 0, {channelName});
return;
}

Expand Down
102 changes: 102 additions & 0 deletions src/page/HomePage/Report/ReportHistoryCompose.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import React from 'react';
import PropTypes from 'prop-types';
import {View, TextInput, Button} from 'react-native';
import styles from '../../../style/StyleSheet';

const propTypes = {
// A method to call when the form is submitted
onSubmit: PropTypes.func.isRequired,
};

class ReportHistoryCompose extends React.Component {
constructor(props) {
super(props);

this.updateComment = this.updateComment.bind(this);
this.submitForm = this.submitForm.bind(this);
this.triggerSubmitShortcut = this.triggerSubmitShortcut.bind(this);

this.state = {
comment: '',
};
}

componentDidMount() {
this.textInput.focus();
}

componentDidUpdate() {
this.textInput.focus();
}

/**
* Update the value of the comment input in the state
*
* @param {string} newComment
*/
updateComment(newComment) {
this.setState({
comment: newComment,
});
}

/**
* Listens for the keyboard shortcut and submits
* the form when we have enter
*
* @param {Object} e
*/
triggerSubmitShortcut(e) {
if (e && e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
this.submitForm();
}
}

/**
* Add a new comment to this chat
*
* @param {SyntheticEvent} [e]
*/
submitForm(e) {
if (e) {
e.preventDefault();
}

// Don't submit empty commentes
// @TODO show an error in the UI
if (!this.state.comment) {
return;
}

this.props.onSubmit(this.state.comment);
this.setState({
comment: '',
});
}

render() {
return (
<View style={[styles.mt2]}>
<TextInput
ref={el => this.textInput = el}
multiline
textAlignVertical
numberOfLines={3}
minHeight={60}
maxHeight={60}
onChangeText={this.updateComment}
onKeyPress={this.triggerSubmitShortcut}
style={[styles.textInput]}
value={this.state.comment}
/>
<View style={[styles.mt1, styles.flexRow]}>
<Button title="Send" onPress={this.submitForm} />
</View>
</View>
);
}
}
ReportHistoryCompose.propTypes = propTypes;

export default ReportHistoryCompose;
4 changes: 2 additions & 2 deletions src/page/HomePage/Report/ReportHistoryItem.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import {Text, View} from 'react-native';
import {ActivityIndicator, View} from 'react-native';
import PropTypes from 'prop-types';
import ReportHistoryItemSingle from './ReportHistoryItemSingle';
import ReportHistoryPropsTypes from './ReportHistoryPropsTypes';
Expand All @@ -21,7 +21,7 @@ class ReportHistoryItem extends React.Component {
<View>
{!this.props.displayAsGroup && <ReportHistoryItemSingle historyItem={this.props.historyItem} />}
{this.props.displayAsGroup && <ReportHistoryItemGrouped historyItem={this.props.historyItem} />}
{this.props.historyItem.tempGuid && <Text>pending...</Text>}
{this.props.historyItem.tempGuid && <ActivityIndicator type="small" color="#7d8b8f" />}
</View>
);
}
Expand Down
18 changes: 11 additions & 7 deletions src/page/HomePage/Report/ReportHistoryView.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import {Text, FlatList} from 'react-native';
import {Text, VirtualizedList} from 'react-native';
import PropTypes from 'prop-types';
import _ from 'underscore';
import lodashGet from 'lodash.get';
Expand All @@ -18,6 +18,10 @@ const propTypes = {
};

class ReportHistoryView extends React.Component {
constructor(props) {
super(props);
}

componentDidMount() {
this.bindToStore();
}
Expand Down Expand Up @@ -54,10 +58,6 @@ class ReportHistoryView extends React.Component {
loaderParams: [this.props.reportID],
}
}, this);

if (this.reportHistoryList) {
this.reportHistoryList.scrollToEnd();
}
}

/**
Expand Down Expand Up @@ -97,9 +97,13 @@ class ReportHistoryView extends React.Component {
}

return (
<FlatList
<VirtualizedList
ref={el => this.reportHistoryList = el}
data={filteredHistory}
data={filteredHistory.reverse()}
getItemCount={() => filteredHistory.length}
getItem={(data, index) => filteredHistory[index]}
initialNumToRender="10"
inverted
renderItem={({index, item}) => (
<ReportHistoryItem
historyItem={item}
Expand Down
3 changes: 3 additions & 0 deletions src/page/HomePage/Report/ReportView.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import WithStore from '../../../components/WithStore';
import STOREKEYS from '../../../store/STOREKEYS';
import styles from '../../../style/StyleSheet';
import ReportHistoryView from './ReportHistoryView';
import ReportHistoryCompose from './ReportHistoryCompose';
import {addHistoryItem} from '../../../store/actions/ReportActions';

const propTypes = {
// These are from WithStore
Expand Down Expand Up @@ -58,6 +60,7 @@ class ReportView extends React.Component {
<View style={styles.flex1}>
<Route path="/:reportID" exact>
<ReportHistoryView reportID={this.props.match.params.reportID} />
<ReportHistoryCompose onSubmit={text => addHistoryItem(this.props.match.params.reportID, text)} />
</Route>
</View>
);
Expand Down
Loading

0 comments on commit 55ae09e

Please sign in to comment.