1
0
Fork 0

Merge branch 'fix_loading_cookies' of Asara/sudoscientist-js-frontend into master

This commit is contained in:
Amarpreet Minhas 2019-10-26 12:25:33 -04:00 committed by Gogs
commit d4651a2315
13 changed files with 3256 additions and 2582 deletions

View file

@ -1,5 +1,5 @@
# TODO
1. Add filtering posts by tags
2. Auth
1. Fix up UX, return errors to screen instead of doing nothing.
2. Add filtering posts by tags
3. Comments

5622
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -6,15 +6,15 @@
"axios": "^0.18.1",
"github-markdown-css": "^3.0.1",
"react": "^16.10.2",
"react-cookie": "^4.0.1",
"react-dom": "^16.10.2",
"react-markdown": "^4.2.2",
"react-mde": "^7.6.2",
"react-redux": "^7.1.1",
"react-router-dom": "^5.1.2",
"react-scripts": "3.0.0",
"redux": "^4.0.4",
"redux-thunk": "^2.3.0",
"semantic-ui-react": "^0.87.3"
"universal-cookie": "^4.0.2"
},
"scripts": {
"start": "react-scripts start",

View file

@ -4,7 +4,6 @@
<meta charset="utf-8" />
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#EEEEEE" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.css">
<!--
manifest.json provides metadata used when your web app is installed on a

2
src/actions/history.js Normal file
View file

@ -0,0 +1,2 @@
import { createBrowserHistory } from 'history'
export default createBrowserHistory()

View file

@ -1,4 +1,5 @@
import sudoscientist from '../apis/sudoscientist';
import history from './history'
export const fetchPosts = () => async (dispatch) => {
const response = await sudoscientist.get('/blog');
@ -25,9 +26,21 @@ export const userLogin = (username, password) => async (dispatch) => {
}
)
if (response.status === 401) {
console.log("Please check your credentials")
dispatch({ type: 'USER_LOGIN', payload: null })
}
if (response.status === 200) {
dispatch({ type: 'USER_LOGIN', payload: response })
}
};
export const loadCookieToState = (data) => async (dispatch) => {
dispatch({ type: 'LOAD_COOKIE', data })
};
export const newBlogPost = (payload) => async (dispatch) => {
const response = await sudoscientist.post('/blog', payload)
if (response.status === 201) {
history.push('/posts/' + response.data.slug)
}
};

View file

@ -1,6 +1,6 @@
import axios from 'axios';
export default axios.create({
baseURL: 'http://api.sudosci.test:8080/v1/api/',
baseURL: 'https://api.sudoscientist.com/v1/api/',
withCredentials: true
});

View file

@ -4,12 +4,9 @@ import ReactMarkdown from 'react-markdown';
import AboutMarkdown from '../static/about.md';
class About extends React.Component {
constructor () {
super();
this.state = { about: '' };
}
state = { about: '' };
componentWillMount() {
componentDidMount() {
fetch(AboutMarkdown).then(res => res.text()).then(text => this.setState({ markdown: text }));
}

View file

@ -1,21 +1,25 @@
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import { Router, Route, Switch } from "react-router-dom";
import NavBar from './NavBar';
import Footer from './Footer';
import PostList from './PostList';
import Post from './Post';
import User from './User';
import About from './About'
import NewPost from './NewPost'
import history from '../actions/history';
function App() {
return (
<>
<Router>
<Router history={history}>
<NavBar/>
<Switch>
<Route exact path="/" component={PostList}/>
<Route exact path="/about/" component={About}/>
<Route exact path="/posts/" component={PostList}/>
<Route exact path="/newpost/" component={NewPost}/>
<Route path="/posts/:slug" component={Post}/>
<Route path="/users/:user" component={User}/>
</Switch>

View file

@ -2,19 +2,47 @@ import React, { Component } from 'react';
import Cookies from 'universal-cookie';
import { connect } from 'react-redux';
import { userLogin } from '../actions';
import { userLogin, loadCookieToState } from '../actions';
class AuthMenu extends Component {
constructor (props) {
super(props)
const cookies = new Cookies();
const datacookie = cookies.get('DataCookie');
if (datacookie) {
const data = JSON.parse(atob(datacookie.split('.')[1]))
if (data.exp > Math.floor(Date.now() / 1000)) {
this.state = {
user_authed: true,
where_in_auth_menu: "loggedIn",
username: data.username,
exp: data.exp,
}
}
else {
this.state = {
user_authed: false,
where_in_auth_menu: "requestUsername",
username: "",
password: "",
email: ""
email: "",
exp: null,
}
}
} else {
this.state = {
user_authed: false,
where_in_auth_menu: "requestUsername",
username: "",
password: "",
email: "",
exp: null
}
}
this.props.loadCookieToState(this.state)
this.handleInputChange = this.handleInputChange.bind(this)
@ -27,7 +55,6 @@ class AuthMenu extends Component {
this.handleCreateAccount = this.handleCreateAccount.bind(this)
this.authMenu = this.authMenu.bind(this)
}
@ -63,16 +90,15 @@ class AuthMenu extends Component {
}
handleLogin() {
const cookies = new Cookies();
this.props.userLogin(this.state.username, this.state.password)
.then(res => {
this.setState(state => ({
auth_menu_visible: false
auth_menu_visible: false,
where_in_auth_menu: "loggedIn"
}))
this.props.close()
}
)
.then(console.log(cookies.getAll()))
.catch(err => {
console.log(err);
})
@ -159,6 +185,15 @@ class AuthMenu extends Component {
<button onClick={this.handleCreateAccount} className="fluid ui positive button">Create Account!</button>
</div>
)
case 'loggedIn':
return (
<div className="ui menu dropdown" style={{display: "inline"}}>
<div className="ui left icon input">
<i className="edit icon"></i>
<button onClick={() => { document.location.href = "/newpost/"; }} className="fluid ui positive button">Create Post!</button>
</div>
</div>
)
default:
return null;
}
@ -171,12 +206,7 @@ class AuthMenu extends Component {
}
}
const mapStateToProps = (state) => {
return {
username: state.username,
};
}
export default connect(
mapStateToProps,
{ userLogin }
null,
{ userLogin, loadCookieToState }
)(AuthMenu);

View file

@ -7,8 +7,9 @@ class NavBar extends Component {
constructor (props) {
super(props)
this.state = {
logged_in: false,
user_authed: false,
auth_menu_visible: false,
user_or_login: 'Login'
}
this.handleLoginDropdown = this.handleLoginDropdown.bind(this)
}
@ -20,6 +21,7 @@ class NavBar extends Component {
}
render() {
const { user } = this.props;
return (
<div>
<div className="ui four item secondary menu">
@ -27,7 +29,7 @@ class NavBar extends Component {
<NavLink to="/posts/" className='item' activeClassName='active'>Posts</NavLink>
<NavLink to="/about/" className='item' activeClassName='active'>About</NavLink>
<div onClick={this.handleLoginDropdown} className='item ui button dropdown'>
Login
{user.user_authed ? user.username : 'Login'}
<i className="dropdown icon"></i>
<AuthMenu auth_menu_visible={this.state.auth_menu_visible} close={ () => this.setState({auth_menu_visible: false})}></AuthMenu>
</div>
@ -39,7 +41,7 @@ class NavBar extends Component {
const mapStateToProps = (state) => {
return {
auth: state.auth
user: state.auth,
};
}

67
src/components/NewPost.js Normal file
View file

@ -0,0 +1,67 @@
import React from 'react';
import { useSelector } from "react-redux";
import ReactMde from "react-mde";
import ReactMarkdown from 'react-markdown';
import { connect } from 'react-redux';
import 'github-markdown-css'
import "react-mde/lib/styles/css/react-mde-all.css"
import { newBlogPost } from '../actions';
const NewPost = (props) => {
const [title, setTitle] = React.useState("");
const [content, setContent] = React.useState("");
const [tags, setTags] = React.useState("");
const [selectedTab, setSelectedTab] = React.useState("write");
const username = useSelector(state => state.auth.username);
const submitPost = () => {
const payload = {
title: title,
content: content,
tags: tags,
author: username
}
props.newBlogPost(payload)
}
return(
<div className="container">
<input
value={title}
placeholder="Title..."
onChange={e => setTitle(e.target.value)}
/>
<div className="markdown-body">
<ReactMde
value={content}
onChange={setContent}
selectedTab={selectedTab}
onTabChange={setSelectedTab}
generateMarkdownPreview={(markdown) =>
Promise.resolve(<ReactMarkdown source={markdown} />)}
/>
</div>
<input
value={tags}
placeholder="Comma,Seperated,Tags..."
onChange={e => setTags(e.target.value)}
/>
<div>
<button onClick={submitPost}>Submit Post</button>
</div>
</div>
)
}
const mapStateToProps = (state) => {
return {
user: state.auth,
};
}
export default connect(
mapStateToProps,
{ newBlogPost }
)(NewPost);

View file

@ -1,18 +1,24 @@
const initialState = {
user_logged_in: false,
username: '',
user_authed: false,
where_in_auth_menu: "requestUsername",
email: "",
exp: null
};
export default (state = initialState, action) => {
switch (action.type) {
case 'LOAD_COOKIE':
return {...state, ...action.data}
case 'USER_LOGIN':
if (action.payload) {
var data = JSON.parse(atob(action.payload.data.split('.')[1]))
return {...state, ...{
username: action.payload.data.username,
user_logged_in: true
user_authed: true,
username: data.username,
}}
}
else return;
default:
return state;
return state
}
};