From c2b959a9da1bd8b66d9a0f67280778d36dcd3faa Mon Sep 17 00:00:00 2001 From: Kacper Donat Date: Tue, 20 Oct 2020 21:10:56 +0200 Subject: [PATCH] Add ability to replace favourite with confirmation. --- resources/components/favourites/save.html | 18 ++++++++++++++---- resources/styles/_controls.scss | 15 +++++++++++++++ resources/styles/main.scss | 2 ++ resources/styles/ui/_modal.scss | 1 + resources/ts/components/favourites.ts | 15 +++++++++++---- resources/ts/components/ui/icon.ts | 18 ++++++++++-------- resources/ts/store/favourites.ts | 9 ++++++++- resources/ts/utils.ts | 8 ++++++++ 8 files changed, 69 insertions(+), 17 deletions(-) diff --git a/resources/components/favourites/save.html b/resources/components/favourites/save.html index 6f31d62..0347554 100644 --- a/resources/components/favourites/save.html +++ b/resources/components/favourites/save.html @@ -16,9 +16,19 @@
- + +
diff --git a/resources/styles/_controls.scss b/resources/styles/_controls.scss index 6a479c8..e8879c4 100644 --- a/resources/styles/_controls.scss +++ b/resources/styles/_controls.scss @@ -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; + } + } } diff --git a/resources/styles/main.scss b/resources/styles/main.scss index 67dc67a..ada8ede 100644 --- a/resources/styles/main.scss +++ b/resources/styles/main.scss @@ -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; diff --git a/resources/styles/ui/_modal.scss b/resources/styles/ui/_modal.scss index 770be0b..242138c 100644 --- a/resources/styles/ui/_modal.scss +++ b/resources/styles/ui/_modal.scss @@ -73,6 +73,7 @@ $dialog-sizes: ( @each $size, $width in $dialog-sizes { .ui-modal.ui-modal--#{$size} { width: 100%; + box-sizing: border-box; } } } diff --git a/resources/ts/components/favourites.ts b/resources/ts/components/favourites.ts index 5a5f5bf..a7e0fd1 100644 --- a/resources/ts/components/favourites.ts +++ b/resources/ts/components/favourites.ts @@ -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; diff --git a/resources/ts/components/ui/icon.ts b/resources/ts/components/ui/icon.ts index b25535a..2dad8a9 100644 --- a/resources/ts/components/ui/icon.ts +++ b/resources/ts/components/ui/icon.ts @@ -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 = { 'message-breakdown': simple(faExclamationTriangle), @@ -66,7 +66,7 @@ const messageTypeIcons: Dictionary = { 'message-unknown': simple(faQuestionCircle), }; -const definitions: Dictionary = { +const definitions = { 'favourite': simple(faStar), 'unknown': simple(faQuestionSquare), 'add': simple(faCheck), @@ -93,14 +93,16 @@ const definitions: Dictionary = { '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" diff --git a/resources/ts/store/favourites.ts b/resources/ts/store/favourites.ts index 0f61f68..94f608e 100644 --- a/resources/ts/store/favourites.ts +++ b/resources/ts/store/favourites.ts @@ -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 = { }, 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); diff --git a/resources/ts/utils.ts b/resources/ts/utils.ts index d7d6a22..213ee92 100644 --- a/resources/ts/utils.ts +++ b/resources/ts/utils.ts @@ -38,6 +38,14 @@ export function filter(source: T, filter: (value: T[KT], return result; } +export function except(source: T, keys: (keyof T)[]) { + return filter(source, (_, key) => !keys.includes(key)) +} + +export function only(source: T, keys: (keyof T)[]) { + return filter(source, (_, key) => keys.includes(key)) +} + export function signed(number: number): string { return number > 0 ? `+${number}` : number.toString(); }