Added redux for handling status state

This commit is contained in:
Jesper Wrang 2018-01-13 18:20:08 +01:00
parent 503c4c383a
commit c8dd37d6ae
14 changed files with 250 additions and 57 deletions

View file

@ -4,6 +4,7 @@
"@babel/preset-es2015"
],
"plugins": [
"@babel/plugin-transform-async-to-generator"
"@babel/plugin-transform-async-to-generator",
"@babel/plugin-proposal-object-rest-spread"
]
}

View file

@ -69,13 +69,7 @@ return {
missing: [],
isPermalink: (Reddit.permalink !== undefined && Reddit.permalink !== ""),
to36: function(id){
return parseInt(id).toString(36);
},
to10: function(id){
return parseInt(id, 36);
},
addComments: function(json){

67
package-lock.json generated
View file

@ -243,12 +243,27 @@
"integrity": "sha512-SiP9hU9L6OAIog8Mywyh5aplF1WjbDa5Z+PMfN3Gld4JnDWqO3HbXHf8Oau298xzpDwpz77dHWV963tUqRzuMA==",
"dev": true
},
"@babel/plugin-proposal-object-rest-spread": {
"version": "7.0.0-beta.37",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.0.0-beta.37.tgz",
"integrity": "sha512-VwS0evYuXYcDdxK66fPPiye1mbktFpE5KXE/nsQiris3jsnRPVzP+7l9Fn/8ZvRmS31WcjJTjziKyNfGaOFGeg==",
"dev": true,
"requires": {
"@babel/plugin-syntax-object-rest-spread": "7.0.0-beta.37"
}
},
"@babel/plugin-syntax-jsx": {
"version": "7.0.0-beta.37",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.0.0-beta.37.tgz",
"integrity": "sha512-5ZER7tkR6E1V/lUOTLqxrBDm1KWbEsMppdHsvKdtHxY5WXlW1TCtvKwhr9dradrl8HA+9tIekL2k724f6kMw6Q==",
"dev": true
},
"@babel/plugin-syntax-object-rest-spread": {
"version": "7.0.0-beta.37",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.0.0-beta.37.tgz",
"integrity": "sha512-p3jG3QXmtrQ01DS/Dy3MqF2065VR6tnDirVatdx5bLKsHKHf+TPVevwxgAo0nOWx3IFCVjRyrRsWL2Z7n3bqgw==",
"dev": true
},
"@babel/plugin-transform-arrow-functions": {
"version": "7.0.0-beta.37",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.0.0-beta.37.tgz",
@ -2194,6 +2209,12 @@
"integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
"dev": true
},
"deep-diff": {
"version": "0.3.8",
"resolved": "https://registry.npmjs.org/deep-diff/-/deep-diff-0.3.8.tgz",
"integrity": "sha1-wB3mPvsO7JeYgB1Ax+Da4ltYLIQ=",
"dev": true
},
"deep-equal": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
@ -5361,8 +5382,12 @@
"lodash": {
"version": "4.17.4",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
"integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=",
"dev": true
"integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4="
},
"lodash-es": {
"version": "4.17.4",
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.4.tgz",
"integrity": "sha1-3MHXVS4VCgZABzupyzHXDwMpUOc="
},
"lodash.assign": {
"version": "4.2.0",
@ -7386,6 +7411,19 @@
"prop-types": "15.6.0"
}
},
"react-redux": {
"version": "5.0.6",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-5.0.6.tgz",
"integrity": "sha512-8taaaGu+J7PMJQDJrk/xiWEYQmdo3mkXw6wPr3K3LxvXis3Fymiq7c13S+Tpls/AyNUAsoONkU81AP0RA6y6Vw==",
"requires": {
"hoist-non-react-statics": "2.3.1",
"invariant": "2.2.2",
"lodash": "4.17.4",
"lodash-es": "4.17.4",
"loose-envify": "1.3.1",
"prop-types": "15.6.0"
}
},
"react-router": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-4.2.0.tgz",
@ -7552,6 +7590,26 @@
}
}
},
"redux": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/redux/-/redux-3.7.2.tgz",
"integrity": "sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A==",
"requires": {
"lodash": "4.17.4",
"lodash-es": "4.17.4",
"loose-envify": "1.3.1",
"symbol-observable": "1.1.0"
}
},
"redux-logger": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/redux-logger/-/redux-logger-3.0.6.tgz",
"integrity": "sha1-91VZZvMJjzyIYExEnPC69XeCdL8=",
"dev": true,
"requires": {
"deep-diff": "0.3.8"
}
},
"regenerate": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.3.tgz",
@ -8833,6 +8891,11 @@
"whet.extend": "0.9.9"
}
},
"symbol-observable": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.1.0.tgz",
"integrity": "sha512-dQoid9tqQ+uotGhuTKEY11X4xhyYePVnqGSoSm3OGKh2E8LZ6RPULp1uXTctk33IeERlrRJYoVSBglsL05F5Uw=="
},
"tapable": {
"version": "0.2.8",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.8.tgz",

View file

@ -29,12 +29,15 @@
"@babel/polyfill": "^7.0.0-beta.37",
"react": "^16.2.0",
"react-dom": "^16.2.0",
"react-redux": "^5.0.6",
"react-router-dom": "^4.2.2",
"redux": "^3.7.2",
"whatwg-fetch": "^2.0.3"
},
"devDependencies": {
"@babel/cli": "^7.0.0-beta.37",
"@babel/core": "^7.0.0-beta.37",
"@babel/plugin-proposal-object-rest-spread": "^7.0.0-beta.37",
"@babel/plugin-transform-async-to-generator": "^7.0.0-beta.37",
"@babel/preset-es2015": "^7.0.0-beta.37",
"@babel/preset-react": "^7.0.0-beta.37",
@ -47,6 +50,7 @@
"html-loader": "^0.5.4",
"html-webpack-plugin": "^2.30.1",
"node-sass": "^4.7.2",
"redux-logger": "^3.0.6",
"sass-loader": "^6.0.6",
"uglifyjs-webpack-plugin": "^1.1.6",
"webpack": "^3.10.0",

View file

@ -9,7 +9,7 @@ import {
import Menu from 'components/Menu'
import {About, Thread, Subreddit} from 'pages'
export default class App extends React.Component {
class App extends React.Component {
constructor(props) {
super(props)
@ -26,7 +26,7 @@ export default class App extends React.Component {
return (
<BrowserRouter basename={__dirname}>
<>
<Menu />
<Menu status={this.props.status}/>
<Switch>
<Route exact path='/' component={Thread} />
<Route path='/about' component={About}/>
@ -36,4 +36,6 @@ export default class App extends React.Component {
</BrowserRouter>
)
}
}
}
export default App

View file

View file

@ -1,8 +1,10 @@
import React from 'react'
import {Link} from 'react-router-dom'
import StatusBox from 'components/StatusBox'
import { setStatusLoading, setStatusSuccess, setStatusError } from 'state'
import {connect} from 'react-redux'
export default class Menu extends React.Component {
class Menu extends React.Component {
render () {
return (
<header>
@ -15,9 +17,24 @@ export default class Menu extends React.Component {
<Link to='/about/'>about</Link>
</nav>
</div>
<StatusBox />
<StatusBox {...this.props.status} />
</header>
)
}
}
}
const mapStateToProps = (state) => {
return {
status: state.status
}
}
const mapDispatchToProps = (dispatch) => {
return {
setStatusSuccess: text => dispatch(setStatusSuccess(text)),
setStatusLoading: text => dispatch(setStatusLoading(text)),
setStatusError: text => dispatch(setStatusError(text)),
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Menu)

View file

@ -5,9 +5,9 @@ export default class StatusBox extends React.Component {
return (
<div id='status'>
{this.props.text &&
<p id='status-text'>{lol}</p>}
<p id='status-text'>{this.props.text}</p>}
{this.props.image &&
<img id='status-image' src={lol}/>}
<img id='status-image' src={this.props.image}/>}
</div>
)
}

View file

@ -1,10 +1,26 @@
import '../sass/main.sass'
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import { store } from 'state'
import App from './App'
ReactDOM.render(
<App />,
<Provider store={store}>
<App />
</Provider>,
document.getElementById("app")
)
)
// console.log(store.getState())
import {setStatusError} from 'state'
// store.subscribe(() => console.log(store.getState()))
store.dispatch(setStatusError('Hello world'))
store.dispatch(setStatusError('Hi again :)'))
// import {json} from 'utils'
// import {test} from 'pushshift'
// test('7q2k2g').then(console.log)

View file

@ -0,0 +1,37 @@
const baseURL = 'https://elastic.pushshift.io'
const submissionURL = baseURL + '/rs/submissions/_search?source='
const commentURL = baseURL + '/rc/comments/_search?source='
const commentIDsURL = 'https://api.pushshift.io/reddit/submission/comment_ids/'
import { json, toBase10, toBase36 } from 'utils'
export const getCommentIDs = threadID => {
return fetch(commentIDsURL + threadID)
.then(json)
.then(results => {
return results.data
})
}
export const test = threadID => {
const elasticQuery = {
query: {
term: {
link_id: toBase10(threadID)
}
},
size: 10000,
}
return fetch(commentURL + JSON.stringify(elasticQuery))
.then(json)
.then(results => {
results.hits.hits.map(result => {
result._source.link_id = toBase36(result._source.link_id )
result._source.parent_id = toBase36(result._source.parent_id)
result._source.id = toBase36(result._id)
return result._source
})
})
}

View file

@ -16,7 +16,7 @@ const tokenInit = {
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'
},
method: 'POST',
body: 'grant_type='+encodeURIComponent('https://oauth.reddit.com/grants/installed_client')+'&device_id=DO_NOT_TRACK_THIS_DEVICE'
body: `grant_type=${encodeURIComponent('https://oauth.reddit.com/grants/installed_client')}&device_id=DO_NOT_TRACK_THIS_DEVICE`
}
const fetchToken = () => {
@ -32,30 +32,27 @@ const fetchToken = () => {
})
}
export default {
comments(subreddit, threadID) {
return fetchToken()
}
}
export const getComments = (subreddit, threadID) => {
return fetchToken()
.then(() => {
return Promise.all([
fetch(URLs.thread, Reddit.init)
.then(Fetch2.json)
.then(ThreadHTML.createThread)
.catch(function(error) {
return Promise.reject("Could not get thread from Reddit");
}),
// Reddit.fetchToken()
// .then(function(){
// return Promise.all([
// fetch(URLs.thread, Reddit.init)
// .then(Fetch2.json)
// .then(ThreadHTML.createThread)
// .catch(function(error) {
// return Promise.reject("Could not get thread from Reddit");
// }),
// fetch(URLs.pushshiftIDs)
// .then(Fetch2.json)
// .then(_.property("data"))
// .catch(function(error) {
// return Promise.reject("Could not get removed comment IDs");
// }),
// ])
// })
fetch(URLs.pushshiftIDs)
.then(Fetch2.json)
.then(_.property("data"))
.catch(function(error) {
return Promise.reject("Could not get removed comment IDs");
}),
])
})
}
// .then(function(results) {
// var thread = results[0];
// Comments.allIDs = results[1];

13
src/js/state/index.js Normal file
View file

@ -0,0 +1,13 @@
import { createStore, combineReducers, applyMiddleware } from 'redux'
import logger from 'redux-logger'
import { statusReducer } from './status'
export { setStatusLoading, setStatusSuccess, setStatusError } from './status'
const reducer = combineReducers({
status: statusReducer
})
export const store = createStore(reducer, applyMiddleware(logger))

54
src/js/state/status.js Normal file
View file

@ -0,0 +1,54 @@
const images = {
loading: '/images/loading.gif',
error: '/images/error.png',
success: '/images/done.png'
}
// Action types
const STATUS_SET_LOADING = 'STATUS_SET_LOADING'
const STATUS_SET_SUCCESS = 'STATUS_SET_SUCCESS'
const STATUS_SET_ERROR = 'STATUS_SET_ERROR'
// Action creators
export const setStatusLoading = (payload = '') => {
return {type: STATUS_SET_LOADING, payload}
}
export const setStatusSuccess = (payload = '') => {
return {type: STATUS_SET_SUCCESS, payload}
}
export const setStatusError = (payload = '') => {
return {type: STATUS_SET_ERROR, payload}
}
// Init state
const initialStatusState = {
text: null,
image: null
}
export const statusReducer = (state = initialStatusState, action) => {
switch (action.type) {
case STATUS_SET_SUCCESS:
return {
...state,
text: action.payload,
image: images.success
}
case STATUS_SET_LOADING:
return {
...state,
text: action.payload,
image: images.loading
}
case STATUS_SET_ERROR:
return {
...state,
text: action.payload,
image: images.error
}
default:
return state
}
}

View file

@ -2,23 +2,18 @@ import SnuOwnd from 'libraries/snuownd.js'
const markdown = SnuOwnd.getParser()
// Change bases
export const toBase36 = number => parseInt(number).toString(36)
export const toBase10 = numberString => parseInt(numberString, 36)
// Default thumbnails for reddit threads
export const redditThumbnails = ['self', 'default', 'image', 'nsfw']
// Images for the status box in right side of header
export const statusImages = {
loading: '/images/loading.gif',
error: '/images/error.png',
success: '/images/done.png'
}
// JSON parsing for fetch
export const json = x => x.json()
// Parse comments
export const parse = text => {
return markdown.render(text)
}
export const parse = text => markdown.render(text)
// UTC -> "Reddit time format" (e.g. 5 hours ago, just now, etc...)
export const prettyDate = createdUTC => {
@ -26,7 +21,7 @@ export const prettyDate = createdUTC => {
const secondDiff = currentUTC - createdUTC
const dayDiff = Math.floor(secondDiff / 86400)
if(dayDiff < 0) return ""
if(dayDiff < 0) return ""
if(dayDiff == 0) {
if(secondDiff < 10) return "just now"
if(secondDiff < 60) return secondDiff + " seconds ago"