first vuex experiments
This commit is contained in:
parent
1788bacdfa
commit
f29fb2206e
@ -38,6 +38,8 @@
|
|||||||
"copy-webpack-plugin": "^4.5.2",
|
"copy-webpack-plugin": "^4.5.2",
|
||||||
"imagemin-webpack-plugin": "^2.3.0",
|
"imagemin-webpack-plugin": "^2.3.0",
|
||||||
"mini-css-extract-plugin": "^0.4.2",
|
"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;
|
window['Popper'] = Popper;
|
||||||
|
|
||||||
// dependencies
|
// dependencies
|
||||||
import { Vue } from "vue-property-decorator";
|
import Vue from "vue";
|
||||||
|
import Vuex, { mapActions, mapState, Store } from 'vuex';
|
||||||
|
|
||||||
|
Vue.use(Vuex);
|
||||||
|
|
||||||
// async dependencies
|
// async dependencies
|
||||||
(async function () {
|
(async function () {
|
||||||
const [ components ] = await Promise.all([
|
const [ components, { default: store } ] = await Promise.all([
|
||||||
import('./components'),
|
import('./components'),
|
||||||
|
import('./store'),
|
||||||
import('./font-awesome'),
|
import('./font-awesome'),
|
||||||
import('./filters'),
|
import('./filters'),
|
||||||
import('bootstrap'),
|
import('bootstrap'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
store.dispatch('messages/update');
|
||||||
|
|
||||||
// here goes "public" API
|
// here goes "public" API
|
||||||
window['czydojade'] = {
|
window['czydojade'] = {
|
||||||
components
|
components
|
||||||
@ -28,19 +34,29 @@ import { Vue } from "vue-property-decorator";
|
|||||||
|
|
||||||
window['app'] = new Vue({
|
window['app'] = new Vue({
|
||||||
el: '#app',
|
el: '#app',
|
||||||
|
store: store,
|
||||||
data: {
|
data: {
|
||||||
stops: [],
|
stops: [],
|
||||||
messages: {
|
sections: {
|
||||||
count: 0,
|
messages: true
|
||||||
visible: true
|
|
||||||
},
|
},
|
||||||
departures: {
|
departures: {
|
||||||
state: ''
|
state: ''
|
||||||
}
|
}
|
||||||
}, methods: {
|
},
|
||||||
handleMessagesUpdate(messages) {
|
computed: {
|
||||||
this.messages.count = messages.length;
|
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 Vue from 'vue';
|
||||||
import { Component, Prop, Watch } from "vue-property-decorator";
|
import { Component } from "vue-property-decorator";
|
||||||
import { Message } from "../model/message";
|
import { Message } from "../model/message";
|
||||||
import urls from "../urls";
|
|
||||||
|
|
||||||
import { faInfoCircle, faExclamationTriangle, faQuestionCircle } from "@fortawesome/pro-light-svg-icons";
|
import { faInfoCircle, faExclamationTriangle, faQuestionCircle } from "@fortawesome/pro-light-svg-icons";
|
||||||
import { Jsonified } from "../utils";
|
import { namespace } from 'vuex-class';
|
||||||
import * as moment from "moment";
|
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 {
|
export class MessagesComponent extends Vue {
|
||||||
public messages: Message[] = [];
|
@State 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
public icon(message: Message) {
|
public icon(message: Message) {
|
||||||
switch (message.type) {
|
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">
|
<h2 class="section__title flex">
|
||||||
<fa :icon="['fal', 'bullhorn']" fixed-width class="mr-2"></fa>
|
<fa :icon="['fal', 'bullhorn']" fixed-width class="mr-2"></fa>
|
||||||
Komunikaty <span class="ml-2 badge badge-pill badge-dark">{{ '{{ messages.count }}' }}</span>
|
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">
|
<button class="btn btn-action flex-space-left" @click="updateMessages">
|
||||||
<fa :icon="['fal', messages.visible ? 'chevron-up' : 'chevron-down']" fixed-width/>
|
<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>
|
</button>
|
||||||
</h2>
|
</h2>
|
||||||
<fold :visible="messages.visible">
|
<fold :visible="sections.messages">
|
||||||
<messages @update="handleMessagesUpdate"></messages>
|
<messages></messages>
|
||||||
</fold>
|
</fold>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user