diff --git a/.eslintignore b/.eslintignore
index fa9c5eb..86042d8 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -1,2 +1,3 @@
public/
node_modules/
+chat-program/
diff --git a/.eslintrc.json b/.eslintrc.json
index 5a2ab38..bdd5414 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -1,6 +1,7 @@
{
"extends": ["airbnb", "prettier", "prettier/react"],
"plugins": ["prettier"],
+ "parser": "babel-eslint",
"parserOptions": {
"ecmaVersion": 2016,
"sourceType": "module",
diff --git a/404.html b/404.html
new file mode 100644
index 0000000..6da6f67
--- /dev/null
+++ b/404.html
@@ -0,0 +1,11 @@
+
+
+
+
-
{this.state.differencePercentage}
+
{this.state.monthChangeP}
{`Change Since Last ${durationText} (%)`}{' '}
diff --git a/src/js/Landing.jsx b/src/js/Landing.jsx
index 83d0ead..124ed2e 100644
--- a/src/js/Landing.jsx
+++ b/src/js/Landing.jsx
@@ -1,8 +1,10 @@
-import React from 'react';
+import React, { Component } from 'react';
import { Link } from 'react-router-dom';
+import { connect } from 'react-redux';
+import axios from 'axios';
import styled from 'styled-components';
import MarketData from './MarketData';
-
+import { setAuthenticated } from './actionCreators';
const Wrapper = styled.div`
background-color: #2f9999;
@@ -19,6 +21,8 @@ const LandingNavbar = styled.div`
float: right;
margin: 5px;
font-weight: bolder;
+ text-decoration: none;
+ color: #fff;
}
font-family: Roboto;
`;
@@ -41,6 +45,7 @@ const LandingHeader = styled.div`
}
`;
const LandingGraph = styled.div`
+ padding: 20px 10px;
background-color: #f0ebe1;
text-align: center;
@@ -68,41 +73,61 @@ const LandingSafety = styled.div`
const LandingFooter = styled.div`
float: right;
`;
-const Landing = () => (
-
-
-
-
-
- GET INTO CRYPTOCURRENCIES
TODAY
-
-
-
-
-
-
-
-
-
-
- SAFELY MAKE YOUR FIRST TRADE
-
- learn how to buy cryptocurrency, which coin to invest in, all in one
- place.{' '}
-
-
+class Landing extends Component {
+ componentDidMount() {
+ this.props.handleBeginJourney();
+ }
+ render() {
+ const landingRedirect = this.props.authenticated ? '/learn' : '/login';
+ return (
+
+
+
+
+ CryptoCoin
+ Sign In
+ Sign Up
+
+
+
+
+ GET INTO CRYPTOCURRENCIES
TODAY
+
+
+
+
+
+
+
+
+
+ SAFELY MAKE YOUR FIRST TRADE
+
+ learn how to buy cryptocurrency, which coin to invest in, all in
+ one place.{' '}
+
+
-
- Contact Us Security Help
-
-
-
-);
+
+ Contact Us Security Help
+
+
+
+ );
+ }
+}
+const mapStatetoProps = state => ({
+ authenticated: state.authenticated
+ // landingRedirect: state.landingRedirect
+});
+const mapDispatchtoProps = dispatch => ({
+ handleBeginJourney() {
+ axios.get('/api/authenticated').then(result => {
+ dispatch(setAuthenticated(result.data));
+ });
+ }
+});
-export default Landing;
+export default connect(mapStatetoProps, mapDispatchtoProps)(Landing);
diff --git a/src/js/Layout.jsx b/src/js/Layout.jsx
new file mode 100644
index 0000000..112ab7e
--- /dev/null
+++ b/src/js/Layout.jsx
@@ -0,0 +1,61 @@
+import React, { Component } from 'react';
+import io from 'socket.io-client';
+import LoginForm from './LoginForm';
+import ChatContainer from './ChatContainer';
+
+const socketUrl = 'http://localhost:8080';
+class Layout extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ socket: null,
+ user: null
+ };
+
+ this.setUser = this.setUser.bind(this);
+ this.logout = this.logout.bind(this);
+ this.initSocket = this.initSocket.bind(this);
+ }
+
+ componentWillMount() {
+ this.initSocket();
+ }
+ setUser(user) {
+ const { socket } = this.state;
+ socket.emit('USER_CONNECTED', user);
+ this.setState({ user });
+ }
+
+ initSocket() {
+ const socket = io(socketUrl);
+
+ socket.on('connect', () => {
+ console.log('Connected');
+ });
+
+ this.setState({ socket });
+ }
+
+ logout() {
+ const { socket } = this.state;
+ socket.emit('LOGOUT');
+ this.setState({ user: null });
+ }
+
+ render() {
+ const { title } = this.props;
+ const { socket, user } = this.state;
+ return (
+
+ {!user ? (
+
+ ) : (
+
+ )}
+
+ );
+ }
+}
+
+export default Layout;
diff --git a/src/js/LineChart.jsx b/src/js/LineChart.jsx
index 7231c22..624d7e5 100644
--- a/src/js/LineChart.jsx
+++ b/src/js/LineChart.jsx
@@ -12,7 +12,6 @@ class LineChart extends Component {
constructor(props) {
super(props);
}
- // GET X & Y || MAX & MIN
getX() {
const { data, duration, coin } = this.props;
const lookAt = data[coin];
@@ -34,7 +33,6 @@ class LineChart extends Component {
)
};
}
- // GET SVG COORDINATES
getSvgX(x) {
const { svgWidth, yLabelSize, duration, coin } = this.props;
return yLabelSize + x / this.getX().max * (svgWidth - yLabelSize);
@@ -47,7 +45,6 @@ class LineChart extends Component {
(gY.max - gY.min)
);
}
- // BUILD SVG PATH
makePath() {
const { data, color, duration, coin } = this.props;
let pathD =
@@ -67,7 +64,6 @@ class LineChart extends Component {
);
}
- // BUILD SHADED AREA
makeArea() {
const { data, duration, coin } = this.props;
let pathD =
@@ -99,7 +95,6 @@ class LineChart extends Component {
return
;
}
- // BUILD GRID AXIS
makeAxis() {
const { yLabelSize } = this.props;
const x = this.getX();
@@ -136,7 +131,7 @@ class LineChart extends Component {
const padding = 5;
return (
- {/* Y AXIS LABELS */}
+
- {/* X AXIS LABELS */}
);
}
- // FIND CLOSEST POINT TO MOUSE
getCoords(e) {
const { svgWidth, data, yLabelSize, duration, coin } = this.props;
const svgLocation = document
.getElementsByClassName('linechart')[0]
.getBoundingClientRect();
- const adjustment = (svgLocation.width - svgWidth) / 2; //takes padding into consideration
+ const adjustment = (svgLocation.width - svgWidth) / 2;
const relativeLoc = e.clientX - svgLocation.left - adjustment;
let svgData = [];
@@ -208,12 +201,10 @@ class LineChart extends Component {
this.props.onChartHover(relativeLoc, closestPoint);
}
- // STOP HOVER
stopHover() {
this.props.handleHover(null, null);
this.props.onChartHover(null, null);
}
- // MAKE ACTIVE POINT
makeActivePoint() {
const { color, pointRadius } = this.props;
return (
@@ -226,7 +217,6 @@ class LineChart extends Component {
/>
);
}
- // MAKE HOVER LINE
createLine() {
const { svgHeight, xLabelSize } = this.props;
return (
@@ -264,7 +254,6 @@ class LineChart extends Component {
);
}
}
-// DEFAULT PROPS
LineChart.defaultProps = {
data: [],
color: '#fc4a1a',
diff --git a/src/js/Login.jsx b/src/js/Login.jsx
new file mode 100644
index 0000000..38698fb
--- /dev/null
+++ b/src/js/Login.jsx
@@ -0,0 +1,331 @@
+import React from 'react';
+import styled from 'styled-components';
+import { Link, Redirect } from 'react-router-dom';
+import ReactDOM from 'react-dom';
+import axios from 'axios';
+
+const LandingNavbar = styled.div`
+ a {
+ float: right;
+ margin: 5px;
+ font-weight: bolder;
+ text-decoration: none;
+ color: #fff;
+ }
+ font-family: Roboto;
+`;
+
+const LoginDiv = styled.div`
+ /* Demo 3 */
+
+ .form-3 {
+ font-family: 'Ubuntu', 'Lato', sans-serif;
+ font-weight: 400;
+ /* Size and position */
+ width: 300px;
+ position: relative;
+ margin: 60px auto 30px;
+ padding: 10px;
+ overflow: hidden;
+
+ /* Styles */
+ background: #111;
+ border-radius: 0.4em;
+ border: 1px solid #191919;
+ box-shadow: inset 0 0 2px 1px rgba(255, 255, 255, 0.08),
+ 0 16px 10px -8px rgba(0, 0, 0, 0.6);
+ }
+
+ .form-3 label {
+ /* Size and position */
+ width: 50%;
+ float: left;
+ padding-top: 9px;
+
+ /* Styles */
+ color: #ddd;
+ font-size: 12px;
+ text-transform: uppercase;
+ letter-spacing: 1px;
+ text-shadow: 0 1px 0 #000;
+ text-indent: 10px;
+ font-weight: 700;
+ cursor: pointer;
+ }
+
+ .form-3 input[type='text'],
+ .form-3 input[type='password'] {
+ /* Size and position */
+ width: 50%;
+ float: left;
+ padding: 8px 5px;
+ margin-bottom: 10px;
+ font-size: 12px;
+
+ /* Styles */
+ background: #1f2124; /* Fallback */
+ background: -webkit-gradient(
+ linear,
+ 0 0,
+ 0 100%,
+ from(#1f2124),
+ to(#27292c)
+ );
+ background: -webkit-linear-gradient(#1f2124, #27292c);
+ background: linear-gradient(#1f2124, #27292c);
+ border: 1px solid #000;
+ box-shadow: 0 1px 0 rgba(255, 255, 255, 0.1);
+ border-radius: 3px;
+
+ /* Font styles */
+ font-family: 'Ubuntu', 'Lato', sans-serif;
+ color: #fff;
+ }
+
+ .form-3 input[type='text']:hover,
+ .form-3 input[type='password']:hover,
+ .form-3 label:hover ~ input[type='text'],
+ .form-3 label:hover ~ input[type='password'] {
+ background: #27292c;
+ }
+
+ .form-3 input[type='text']:focus,
+ .form-3 input[type='password']:focus {
+ box-shadow: inset 0 0 2px #000;
+ background: #494d54;
+ border-color: #51cbee;
+ outline: none; /* Remove Chrome outline */
+ }
+
+ .form-3 p:nth-child(3),
+ .form-3 p:nth-child(4) {
+ float: left;
+ width: 50%;
+ }
+
+ .form-3 label[for='remember'] {
+ width: auto;
+ float: none;
+ display: inline-block;
+ text-transform: capitalize;
+ font-size: 11px;
+ font-weight: 400;
+ letter-spacing: 0px;
+ text-indent: 2px;
+ }
+
+ .form-3 input[type='checkbox'] {
+ margin-left: 10px;
+ vertical-align: middle;
+ }
+
+ .form-3 input[type='submit'] {
+ /* Width and position */
+ width: 100%;
+ padding: 8px 5px;
+
+ /* Styles */
+ border: 1px solid #0273dd; /* Fallback */
+ border: 1px solid rgba(0, 0, 0, 0.4);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3),
+ inset 0 10px 10px rgba(255, 255, 255, 0.1);
+ border-radius: 3px;
+ background: #38a6f0;
+ cursor: pointer;
+
+ /* Font styles */
+ font-family: 'Ubuntu', 'Lato', sans-serif;
+ color: white;
+ font-weight: 700;
+ font-size: 15px;
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.8);
+ }
+
+ .form-3 input[type='submit']:hover {
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.6);
+ }
+
+ .form-3 input[type='submit']:active {
+ background: #287db5;
+ box-shadow: inset 0 0 3px rgba(0, 0, 0, 0.6);
+ border-color: #000; /* Fallback */
+ border-color: rgba(0, 0, 0, 0.9);
+ }
+
+ .no-boxshadow .form-3 input[type='submit']:hover {
+ background: #2a92d8;
+ }
+
+ .form-3:after {
+ /* Size and position */
+ content: '';
+ height: 1px;
+ width: 33%;
+ position: absolute;
+ left: 20%;
+ top: 0;
+
+ background: -webkit-gradient(
+ linear,
+ 0 0,
+ 100% 0,
+ from(transparent),
+ color-stop(0.25, #444),
+ color-stop(0.5, #b6b6b8),
+ color-stop(0.75, #444),
+ to(transparent)
+ );
+ background: -webkit-linear-gradient(
+ left,
+ transparent,
+ #444,
+ #b6b6b8,
+ #444,
+ transparent
+ );
+ background: linear-gradient(
+ left,
+ transparent,
+ #444,
+ #b6b6b8,
+ #444,
+ transparent
+ );
+ }
+
+ .form-3:before {
+ /* Size and position */
+ content: '';
+ width: 8px;
+ height: 5px;
+ position: absolute;
+ left: 34%;
+ top: -7px;
+
+ /* Styles */
+ border-radius: 50%;
+ box-shadow: 0 0 6px 4px #fff;
+ }
+
+ .form-3 p:nth-child(1):before {
+ /* Size and position */
+ content: '';
+ width: 250px;
+ height: 100px;
+ position: absolute;
+ top: 0;
+ left: 45px;
+
+ /* Styles */
+ -webkit-transform: rotate(75deg);
+ transform: rotate(75deg);
+
+ background: -webkit-linear-gradient(
+ 50deg,
+ rgba(255, 255, 255, 0.15),
+ rgba(0, 0, 0, 0)
+ );
+ background: linear-gradient(
+ 50deg,
+ rgba(255, 255, 255, 0.15),
+ rgba(0, 0, 0, 0)
+ );
+ pointer-events: none;
+ }
+
+ .no-pointerevents .form-3 p:nth-child(1):before {
+ display: none;
+ }
+`;
+
+class LoginPage extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ invalidInput: null,
+ loggedin: false,
+ username: null,
+ password: null
+ };
+
+ this.handleUser = this.handleUser.bind(this);
+ this.handlePassword = this.handlePassword.bind(this);
+ this.handleSubmit = this.handleSubmit.bind(this);
+ }
+
+ handleSubmit(e) {
+ e.preventDefault();
+ const { username } = this.state;
+ const { password } = this.state;
+ axios.post('/api/login', { username, password }).then(response => {
+ if (response.status == 500) {
+ this.setState({ invalidInput: 'oooops Server error' });
+ } else if (response.status == 200) {
+ if (response.data == '') {
+ this.setState({ loggedin: true });
+ } else {
+ this.setState({ invalidInput: response.data });
+ }
+ }
+ });
+ }
+ handleUser(e) {
+ this.setState({ username: e.target.value });
+ }
+ handlePassword(e) {
+ this.setState({ password: e.target.value });
+ }
+
+ render() {
+ if (this.state.loggedin) {
+ return ;
+ } else {
+ return (
+
+
+
+
+
+ );
+ }
+ }
+}
+
+export default LoginPage;
diff --git a/src/js/LoginForm.jsx b/src/js/LoginForm.jsx
new file mode 100644
index 0000000..607e5d0
--- /dev/null
+++ b/src/js/LoginForm.jsx
@@ -0,0 +1,64 @@
+import React, { Component } from 'react';
+
+class LoginForm extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ nickname: '',
+ error: ''
+ };
+ this.setUser = this.setUser.bind(this);
+ }
+
+ setUser({ user, isUser }) {
+ if (isUser) {
+ this.setError('User name taken');
+ } else {
+ this.props.setUser(user);
+ this.setError('');
+ }
+ }
+
+ setError(error) {
+ this.setState({ error });
+ }
+
+ handleSubmit(e) {
+ e.preventDefault();
+
+ const { socket } = this.props;
+ const { nickname } = this.state;
+ socket.emit('VERIFY_USER', nickname, this.setUser);
+ }
+
+ handleChange(e) {
+ this.setState({ nickname: e.target.value });
+ }
+
+ render() {
+ const { nickname, error } = this.state;
+ return (
+
+ );
+ }
+}
+
+export default LoginForm;
diff --git a/src/js/MessageInput.jsx b/src/js/MessageInput.jsx
new file mode 100644
index 0000000..d405e51
--- /dev/null
+++ b/src/js/MessageInput.jsx
@@ -0,0 +1,87 @@
+import React, { Component } from 'react';
+
+class MessageInput extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ message: '',
+ isTyping: false
+ };
+ this.handleSubmit = this.handleSubmit.bind(this);
+ this.sendTyping = this.sendTyping.bind(this);
+ this.sendMessage = this.sendMessage.bind(this);
+ this.startCheckingTyping = this.startCheckingTyping.bind(this);
+ this.stopCheckingTyping = this.stopCheckingTyping.bind(this);
+ }
+
+ componentWillUnmount() {
+ this.stopCheckingTyping();
+ }
+
+ handleSubmit(e) {
+ e.preventDefault();
+ this.sendMessage();
+ this.setState({ message: '' });
+ }
+
+ sendMessage() {
+ this.props.sendMessage(this.state.message);
+ }
+
+ sendTyping() {
+ this.lastUpdateTime = Date.now();
+ if (!this.state.isTyping) {
+ this.setState({ isTyping: true });
+ this.props.sendTyping(true);
+ this.startCheckingTyping();
+ }
+ }
+
+ startCheckingTyping() {
+ this.typingInterval = setInterval(() => {
+ if (Date.now() - this.lastUpdateTime > 300) {
+ this.setState({ isTyping: false });
+ this.stopCheckingTyping();
+ }
+ }, 300);
+ }
+
+ stopCheckingTyping() {
+ if (this.typingInterval) {
+ clearInterval(this.typingInterval);
+ this.props.sendTyping(false);
+ }
+ }
+
+ render() {
+ const { message } = this.state;
+ return (
+
+
+
+ );
+ }
+}
+
+export default MessageInput;
diff --git a/src/js/Messages.jsx b/src/js/Messages.jsx
new file mode 100644
index 0000000..c0af21d
--- /dev/null
+++ b/src/js/Messages.jsx
@@ -0,0 +1,49 @@
+import React, { Component } from 'react';
+
+export default class Messages extends Component {
+ constructor(props) {
+ super(props);
+
+ this.scrollDown = this.scrollDown.bind(this);
+ }
+ componentDidMount() {
+ this.scrollDown();
+ }
+
+ componentDidUpdate() {
+ this.scrollDown();
+ }
+
+ scrollDown() {
+ const { container } = this.refs;
+ container.scrollTop = container.scrollHeight;
+ }
+
+ render() {
+ const { messages, user, typingUsers } = this.props;
+ return (
+
+
+ {messages.map(mes => (
+
+
{mes.time}
+
+
{mes.message}
+
{mes.sender}
+
+
+ ))}
+ {typingUsers.map(name => (
+
+ {`${name} is typing . . .`}
+
+ ))}
+
+
+ );
+ }
+}
diff --git a/src/js/Navbar.jsx b/src/js/Navbar.jsx
index bc5648b..6105e03 100644
--- a/src/js/Navbar.jsx
+++ b/src/js/Navbar.jsx
@@ -1,8 +1,10 @@
import React from 'react';
import styled from 'styled-components';
import { Link } from 'react-router-dom';
+import axios from 'axios';
const NavbarDesktopUser = styled.div`
+ z-index: 1;
position: fixed;
list-style-type: none;
width: -webkit-fill-available;
@@ -95,53 +97,69 @@ const NavbarMobileNavbar = styled.ul`
}
`;
-const Navbar = () => (
-
-
-
-
-
- public chat
-
- chat
- wallet
- user
-
-
-
-
- CryptoCoin
-
- SELL
-
-
- BUY
-
-
- MARKETS
-
-
- LEARN
-
-
-
- CryptoCoin
-
- SELL
-
-
- BUY
-
-
- MARKETS
-
-
- LEARN
-
-
+class Navbar extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ username: null
+ };
+ }
+ componentDidMount() {
+ axios
+ .get('/api/username')
+ .then(response => {
+ this.setState({ username: response });
+ })
+ .catch(err => {
+ console.log('err => ', err);
+ });
+ }
+ render() {
+ return (
+
+
+
+
+ chat
+ wallet
+ user
+
+
+
+
+ CryptoCoin
+
+ SELL
+
+
+ BUY
+
+
+ MARKETS
+
+
+ LEARN
+
+
+
+ CryptoCoin
+
+ SELL
+
+
+ BUY
+
+
+ MARKETS
+
+
+ LEARN
+
+
+
+
-
-
-);
-
+ );
+ }
+}
export default Navbar;
diff --git a/src/js/PostTemplate.jsx b/src/js/PostTemplate.jsx
index 3a45e84..ae94634 100644
--- a/src/js/PostTemplate.jsx
+++ b/src/js/PostTemplate.jsx
@@ -22,16 +22,16 @@ const p = {
const posts = props => (
-
{props.post.user_name}
+ {props.post.username}
-
{props.post.preferedPaymentMethod}
+ {props.post.prefferedpayment}
{props.post.country}
{props.post.city}
-
{props.post.coin}
{props.post.amount} - QTY
+ {props.post.coin}
{props.post.qty} - QTY
diff --git a/src/js/PublicChat.jsx b/src/js/PublicChat.jsx
index ea764ce..253a015 100644
--- a/src/js/PublicChat.jsx
+++ b/src/js/PublicChat.jsx
@@ -1,42 +1,496 @@
import React from 'react';
-import Navbar from './Navbar';
import styled from 'styled-components';
+import Navbar from './Navbar';
+import Layout from './Layout';
const Wrapper = styled.div`
- * {
- box-sizing: border-box;
- padding: 0;
+ html,
+ body,
+ #root {
margin: 0;
+ padding: 0;
+ font-family: sans-serif;
+ height: 100%;
}
- body {
- font-family: 'Press Start 2P';
+
+ input,
+ textarea {
+ font-family: Arial;
}
- #container {
- display: grid;
- grid-template-columns: 1fr 3fr;
- grid-template-areas: 'sidebar main';
- width: 100vw;
- height: 100vh;
+
+ .login {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
}
- #main {
- grid-area: main;
+
+ .login-form {
+ display: flex;
+ justify-content: center;
+ flex-direction: column;
}
- #new-message {
- position: fixed;
- bottom: 0;
+
+ .login-form input {
+ max-width: 100%;
+ border-top: none;
+ border-left: none;
+ border-right: none;
+ height: 20px;
+ line-height: 20px;
+ font-size: 20px;
+ border-bottom: solid 2px #b3b2ca;
+ transition: all 0.23s ease-in;
+ }
+
+ .login-form input:focus {
+ border-bottom: solid 2px black;
+ outline: none;
+ }
+
+ .login-form .error {
+ text-align: center;
+ margin: 5px 0;
+ padding: 5px 10px;
+ color: #c92c43;
+ }
+
+ .container {
+ padding-bottom: 10vh;
+ color: #ffffff;
+ display: flex;
+ flex-direction: row;
+ align-items: flex-start;
+ justify-content: center;
+ height: 90%;
+ width: 90%;
+ }
+
+ #side-bar {
+ order: 1;
+ box-sizing: border-box;
+ width: 15%;
+ height: 100%;
+ display: flex;
+ justify-content: space-around;
+ flex-direction: column;
+ }
+
+ #side-bar .heading {
+ font-size: 1em;
+ box-sizing: border-box;
+ height: 8vh;
+ max-height: 65px;
+ padding: 18px 16px;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-between;
+ background: #2f9999;
+ }
+
+ #side-bar .search {
+ background: #2f9999;
+ box-sizing: border-box;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ border-width: 1px 0;
+ border-style: solid;
+ border-color: black;
+ padding-left: 15px;
+ padding-right: 20px;
+ height: 10vh;
+ max-height: 65px;
+ }
+
+ #side-bar .search .search-icon {
+ margin-right: 15px;
+ cursor: pointer;
+ }
+
+ #side-bar .search input {
width: 100%;
- padding: 5px;
- margin-left: 0px;
- border-top: 1px solid #3f3f3f;
+ background: #2f9999;
+ flex-grow: 1;
+ box-sizing: border-box;
+ border: none;
+ color: #2f9999;
+ }
+
+ #side-bar .search input:focus {
+ outline: none;
+ }
+
+ #side-bar .search input::placeholder {
+ color: #2f9999;
+ opacity: 0.6;
+ }
+
+ #side-bar .search .plus {
+ display: inline-block;
+ position: relative;
+ cursor: pointer;
+ width: 13px;
+ height: 13px;
+ }
+
+ #side-bar .search .plus::after,
+ #side-bar .search .plus::before {
+ content: '';
+ position: absolute;
+ background: #b3b2ca;
}
- #messages-list {
- padding: 5px 0 0 5px;
+
+ #side-bar .search .plus::after {
+ width: 16px;
+ height: 2px;
+ top: 5px;
+ }
+
+ #side-bar .search .plus::before {
+ width: 2px;
+ height: 16px;
+ top: -2px;
+ left: 7px;
+ }
+
+ #side-bar .users {
+ ${''} background: #2f9999;
+ flex-grow: 1;
+ text-align: center;
+ height: 4.5vh;
+ max-height: 65px;
+ padding: 18px 5px;
+ }
+
+ #side-bar .users::-webkit-scrollbar-track {
+ background-color: #484d79;
+ }
+
+ #side-bar .users::-webkit-scrollbar {
+ width: 5px;
+ background-color: green;
+ }
+
+ #side-bar .users::-webkit-scrollbar-thumb {
+ background-color: #2f9999;
+ }
+
+ #side-bar .users .user {
+ align-items: center;
+ display: flex;
+ height: 66px;
+ justify-content: flex-start;
+ padding: 18px 16px;
+ }
+
+ #side-bar .users .user.active,
+ #side-bar .users .user:hover {
+ background: #2f9999;
+ }
+
+ #side-bar .users .user:hover:not(.active) {
+ cursor: pointer;
+ }
+
+ #side-bar .users .user .user-info {
+ margin-left: 15px;
+ flex-grow: 1;
+ }
+
+ #side-bar .users .user .user-info .last-message {
+ font-size: 12px;
+ opacity: 0.56;
}
- #sidebar {
- grid-area: sidebar;
- padding: 5px 0 0 5px;
- border-right: 1px solid #3f3f3f;
+
+ #side-bar .users .user .new-message {
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ #side-bar .current-user {
+ align-items: center;
+ background: #fff;
+ color: #fc4a1a;
+ box-sizing: border-box;
+ display: flex;
+ flex-direction: row;
+ height: 10vh;
+ max-height: 65px;
+ justify-content: space-between;
+ padding-left: 16px;
+ padding-right: 16px;
+ }
+
+ #side-bar .current-user .logout {
+ align-items: center;
+ cursor: pointer;
+ display: flex;
+ justify-content: center;
+ font-size: 2em;
+ }
+
+ .chat-header {
+ border-radius: 15px 0 0 0;
+ background: #2f9999;
+ box-shadow: 0px 6px 5px -2px rgba(225, 225, 225, 0.7);
+ box-sizing: border-box;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ height: 12vh;
+ max-height: 65px;
+ padding: 18px 16px;
+ }
+
+ .chat-header .user-info {
+ align-items: center;
+ display: flex;
+ }
+
+ .chat-header .user-info .user-name {
+ margin-right: 10px;
+ }
+
+ .chat-header .user-info .status {
+ align-items: center;
+ display: flex;
+ }
+
+ .chat-header .options {
+ display: flex;
+ align-items: center;
+ flex-direction: row;
+ justify-content: space-around;
height: 100%;
+ width: 15%;
+ }
+
+ .chat-header .options svg {
+ cursor: pointer;
+ }
+
+ .chat-room-container {
+ height: 100%;
+ width: 76.25%;
+ }
+
+ @media screen and (max-width: 510px) {
+ #side-bar {
+ position: absolute;
+ left: -100%;
+ }
+ .chat-room-container {
+ width: 100%;
+ }
+ }
+
+ .chat-room {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ height: 100%;
+ width: 100%;
+ }
+
+ .chat-room.choose {
+ align-items: center;
+ justify-content: center;
+ font-size: 2em;
+ }
+
+ .thread-container {
+ height: 90vh;
+ overflow: scroll;
+ flex-grow: 1;
+ overflow-y: scroll;
+ position: relative;
+ }
+
+ .thread-container::-webkit-scrollbar-track {
+ background-color: #2f9999;
+ }
+
+ .thread-container::-webkit-scrollbar {
+ width: 5px;
+ background-color: #2f9999;
+ }
+
+ .thread-container::-webkit-scrollbar-thumb {
+ background-color: #2f9999;
+ }
+
+ .thread-container .thread {
+ position: relative;
+ width: 100%;
+ min-height: 89vh;
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-end;
+ color: #ffffff;
+ background: #ffffff;
+ }
+
+ .message-container {
+ display: flex;
+ justify-content: flex-start;
+ min-height: 50px;
+ margin: 10px 15px;
+ animation: 0.65s ease-out 0s show;
+ }
+
+ .message-container .time {
+ order: 1;
+ }
+
+ .message-container .data {
+ order: 2;
+ height: 100%;
+ margin-left: 25px;
+ }
+
+ .message-container .name {
+ color:#FC4A1A;
+ font-size: 0.65em;
+ margin-top: 5px;
+ text-align: right;
+ }
+
+ .message-container .message {
+ border-style: solid;
+ border-color:#b3b2ca;
+ background: #fff;
+ border-radius: 5px;
+ border-top-left-radius: 0;
+ box-sizing: border-box;
+ color: #FC4A1A;
+ height: 100%;
+ padding: 10px 15px;
+ position: relative;
+ }
+
+ @keyframes show {
+ 0% {
+ opacity: 0;
+ }
+ 100% {
+ opacity: 1;
+ }
+ }
+
+ ${
+ ''
+ }
+
+ .message-container.right {
+ text-align: right;
+ justify-content: flex-end;
+ }
+
+ .message-container.right .time {
+ order: 2;
+ margin-left: 25px;
+ }
+
+ .message-container.right .data {
+ margin-left: 0;
+ order: 1;
+ }
+
+ .message-container.right .name {
+ display: none;
+ }
+
+ .message-container.right .message {
+ border-style:none;
+ background: #2f9999;
+ color: #fff;
+ border-top-right-radius: 0;
+ border-top-left-radius: 5px;
+ }
+
+ ${
+ ''
+ }
+ ${'' }
+ ${'' }
+ left: auto;
+ right: -7px;
+ } */}
+
+ .typing-user {
+ text-align: right;
+ margin: 10px 15px;
+ }
+
+ .message-input {
+ border-radius: 0 0 15px 15px;
+
+ padding: 10px;
+ background: white;
+ color: #484d79;
+ box-sizing: border-box;
+ height: 15vh;
+ max-height: 65px;
+ }
+
+ .message-input .message-form {
+ height: 100%;
+ width: 100%;
+ display: flex;
+ justify-content: space-between;
+ }
+
+ .message-input .message-form .form-control {
+ border-radius: 0 0 0 10px;
+
+ padding-top: 24px;
+ padding-bottom: 24px;
+ resize: none;
+ padding-left: 15px;
+ box-sizing: border-box;
+ width: 80%;
+ height: 100%;
+ border: none;
+ }
+
+ .message-input .message-form .form-control::-webkit-scrollbar-track {
+
+ background-color: #484d79;
+ }
+
+ .message-input .message-form .form-control::-webkit-scrollbar {
+ width: 5px;
+ background-color: #2f9999;
+ }
+
+ .message-input .message-form .form-control::-webkit-scrollbar-thumb {
+ background-color: #2f9999;
+ }
+
+ .message-input .message-form .form-control:focus {
+ outline: none;
+ }
+
+ .message-input .message-form .send {
+ box-sizing: border-box;
+ font-size: 1.25em;
+ text-align: center;
+ border: none;
+ height: 100%;
+ color: #fff;
+ background: #f7b733;
+ transition: all 0.35s ease-out;
+ }
+
+ .message-input .message-form .send:disabled {
+ opacity: 0.2;
+ background: #5d5d8a;
}
`;
@@ -46,7 +500,11 @@ const PublicChat = () => (
this is the public chat page
hello
-
+
+
+
+
+
);
diff --git a/src/js/SideBar.jsx b/src/js/SideBar.jsx
new file mode 100644
index 0000000..2b5b7b5
--- /dev/null
+++ b/src/js/SideBar.jsx
@@ -0,0 +1,46 @@
+import React, { Component } from 'react';
+import FAChevronDown from 'react-icons/lib/md/keyboard-arrow-down';
+import FAMenu from 'react-icons/lib/fa/list-ul';
+import FASearch from 'react-icons/lib/fa/search';
+import MdEject from 'react-icons/lib/md/eject';
+
+export default class SideBar extends Component {
+ render() {
+ const { chats, activeChat, user, setActiveChat, logout } = this.props;
+ return (
+
+
{
+ e.target === this.refs.user && setActiveChat(null);
+ }}
+ >
+ {chats.map(chat => {
+ if (chat.name) {
+ const lastMessage = chat.messages[chat.messages.length - 1];
+ const user = chat.users.find(({ name }) => {
+ return name !== this.props.name;
+ }) || { name: 'Users' };
+ const classNames =
+ activeChat && activeChat.id === chat.id ? 'active' : '';
+
+ return (
+
+ );
+ }
+
+ return null;
+ })}
+
+
+ {user.name}
+
+
+ );
+ }
+}
diff --git a/src/js/Signup.jsx b/src/js/Signup.jsx
new file mode 100644
index 0000000..7ab68f4
--- /dev/null
+++ b/src/js/Signup.jsx
@@ -0,0 +1,276 @@
+import React from "react";
+import styled from "styled-components";
+import { Link } from "react-router-dom";
+
+
+const LandingNavbar = styled.div`
+ a {
+ float: right;
+ margin: 5px;
+ font-weight: bolder;
+ text-decoration: none;
+ color: #fff;
+ }
+ font-family: Roboto;
+`;
+
+const SignupDiv = styled.div`
+ /* Demo 3 */
+
+ .form-3 {
+ font-family: "Ubuntu", "Lato", sans-serif;
+ font-weight: 400;
+ /* Size and position */
+ width: 300px;
+ position: relative;
+ margin: 60px auto 30px;
+ padding: 10px;
+ overflow: hidden;
+
+ /* Styles */
+ background: #111;
+ border-radius: 0.4em;
+ border: 1px solid #191919;
+ box-shadow: inset 0 0 2px 1px rgba(255, 255, 255, 0.08),
+ 0 16px 10px -8px rgba(0, 0, 0, 0.6);
+ }
+
+ .form-3 label {
+ /* Size and position */
+ width: 50%;
+ float: left;
+ padding-top: 9px;
+
+ /* Styles */
+ color: #ddd;
+ font-size: 12px;
+ text-transform: uppercase;
+ letter-spacing: 1px;
+ text-shadow: 0 1px 0 #000;
+ text-indent: 10px;
+ font-weight: 700;
+ cursor: pointer;
+ }
+
+ .form-3 input[type="text"],
+ .form-3 input[type="password"],
+ .form-3 input[type="country"],
+ .form-3 input[type="city"],
+ .form-3 input[type="email"] {
+ /* Size and position */
+ width: 50%;
+ float: left;
+ padding: 8px 5px;
+ margin-bottom: 10px;
+ font-size: 12px;
+
+ /* Styles */
+ background: #1f2124; /* Fallback */
+ background: -moz-linear-gradient(#1f2124, #27292c);
+ background: -ms-linear-gradient(#1f2124, #27292c);
+ background: -o-linear-gradient(#1f2124, #27292c);
+ background: -webkit-gradient(
+ linear,
+ 0 0,
+ 0 100%,
+ from(#1f2124),
+ to(#27292c)
+ );
+ background: -webkit-linear-gradient(#1f2124, #27292c);
+ background: linear-gradient(#1f2124, #27292c);
+ border: 1px solid #000;
+ box-shadow: 0 1px 0 rgba(255, 255, 255, 0.1);
+ border-radius: 3px;
+
+ /* Font styles */
+ font-family: "Ubuntu", "Lato", sans-serif;
+ color: #fff;
+ }
+
+ .form-3 input[type="text"]:hover,
+ .form-3 input[type="password"]:hover,
+ .form-3 input[type="email"]:hover,
+ .form-3 input[type="country"]:hover,
+ .form-3 input[type="city"]:hover,
+ .form-3 label:hover ~ input[type="text"],
+ .form-3 label:hover ~ input[type="password"], .form-3 label:hover ~ input[type="email"] {
+ background: #27292c;
+ }
+
+ .form-3 input[type="text"]:focus,
+ .form-3 input[type="password"]:focus,
+ .form-3 input[type="country"]:focus,
+ .form-3 input[type="city"]:focus,
+ .form-3 input[type="email"]:focus {
+ box-shadow: inset 0 0 2px #000;
+ background: #494d54;
+ border-color: #51cbee;
+ outline: none; /* Remove Chrome outline */
+ }
+
+
+ .form-3 p:nth-child(3),
+ .form-3 p:nth-child(4) {
+ float: left;
+ width: 50%;
+ }
+
+ .form-3 input[type="checkbox"] {
+ margin-left: 10px;
+ vertical-align: middle;
+ }
+
+ .form-3 input[type="submit"] {
+ /* Width and position */
+ width: 100%;
+ padding: 8px 5px;
+
+ /* Styles */
+ border: 1px solid #0273dd; /* Fallback */
+ border: 1px solid rgba(0, 0, 0, 0.4);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3),
+ inset 0 10px 10px rgba(255, 255, 255, 0.1);
+ border-radius: 3px;
+ background: #38a6f0;
+ cursor: pointer;
+
+ /* Font styles */
+ font-family: "Ubuntu", "Lato", sans-serif;
+ color: white;
+ font-weight: 700;
+ font-size: 15px;
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.8);
+ }
+
+ .form-3 input[type="submit"]:hover {
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.6);
+ }
+
+ .form-3 input[type="submit"]:active {
+ background: #287db5;
+ box-shadow: inset 0 0 3px rgba(0, 0, 0, 0.6);
+ border-color: #000; /* Fallback */
+ border-color: rgba(0, 0, 0, 0.9);
+ }
+
+ .no-boxshadow .form-3 input[type="submit"]:hover {
+ background: #2a92d8;
+ }
+
+ .form-3:after {
+ /* Size and position */
+ content: "";
+ height: 1px;
+ width: 33%;
+ position: absolute;
+ left: 20%;
+ top: 0;
+
+ background: -webkit-gradient(
+ linear,
+ 0 0,
+ 100% 0,
+ from(transparent),
+ color-stop(0.25, #444),
+ color-stop(0.5, #b6b6b8),
+ color-stop(0.75, #444),
+ to(transparent)
+ );
+ background: -webkit-linear-gradient(
+ left,
+ transparent,
+ #444,
+ #b6b6b8,
+ #444,
+ transparent
+ );
+ background: linear-gradient(
+ left,
+ transparent,
+ #444,
+ #b6b6b8,
+ #444,
+ transparent
+ );
+ }
+
+ .form-3:before {
+ /* Size and position */
+ content: "";
+ width: 8px;
+ height: 5px;
+ position: absolute;
+ left: 34%;
+ top: -7px;
+
+ /* Styles */
+ border-radius: 50%;
+ box-shadow: 0 0 6px 4px #fff;
+ }
+
+ .form-3 p:nth-child(1):before {
+ /* Size and position */
+ content: "";
+ width: 250px;
+ height: 100px;
+ position: absolute;
+ top: 0;
+ left: 45px;
+
+ /* Styles */
+ -webkit-transform: rotate(75deg);
+ transform: rotate(75deg);
+
+ background: -webkit-linear-gradient(
+ 50deg,
+ rgba(255, 255, 255, 0.15),
+ rgba(0, 0, 0, 0)
+ );
+ background: linear-gradient(
+ 50deg,
+ rgba(255, 255, 255, 0.15),
+ rgba(0, 0, 0, 0)
+ );
+ pointer-events: none;
+ }
+
+ .no-pointerevents .form-3 p:nth-child(1):before {
+ display: none;
+ }
+`;
+
+const SignupPage = () => (
+
+
+ Sign In
+ Sign Up
+
+
+
+
+
+
+);
+
+export default SignupPage;
diff --git a/src/js/UserPage.js b/src/js/UserPage.js
new file mode 100644
index 0000000..76982f6
--- /dev/null
+++ b/src/js/UserPage.js
@@ -0,0 +1,41 @@
+import React from 'react';
+import styled from "styled-components";
+import {Link, Redirect} from "react-router-dom";
+import Navbar from './Navbar';
+import axios from 'axios';
+import PostTemplate from './PostTemplate';
+
+class UserPage extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ username: null,
+ img: null,
+ posts: null
+ }
+ }
+ componentDidMount() {
+ axios.get('/api/userPosts').then(response => {
+ this.setState({posts: response})
+ })
+ }
+ render() {
+ return (
+
+
+
+

+
{this.state.username}
+
+
{
+ this.state.posts
+ ? (this.state.posts.map(post => {
+ return
;
+ })):""
+ }
+
+
)
+ }
+}
+
+export default UserPage;
diff --git a/src/js/actionCreators.js b/src/js/actionCreators.js
index b46703f..5d85f2a 100644
--- a/src/js/actionCreators.js
+++ b/src/js/actionCreators.js
@@ -13,3 +13,11 @@ export function setActivePoint(activePoint) {
export function setHoverLoc(hoverLoc) {
return { type: 'SET_HOVER_LOC', payload: hoverLoc };
}
+
+export function setAuthenticated(authenticated) {
+ return { type: 'SET_AUTHENTICATED', payload: authenticated };
+}
+
+export function setLandingRedirect(redirect) {
+ return { type: 'SET_LANDING_REDIRECT', payload: redirect };
+}
diff --git a/src/js/reducers/index.js b/src/js/reducers/index.js
index 3f75b85..a0a09a0 100644
--- a/src/js/reducers/index.js
+++ b/src/js/reducers/index.js
@@ -1,12 +1,22 @@
import { combineReducers } from 'redux';
-import { data, coin, duration, hoverLoc, activePoint } from './reducers';
+import {
+ data,
+ coin,
+ duration,
+ hoverLoc,
+ activePoint,
+ authenticated,
+ landingRedirect
+} from './reducers';
const rootReducer = combineReducers({
coin,
duration,
hoverLoc,
activePoint,
- data
+ data,
+ authenticated,
+ landingRedirect
});
export default rootReducer;
diff --git a/src/js/reducers/reducers.js b/src/js/reducers/reducers.js
index 2008dec..a64e242 100644
--- a/src/js/reducers/reducers.js
+++ b/src/js/reducers/reducers.js
@@ -54,7 +54,6 @@ const defaultState = {
};
export function data(state = defaultState, action) {
- let apiData;
let sortedData;
switch (action.type) {
case 'ADD_API_DATA_PENDING':
@@ -83,3 +82,17 @@ export function data(state = defaultState, action) {
return state;
}
}
+
+export function authenticated(state = false, action) {
+ if (action.type === 'SET_AUTHENTICATED') {
+ return action.payload;
+ }
+ return state;
+}
+
+// export function landingRedirect(state = '/login', action) {
+// if (action.type === 'SET_LANDING_REDIRECT') {
+// return action.payload;
+// }
+// return state;
+// }
diff --git a/src/js/util/sortData.js b/src/js/util/sortData.js
index 2ee3282..2fc679e 100644
--- a/src/js/util/sortData.js
+++ b/src/js/util/sortData.js
@@ -23,8 +23,8 @@ export function coindeskSort(apiData) {
style: 'currency',
currency: 'USD'
}),
- x: count, //previous days
- y: apiData[date] // numerical price
+ x: count,
+ y: apiData[date]
});
count++;
}
diff --git a/webpack.config.js b/webpack.config.js
index 3e70c15..b439fb9 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -4,9 +4,9 @@ const webpack = require('webpack');
module.exports = {
context: __dirname,
entry: [
- 'react-hot-loader/patch',
- 'webpack-dev-server/client?http://localhost:8080',
- 'webpack/hot/only-dev-server',
+ // 'react-hot-loader/patch',
+ // 'webpack-dev-server/client?http://localhost:8080',
+ // 'webpack/hot/only-dev-server',
'./src/js/ClientApp.jsx'
],
devtool: 'inline-source-map',
@@ -16,7 +16,7 @@ module.exports = {
publicPath: '/public/'
},
devServer: {
- hot: true,
+ // hot: true,
publicPath: '/public/',
historyApiFallback: true
},
@@ -29,9 +29,9 @@ module.exports = {
chunks: false
},
plugins: [
- new webpack.optimize.UglifyJsPlugin(),
- new webpack.HotModuleReplacementPlugin(),
- new webpack.NamedModulesPlugin()
+ // new webpack.optimize.UglifyJsPlugin()
+ // new webpack.HotModuleReplacementPlugin(),
+ // new webpack.NamedModulesPlugin()
],
module: {
rules: [