init
This commit is contained in:
150
src/components/settings/CategoryCreateUpdate.vue
Normal file
150
src/components/settings/CategoryCreateUpdate.vue
Normal file
@@ -0,0 +1,150 @@
|
||||
<script setup lang="ts">
|
||||
import {useRoute} from "vue-router";
|
||||
import {computed, onMounted, ref} from "vue";
|
||||
import {useToolbarStore} from "@/stores/toolbar-store";
|
||||
import {useToast} from "primevue/usetoast";
|
||||
import {SelectButton} from "primevue";
|
||||
import {categoriesService} from "@/services/categories-service";
|
||||
import {useSpaceStore} from "@/stores/spaceStore";
|
||||
import {CategoryType, CategoryTypeName} from "@/models/enums";
|
||||
import emojiRegex from 'emoji-regex'
|
||||
|
||||
const route = useRoute()
|
||||
const toolbar = useToolbarStore();
|
||||
const toast = useToast();
|
||||
const spaceStore = useSpaceStore();
|
||||
const categoryId = ref<string | undefined>(route.params.id)
|
||||
const mode = computed(() => {
|
||||
return categoryId.value ? "edit" : "create"
|
||||
})
|
||||
const categoryType = ref<CategoryType>(CategoryType.EXPENSE)
|
||||
const categoryName = ref<string>()
|
||||
const categoryIcon = ref<string>("🛍️")
|
||||
const categoryDescription = ref<string>()
|
||||
|
||||
|
||||
// Генерим опции: [{ label: "Расходы", value: "EXPENSE" }, ...]
|
||||
const options = Object.values(CategoryType).map(type => ({
|
||||
label: CategoryTypeName[type],
|
||||
value: type
|
||||
}))
|
||||
|
||||
const fetchCategory = async () => {
|
||||
try {
|
||||
console.log('here')
|
||||
if (spaceStore.selectedSpaceId && categoryId.value) {
|
||||
console.log('here2')
|
||||
let category = await categoriesService.fetchCategory(spaceStore.selectedSpaceId, Number(categoryId.value))
|
||||
categoryType.value = category.type
|
||||
categoryName.value = category.name
|
||||
categoryDescription.value = category.description
|
||||
categoryIcon.value = category.icon
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
toast.add({
|
||||
severity: "error",
|
||||
summary: "Error while fetching category",
|
||||
detail: err.detail.message,
|
||||
life: 3000,
|
||||
})
|
||||
}
|
||||
}
|
||||
const re = emojiRegex()
|
||||
|
||||
function toOneEmoji(raw: string): string {
|
||||
const matches = raw.match(re) ?? [] // ← вместо [...raw.matchAll(re)]
|
||||
return matches.length ? matches[matches.length - 1] : '🛍️'
|
||||
}
|
||||
|
||||
function handleInput(e: Event) {
|
||||
const el = e.target as HTMLInputElement
|
||||
const next = toOneEmoji(el.value)
|
||||
if (el.value !== next) {
|
||||
el.value = next // визуально заменить
|
||||
}
|
||||
categoryIcon.value = next // обновить v-model
|
||||
}
|
||||
|
||||
function handlePaste(e: ClipboardEvent) {
|
||||
const text = e.clipboardData?.getData('text') ?? ''
|
||||
const next = toOneEmoji(text)
|
||||
e.preventDefault()
|
||||
const target = e.target as HTMLInputElement
|
||||
target.value = next
|
||||
categoryIcon.value = next
|
||||
}
|
||||
|
||||
// для мобильных IME: окончание композиции
|
||||
function handleCompositionEnd(e: CompositionEvent) {
|
||||
handleInput(e as unknown as Event)
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
if (mode.value === "edit") {
|
||||
await fetchCategory()
|
||||
toolbar.registerHandler('deleteCategory', () => {
|
||||
console.log("delete category")
|
||||
})
|
||||
toolbar.registerHandler('updateCategory', () => {
|
||||
console.log("update category")
|
||||
})
|
||||
} else {
|
||||
toolbar.registerHandler('createCategory', () => {
|
||||
console.log("create category")
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
<div class="flex flex-col w-full justify-items-start gap-7">
|
||||
|
||||
<div class="flex flex-col w-full ">
|
||||
<div class=" flex-col " v-tooltip.bottom="'Only emoji supported'">
|
||||
<input class=" !justify-items-center !justify-center font-extralight text-9xl w-full focus:outline-0"
|
||||
placeholder="Icon" v-model="categoryIcon" @input="handleInput" @paste="handlePaste"
|
||||
@compositionend="handleCompositionEnd" inputmode="text"
|
||||
autocomplete="off"
|
||||
spellcheck="false"/>
|
||||
<label class="!justify-items-center !justify-center !font-extralight text-gray-600 text-center">Category
|
||||
icon</label>
|
||||
</div>
|
||||
|
||||
<div class="w-full !justify-items-center !items-center !justify-center">
|
||||
<SelectButton
|
||||
v-model="categoryType"
|
||||
:options="options"
|
||||
optionLabel="label"
|
||||
optionValue="value"
|
||||
class="!w-full !justify-items-center !items-center !justify-center "
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="flex flex-col w-full justify-items-start">
|
||||
<label class="!font-semibold text-2xl text-gray-600 pl-2">Category name</label>
|
||||
<div class="card !justify-start !items-start !p-4 !pl-5 ">
|
||||
<input class="font-extralight text-xl w-full focus:outline-0" placeholder="Name" v-model="categoryName"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col w-full justify-items-start">
|
||||
<label class="!font-semibold text-2xl text-gray-600 !pl-2">Category description</label>
|
||||
<div class="card !justify-start !items-start !pl-2">
|
||||
<textarea
|
||||
class="font-extralight text-xl w-full focus:outline-0 !focus:border-0 !@focus:shadow-none !bg-white !border-0 min-h-36"
|
||||
style="box-shadow: none !important;"
|
||||
placeholder="Description" v-model="categoryDescription"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.p-togglebutton-label, .p-togglebutton {
|
||||
padding: 10rem !important;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user