Add ability to replace favourite with confirmation.

This commit is contained in:
Kacper Donat 2020-10-20 21:10:56 +02:00
parent 4647bb2cc1
commit c2b959a9da
8 changed files with 69 additions and 17 deletions

View File

@ -16,9 +16,19 @@
</li>
</ul>
<div class="favourite-add-form__actions">
<button class="btn btn-sm btn-primary" type="submit">
<ui-icon icon="add" />
zapisz
</button>
<template v-if="confirmation">
<button class="btn btn-xs btn-danger" type="submit">
nadpisz
</button>
<button class="btn btn-xs btn-action" @click="$emit('close')">
anuluj
</button>
</template>
<template v-else>
<button class="btn btn-xs btn-primary" type="submit">
<ui-icon icon="add" />
zapisz
</button>
</template>
</div>
</form>

View File

@ -13,6 +13,12 @@
}
}
&.btn-xs {
font-size: 0.75rem;
font-weight: bold;
padding: 0.25rem 0.5rem;
}
border-radius: 1.5px;
display: inline-block;
@ -29,4 +35,13 @@
border: 1px $primary solid;
}
}
&.btn-danger {
background: $danger-gradient;
border-color: transparent;
&:hover {
border: 1px $danger solid;
}
}
}

View File

@ -2,12 +2,14 @@ $border-radius: 0;
$border-radius-lg: $border-radius;
$border-radius-sm: $border-radius;
$danger: #cd2e12;
@import "~bootstrap/scss/functions";
@import "~bootstrap/scss/variables";
$primary: #005ea8;
$primary-gradient: linear-gradient(120deg, #0083c5 10%, #005ea8 90%);
$danger-gradient: linear-gradient(120deg, $danger 10%, darken($danger, 10%) 90%);
$custom-control-indicator-checked-bg: $dark;
$custom-control-indicator-active-bg: $dark;

View File

@ -73,6 +73,7 @@ $dialog-sizes: (
@each $size, $width in $dialog-sizes {
.ui-modal.ui-modal--#{$size} {
width: 100%;
box-sizing: border-box;
}
}
}

View File

@ -1,8 +1,7 @@
import Vue from 'vue'
import { Component, Prop } from 'vue-property-decorator'
import { namespace, State, Mutation } from "vuex-class";
import { Component, Watch } from 'vue-property-decorator'
import { Mutation, State } from "vuex-class";
import { Favourite } from "../store/favourites";
import { SavedState } from "../store/root";
import { Stop } from "../model";
import * as uuid from "uuid";
import { Favourites } from "../store";
@ -34,8 +33,15 @@ export class FavouritesAdderComponent extends Vue {
private name = "";
private errors = { name: [] };
private confirmation = false;
@Favourites.Mutation add: (favourite: Favourite) => void;
@Watch('name')
handleNameChange() {
this.confirmation = false;
}
async save() {
const favourite: Favourite = createFavouriteEntry(this.name, this.stops);
@ -54,8 +60,9 @@ export class FavouritesAdderComponent extends Vue {
errors.name.push("Musisz podać nazwę.");
}
if (this.$store.state.favourites.favourites.filter(other => other.name == favourite.name).length > 0) {
if (this.$store.state.favourites.favourites.filter(other => other.name == favourite.name).length > 0 && !this.confirmation) {
errors.name.push("Istnieje już zapisana grupa przystanków o takiej nazwie.");
this.confirmation = true;
}
this.errors = errors;

View File

@ -53,12 +53,12 @@ const simple = (icon: IconDefinition, props: any = {}): SimpleIcon => ({
icon, ...props, type: "simple"
});
const stack = (icons: IconDescription[]): StackedIcon => ({type: "stacked", icons});
const stack = (icons: IconDescription[]): StackedIcon => ({ type: "stacked", icons });
const lineTypeIcons = Object
.values(fac)
.map<[string, Icon]>(icon => [ `line-${icon.iconName}`, simple(icon) ])
.reduce((acc, [icon, definition]) => ({ ...acc, [icon]: definition}), {})
.map<[string, Icon]>(icon => [`line-${ icon.iconName }`, simple(icon)])
.reduce((acc, [icon, definition]) => ({ ...acc, [icon]: definition }), {})
const messageTypeIcons: Dictionary<Icon> = {
'message-breakdown': simple(faExclamationTriangle),
@ -66,7 +66,7 @@ const messageTypeIcons: Dictionary<Icon> = {
'message-unknown': simple(faQuestionCircle),
};
const definitions: Dictionary<Icon> = {
const definitions = {
'favourite': simple(faStar),
'unknown': simple(faQuestionSquare),
'add': simple(faCheck),
@ -93,14 +93,16 @@ const definitions: Dictionary<Icon> = {
'decrement': simple(faMinus, { "fixed-width": true }),
'relative-time': simple(faHourglassHalf),
'departure-warning': stack([
{icon: faClockBold},
{icon: faSolidExclamationTriangle, transform: "shrink-5 down-4 right-6"}
{ icon: faClockBold },
{ icon: faSolidExclamationTriangle, transform: "shrink-5 down-4 right-6" }
]),
'close': simple(faTimes),
...lineTypeIcons,
...messageTypeIcons,
};
export type PredefinedIcon = keyof typeof definitions;
const extractAllIcons = (icons: Icon[]) => icons.map(icon => {
switch (icon.type) {
case "simple":
@ -122,11 +124,11 @@ library.add(...extractAllIcons(Object.values(definitions)));
})
export class UiIcon extends Vue {
@Prop({
type: [ String, Object ],
type: [String, Object],
validator: value => typeof value === "object" || Object.keys(definitions).includes(value),
required: true,
})
icon: string | IconDefinition;
icon: PredefinedIcon | IconDefinition;
get definition(): Icon {
return typeof this.icon === "string"

View File

@ -1,6 +1,7 @@
import { RootState } from "./root";
import { Module } from "vuex";
import { Stop } from "../model";
import { except } from "../utils";
export interface Favourite {
id: string;
@ -19,7 +20,13 @@ const favourites: Module<FavouritesState, RootState> = {
},
mutations: {
add(state, favourite: Favourite) {
state.favourites.push(favourite);
const existing = state.favourites.find((current: Favourite) => current.name === favourite.name);
if (!existing) {
state.favourites.push(favourite);
}
Object.assign(existing, except(favourite, ["id"]));
},
remove(state, favourite: Favourite) {
state.favourites = state.favourites.filter(f => f != favourite);

View File

@ -38,6 +38,14 @@ export function filter<T, KT extends keyof T>(source: T, filter: (value: T[KT],
return result;
}
export function except<T>(source: T, keys: (keyof T)[]) {
return filter(source, (_, key) => !keys.includes(key))
}
export function only<T>(source: T, keys: (keyof T)[]) {
return filter(source, (_, key) => keys.includes(key))
}
export function signed(number: number): string {
return number > 0 ? `+${number}` : number.toString();
}