Extract departures settings to its own component and store module

This commit is contained in:
Kacper Donat 2020-03-18 22:00:17 +01:00
parent 87e4121444
commit 5c8a0238f1
15 changed files with 140 additions and 74 deletions

View File

@ -26,4 +26,4 @@ server {
internal;
}
}
}
}

View File

@ -2,8 +2,4 @@
<ul class="departures__list list-underlined">
<departure :departure="departure" :key="departure.key" v-for="departure in departures"/>
</ul>
<div class="alert alert-info" v-if="stops.length === 0">
<ui-icon icon="info"/>
Wybierz przystanki korzystając z wyszukiwarki poniżej, aby zobaczyć listę odjazdów.
</div>
</div>

View File

@ -0,0 +1,31 @@
<fragment>
<div class="form-group">
<h3 class="popper__heading flex">
<label class="text" for="departures-auto-refresh-interval">
<ui-icon icon="refresh" fixed-width/>
autoodświeżanie
</label>
<ui-switch id="departures-auto-refresh" :value="autorefresh" @input="update({ autorefresh: $event })" class="flex-space-left"/>
</h3>
<div class="flex " v-if="autorefresh">
<label for="departures-auto-refresh-interval" class="text">
<span class="sr-only">częstotliwość odświeżania</span>
co
</label>
<div class="input-group input-group-sm">
<input type="text" class="form-control form-control-sm form-control-simple" id="departures-auto-refresh-interval"
:value="autorefreshInterval" @input="update({ autorefreshInterval: Number.parseInt($event.target.value) })" />
<div class="input-group-append">
<span class="input-group-text" aria-label="sekund">s</span>
</div>
</div>
</div>
</div>
<div class="form-group">
<label class="text" for="departures-count">
<ui-icon icon="line-bus" fixed-width/>
liczba wpisów
</label>
<ui-numeric-input id="departures-count" :value="displayedEntriesCount" @input="update({ displayedEntriesCount: $event })" :min="1" :max="20"/>
</div>
</fragment>

View File

@ -38,6 +38,11 @@ label {
margin-left: 0;
}
.btn-addon:disabled {
opacity: 1;
color: rgba($dark, .5)
}
.input-group-prepend {
margin-right: 0;
}

View File

@ -2,9 +2,8 @@ import Vue from 'vue'
import store from '../store'
import { Component, Watch } from "vue-property-decorator";
import { Mutation, Action } from 'vuex-class'
import { ObtainPayload } from "../store/departures";
import { Stop } from "../model";
import { PopperComponent } from "./utils";
import { DeparturesSettingsState } from "../store/settings/departures";
@Component({ store })
export class Application extends Vue {
@ -23,15 +22,9 @@ export class Application extends Vue {
messages: {
active: true,
interval: 60
},
departures: {
active: true,
interval: 10
}
};
private count = 8;
private intervals = { messages: null, departures: null };
get messages() {
@ -60,16 +53,39 @@ export class Application extends Vue {
this.$el.classList.remove('not-ready');
}
created() {
this.initDeparturesRefreshInterval();
}
private initDeparturesRefreshInterval() {
const departuresAutorefreshCallback = () => {
const {autorefresh, autorefreshInterval} = this.$store.state['departures-settings'] as DeparturesSettingsState;
if (this.intervals.departures) {
clearInterval(this.intervals.departures);
}
if (autorefresh) {
this.intervals.departures = setInterval(() => this.updateDepartures(), Math.max(5, autorefreshInterval) * 1000)
}
};
this.$store.watch(({"departures-settings": state}) => state.autorefresh, departuresAutorefreshCallback);
this.$store.watch(({"departures-settings": state}) => state.autorefreshInterval, departuresAutorefreshCallback);
departuresAutorefreshCallback();
}
@Action('messages/update') updateMessages: () => void;
@Action('departures/update') updateDepartures: (payload: ObtainPayload) => void;
@Action('departures/update') updateDepartures: () => void;
@Mutation add: (stops: Stop[]) => void;
@Mutation remove: (stop: Stop) => void;
@Mutation clear: () => void;
@Watch('stops')
onStopUpdate(this: any, stops) {
this.updateDepartures({ stops });
onStopUpdate() {
this.updateDepartures();
}
@Watch('autorefresh', { immediate: true, deep: true })
@ -79,17 +95,8 @@ export class Application extends Vue {
this.intervals.messages = null;
}
if (this.intervals.departures) {
clearInterval(this.intervals.departures);
this.intervals.messages = null;
}
if (settings.messages.active) {
this.intervals.messages = setInterval(() => this.updateMessages(), Math.max(5, settings.messages.interval) * 1000);
}
if (settings.departures.active) {
this.intervals.departures = setInterval(() => this.updateDepartures({ stops: this.stops }), Math.max(5, settings.departures.interval) * 1000);
}
}
}

View File

@ -1,21 +1,15 @@
import Vue from 'vue'
import { Departure, Stop } from "../model";
import { Departure } from "../model";
import { Component, Prop, Watch } from "vue-property-decorator";
import { namespace } from 'vuex-class';
import store from '../store'
import store, { Departures } from '../store'
import { Trip } from "../model/trip";
import urls from "../urls";
import { Jsonified } from "../utils";
import * as moment from "moment";
const { State } = namespace('departures');
@Component({ template: require("../../components/departures.html"), store })
export class DeparturesComponent extends Vue {
@State departures: Departure[];
@Prop(Array)
stops: Stop[];
@Departures.State departures: Departure[];
}
@Component({ template: require("../../components/departures/departure.html") })

View File

@ -10,3 +10,5 @@ export * from './app'
export * from './favourites'
export * from './trip'
export * from './ui'
export * from './settings'
export { Departures } from "../store";

View File

@ -0,0 +1,21 @@
import { Component, Prop } from "vue-property-decorator";
import store, { DeparturesSettings } from "../../store";
import Vue from "vue";
import { DeparturesSettingsState } from "../../store/settings/departures";
@Component({ template: require("../../../components/settings/departures.html"), store })
export class SettingsDepartures extends Vue {
@DeparturesSettings.State
public autorefresh: boolean;
@DeparturesSettings.State
public autorefreshInterval: number;
@DeparturesSettings.State
public displayedEntriesCount: number;
@DeparturesSettings.Mutation
public update: (state: Partial<DeparturesSettingsState>) => void;
}
Vue.component('SettingsDepartures', SettingsDepartures);

View File

@ -0,0 +1 @@
export * from "./departures"

View File

@ -1,7 +1,6 @@
import { FetchingState } from "../utils";
import { Moment } from "moment";
import { Module, MutationTree } from "vuex";
import { RootState } from "./root";
import * as moment from "moment";
export interface CommonState {
@ -24,4 +23,4 @@ export const mutations: MutationTree<CommonState> = {
}
};
export default { state, mutations };
export default { state, mutations };

View File

@ -10,10 +10,6 @@ export interface DeparturesState extends CommonState {
departures: Departure[],
}
export interface ObtainPayload {
stops: Stop[]
}
export const departures: Module<DeparturesState, RootState> = {
namespaced: true,
state: {
@ -29,10 +25,15 @@ export const departures: Module<DeparturesState, RootState> = {
...common.mutations
},
actions: {
async update({ commit }, { stops }: ObtainPayload) {
async update({ commit }) {
const count = this.state['departures-settings'].displayedEntriesCount;
const stops = this.state.stops;
commit('fetching');
const response = await fetch(urls.prepare(urls.departures, {
stop: stops.map(stop => stop.id),
limit: count || 8,
}));
if (!response.ok) {

View File

@ -4,9 +4,10 @@ import messages, { MessagesState } from './messages';
import departures, { DeparturesState } from './departures'
import favourites, { FavouritesState, localStorageSaver } from './favourites'
import { state, mutations, actions, RootState } from "./root";
import { actions, mutations, RootState, state } from "./root";
import VuexPersistence from "vuex-persist";
import { namespace } from "vuex-class";
import departureSettings from "./settings/departures";
export type State = {
messages: MessagesState;
@ -15,7 +16,7 @@ export type State = {
} & RootState;
const localStoragePersist = new VuexPersistence<State>({
reducer: state => ({ favourites: state.favourites })
modules: ['favourites', 'departures-settings'],
});
const sessionStoragePersist = new VuexPersistence<State>({
@ -25,7 +26,12 @@ const sessionStoragePersist = new VuexPersistence<State>({
const store = new Vuex.Store({
state, mutations, actions,
modules: { messages, departures, favourites },
modules: {
messages,
departures,
favourites,
'departures-settings': departureSettings
},
plugins: [
// todo: remove after some time
localStorageSaver('favourites.favourites', 'favourites'),
@ -37,3 +43,5 @@ const store = new Vuex.Store({
export default store;
export const Favourites = namespace('favourites');
export const DeparturesSettings = namespace('departures-settings');
export const Departures = namespace('departures');

View File

@ -0,0 +1,24 @@
import { ActionContext, Module } from "vuex";
import { RootState } from "../root";
export type DeparturesSettingsState = {
autorefresh: boolean;
autorefreshInterval?: number;
displayedEntriesCount?: number;
}
const departureSettings: Module<DeparturesSettingsState, RootState> = {
namespaced: true,
state: {
autorefresh: true,
autorefreshInterval: 10,
displayedEntriesCount: 10
},
mutations: {
update(state: DeparturesSettingsState, patch: Partial<DeparturesSettingsState>) {
Object.assign(state, patch);
}
}
};
export default departureSettings;

View File

@ -68,7 +68,7 @@ class DeparturesController extends Controller
*/
public function stops(DepartureRepository $departures, StopRepository $stops, Request $request)
{
$stops = $stops->all(new IdFilter($request->query->get('stop')));
$stops = $stops->all(new IdFilter($request->query->get('stop', [])));
$result = $departures->current($stops, ...$this->getModifiersFromRequest($request));
return $this->json(

View File

@ -73,38 +73,15 @@
</button>
<portal to="popups">
<popper reference="settings-departures" v-if="visibility.departures" arrow placement="left-start" @leave="visibility.departures = false">
<div class="form-group">
<h3 class="popper__heading flex">
<label class="text" for="departures-auto-refresh-interval">
<ui-icon icon="refresh" fixed-width></ui-icon>
autoodświeżanie
</label>
<ui-switch id="departures-auto-refresh" v-model="autorefresh.departures.active" class="flex-space-left"></ui-switch>
</h3>
<div class="flex " v-if="autorefresh.departures.active">
<label for="departures-auto-refresh-interval" class="text">
<span class="sr-only">częstotliwość odświeżania</span>
co
</label>
<div class="input-group input-group-sm">
<input type="text" class="form-control form-control-sm form-control-simple" id="departures-auto-refresh-interval" v-model="autorefresh.departures.interval"/>
<div class="input-group-append">
<span class="input-group-text" aria-label="sekund">s</span>
</div>
</div>
</div>
</div>
<div class="form-group">
<label class="text" for="departures-count">
<ui-icon icon="line-bus" fixed-width></ui-icon>
Liczba wpisów
</label>
<ui-numeric-input id="departures-count" v-model="count" :min="1" :max="16"></ui-numeric-input>
</div>
<settings-departures></settings-departures>
</popper>
</portal>
</header>
<departures :stops="stops"></departures>
<departures :stops="stops" v-if="stops.length > 0"></departures>
<div class="alert alert-info" v-else>
<ui-icon icon="info"></ui-icon>
Wybierz przystanki korzystając z wyszukiwarki poniżej, aby zobaczyć listę odjazdów.
</div>
{% if provider.attribution %}
<div class="attribution">
<ui-icon icon="info"></ui-icon>