Display results nicer

This commit is contained in:
Linus Miller 2017-02-24 18:22:26 +01:00
parent bedcf95596
commit 3a5dfdd115
13 changed files with 216 additions and 15 deletions

View File

@ -31,7 +31,22 @@ div.item {
align-items: center;
}
pre {
width: 100%;
overflow: scroll;
#results {
> ul {
> li {
padding: 5px 0;
cursor: pointer;
&:hover {
background: #ddd;
}
> ul {
display: none;
}
&.expand {
> ul {
display: block;
}
}
}
}
}

51
client/actions/results.js Normal file
View File

@ -0,0 +1,51 @@
import { pick } from 'lowline';
export const DELETE_RESULT = 'DELETE_RESULT';
const baseUrl = '/api/results';
const headers = {
'X-Requested-With': 'XMLHttpRequest',
accept: 'application/json',
};
export const FETCH_RESULTS = 'FETCH_RESULTS';
// query can be a query string (without ?, ie not a search string)
export function fetchResults(query = {}) {
query = typeof query === 'string' ? query : qs.stringify(query);
return (dispatch) => {
fetch(`${baseUrl}${query ? `?${query}` : ''}`, {
credentials: 'same-origin',
headers,
}).then((res) => res.json())
.then((json) => {
const actions = [receiveResults(json.results || [])];
if (json.perPage) {
actions.push(setPagination(pick(json, 'perPage', 'totalCount')));
}
dispatch(batchActions(actions));
});
};
}
export const RECEIVE_RESULTS = 'RECEIVE_RESULTS';
export function receiveResults(json) {
return {
type: RECEIVE_RESULTS,
payload: json,
receivedAt: Date.now(),
};
}
export const REMOVE_RESULTS = 'REMOVE_RESULTS';
export function removeResults() {
return {
type: REMOVE_RESULTS,
};
}

View File

@ -0,0 +1,13 @@
import { h } from 'preact';
import formatTime from '../util/formatTime';
export default (props) => (
<li>
<span class="line">{props.Line.Name}</span>
<ul>
<li>{formatTime(props.DepDateTime)} {props.From.Name}</li>
<li>{formatTime(props.ArrDateTime)} {props.To.Name}</li>
</ul>
</li>
);

View File

@ -0,0 +1,25 @@
import { h, Component } from 'preact';
import Link from './Link';
import formatTime from '../util/formatTime';
export default class Result extends Component {
toggle() {
console.log('toggle');
this.setState({
expand: !this.state.expand,
})
}
render(props, { expand }) {
return (
<li className={{ expand }} onClick={() => this.toggle()}>
{formatTime(props.DepDateTime)} - {formatTime(props.ArrDateTime)}
<ul>
{props.RouteLinks.RouteLink.map((link, i) => <Link key={i} {...link} />)}
</ul>
</li>
);
}
}

View File

@ -0,0 +1,24 @@
import { h, Component } from 'preact';
import Result from './Result';
import store from '../store';
export default class ResultList extends Component {
componentDidMount() {
this.unsubscribe = store.subscribe(() => this.forceUpdate());
}
componentWillUnmount() {
this.unsubscribe();
}
render() {
const { results } = store.getState();
console.log(results);
return (
<ul>{results && results.map((result, i) => <Result key={i} {...result} />)}</ul>
);
}
}

View File

@ -1,7 +1,11 @@
import { $, $$ } from 'dollr';
import dragula from 'dragula';
import { h, render } from 'preact';
import ResultList from './components/ResultList';
import store from './store';
import { receiveResults } from './actions/results';
const result = $('pre');
const containers = $$('.location');
@ -34,7 +38,8 @@ drake.on('drop', (el, target, source) => {
return res.json();
}).then((json) => {
console.log(json);
result.textContent = JSON.stringify(json, null, ' ')
// result.textContent = JSON.stringify(json, null, ' ')
store.dispatch(receiveResults(json));
}).catch((err) => {
console.log('error');
console.log(err);
@ -46,10 +51,6 @@ function prevent(e) {
e.preventDefault();
}
document.body.addEventListener('touchmove', (e) => {
if (e.target.classList.contains('item')) e.preventDefault();
}, { passive: false });
drake.on('over', (el, target, source) => {
if (target !== source) {
target.classList.add('over');
@ -62,3 +63,8 @@ drake.on('out', (el, target, source) => {
}
});
render(
<ResultList />,
$('#results')
);

View File

@ -18,7 +18,7 @@ export default ({ articleUrl, protocol, hostname, websocketsPort, INITIAL_STATE,
<div data-location="brother" class="location l03"><div data-location="brother" class="item"><span>Brother</span></div></div>
<div data-location="therapist" class="location l04"><div data-location="therapist" class="item"><span>The Rapist</span></div></div>
</div>
<pre></pre>
<div id="results"></div>
<script src={"/js/app" + (js ? js.suffix : '') + '.js'} />
</body>
</html>

View File

@ -0,0 +1,16 @@
import {
RECEIVE_RESULTS,
REMOVE_RESULTS,
} from '../actions/results';
export default (state = null, action) => {
switch (action.type) {
case RECEIVE_RESULTS:
return action.payload || [];
case REMOVE_RESULTS:
return null;
default:
return state;
}
};

7
client/reducers/root.js Normal file
View File

@ -0,0 +1,7 @@
import { combineReducers } from 'redux';
import results from './results';
export default combineReducers({
results,
});

15
client/store.js Normal file
View File

@ -0,0 +1,15 @@
import thunkMiddleware from 'redux-thunk';
import createLogger from 'redux-logger';
import { createStore, applyMiddleware } from 'redux';
const loggerMiddleware = createLogger();
import rootReducer from './reducers/root';
export default createStore(
rootReducer,
applyMiddleware(
thunkMiddleware,
loggerMiddleware
)
);

View File

@ -0,0 +1,3 @@
export default function formatDateTime(str) {
return str.split('T')[1].slice(0, -3);
}

View File

@ -17,15 +17,22 @@
"chalk": "^1.1.3",
"cookie-parser": "^1.4.3",
"dollr": "^0.1.2",
"dragula": "^3.7.2",
"dragula": "github:lohfu/dragula",
"easy-tz": "^0.1.1",
"express": "^4.14.1",
"express-session": "^1.15.1",
"jsx-node": "^0.2.2",
"lodash": "^4.17.4",
"lowline": "^0.1.3",
"midwest": "github:thebitmill/midwest",
"midwest-service-errors": "^0.2.0",
"morgan": "^1.8.1",
"pg": "^6.1.2",
"preact": "^7.2.0",
"react-dragula": "^1.1.17",
"redux": "^3.6.0",
"redux-logger": "^2.8.1",
"redux-thunk": "^2.2.0",
"require-dir": "^0.3.1",
"superagent": "^3.5.0",
"useragent": "^2.1.12",

View File

@ -1,6 +1,8 @@
'use strict';
const format = require('easy-tz/cjs/format');
const request = require('superagent');
// import get from 'get-value';
@ -50,15 +52,32 @@ function formatStation(json) {
return `${encodeURIComponent(json.name)}|${json.id}|${types[json.type]}`
}
function formatTime(date) {
date = date || new Date();
return format(null, 'YYYY-MM-DD HH:mm', date);
}
console.log(formatTime());
function formatLink(link) {
}
function formatResult(result) {
return _.omit(result, 'Prices');
}
console.log(new Date('2017-02-24T17:16:00'.split('T').join(' ')).toLocaleString());
const journeysPath = [ 'soap:Envelope', 'soap:Body', 'GetJourneyResponse', 'GetJourneyResult', 'Journeys', 'Journey']
// http://www.labs.skanetrafiken.se/v2.2/resultspage.asp?cmdaction=next&selPointFr=malm%F6%20C|80000|0&selPointTo=landskrona|82000|0&LastStart=2017-02-23%2016:38
router.post('/trip', (req, res, next) => {
request(`http://www.labs.skanetrafiken.se/v2.2/resultspage.asp?cmdaction=next&selPointFr=${formatStation(stations[req.body.from])}&selPointTo=${formatStation(stations[req.body.to])}&LastStart=2017-02-23%2016:38`).then((response) =>{
request(`http://www.labs.skanetrafiken.se/v2.2/resultspage.asp?cmdaction=next&selPointFr=${formatStation(stations[req.body.from])}&selPointTo=${formatStation(stations[req.body.to])}&LastStart=${encodeURIComponent(formatTime(req.body.datetime))}`).then((response) =>{
const result = _.get(xml2json.toJson(response.text, { object: true }), journeysPath);
result.forEach((obj) => {
delete obj.Prices
});
result.forEach(formatResult);
res.json(result);
});