handling create update delete categories
This commit is contained in:
@@ -9,6 +9,8 @@ import {useSpaceStore} from "@/stores/spaceStore";
|
|||||||
import {CategoryType, CategoryTypeName} from "@/models/enums";
|
import {CategoryType, CategoryTypeName} from "@/models/enums";
|
||||||
import emojiRegex from 'emoji-regex'
|
import emojiRegex from 'emoji-regex'
|
||||||
import {useCategoriesStore} from "@/stores/categories-store";
|
import {useCategoriesStore} from "@/stores/categories-store";
|
||||||
|
import {CreateCategoryDTO, UpdateCategoryDTO} from "@/models/category";
|
||||||
|
import ConfirmDialog from '@/components/ConfirmDialog.vue'
|
||||||
|
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
@@ -17,14 +19,21 @@ const toolbar = useToolbarStore();
|
|||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const spaceStore = useSpaceStore();
|
const spaceStore = useSpaceStore();
|
||||||
const categoriesStore = useCategoriesStore();
|
const categoriesStore = useCategoriesStore();
|
||||||
const categoryId = ref<string | undefined>(route.params.id)
|
const tgApp = window.Telegram.WebApp
|
||||||
|
|
||||||
|
|
||||||
|
const categoryId = ref<string | undefined>(route.params.id as string)
|
||||||
const mode = computed(() => {
|
const mode = computed(() => {
|
||||||
return categoryId.value ? "edit" : "create"
|
return categoryId.value ? "edit" : "create"
|
||||||
})
|
})
|
||||||
const categoryType = ref<CategoryType>(CategoryType.EXPENSE)
|
const categoryType = ref<CategoryType>(CategoryType.EXPENSE)
|
||||||
const categoryName = ref<string>()
|
const isCategoryTypeError = ref<boolean>(false)
|
||||||
|
const categoryName = ref<string>('')
|
||||||
|
const isCategoryNameError = ref<boolean>(false)
|
||||||
const categoryIcon = ref<string>("🛍️")
|
const categoryIcon = ref<string>("🛍️")
|
||||||
const categoryDescription = ref<string>()
|
const isCategoryIconError = ref<boolean>(false)
|
||||||
|
const categoryDescription = ref<string>('')
|
||||||
|
const isCategoryDescriptionError = ref<boolean>(false)
|
||||||
|
|
||||||
|
|
||||||
// Генерим опции: [{ label: "Расходы", value: "EXPENSE" }, ...]
|
// Генерим опции: [{ label: "Расходы", value: "EXPENSE" }, ...]
|
||||||
@@ -82,22 +91,123 @@ function handleCompositionEnd(e: CompositionEvent) {
|
|||||||
handleInput(e as unknown as Event)
|
handleInput(e as unknown as Event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const validateForm = (): boolean => {
|
||||||
|
if (!categoryType.value) {
|
||||||
|
isCategoryTypeError.value = true
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (categoryName.value.length == 0) {
|
||||||
|
isCategoryNameError.value = true
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (categoryIcon.value.length == 0) {
|
||||||
|
isCategoryIconError.value = true
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
console.log(categoryDescription.value.length)
|
||||||
|
if (categoryDescription.value.length == 0) {
|
||||||
|
isCategoryDescriptionError.value = true
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const buildUpdate = (): UpdateCategoryDTO => {
|
||||||
|
if (validateForm()) {
|
||||||
|
return {
|
||||||
|
type: categoryType.value,
|
||||||
|
name: categoryName.value,
|
||||||
|
description: categoryDescription.value,
|
||||||
|
icon: categoryIcon.value,
|
||||||
|
} as UpdateCategoryDTO
|
||||||
|
} else {
|
||||||
|
throw Error("Error while validating form")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const buildCreate = (): CreateCategoryDTO => {
|
||||||
|
if (validateForm()) {
|
||||||
|
return {
|
||||||
|
type: categoryType.value,
|
||||||
|
name: categoryName.value,
|
||||||
|
description: categoryDescription.value,
|
||||||
|
icon: categoryIcon.value,
|
||||||
|
} as CreateCategoryDTO
|
||||||
|
} else {
|
||||||
|
throw Error("Error while validating form")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const moveUser = async () => {
|
||||||
|
if (window.history.length > 1) {
|
||||||
|
console.log('moved back')
|
||||||
|
router.back()
|
||||||
|
} else {
|
||||||
|
console.log('moved forward')
|
||||||
|
await router.push('/categories')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const isDeleteAlertVisible = ref(false)
|
||||||
|
const deleteAlertMessage = ref<string>('Do you really want to delete the category?')
|
||||||
|
const deleteCategory = async () => {
|
||||||
|
if (spaceStore.selectedSpaceId) {
|
||||||
|
await categoriesService.deleteCategory(spaceStore.selectedSpaceId, Number(categoryId.value))
|
||||||
|
await categoriesStore.fetchCategories(spaceStore.selectedSpaceId)
|
||||||
|
await moveUser()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
if (mode.value === "edit") {
|
if (mode.value === "edit") {
|
||||||
await fetchCategory()
|
await fetchCategory()
|
||||||
toolbar.registerHandler('deleteCategory', () => {
|
toolbar.registerHandler('deleteCategory', () => {
|
||||||
|
if (tgApp.initData) {
|
||||||
|
tgApp.showConfirm(deleteAlertMessage, async (confirmed: boolean) => {
|
||||||
|
if (confirmed) {
|
||||||
|
await deleteCategory()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
isDeleteAlertVisible.value = true
|
||||||
|
}
|
||||||
})
|
})
|
||||||
toolbar.registerHandler('updateCategory', async () => {
|
toolbar.registerHandler('updateCategory', async () => {
|
||||||
if (spaceStore.selectedSpaceId) {
|
if (spaceStore.selectedSpaceId) {
|
||||||
// await categoriesStore.fetchCategories(spaceStore.selectedSpaceId)
|
// await categoriesStore.fetchCategories(spaceStore.selectedSpaceId)
|
||||||
router.back()
|
try {
|
||||||
|
let updateDTO = buildUpdate()
|
||||||
|
await categoriesService.updateCategory(spaceStore.selectedSpaceId, updateDTO)
|
||||||
|
console.log(updateDTO)
|
||||||
|
await moveUser()
|
||||||
|
} catch (e) {
|
||||||
|
toast.add({
|
||||||
|
severity: "error",
|
||||||
|
summary: "Error while updating category",
|
||||||
|
detail: e,
|
||||||
|
life: 3000,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
toolbar.registerHandler('createCategory', async () => {
|
toolbar.registerHandler('createCategory', async () => {
|
||||||
if (spaceStore.selectedSpaceId) {
|
if (spaceStore.selectedSpaceId) {
|
||||||
// await categoriesStore.fetchCategories(spaceStore.selectedSpaceId)
|
// await categoriesStore.fetchCategories(spaceStore.selectedSpaceId)
|
||||||
router.back()
|
try {
|
||||||
|
let createDTO = buildCreate()
|
||||||
|
await categoriesService.createCategory(spaceStore.selectedSpaceId, createDTO)
|
||||||
|
console.log(createDTO)
|
||||||
|
await moveUser()
|
||||||
|
} catch (e) {
|
||||||
|
toast.add({
|
||||||
|
severity: "error",
|
||||||
|
summary: "Error while creating category",
|
||||||
|
detail: e,
|
||||||
|
life: 3000
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
@@ -108,7 +218,11 @@ onMounted(async () => {
|
|||||||
<template>
|
<template>
|
||||||
|
|
||||||
<div class="flex flex-col w-full justify-items-start gap-7">
|
<div class="flex flex-col w-full justify-items-start gap-7">
|
||||||
|
<ConfirmDialog
|
||||||
|
v-if="isDeleteAlertVisible"
|
||||||
|
:message="deleteAlertMessage"
|
||||||
|
:callback="(confirmed: boolean) => { if (confirmed) deleteCategory(); isDeleteAlertVisible = false; }"
|
||||||
|
/>
|
||||||
<div class="flex flex-col w-full ">
|
<div class="flex flex-col w-full ">
|
||||||
<div class=" flex-col " v-tooltip.focus.bottom="'Only emoji supported'">
|
<div class=" flex-col " v-tooltip.focus.bottom="'Only emoji supported'">
|
||||||
<input
|
<input
|
||||||
@@ -131,6 +245,8 @@ onMounted(async () => {
|
|||||||
/>
|
/>
|
||||||
<label class=" !justify-center !font-extralight text-gray-600 text-center">Category
|
<label class=" !justify-center !font-extralight text-gray-600 text-center">Category
|
||||||
icon</label>
|
icon</label>
|
||||||
|
<span v-if="isCategoryIconError"
|
||||||
|
class="text-sm !text-red-500 font-extralight">Icon cannot be empty or non-emoji</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="w-full !items-center !justify-center">
|
<div class="w-full !items-center !justify-center">
|
||||||
@@ -141,14 +257,18 @@ onMounted(async () => {
|
|||||||
optionValue="value"
|
optionValue="value"
|
||||||
class="!w-full !items-center !justify-center "
|
class="!w-full !items-center !justify-center "
|
||||||
/>
|
/>
|
||||||
|
<span v-if="isCategoryTypeError"
|
||||||
|
class="text-sm !text-red-500 font-extralight">Category type cannot be empty</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col w-full justify-items-start">
|
<div class="flex flex-col w-full justify-items-start">
|
||||||
<label class="!font-semibold text-gray-600 pl-2">Category name</label>
|
<label class="!font-semibold text-gray-600 pl-2">Category name</label>
|
||||||
<div class="card !rounded-3xl !justify-start !items-start !p-4 !pl-5 ">
|
<div class="card !rounded-3xl !justify-start !items-start !p-4 !pl-5 ">
|
||||||
<input class="font-extralight w-full focus:outline-0" placeholder="Name" v-model="categoryName"/>
|
<input class="font-extralight w-full focus:outline-0" placeholder="Name" v-model="categoryName"
|
||||||
|
@input="categoryName.length !== 0 ? isCategoryNameError = false : true"/>
|
||||||
</div>
|
</div>
|
||||||
|
<span v-if="isCategoryNameError" class="text-sm !text-red-500 font-extralight">Name cannot be empty</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col w-full justify-items-start">
|
<div class="flex flex-col w-full justify-items-start">
|
||||||
<label class="!font-semibold text-gray-600 !pl-2">Category description</label>
|
<label class="!font-semibold text-gray-600 !pl-2">Category description</label>
|
||||||
@@ -156,8 +276,11 @@ onMounted(async () => {
|
|||||||
<textarea
|
<textarea
|
||||||
class="!font-extralight !text-start !pl-2 w-full focus:outline-0 !focus:border-0 !@focus:shadow-none !bg-white !border-0 min-h-36"
|
class="!font-extralight !text-start !pl-2 w-full focus:outline-0 !focus:border-0 !@focus:shadow-none !bg-white !border-0 min-h-36"
|
||||||
style="box-shadow: none !important;"
|
style="box-shadow: none !important;"
|
||||||
placeholder="Description" v-model="categoryDescription"/>
|
placeholder="Description" v-model="categoryDescription"
|
||||||
|
@input="categoryDescription.length !== 0 ? isCategoryDescriptionError = false : true"/>
|
||||||
</div>
|
</div>
|
||||||
|
<span v-if="isCategoryDescriptionError"
|
||||||
|
class="text-sm !text-red-500 font-extralight">Description cannot be empty</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ const recurrentDate = ref<number>(Math.floor(Math.random() * 31))
|
|||||||
const isDateError = ref(false)
|
const isDateError = ref(false)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
try {
|
try {
|
||||||
if (spaceStore.selectedSpaceId) {
|
if (spaceStore.selectedSpaceId) {
|
||||||
@@ -172,7 +171,11 @@ const deleteAlertMessage = ref('Do you want to delete recurrent?')
|
|||||||
const deleteRecurrent = async () => {
|
const deleteRecurrent = async () => {
|
||||||
await recurrentsService.deleteRecurrent(spaceStore.selectedSpaceId, recurrentId.value)
|
await recurrentsService.deleteRecurrent(spaceStore.selectedSpaceId, recurrentId.value)
|
||||||
await recurrentsStore.fetchRecurrents(spaceStore.selectedSpaceId)
|
await recurrentsStore.fetchRecurrents(spaceStore.selectedSpaceId)
|
||||||
router.back()
|
if (window.history.length > 1) {
|
||||||
|
router.back()
|
||||||
|
} else {
|
||||||
|
await router.push('/categories')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
@@ -190,7 +193,7 @@ onMounted(async () => {
|
|||||||
console.log('deleteRecurrent2')
|
console.log('deleteRecurrent2')
|
||||||
if (tgApp.initData) {
|
if (tgApp.initData) {
|
||||||
console.log('deleteRecurrent3')
|
console.log('deleteRecurrent3')
|
||||||
tgApp.showConfirm(deleteAlertMessage.value, async (confirmed) => {
|
tgApp.showConfirm(deleteAlertMessage.value, async (confirmed: boolean) => {
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
console.log("recurrent id is deleted")
|
console.log("recurrent id is deleted")
|
||||||
await deleteRecurrent()
|
await deleteRecurrent()
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import {Category} from "@/models/category";
|
import {Category, CreateCategoryDTO, UpdateCategoryDTO} from "@/models/category";
|
||||||
import {CategoryType} from "@/models/enums";
|
import {CategoryType} from "@/models/enums";
|
||||||
import {User} from "@/models/user";
|
import {User} from "@/models/user";
|
||||||
|
|
||||||
async function fetchCategories(spaceId: number) {
|
async function fetchCategories(spaceId: number) {
|
||||||
let categories : Category[] = []
|
let categories: Category[] = []
|
||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
categories.push({
|
categories.push({
|
||||||
id: i,
|
id: i,
|
||||||
@@ -23,21 +23,33 @@ async function fetchCategories(spaceId: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function fetchCategory(spaceId: number, categoryId: number): Promise<Category> {
|
async function fetchCategory(spaceId: number, categoryId: number): Promise<Category> {
|
||||||
return {
|
return {
|
||||||
id: 1,
|
id: 1,
|
||||||
type: Math.floor(Math.random() * 2) === 0 ? CategoryType.INCOME : CategoryType.EXPENSE,
|
type: Math.floor(Math.random() * 2) === 0 ? CategoryType.INCOME : CategoryType.EXPENSE,
|
||||||
name: `Category ${1}`,
|
name: `Category ${1}`,
|
||||||
description: `Description of Category ${1}`,
|
description: `Description of Category ${1}`,
|
||||||
icon: "😇",
|
icon: "😇",
|
||||||
createdBy: {
|
createdBy: {
|
||||||
id: 1,
|
id: 1,
|
||||||
username: `username_${1}`,
|
username: `username_${1}`,
|
||||||
firstName: `firstName ${1}`,
|
firstName: `firstName ${1}`,
|
||||||
} as User,
|
} as User,
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
} as Category
|
} as Category
|
||||||
}
|
}
|
||||||
|
|
||||||
export const categoriesService = {
|
async function createCategory(spaceId: number, category: CreateCategoryDTO): Promise<number> {
|
||||||
fetchCategories, fetchCategory
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateCategory(spaceId: number, category: UpdateCategoryDTO): Promise<void> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteCategory(spaceId: number, categoryId: number): Promise<void> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export const categoriesService = {
|
||||||
|
fetchCategories, fetchCategory, createCategory, updateCategory, deleteCategory,
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user