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> </li>
</ul> </ul>
<div class="favourite-add-form__actions"> <div class="favourite-add-form__actions">
<button class="btn btn-sm btn-primary" type="submit"> <template v-if="confirmation">
<ui-icon icon="add" /> <button class="btn btn-xs btn-danger" type="submit">
zapisz nadpisz
</button> </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> </div>
</form> </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; border-radius: 1.5px;
display: inline-block; display: inline-block;
@ -29,4 +35,13 @@
border: 1px $primary solid; 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-lg: $border-radius;
$border-radius-sm: $border-radius; $border-radius-sm: $border-radius;
$danger: #cd2e12;
@import "~bootstrap/scss/functions"; @import "~bootstrap/scss/functions";
@import "~bootstrap/scss/variables"; @import "~bootstrap/scss/variables";
$primary: #005ea8; $primary: #005ea8;
$primary-gradient: linear-gradient(120deg, #0083c5 10%, #005ea8 90%); $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-checked-bg: $dark;
$custom-control-indicator-active-bg: $dark; $custom-control-indicator-active-bg: $dark;

View File

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

View File

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

View File

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

View File

@ -1,6 +1,7 @@
import { RootState } from "./root"; import { RootState } from "./root";
import { Module } from "vuex"; import { Module } from "vuex";
import { Stop } from "../model"; import { Stop } from "../model";
import { except } from "../utils";
export interface Favourite { export interface Favourite {
id: string; id: string;
@ -19,7 +20,13 @@ const favourites: Module<FavouritesState, RootState> = {
}, },
mutations: { mutations: {
add(state, favourite: Favourite) { 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) { remove(state, favourite: Favourite) {
state.favourites = state.favourites.filter(f => f != 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; 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 { export function signed(number: number): string {
return number > 0 ? `+${number}` : number.toString(); return number > 0 ? `+${number}` : number.toString();
} }