mirror of
https://github.com/aelve/guide.git
synced 2024-12-23 12:52:31 +03:00
Front/feat/duplicate category creation warning (#300)
* Confirm Dialog extended * Confirmation for duplicate name dialog creation
This commit is contained in:
parent
466eb11363
commit
199e55d435
@ -1,58 +1,76 @@
|
||||
<template>
|
||||
<v-dialog
|
||||
:value="value"
|
||||
@input="close"
|
||||
max-width="500px"
|
||||
>
|
||||
<div>
|
||||
<v-dialog
|
||||
:value="value"
|
||||
@input="close"
|
||||
max-width="500px"
|
||||
>
|
||||
|
||||
<slot slot="activator" />
|
||||
<slot slot="activator" />
|
||||
|
||||
<v-card @keyup.esc.native="close" tabindex="0">
|
||||
<v-card-text>
|
||||
<v-form
|
||||
ref="form"
|
||||
lazy-validation
|
||||
v-model="isValid"
|
||||
@keydown.native.enter="submit"
|
||||
>
|
||||
<!-- v-if="value" - cause without it autofocus triggers on first modal open
|
||||
https://stackoverflow.com/questions/51472947/vuetifys-autofocus-works-only-on-first-modal-open -->
|
||||
<v-text-field
|
||||
v-if="value"
|
||||
class="mb-3"
|
||||
label="Category name"
|
||||
autofocus
|
||||
:rules="categoryValidationRules"
|
||||
v-model="categoryName"
|
||||
ref="categoryNameInput"
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="groupNameInternal"
|
||||
label="Group"
|
||||
/>
|
||||
</v-form>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn
|
||||
flat
|
||||
color="primary"
|
||||
@click.native="close"
|
||||
>
|
||||
Cancel
|
||||
</v-btn>
|
||||
<v-btn
|
||||
flat
|
||||
color="primary"
|
||||
class="add-category-submit-btn"
|
||||
:disabled="!isValid"
|
||||
@click.native="submit"
|
||||
>
|
||||
Submit
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
<v-card @keyup.esc.native="close" tabindex="0">
|
||||
<v-card-text>
|
||||
<v-form
|
||||
ref="form"
|
||||
lazy-validation
|
||||
v-model="isValid"
|
||||
@keydown.native.enter="submit"
|
||||
>
|
||||
<!-- v-if="value" - cause without it autofocus triggers on first modal open
|
||||
https://stackoverflow.com/questions/51472947/vuetifys-autofocus-works-only-on-first-modal-open -->
|
||||
<v-text-field
|
||||
v-if="value"
|
||||
class="mb-3"
|
||||
label="Category name"
|
||||
autofocus
|
||||
:rules="categoryValidationRules"
|
||||
v-model="categoryName"
|
||||
ref="categoryNameInput"
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="groupNameInternal"
|
||||
label="Group"
|
||||
/>
|
||||
</v-form>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn
|
||||
flat
|
||||
color="primary"
|
||||
@click.native="close"
|
||||
>
|
||||
Cancel
|
||||
</v-btn>
|
||||
<v-btn
|
||||
flat
|
||||
color="primary"
|
||||
class="add-category-submit-btn"
|
||||
:disabled="!isValid"
|
||||
@click.native="submit"
|
||||
>
|
||||
Submit
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
|
||||
</v-dialog>
|
||||
|
||||
<ConfirmDialog
|
||||
v-if="isDuplicateConfirmShow"
|
||||
:value="isDuplicateConfirmShow"
|
||||
max-width="500px"
|
||||
attach="#app"
|
||||
ref="duplicateConfirm"
|
||||
>
|
||||
This group already has categories with the same name:
|
||||
<a
|
||||
v-for="category in sameNameCategories"
|
||||
:key="category.id"
|
||||
target="_blank"
|
||||
>{{ category.title }}</a>
|
||||
</ConfirmDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@ -60,18 +78,37 @@ import Vue from 'vue'
|
||||
import Component from 'vue-class-component'
|
||||
import { Prop, Watch } from 'vue-property-decorator'
|
||||
import { CategoryService } from 'client/service/Category'
|
||||
import ConfirmDialog from 'client/components/ConfirmDialog.vue'
|
||||
import DeferredPromise from 'utils/DeferredPromise'
|
||||
|
||||
@Component
|
||||
@Component({
|
||||
components: {
|
||||
ConfirmDialog
|
||||
}
|
||||
})
|
||||
export default class AddCategoryDialog extends Vue {
|
||||
@Prop(String) groupName!: string
|
||||
@Prop(Boolean) value!: boolean
|
||||
|
||||
groupNameInternal: string = this.groupName || ''
|
||||
categoryName: string = ''
|
||||
categoryValidationRules: Function[] = [
|
||||
categoryValidationRules: Array<(x: string) => boolean | string> = [
|
||||
(x: string) => !!x || `Category name can't be empty`
|
||||
]
|
||||
isValid: boolean = false
|
||||
isDuplicateConfirmShow: boolean = false
|
||||
|
||||
get categories () {
|
||||
return this.$store.state.category.categoryList
|
||||
}
|
||||
|
||||
get sameNameCategories () {
|
||||
if (!this.categoryName || !this.groupName) {
|
||||
return []
|
||||
}
|
||||
return this.categories
|
||||
.filter(x => x.group === this.groupName && x.title === this.categoryName)
|
||||
}
|
||||
|
||||
@Watch('value')
|
||||
onOpen (newVal: boolean) {
|
||||
@ -87,12 +124,37 @@ export default class AddCategoryDialog extends Vue {
|
||||
if (!this.$refs.form.validate()) {
|
||||
return
|
||||
}
|
||||
|
||||
if (this.sameNameCategories.length) {
|
||||
const isDuplicationConfirmed = await this.confirmDuplicate()
|
||||
if (!isDuplicationConfirmed) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const createdId = await this.$store.dispatch('category/createCategory', {
|
||||
title: this.categoryName,
|
||||
group: this.groupNameInternal
|
||||
})
|
||||
this.$router.push(`haskell/${createdId}`)
|
||||
}
|
||||
|
||||
async confirmDuplicate () {
|
||||
const promise = new DeferredPromise()
|
||||
this.isDuplicateConfirmShow = true
|
||||
this.$nextTick(() => {
|
||||
const duplicateConfirm = this.$refs.duplicateConfirm
|
||||
duplicateConfirm.$once('canceled', () => {
|
||||
promise.resolve(false)
|
||||
this.isDuplicateConfirmShow = false
|
||||
})
|
||||
duplicateConfirm.$once('confirmed', () => {
|
||||
promise.resolve(true)
|
||||
this.isDuplicateConfirmShow = false
|
||||
})
|
||||
})
|
||||
return promise
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -2,14 +2,18 @@
|
||||
<template>
|
||||
<v-dialog
|
||||
:value="value"
|
||||
@input="close"
|
||||
:attach="attach"
|
||||
max-width="500px"
|
||||
@input="close"
|
||||
>
|
||||
<slot slot="activator" />
|
||||
|
||||
<v-card>
|
||||
<v-card-text>
|
||||
Are you sure you want to {{ text }} ?
|
||||
<v-card-text v-if="$slots.default">
|
||||
<slot />
|
||||
</v-card-text>
|
||||
<v-card-text v-else>
|
||||
{{ fullText || `Are you sure you want to ${text} ?` }}
|
||||
</v-card-text>
|
||||
<v-divider />
|
||||
<v-card-actions>
|
||||
@ -17,17 +21,16 @@
|
||||
<v-btn
|
||||
flat
|
||||
color="primary"
|
||||
class="confirm-btn"
|
||||
@click.native="confirm"
|
||||
@click.native="cancel"
|
||||
>
|
||||
{{ confirmBtnText }}
|
||||
{{ cancelBtnText }}
|
||||
</v-btn>
|
||||
<v-btn
|
||||
flat
|
||||
color="primary"
|
||||
@click.native="cancel"
|
||||
@click.native="confirm"
|
||||
>
|
||||
{{ cancelBtnText }}
|
||||
{{ confirmBtnText }}
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
@ -42,12 +45,15 @@ import { Prop } from 'vue-property-decorator'
|
||||
@Component
|
||||
export default class ConfirmDialog extends Vue {
|
||||
@Prop(String) text!: string
|
||||
@Prop(String) fullText!: string
|
||||
@Prop(Boolean) value!: boolean
|
||||
@Prop(String) attach!: string
|
||||
@Prop({ default: 'Continue' }) confirmBtnText!: string
|
||||
@Prop({ default: 'Cancel' }) cancelBtnText!: string
|
||||
|
||||
close () {
|
||||
this.$emit('input', false)
|
||||
this.$emit('canceled')
|
||||
}
|
||||
confirm () {
|
||||
this.$emit('confirmed')
|
||||
|
@ -1,14 +1,17 @@
|
||||
interface IConfirmDialogProps {
|
||||
text: string,
|
||||
confirmBtnText?: string,
|
||||
fullText: string
|
||||
text: string
|
||||
confirmBtnText?: string
|
||||
cancelBtnText?: string
|
||||
}
|
||||
// TODO looks like documentation isn't working
|
||||
/**
|
||||
* Use only for vue components methods.
|
||||
* Executes '_confirm' function (see confirmDialogMixin.ts) with provided options before executing following method.
|
||||
* If not confirmed method is not executed.
|
||||
* @param {Object} options - options passed to _confirm function
|
||||
* @param {String} options.text
|
||||
* @param {String} options.fullText
|
||||
* @param {String} options.confirmBtnText
|
||||
* @param {String} options.cancelBtnText
|
||||
*/
|
||||
|
@ -6,18 +6,20 @@ import DeferredPromise from 'utils/DeferredPromise'
|
||||
const ComponentClass = Vue.extend(ConfirmDialog)
|
||||
|
||||
interface IConfirmDialogProps {
|
||||
text: string,
|
||||
confirmBtnText?: string,
|
||||
fullText: string
|
||||
text: string
|
||||
confirmBtnText?: string
|
||||
cancelBtnText?: string
|
||||
}
|
||||
|
||||
@Mixin
|
||||
export default class ConfirmDialogMixin extends Vue {
|
||||
async _confirm ({ text, confirmBtnText, cancelBtnText }: IConfirmDialogProps): Promise<boolean> {
|
||||
async _confirm ({ text, fullText, confirmBtnText, cancelBtnText }: IConfirmDialogProps): Promise<boolean> {
|
||||
const instance = new ComponentClass({
|
||||
propsData: {
|
||||
value: true,
|
||||
text,
|
||||
fullText,
|
||||
confirmBtnText,
|
||||
cancelBtnText
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user