simple style, polling

This commit is contained in:
DieMyst
2019-08-18 00:33:06 +03:00
parent e71e01dde5
commit bf455c416c
11 changed files with 279 additions and 105 deletions

View File

@ -9,7 +9,6 @@
"react-icons": "^3.7.0", "react-icons": "^3.7.0",
"react-redux": "^7.1.0", "react-redux": "^7.1.0",
"react-redux-loading": "^1.0.1", "react-redux-loading": "^1.0.1",
"react-router-dom": "^5.0.1",
"redux": "^4.0.4", "redux": "^4.0.4",
"redux-thunk": "^2.3.0", "redux-thunk": "^2.3.0",
"fluence": "^0.3.9" "fluence": "^0.3.9"

View File

@ -1,6 +1,4 @@
import { saveMessage } from "../utils/api"; import {getMessages, saveMessage} from "../utils/api";
//importing loading bar to show when we submit a tweet
import { showLoading, hideLoading } from "react-redux-loading"; import { showLoading, hideLoading } from "react-redux-loading";
export const ADD_MESSAGE = "ADD_MESSAGE"; export const ADD_MESSAGE = "ADD_MESSAGE";
@ -13,9 +11,31 @@ function addMessage(message) {
}; };
} }
//args: message text and the message that the newTweet is replying to, if any export function fetchPosts(counter) {
return dispatch => {
return getMessages().then((messages) => {
dispatch(receiveMessages(messages, counter));
dispatch(hideLoading());
});
};
}
export function handleInitialData() {
return dispatch => {
//before retrieving info, show loading bar
dispatch(showLoading());
return getMessages().then((messages) => {
dispatch(receiveMessages(messages, 0));
//after everything has loaded, hide loading bar
dispatch(hideLoading());
});
};
}
export function handleAddMessage(text, name) { export function handleAddMessage(text, name) {
//using getState to get the current state of our store
return (dispatch) => { return (dispatch) => {
dispatch(showLoading()); dispatch(showLoading());
return saveMessage({ return saveMessage({
@ -28,9 +48,10 @@ export function handleAddMessage(text, name) {
} }
//action creator //action creator
export function receiveMessages(messages) { export function receiveMessages(messages, counter) {
return { return {
type: RECEIVE_MESSAGES, type: RECEIVE_MESSAGES,
counter,
messages messages
}; };
} }

View File

@ -1,21 +0,0 @@
import { getMessages } from "../utils/api";
//importing action creators
import { receiveMessages } from "./messages";
//importing action creators of loading bar
import { showLoading, hideLoading } from "react-redux-loading";
export function handleInitialData() {
return dispatch => {
//before retrieving info, show loading bar
dispatch(showLoading());
return getMessages().then((messages) => {
dispatch(receiveMessages(messages));
//after everything has loaded, hide loading bar
dispatch(hideLoading());
});
};
}

View File

@ -1,42 +1,30 @@
import React, { Component, Fragment } from "react"; import React, {Component, Fragment} from "react";
import { BrowserRouter as Router, Route } from "react-router-dom"; import {BrowserRouter as Router} from "react-router-dom";
import { connect } from "react-redux"; import {connect} from "react-redux";
import { handleInitialData } from "../actions/shared";
import LoadingBar from "react-redux-loading"; //importing the loading bar given by react-redux-loading import LoadingBar from "react-redux-loading"; //importing the loading bar given by react-redux-loading
import Dashboard from "./Dashboard"; import Dashboard from "./Dashboard";
import NewMessage from "./NewMessage"; import NewMessage from "./NewMessage";
class App extends Component { class App extends Component {
componentDidMount() {
this.props.dispatch(handleInitialData());
}
render() { render() {
return ( return (
<Router> <Router>
{/* using a fragment so we don't add another element (div) to the DOM */} <Fragment>
<Fragment> <LoadingBar />
<LoadingBar /> <div className="container">
<div className="container"> {this.props.loading === true ? null : (
{this.props.loading === true ? null : ( <div>
<div> <NewMessage />
<NewMessage /> <Dashboard />
<Dashboard /> </div>
</div> )}
)} </div>
</div> </Fragment>
</Fragment> </Router>
</Router> );
); }
}
} }
function mapStateToProps({ }) { export default connect()(App);
return {
};
}
export default connect(mapStateToProps)(App);

View File

@ -2,14 +2,53 @@ import React, { Component } from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import Message from "./Message"; import Message from "./Message";
import {handleInitialData, fetchPosts} from "../actions/messages";
class Dashboard extends Component { class Dashboard extends Component {
constructor(props) {
super(props);
this.state = {counter: 1, lastUpdateCounter: 0};
}
componentDidMount() {
this.pollingMessages = setInterval(
() => this.getMessages(),
2000
);
this.props.dispatch(handleInitialData());
}
componentWillUnmount() {
clearInterval(this.pollingMessages);
}
getMessages() {
this.props.dispatch(fetchPosts(this.state.counter + 1));
this.setState((state) => ({
counter: state.counter + 1
}));
}
shouldComponentUpdate(nextProps) {
return nextProps.updates.counter > this.state.lastUpdateCounter
}
render() { render() {
let updates = this.props.updates;
if (updates.counter) {
this.setState(() => ({
lastUpdateCounter: updates.counter
}));
}
return ( return (
<div> <div>
<h3 className="center">Your Timeline</h3> <b>Counter: {this.state.counter}</b>
<b>Last update: {this.state.lastUpdateCounter}</b>
<h3 className="center">Feed</h3>
<ul className="dashbord-list"> <ul className="dashbord-list">
{this.props.messages.map((m, i) => { {updates.messages.map((m, i) => {
return ( return (
<li key={i}> <li key={i}>
<Message message={m} /> <Message message={m} />

View File

@ -18,7 +18,7 @@ class Message extends Component {
return ( return (
<div className="message-info"> <div className="message-info">
<div> <div>
<span>{name}</span> <span><b>{name}</b></span>
<p>{text}</p> <p>{text}</p>
</div> </div>
</div> </div>

View File

@ -1,6 +1,6 @@
import React, { Component } from "react"; import React, {Component} from "react";
import { connect } from "react-redux"; import {connect} from "react-redux";
import { handleAddMessage } from "../actions/messages"; import {handleAddMessage} from "../actions/messages";
class NewMessage extends Component { class NewMessage extends Component {
state = { state = {
@ -45,16 +45,17 @@ class NewMessage extends Component {
return ( return (
<div> <div>
<h3 className="center">Compose new Tweet </h3> <h3 className="center">Compose new message </h3>
<form className="new-message" onSubmit={this.handleSubmit}> <form className="new-message" onSubmit={this.handleSubmit}>
<textarea <textarea
placeholder="Message" placeholder="Message"
value={text} value={text}
onChange={this.handleChangeText} onChange={this.handleChangeText}
className="textarea" className="textarea"
maxLength={280} maxLength={280}
/> />
<input type="text" placeholder="Name" value={name} onChange={this.handleChangeName}/> <input type="text" className="nameinput" placeholder="Name" value={name}
onChange={this.handleChangeName}/>
{/* show how many characters are left */} {/* show how many characters are left */}
{messageLeft <= 100 && <div className="message-length">{messageLeft}</div>} {messageLeft <= 100 && <div className="message-length">{messageLeft}</div>}

View File

@ -1,13 +1,171 @@
body { body {
margin: 0; margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", padding: 0;
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", font-family: sans-serif;
sans-serif; color: #252525;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
} }
code { a {
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", text-decoration: none;
monospace; color: #252525;
}
.container {
/* border: 1px solid #dad7d7; */
max-width: 1000px;
margin: 0 auto;
padding: 10px;
}
.btn {
text-transform: uppercase;
margin: 20px auto;
padding: 10px;
border: 1px solid rgba(0, 0, 0, 0.29);
cursor: pointer;
background: #fff;
font-size: 16px;
width: 250px;
position: relative;
}
.btn:hover {
border-color: rgba(0, 0, 0, 0.5);
text-decoration: none;
}
.btn:focus {
outline: 0;
font-weight: 700;
border-width: 2px;
}
.center {
text-align: center;
}
.active {
font-weight: bold;
}
.nav ul {
display: flex;
flex-direction: row;
justify-content: flex-start;
text-decoration: none;
}
.nav li:first-child {
padding-left: 0;
}
ul {
padding-left: 0;
}
li {
list-style-type: none;
padding: 6px;
text-decoration: none;
}
.avatar {
height: 50px;
border-radius: 25px;
margin: 10px;
}
.message {
width: 100%;
max-width: 590px;
padding: 10px;
display: flex;
margin: 0 auto;
border: 1px solid #dad7d7;
border-radius: 3px;
cursor: pointer;
}
.message-info {
margin: 5px;
display: flex;
flex-direction: column;
}
/* Hacky but less typing in the video */
.message-info > div > span:first-child {
font-weight: bold;
margin-right: 5px;
}
.message-info > div > span:nth-child(2) {
color: #969696;
font-size: 16px;
}
.message-info > div > div {
color: #969696;
font-size: 15px;
}
.message-info > div > p {
font-size: 18px;
margin: 6px 0;
}
.message-icons {
display: flex;
align-items: center;
}
.message-icons > span {
color: #969696;
margin: 0 15px 0 5px;
font-size: 18px !important;
}
.message-icon {
font-size: 27px;
color: #697784;
}
.message-icon:hover {
color: #00b5d6;
cursor: pointer;
}
.replying-to {
border: none;
background: transparent;
margin: 0;
padding: 0;
color: #969696;
cursor: pointer;
}
.heart-button {
background: transparent;
border: none;
}
.new-message {
width: 100%;
max-width: 590px;
margin: 0 auto;
display: flex;
flex-direction: column;
}
.textarea {
border-radius: 4px;
border: 1px solid #dad7d7;
padding: 10px;
font-size: 15px;
height: 100px;
}
.nameinput {
border-radius: 4px;
border: 1px solid #dad7d7;
padding: 10px;
font-size: 15px;
}
.message-length {
text-align: right;
margin-top: 10px;
font-size: 20px;
color: #c3392a;
} }

View File

@ -1,10 +1,10 @@
import { combineReducers } from "redux"; import { combineReducers } from "redux";
import messages from "./messages"; import updates from "./messages";
import { loadingBarReducer } from "react-redux-loading"; import { loadingBarReducer } from "react-redux-loading";
export default combineReducers({ export default combineReducers({
messages, updates: updates,
loadingBar: loadingBarReducer loadingBar: loadingBarReducer
}); });

View File

@ -1,16 +1,16 @@
import { RECEIVE_MESSAGES, ADD_MESSAGE } from "../actions/messages"; import { RECEIVE_MESSAGES, ADD_MESSAGE } from "../actions/messages";
export default function messages(state = [], action) { export default function updates(state = {messages: []}, action) {
switch (action.type) { switch (action.type) {
case RECEIVE_MESSAGES: case RECEIVE_MESSAGES:
return action.messages; return action;
case ADD_MESSAGE: case ADD_MESSAGE:
console.log("reducer message"); console.log("reducer message");
console.log(state); console.log(state);
console.log(action); console.log(action);
const { message } = action; //getting the newly added message from action const { message } = action; //getting the newly added message from action
state.push(message); state.messages.unshift(message);
return state; return state;

View File

@ -1,8 +1,3 @@
import {
_getMessages,
_saveMessage,
} from './_DATA.js'
import * as fluence from "fluence"; import * as fluence from "fluence";
let session = fluence.directConnect("localhost", 30000, 1); let session = fluence.directConnect("localhost", 30000, 1);
@ -14,26 +9,20 @@ export function getMessages () {
return session.request(JSON.stringify(request)) return session.request(JSON.stringify(request))
.then((r) => r.asString()) .then((r) => r.asString())
.then((r) => { .then((r) => {
let posts = JSON.parse(r); let response = JSON.parse(r);
console.log("posts"); return response.posts.map((p) => {
console.log(posts);
let list = posts.map((p) => {
return { return {
text: p.msg, text: p.message,
name: p.username name: p.username
} }
}); }).reverse();
console.log(list);
return list;
}); });
} }
export function saveMessage(message) { export function saveMessage(message) {
console.log("save message");
console.log(message);
let request = { let request = {
action: "Post", action: "Post",
msg: message.text, message: message.text,
username: message.name username: message.name
}; };
return session.requestAsync(JSON.stringify(request)).then(() => message); return session.requestAsync(JSON.stringify(request)).then(() => message);