Commit 03e1ffca authored by MrMan's avatar MrMan

Debounce location updates, add convo message page

parent 6ad739e1
......@@ -8,17 +8,17 @@ import { generateI18NTemplateFn } from "../i18n";
const DEFAULT_STATE = {matchId: null, userInfo: null};
class MatchConvoLink extends React.Component {
constructor(params) {
super(params);
constructor(props) {
super(props);
this.state = DEFAULT_STATE;
this.unsubFunctions = {};
this.i18n = generateI18NTemplateFn("en-US");
// Process params
// Process props
this.state = _.extend(this.state, {
matchId: params.matchId || null,
user: params.user || null,
unseenMessageCount: params.unseenMessageCount || 0
matchId: props.matchId || null,
user: props.user || null,
unseenMessageCount: props.unseenMessageCount || 0
});
console.log("[MATCH CONVO LINK COMPONENT] Match convo link component constructed, initial state:", this.state);
......@@ -65,16 +65,18 @@ class MatchConvoLink extends React.Component {
<div className="match-convo-link-container">
<div className="pure-g">
<div className="pure-u-5-6 right-aligned-text">
<h3 className="match-convo-link-name slim-text no-vertical-margins">{user.name}</h3>
<p className="match-convo-link-last-active-blurb no-vertical-margins super-slim-text">
{this.i18n`pages.matches.lastActive`} <MomentFuzzyDate date={user.ping_time}/>
</p>
<div className="slim-right-padding">
<h3 className="match-convo-link-name slim-text no-vertical-margins">{user.name}</h3>
<p className="match-convo-link-last-active-blurb no-vertical-margins super-slim-text">
{this.i18n`pages.matches.lastActive`} <MomentFuzzyDate date={user.ping_time}/>
</p>
</div>
</div>
<div className="pure-u-1-6 center-aligned-text">
<div className="pure-g">
<div className="message-count-container">
<div className="message-count-container match-convo-link-rhs nephritis-bg slim-vertical-padding">
<div className="pure-u-1">{this.state.unseenMessageCount}</div>
<div className="pure-u-1"><i className="fa fa-comment"></i></div>
</div>
......
import React from "react";
import TinderMatchStore from "../stores/tinder-match";
import Actions from "../actions";
import MomentFuzzyDate from "./moment-fuzzy-date";
import _ from "lodash";
import { generateI18NTemplateFn } from "../i18n";
const DEFAULT_STATE = {match: null};
const DEFAULT_CLOSE_FN = () => console.log("[MATCH CONVO PAGE COMPONENT] Would have closed convo page!");
class MatchConvoPage extends React.Component {
constructor(props) {
super(props);
this.state = DEFAULT_STATE;
this.unsubFunctions = {};
this.i18n = generateI18NTemplateFn("en-US");
// Process props
this.state = _.extend(this.state, {
match: props.match || null,
showCloseButton: props.showCloseButton || false,
closeFn: props.closeFn || DEFAULT_CLOSE_FN
});
console.log("[MATCH CONVO PAGE COMPONENT] Match convo link component constructed, initial state:", this.state);
}
componentDidMount() {
this.unsubFunctions["store-tinder-match"] = TinderMatchStore.listen(store => {
console.log("[MATCH CONVO PAGE COMPONENT] Detected tinder match store update:", store);
// Update the user info state if the user info is relevant to this component
if (_.has(store.matchedUserInfo, this.state.matchId)) {
console.log(`[MATCH CONVO PAGE COMPONENT] Found match ID ${this.state.matchId} in update, updating state`);
this.setState({user: store.matchedUserInfo[this.state.matchId]});
}
});
}
componentWillUnmount() {
_.each(this.unsubFunctions, f => f());
}
render() {
console.log("[MATCH CONVO PAGE COMPONENT] Rendering link for match with ID:", this.state.matchId);
let messages = _.get(this.state, "match.messages", []);
let messageBubbles = messages.map(m => {
return (
<div key={m._id} className="pure-u-1 match-convo-message">
<div className="match-convo-message">{m.message}</div>
<p className="match-convo-sent-date">Sent <MomentFuzzyDate date={m.sent_date}/></p>
</div>
);
});
let closeButton = "";
if (this.props.showClose) {
closeButton = (
<div className="float-right" onClick={this.state.closeFn}>
<h4>
<i className="fa fa-times"></i>
</h4>
</div>
);
}
return (
<div className="match-convo-page-container">
{closeButton}
<div className="pure-g">
{messageBubbles}
</div>
</div>
);
}
}
export default MatchConvoPage;
......@@ -4,11 +4,12 @@ import LHSNav from "./lhs-nav";
import TinderMatchStore from "../stores/tinder-match";
import TinderUserStore from "../stores/tinder-user";
import MatchConvoLink from "./match-convo-link";
import MatchConvoPage from "./match-convo-page";
import Constants from "../constants";
import _ from "lodash";
import { generateI18NTemplateFn } from "../i18n";
const DEFAULT_STATE = { matches: [], matchedUserInfo: {}};
const DEFAULT_STATE = { matches: [], matchedUserInfo: {}, selectedMatch: null};
class MatchesPage extends React.Component {
constructor(props) {
......@@ -45,28 +46,42 @@ class MatchesPage extends React.Component {
console.log("[MATCHES PAGE] Opening chat page for match with ID ", id);
}
hideMatchConvoContainer() {
console.log("[MATCHES PAGE] Hiding match convo container...");
this.setState({selectedMatch: null});
}
showMatchConvoContainerWithMatch(m) {
console.log("[MATCHES PAGE] Showing convo container for match:", m);
this.setState({selectedMatch: m});
}
render() {
console.log(`[MATCHES PAGE] Rendering matches page with ${this.state.matches.length} matches`);
let matchLinks = _.map(this.state.matches, m => {
let unseen = _.reduce(m.messages, (acc, m) => !m.seen ? acc+1 : acc , 0);
return (
<MatchConvoLink key={m.id} unseenMessageCount={unseen} matchId={m.id} />
<div key={m.id} onClick={() => this.showMatchConvoContainerWithMatch(m)} >
<MatchConvoLink unseenMessageCount={unseen} matchId={m.id} />
</div>
);
});
let slideConvoOnScreen = _.isNull(this.currentMatch) ? "" : "onscreen-from-offscreen-right";
return (
<div>
<LHSNav />
<div className="matches-page-container">
<div className="pure-g">
<div className="pure-u-1 right-aligned-text">
<div className="right-aligned-text">
<h1 className="no-vertical-margins slim-text">{this.i18n`nav.sections.matches`}</h1>
<h3 className="no-vertical-margins super-slim-text">{this.i18n`pages.matches.pageSubtitle`}</h3>
<div className="pure-g">
<div className="pure-u-1 right-aligned-text">
<div className="right-aligned-text">
<h1 className="no-vertical-margins slim-text">{this.i18n`nav.sections.matches`}</h1>
<h3 className="no-vertical-margins super-slim-text">{this.i18n`pages.matches.pageSubtitle`}</h3>
</div>
</div>
</div>
</div>
<div className="pure-g">
<div className="pure-u-1">
......@@ -74,6 +89,12 @@ class MatchesPage extends React.Component {
</div>
</div>
</div>
<div id="match-convo-sliding-container" className={`offscreen-right ${slideConvoOnScreen}`}>
<MatchConvoPage match={this.state.selectedMatch}
showCloseButton={true}
closeFn={this.hideMatchConvoContainer.bind(this)}/>
</div>
</div>
);
}
......
......@@ -46,7 +46,7 @@ export default {
lastActive: "last active"
},
matches: {
pageSubtitle: "Chat it up"
pageSubtitle: "Talk with your matches"
}
}
};
......@@ -19,7 +19,7 @@ let TinderLocationStore = Reflux.createStore({
console.log("[TINDER LOCATION STORE] Initializing tinder location store...");
// Setup action listeners
this.listenTo(Actions.updateLocationFromGPS, this.updateLocation);
this.listenTo(Actions.updateLocationFromGPS, _.debounce(this.updateLocation, 500));
// Save the Tinder access token
TinderAuthStore.listen(auth => {
......
......@@ -107,10 +107,18 @@ body {
padding-bottom: .25em;
}
/****************/
/* Matches page */
/****************/
.matches-page-header-icon-nav > i:last-child {
border-bottom-right-radius: .25em;
}
#match-convo-sliding-container {
transition: left 1s;
}
/*******************/
/* Preference page */
/*******************/
......@@ -154,8 +162,14 @@ section.collapsible-labeled-form-section > label {
/******************/
.match-convo-link-container {
padding-top: 1em;
padding-bottom: 1em;
background-color: #EEE;
margin-top: 1em;
margin-bottom: 1em;
}
.match-convo-link-rhs {
background-color: rgba(0,0,0,0.7);
color: white;
}
.match-convo-link-container > div:first-child {
......@@ -207,8 +221,20 @@ button.borderless { border: none; }
button.squared { border-radius: 0; }
button.in-stack { margin-bottom: .25em; }
.slim-vertical-padding {
padding-top: 1em;
padding-bottom: 1em;
}
.slim-right-padding { padding-right: 1em; }
.float-right { float: right; }
.offscreen-right {
position: absolute;
left: 100%;
}
.onscreen-from-offscreen-right { left: 0; }
/* Pure Overrides */
.button-success,
.button-error,
......@@ -245,4 +271,7 @@ button.in-stack { margin-bottom: .25em; }
.midnight-blue-face { color: #2c3e50; }
.alizarin-bg { background-color: #e74c3c; }
.alizarin-face { color: #e74c3c; }
\ No newline at end of file
.alizarin-face { color: #e74c3c; }
.nephritis-bg { background-color: #27ae60; }
.nephritis-face { color: #27ae60; }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment