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-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"
|
||||||
|
@ -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
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -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 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);
|
|
||||||
|
@ -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} />
|
||||||
|
@ -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>
|
||||||
|
@ -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>}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
});
|
});
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
Reference in New Issue
Block a user