first vuex experiments
This commit is contained in:
parent
1788bacdfa
commit
f29fb2206e
@ -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"
|
||||
}
|
||||
}
|
||||
|
@ -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'
|
||||
})
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
@ -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) {
|
||||
|
7
resources/ts/store/index.ts
Normal file
7
resources/ts/store/index.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import Vuex from 'vuex';
|
||||
|
||||
import { messages } from './messages';
|
||||
|
||||
export default new Vuex.Store({
|
||||
modules: { messages }
|
||||
})
|
62
resources/ts/store/messages.ts
Normal file
62
resources/ts/store/messages.ts
Normal 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;
|
||||
}));
|
||||
}
|
||||
}
|
||||
};
|
9
resources/ts/store/root.ts
Normal file
9
resources/ts/store/root.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { Module } from "vuex";
|
||||
|
||||
const state = { };
|
||||
|
||||
export type RootState = typeof state;
|
||||
|
||||
export default <Module<RootState, unknown>>{
|
||||
state
|
||||
}
|
@ -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>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user