mirror of
https://github.com/fluencelabs/fluid
synced 2025-06-28 04:21:32 +00:00
simple style, polling
This commit is contained in:
@ -9,7 +9,6 @@
|
||||
"react-icons": "^3.7.0",
|
||||
"react-redux": "^7.1.0",
|
||||
"react-redux-loading": "^1.0.1",
|
||||
"react-router-dom": "^5.0.1",
|
||||
"redux": "^4.0.4",
|
||||
"redux-thunk": "^2.3.0",
|
||||
"fluence": "^0.3.9"
|
||||
|
@ -1,6 +1,4 @@
|
||||
import { saveMessage } from "../utils/api";
|
||||
|
||||
//importing loading bar to show when we submit a tweet
|
||||
import {getMessages, saveMessage} from "../utils/api";
|
||||
import { showLoading, hideLoading } from "react-redux-loading";
|
||||
|
||||
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) {
|
||||
//using getState to get the current state of our store
|
||||
return (dispatch) => {
|
||||
dispatch(showLoading());
|
||||
return saveMessage({
|
||||
@ -28,9 +48,10 @@ export function handleAddMessage(text, name) {
|
||||
}
|
||||
|
||||
//action creator
|
||||
export function receiveMessages(messages) {
|
||||
export function receiveMessages(messages, counter) {
|
||||
return {
|
||||
type: RECEIVE_MESSAGES,
|
||||
counter,
|
||||
messages
|
||||
};
|
||||
}
|
||||
|
@ -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());
|
||||
});
|
||||
};
|
||||
}
|
@ -1,42 +1,30 @@
|
||||
import React, { Component, Fragment } from "react";
|
||||
import { BrowserRouter as Router, Route } from "react-router-dom";
|
||||
import { connect } from "react-redux";
|
||||
import { handleInitialData } from "../actions/shared";
|
||||
import React, {Component, Fragment} from "react";
|
||||
import {BrowserRouter as Router} from "react-router-dom";
|
||||
import {connect} from "react-redux";
|
||||
|
||||
import LoadingBar from "react-redux-loading"; //importing the loading bar given by react-redux-loading
|
||||
|
||||
import Dashboard from "./Dashboard";
|
||||
import NewMessage from "./NewMessage";
|
||||
|
||||
class App extends Component {
|
||||
componentDidMount() {
|
||||
this.props.dispatch(handleInitialData());
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Router>
|
||||
{/* using a fragment so we don't add another element (div) to the DOM */}
|
||||
<Fragment>
|
||||
<LoadingBar />
|
||||
<div className="container">
|
||||
{this.props.loading === true ? null : (
|
||||
<div>
|
||||
<NewMessage />
|
||||
<Dashboard />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Fragment>
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<Router>
|
||||
<Fragment>
|
||||
<LoadingBar />
|
||||
<div className="container">
|
||||
{this.props.loading === true ? null : (
|
||||
<div>
|
||||
<NewMessage />
|
||||
<Dashboard />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Fragment>
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps({ }) {
|
||||
return {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(App);
|
||||
export default connect()(App);
|
||||
|
@ -2,14 +2,53 @@ import React, { Component } from "react";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import Message from "./Message";
|
||||
import {handleInitialData, fetchPosts} from "../actions/messages";
|
||||
|
||||
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() {
|
||||
let updates = this.props.updates;
|
||||
if (updates.counter) {
|
||||
this.setState(() => ({
|
||||
lastUpdateCounter: updates.counter
|
||||
}));
|
||||
}
|
||||
return (
|
||||
<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">
|
||||
{this.props.messages.map((m, i) => {
|
||||
{updates.messages.map((m, i) => {
|
||||
return (
|
||||
<li key={i}>
|
||||
<Message message={m} />
|
||||
|
@ -18,7 +18,7 @@ class Message extends Component {
|
||||
return (
|
||||
<div className="message-info">
|
||||
<div>
|
||||
<span>{name}</span>
|
||||
<span><b>{name}</b></span>
|
||||
<p>{text}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { Component } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { handleAddMessage } from "../actions/messages";
|
||||
import React, {Component} from "react";
|
||||
import {connect} from "react-redux";
|
||||
import {handleAddMessage} from "../actions/messages";
|
||||
|
||||
class NewMessage extends Component {
|
||||
state = {
|
||||
@ -45,16 +45,17 @@ class NewMessage extends Component {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h3 className="center">Compose new Tweet </h3>
|
||||
<h3 className="center">Compose new message </h3>
|
||||
<form className="new-message" onSubmit={this.handleSubmit}>
|
||||
<textarea
|
||||
placeholder="Message"
|
||||
value={text}
|
||||
onChange={this.handleChangeText}
|
||||
className="textarea"
|
||||
maxLength={280}
|
||||
/>
|
||||
<input type="text" placeholder="Name" value={name} onChange={this.handleChangeName}/>
|
||||
<textarea
|
||||
placeholder="Message"
|
||||
value={text}
|
||||
onChange={this.handleChangeText}
|
||||
className="textarea"
|
||||
maxLength={280}
|
||||
/>
|
||||
<input type="text" className="nameinput" placeholder="Name" value={name}
|
||||
onChange={this.handleChangeName}/>
|
||||
{/* show how many characters are left */}
|
||||
{messageLeft <= 100 && <div className="message-length">{messageLeft}</div>}
|
||||
|
||||
|
@ -1,13 +1,171 @@
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
|
||||
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
||||
sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
padding: 0;
|
||||
font-family: sans-serif;
|
||||
color: #252525;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
|
||||
monospace;
|
||||
a {
|
||||
text-decoration: none;
|
||||
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;
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { combineReducers } from "redux";
|
||||
|
||||
import messages from "./messages";
|
||||
import updates from "./messages";
|
||||
|
||||
import { loadingBarReducer } from "react-redux-loading";
|
||||
|
||||
export default combineReducers({
|
||||
messages,
|
||||
updates: updates,
|
||||
loadingBar: loadingBarReducer
|
||||
});
|
||||
|
@ -1,16 +1,16 @@
|
||||
import { RECEIVE_MESSAGES, ADD_MESSAGE } from "../actions/messages";
|
||||
|
||||
export default function messages(state = [], action) {
|
||||
export default function updates(state = {messages: []}, action) {
|
||||
switch (action.type) {
|
||||
case RECEIVE_MESSAGES:
|
||||
return action.messages;
|
||||
return action;
|
||||
|
||||
case ADD_MESSAGE:
|
||||
console.log("reducer message");
|
||||
console.log(state);
|
||||
console.log(action);
|
||||
const { message } = action; //getting the newly added message from action
|
||||
state.push(message);
|
||||
state.messages.unshift(message);
|
||||
|
||||
return state;
|
||||
|
||||
|
@ -1,8 +1,3 @@
|
||||
import {
|
||||
_getMessages,
|
||||
_saveMessage,
|
||||
} from './_DATA.js'
|
||||
|
||||
import * as fluence from "fluence";
|
||||
|
||||
let session = fluence.directConnect("localhost", 30000, 1);
|
||||
@ -14,26 +9,20 @@ export function getMessages () {
|
||||
return session.request(JSON.stringify(request))
|
||||
.then((r) => r.asString())
|
||||
.then((r) => {
|
||||
let posts = JSON.parse(r);
|
||||
console.log("posts");
|
||||
console.log(posts);
|
||||
let list = posts.map((p) => {
|
||||
let response = JSON.parse(r);
|
||||
return response.posts.map((p) => {
|
||||
return {
|
||||
text: p.msg,
|
||||
text: p.message,
|
||||
name: p.username
|
||||
}
|
||||
});
|
||||
console.log(list);
|
||||
return list;
|
||||
}).reverse();
|
||||
});
|
||||
}
|
||||
|
||||
export function saveMessage(message) {
|
||||
console.log("save message");
|
||||
console.log(message);
|
||||
let request = {
|
||||
action: "Post",
|
||||
msg: message.text,
|
||||
message: message.text,
|
||||
username: message.name
|
||||
};
|
||||
return session.requestAsync(JSON.stringify(request)).then(() => message);
|
||||
|
Reference in New Issue
Block a user