first vuex experiments

This commit is contained in:
Kacper Donat 2018-09-30 11:06:46 +02:00
parent 1788bacdfa
commit f29fb2206e
8 changed files with 1063 additions and 43 deletions

View File

@ -38,6 +38,8 @@
"copy-webpack-plugin": "^4.5.2",
"imagemin-webpack-plugin": "^2.3.0",
"mini-css-extract-plugin": "^0.4.2",
"vue2-leaflet": "^1.0.2"
"vue2-leaflet": "^1.0.2",
"vuex": "^3.0.1",
"vuex-class": "^0.3.1"
}
}

View File

@ -10,17 +10,23 @@ window['$'] = window['jQuery'] = $;
window['Popper'] = Popper;
// dependencies
import { Vue } from "vue-property-decorator";
import Vue from "vue";
import Vuex, { mapActions, mapState, Store } from 'vuex';
Vue.use(Vuex);
// async dependencies
(async function () {
const [ components ] = await Promise.all([
const [ components, { default: store } ] = await Promise.all([
import('./components'),
import('./store'),
import('./font-awesome'),
import('./filters'),
import('bootstrap'),
]);
store.dispatch('messages/update');
// here goes "public" API
window['czydojade'] = {
components
@ -28,19 +34,29 @@ import { Vue } from "vue-property-decorator";
window['app'] = new Vue({
el: '#app',
store: store,
data: {
stops: [],
messages: {
count: 0,
visible: true
sections: {
messages: true
},
departures: {
state: ''
}
}, methods: {
handleMessagesUpdate(messages) {
this.messages.count = messages.length;
},
computed: {
messages(this: any) {
return {
count: this.$store.getters['messages/count'],
counts: this.$store.getters['messages/counts'],
state: this.$store.state.messages.state
};
}
},
methods: {
...mapActions({
updateMessages: 'messages/update'
})
}
});
})();

View File

@ -1,38 +1,15 @@
import Vue from 'vue';
import { Component, Prop, Watch } from "vue-property-decorator";
import { Component } from "vue-property-decorator";
import { Message } from "../model/message";
import urls from "../urls";
import { faInfoCircle, faExclamationTriangle, faQuestionCircle } from "@fortawesome/pro-light-svg-icons";
import { Jsonified } from "../utils";
import * as moment from "moment";
import { namespace } from 'vuex-class';
import store from '../store'
@Component({ template: require("../../components/messages.html") })
const { State } = namespace('messages');
@Component({ template: require("../../components/messages.html"), store })
export class MessagesComponent extends Vue {
public messages: Message[] = [];
async mounted() {
this.update();
setInterval(() => this.update(), 5000);
}
async update() {
const response = await fetch(urls.prepare(urls.messages));
if (response.ok) {
const messages = (await response.json()) as Jsonified<Message>[];
this.messages = messages.map(m => {
const message = m as Message;
message.validFrom = moment(m.validFrom);
message.validTo = moment(m.validTo);
return message;
});
}
this.$emit('update', this.messages);
}
@State messages: Message[];
public icon(message: Message) {
switch (message.type) {

View File

@ -0,0 +1,7 @@
import Vuex from 'vuex';
import { messages } from './messages';
export default new Vuex.Store({
modules: { messages }
})

View File

@ -0,0 +1,62 @@
import { ActionContext, Module, Store } from "vuex";
import { RootState } from "./root";
import { Message, MessageType } from "../model/message";
import urls from "../urls";
import { FetchingState, Jsonified } from "../utils";
import * as moment from 'moment';
import { Moment } from "moment";
export interface MessagesState {
messages: Message[],
state: FetchingState,
lastUpdate: Moment
}
export const messages: Module<MessagesState, RootState> = {
namespaced: true,
state: {
messages: [],
state: "not-initialized",
lastUpdate: moment()
},
getters: {
count: state => state.messages.length,
counts: (state: MessagesState): { [x in MessageType]: number } => ({
info: state.messages.filter(m => m.type === 'info').length,
unknown: state.messages.filter(m => m.type === 'unknown').length,
breakdown: state.messages.filter(m => m.type === 'breakdown').length,
})
},
mutations: {
update: (state: MessagesState, messages: Message[]) => {
state.messages = messages;
state.lastUpdate = moment();
state.state = 'ready';
},
fetching: (state: MessagesState) => state.state = 'fetching',
error: (state: MessagesState, error) => state.state = 'error',
},
actions: {
async update({ commit }: ActionContext<MessagesState, RootState>) {
commit('fetching');
const response = await fetch(urls.prepare(urls.messages));
if (!response.ok) {
commit('error', await response.json());
return;
}
const messages = await response.json() as Jsonified<Message>[];
commit('update', messages.map(m => {
const message = m as Message;
message.validFrom = moment(m.validFrom);
message.validTo = moment(m.validTo);
return message;
}));
}
}
};

View File

@ -0,0 +1,9 @@
import { Module } from "vuex";
const state = { };
export type RootState = typeof state;
export default <Module<RootState, unknown>>{
state
}

View File

@ -9,12 +9,15 @@
<h2 class="section__title flex">
<fa :icon="['fal', 'bullhorn']" fixed-width class="mr-2"></fa>
Komunikaty <span class="ml-2 badge badge-pill badge-dark">{{ '{{ messages.count }}' }}</span>
<button class="btn btn-action btn-sm flex-space-left" @click="messages.visible = !messages.visible">
<fa :icon="['fal', messages.visible ? 'chevron-up' : 'chevron-down']" fixed-width/>
<button class="btn btn-action flex-space-left" @click="updateMessages">
<fa :icon="['fal', 'sync']" :spin="messages.state === 'fetching'"></fa>
</button>
<button class="btn btn-action" @click="sections.messages = !sections.messages">
<fa :icon="['fal', sections.messages ? 'chevron-up' : 'chevron-down']" fixed-width/>
</button>
</h2>
<fold :visible="messages.visible">
<messages @update="handleMessagesUpdate"></messages>
<fold :visible="sections.messages">
<messages></messages>
</fold>
</section>

944
yarn.lock

File diff suppressed because it is too large Load Diff