From f10bf3c894cf35c38707620b12a4aa081cc4a8a7 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Sun, 19 Apr 2020 02:23:32 +1000 Subject: [PATCH] chat-fe: add unread and day indicators --- pkg/interface/chat/src/css/custom.css | 4 + pkg/interface/chat/src/js/api.js | 4 +- pkg/interface/chat/src/js/components/chat.js | 113 +++++++++++++----- .../src/js/components/lib/unread-notice.js | 40 +++++++ 4 files changed, 127 insertions(+), 34 deletions(-) create mode 100644 pkg/interface/chat/src/js/components/lib/unread-notice.js diff --git a/pkg/interface/chat/src/css/custom.css b/pkg/interface/chat/src/css/custom.css index 0d55d6f43..c6c814428 100644 --- a/pkg/interface/chat/src/css/custom.css +++ b/pkg/interface/chat/src/css/custom.css @@ -169,6 +169,10 @@ h2 { border-radius: 100%; } +.green3 { + color: #7ea899; +} + /* responsive */ @media all and (max-width: 34.375em) { diff --git a/pkg/interface/chat/src/js/api.js b/pkg/interface/chat/src/js/api.js index 8610ba2e6..0a1ec0062 100644 --- a/pkg/interface/chat/src/js/api.js +++ b/pkg/interface/chat/src/js/api.js @@ -120,7 +120,9 @@ class UrbitApi { } }; - this.action("chat-hook", "json", data); + this.action("chat-hook", "json", data).then(() => { + this.chatRead(path); + }) data.message.envelope.author = data.message.envelope.author.substr(1); this.addPendingMessage(data.message); } diff --git a/pkg/interface/chat/src/js/components/chat.js b/pkg/interface/chat/src/js/components/chat.js index 0af011ebd..b6e8a1d71 100644 --- a/pkg/interface/chat/src/js/components/chat.js +++ b/pkg/interface/chat/src/js/components/chat.js @@ -1,6 +1,7 @@ import React, { Component } from 'react'; import classnames from 'classnames'; import _ from 'lodash'; +import moment from 'moment'; import { Route, Link } from "react-router-dom"; import { store } from "/store"; @@ -10,6 +11,7 @@ import { Message } from '/components/lib/message'; import { SidebarSwitcher } from '/components/lib/icons/icon-sidebar-switch.js'; import { ChatTabBar } from '/components/lib/chat-tabbar'; import { ChatInput } from '/components/lib/chat-input'; +import { UnreadNotice } from '/components/lib/unread-notice'; import { deSig } from '/lib/util'; @@ -24,25 +26,26 @@ export class ChatScreen extends Component { this.hasAskedForMessages = false; this.onScroll = this.onScroll.bind(this); - - this.updateReadInterval = setInterval( - this.updateReadNumber.bind(this), - 1000 - ); + + this.unreadMarker = null; + + moment.updateLocale('en', { + calendar: { + sameDay: '[Today]', + nextDay: '[Tomorrow]', + nextWeek: 'dddd', + lastDay: '[Yesterday]', + lastWeek: '[Last] dddd', + sameElse: 'DD/MM/YYYY' + } + }); + } componentDidMount() { - this.updateReadNumber(); this.askForMessages(); } - - componentWillUnmount() { - if (this.updateReadInterval) { - clearInterval(this.updateReadInterval); - this.updateReadInterval = null; - } - } - + componentDidUpdate(prevProps, prevState) { const { props, state } = this; @@ -55,18 +58,11 @@ export class ChatScreen extends Component { if (props.envelopes.length < 100) { this.askForMessages(); } - - clearInterval(this.updateReadInterval); - + this.setState( { scrollLocked: false }, () => { this.scrollToBottom(); - this.updateReadInterval = setInterval( - this.updateReadNumber.bind(this), - 1000 - ); - this.updateReadNumber(); } ); } else if (props.chatInitialized && @@ -80,14 +76,8 @@ export class ChatScreen extends Component { this.hasAskedForMessages = false; } } - - updateReadNumber() { - const { props, state } = this; - if (props.read < props.length) { - props.api.chat.read(props.station); - } - } - + + askForMessages() { const { props, state } = this; @@ -170,6 +160,12 @@ export class ChatScreen extends Component { } else { console.log("Your browser is not supported."); } + if(!!this.unreadMarker && + e.target.scrollHeight - e.target.scrollTop - (e.target.clientHeight * 1.5) + this.unreadMarker.offsetTop > 50 ) { + + this.props.api.chat.read(this.props.station); + + } } render() { @@ -189,6 +185,11 @@ export class ChatScreen extends Component { pendingMessages.map(function(value) { return (value.pending = true); }); + + const unread = props.length - props.read; + + const unreadMsg = unread > 0 && messages[unread - 1]; + let messageElements = pendingMessages.concat(messages).map((msg, i) => { // Render sigil if previous message is not by the same sender @@ -200,8 +201,13 @@ export class ChatScreen extends Component { let paddingBot = _.get(messages[i - 1], aut) !== _.get(msg, aut, msg.author); + + let when = ['when']; + let dayBreak = + moment(_.get(messages[i+1], when)).format('YYYY.MM.DD') !== + moment(_.get(messages[i], when)).format('YYYY.MM.DD') - return ( + const messageElem = ( ); + if(unread > 0 && i === unread) { + return ( + <> + {messageElem} +
(this.unreadMarker = ref)} className="mv2 green2 flex items-center f9"> +
+

+ New messages below +

+
+ { dayBreak && ( +

+ {moment(_.get(messages[i], when)).calendar()} +

+ )} +
+
+ + ); + } else if(dayBreak) { + return ( + <> + {messageElem} +
+

+ {moment(_.get(messages[i], when)).calendar()} +

+
+ + ); + } else { + return messageElem; + } }); let group = Array.from(props.permission.who.values()); @@ -229,11 +268,12 @@ export class ChatScreen extends Component { ? props.association.metadata.title : props.station.substr(1); } - + + return (
+ className="h-100 w-100 overflow-hidden flex flex-column relative">
@@ -265,6 +305,13 @@ export class ChatScreen extends Component { api={props.api} />
+ { !!unreadMsg && ( + props.api.chat.read(props.station)} + /> + ) }
+
+

+ {unread} new messages since{" "} + {datestamp && ( + <> + ~{datestamp} at{" "} + + )} + {timestamp} +

+
+ Mark as Read +
+
+
+ ); + } +}