mirror of
https://github.com/Floriansylvain/snippets-manager-front.git
synced 2026-08-19 11:43:16 +02:00
feat: categories selection and delete
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { Category } from '@/composables/category'
|
import type { Category } from '@/composables/category'
|
||||||
import { useCategoriesStore } from '@/stores/categories'
|
import { useCategoriesStore } from '@/stores/categories'
|
||||||
import { ref, type Ref } from 'vue'
|
import { ref, watch, type Ref } from 'vue'
|
||||||
|
|
||||||
interface CategoryItem {
|
interface CategoryItem {
|
||||||
id: number
|
id: number
|
||||||
@@ -16,6 +16,7 @@ const props = defineProps<{
|
|||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
categoriesUpdated: []
|
categoriesUpdated: []
|
||||||
|
categoriesIdsToDeleteUpdated: [ids: number[]]
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const categoriesStore = useCategoriesStore()
|
const categoriesStore = useCategoriesStore()
|
||||||
@@ -26,6 +27,8 @@ const deleteDialogCategory: Ref<CategoryItem | undefined> = ref()
|
|||||||
const itemsPerPageGlob: Ref<number> = ref(10)
|
const itemsPerPageGlob: Ref<number> = ref(10)
|
||||||
const itemsPage: Ref<number> = ref(0)
|
const itemsPage: Ref<number> = ref(0)
|
||||||
|
|
||||||
|
const itemsSelected: Ref<number[]> = ref([])
|
||||||
|
|
||||||
function onDeleteClick(category: CategoryItem) {
|
function onDeleteClick(category: CategoryItem) {
|
||||||
deleteDialogCategory.value = category
|
deleteDialogCategory.value = category
|
||||||
deleteDialog.value = true
|
deleteDialog.value = true
|
||||||
@@ -57,11 +60,23 @@ async function loadItems({
|
|||||||
else categoriesStore.updateSort(undefined, undefined)
|
else categoriesStore.updateSort(undefined, undefined)
|
||||||
emit('categoriesUpdated')
|
emit('categoriesUpdated')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
watch(itemsSelected, (newItemsSelected) => {
|
||||||
|
emit('categoriesIdsToDeleteUpdated', newItemsSelected)
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.fetchedCategories,
|
||||||
|
() => {
|
||||||
|
itemsSelected.value = []
|
||||||
|
}
|
||||||
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<VDataTableServer
|
<VDataTableServer
|
||||||
:headers="[
|
:headers="[
|
||||||
|
{ title: 'ID', key: 'id', sortable: true },
|
||||||
{ title: 'Name', key: 'name', sortable: true },
|
{ title: 'Name', key: 'name', sortable: true },
|
||||||
{ title: 'Actions', key: 'actions', align: 'end', sortable: false }
|
{ title: 'Actions', key: 'actions', align: 'end', sortable: false }
|
||||||
]"
|
]"
|
||||||
@@ -69,7 +84,9 @@ async function loadItems({
|
|||||||
:loading="props.loading"
|
:loading="props.loading"
|
||||||
:items-length="props.itemsTotal"
|
:items-length="props.itemsTotal"
|
||||||
v-model:items-per-page="itemsPerPageGlob"
|
v-model:items-per-page="itemsPerPageGlob"
|
||||||
|
v-model="itemsSelected"
|
||||||
@update:options="loadItems"
|
@update:options="loadItems"
|
||||||
|
show-select
|
||||||
>
|
>
|
||||||
<template v-slot:[`item.actions`]="{ item }">
|
<template v-slot:[`item.actions`]="{ item }">
|
||||||
<VBtn icon="mdi-pencil" variant="flat" size="small"></VBtn>
|
<VBtn icon="mdi-pencil" variant="flat" size="small"></VBtn>
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { useCategoriesStore } from '@/stores/categories'
|
||||||
|
import { ref, type Ref } from 'vue'
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
categoriesDeleted: []
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
ids: number[]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const dialog: Ref<boolean> = ref(false)
|
||||||
|
|
||||||
|
const categoriesStore = useCategoriesStore()
|
||||||
|
|
||||||
|
async function onSubmit(): Promise<void> {
|
||||||
|
await categoriesStore.deleteCategories(props.ids)
|
||||||
|
emit('categoriesDeleted')
|
||||||
|
dialog.value = false
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<VDialog v-model="dialog" max-width="500">
|
||||||
|
<template v-slot:activator="{ props: activatorProps }">
|
||||||
|
<VBtn
|
||||||
|
v-if="props.ids.length > 0"
|
||||||
|
prepend-icon="mdi-delete"
|
||||||
|
text="Delete selected"
|
||||||
|
color="error"
|
||||||
|
variant="outlined"
|
||||||
|
v-bind="activatorProps"
|
||||||
|
></VBtn>
|
||||||
|
</template>
|
||||||
|
<VCard prepend-icon="mdi-delete" title="Create Category">
|
||||||
|
<VForm @submit.prevent="onSubmit">
|
||||||
|
<VCardText class="text-body-1">
|
||||||
|
Are you absolutely sure you want to delete the {{ ids.length }} selected categories? This
|
||||||
|
is unrecoverable.
|
||||||
|
</VCardText>
|
||||||
|
<VDivider />
|
||||||
|
<VCardActions>
|
||||||
|
<VSpacer />
|
||||||
|
<VBtn color="primary" text="Close" variant="outlined" @click="dialog = false"></VBtn>
|
||||||
|
<VBtn color="error" text="Delete" variant="flat" type="submit"></VBtn>
|
||||||
|
</VCardActions>
|
||||||
|
</VForm>
|
||||||
|
</VCard>
|
||||||
|
</VDialog>
|
||||||
|
</template>
|
||||||
@@ -46,10 +46,19 @@ export const useCategoriesStore = defineStore('categories', () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const deleteCategories = async (ids: number[]): Promise<Response> => {
|
||||||
|
return await fetch(`${api.url}/category`, {
|
||||||
|
...api.options,
|
||||||
|
method: 'DELETE',
|
||||||
|
body: JSON.stringify({ ids })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getCategories,
|
getCategories,
|
||||||
postCategory,
|
postCategory,
|
||||||
deleteCategory,
|
deleteCategory,
|
||||||
|
deleteCategories,
|
||||||
updateSkipTake,
|
updateSkipTake,
|
||||||
updateSort
|
updateSort
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import CategoriesTable from '@/components/CategoriesTable.vue'
|
import CategoriesTable from '@/components/CategoriesTable.vue'
|
||||||
import CategoryCreate from '@/components/CategoryCreate.vue'
|
import CategoryCreate from '@/components/CategoryCreate.vue'
|
||||||
|
import DeleteCategories from '@/components/DeleteCategories.vue'
|
||||||
import type { Category } from '@/composables/category'
|
import type { Category } from '@/composables/category'
|
||||||
import { useCategoriesStore } from '@/stores/categories'
|
import { useCategoriesStore } from '@/stores/categories'
|
||||||
import { onMounted, ref, type Ref } from 'vue'
|
import { onMounted, ref, type Ref } from 'vue'
|
||||||
@@ -9,12 +10,20 @@ const categoriesStore = useCategoriesStore()
|
|||||||
const fetchedCategories: Ref<Category | undefined> = ref()
|
const fetchedCategories: Ref<Category | undefined> = ref()
|
||||||
const loading: Ref<boolean> = ref(true)
|
const loading: Ref<boolean> = ref(true)
|
||||||
|
|
||||||
|
const categoriesIdsToDelete: Ref<number[]> = ref([])
|
||||||
|
|
||||||
async function fetchCategories() {
|
async function fetchCategories() {
|
||||||
const categoriesPromise = await categoriesStore.getCategories()
|
const categoriesPromise = await categoriesStore.getCategories()
|
||||||
fetchedCategories.value = await categoriesPromise.json()
|
fetchedCategories.value = await categoriesPromise.json()
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function deleteCategories() {
|
||||||
|
await categoriesStore.deleteCategories(categoriesIdsToDelete.value)
|
||||||
|
await fetchCategories()
|
||||||
|
categoriesIdsToDelete.value = []
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await fetchCategories()
|
await fetchCategories()
|
||||||
})
|
})
|
||||||
@@ -23,10 +32,14 @@ onMounted(async () => {
|
|||||||
<template>
|
<template>
|
||||||
<header class="d-flex align-center justify-space-between">
|
<header class="d-flex align-center justify-space-between">
|
||||||
<h1 class="text-h3">Categories</h1>
|
<h1 class="text-h3">Categories</h1>
|
||||||
|
<div class="d-flex align-center ga-2">
|
||||||
|
<DeleteCategories @categoriesDeleted="deleteCategories" :ids="categoriesIdsToDelete" />
|
||||||
<CategoryCreate @categoryCreated="fetchCategories" />
|
<CategoryCreate @categoryCreated="fetchCategories" />
|
||||||
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<CategoriesTable
|
<CategoriesTable
|
||||||
@categoriesUpdated="fetchCategories"
|
@categoriesUpdated="fetchCategories"
|
||||||
|
@categoriesIdsToDeleteUpdated="categoriesIdsToDelete = $event"
|
||||||
:fetchedCategories="fetchedCategories"
|
:fetchedCategories="fetchedCategories"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
:itemsTotal="fetchedCategories?.total ?? 0"
|
:itemsTotal="fetchedCategories?.total ?? 0"
|
||||||
|
|||||||
Reference in New Issue
Block a user