tg app fix sizes
This commit is contained in:
@@ -1,16 +1,19 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import SpaceList from "@/components/space-list/SpaceList.vue";
|
import SpaceList from "@/components/space-list/SpaceList.vue";
|
||||||
import Toolbar from "@/components/Toolbar.vue";
|
import Toolbar from "@/components/Toolbar.vue";
|
||||||
|
import Toast from "primevue/toast";
|
||||||
import { useSpaceStore } from "@/stores/spaceStore";
|
import { useSpaceStore } from "@/stores/spaceStore";
|
||||||
import { useToolbarStore } from "@/stores/toolbar-store";
|
import { useToolbarStore } from "@/stores/toolbar-store";
|
||||||
import router from "@/router";
|
import router from "@/router";
|
||||||
import { useRoute, onBeforeRouteUpdate } from "vue-router";
|
import { useRoute, onBeforeRouteUpdate } from "vue-router";
|
||||||
import { computed, onMounted, onBeforeUnmount, ref, watch } from "vue";
|
import { computed, onMounted, onBeforeUnmount, ref, watch } from "vue";
|
||||||
|
import {useToast} from "primevue/usetoast";
|
||||||
|
|
||||||
const spaceStore = useSpaceStore();
|
const spaceStore = useSpaceStore();
|
||||||
const toolbarStore = useToolbarStore();
|
const toolbarStore = useToolbarStore();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const platform = ref<string>("unknown")
|
const platform = ref<string>("unknown")
|
||||||
|
const toast = useToast();
|
||||||
|
|
||||||
const tgApp = (window as any)?.Telegram?.WebApp;
|
const tgApp = (window as any)?.Telegram?.WebApp;
|
||||||
const isTelegram = computed(() => !!tgApp);
|
const isTelegram = computed(() => !!tgApp);
|
||||||
@@ -34,7 +37,7 @@ function spaceSelected() {
|
|||||||
let backHandler: (() => void) | null = null;
|
let backHandler: (() => void) | null = null;
|
||||||
|
|
||||||
function setupBackButton() {
|
function setupBackButton() {
|
||||||
if (!tgApp) return;
|
if (!tgApp.initData) return;
|
||||||
|
|
||||||
if (route.path !== "/") {
|
if (route.path !== "/") {
|
||||||
tgApp.BackButton.show();
|
tgApp.BackButton.show();
|
||||||
@@ -61,7 +64,7 @@ onMounted(() => {
|
|||||||
isSpaceSelectorVisible.value = true;
|
isSpaceSelectorVisible.value = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (tgApp) {
|
if (tgApp.initData) {
|
||||||
try {
|
try {
|
||||||
tgApp.expand?.();
|
tgApp.expand?.();
|
||||||
platform.value = tgApp.platform
|
platform.value = tgApp.platform
|
||||||
@@ -93,6 +96,8 @@ onBeforeUnmount(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<Toast/>
|
||||||
|
{{tgApp.initData}}
|
||||||
<!-- {{platform}}-->
|
<!-- {{platform}}-->
|
||||||
<!-- {{['ios', 'android'].includes(platform) }}-->
|
<!-- {{['ios', 'android'].includes(platform) }}-->
|
||||||
<div class="flex flex-col tg " :class="['ios', 'android'].includes(platform) ? '!pt-10' : ''">
|
<div class="flex flex-col tg " :class="['ios', 'android'].includes(platform) ? '!pt-10' : ''">
|
||||||
|
|||||||
@@ -5,24 +5,25 @@ import {useToast} from "primevue/usetoast";
|
|||||||
import {Divider} from "primevue";
|
import {Divider} from "primevue";
|
||||||
import {onMounted, ref} from "vue";
|
import {onMounted, ref} from "vue";
|
||||||
import {Category} from "@/models/category";
|
import {Category} from "@/models/category";
|
||||||
import {categoriesService} from "@/services/categories-service";
|
|
||||||
import {useToolbarStore} from "@/stores/toolbar-store";
|
import {useToolbarStore} from "@/stores/toolbar-store";
|
||||||
import {useRouter} from "vue-router";
|
import {useRouter} from "vue-router";
|
||||||
|
import {useCategoriesStore} from "@/stores/categories-store";
|
||||||
|
|
||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
const spaceStore = useSpaceStore()
|
const spaceStore = useSpaceStore()
|
||||||
|
const categoryStore = useCategoriesStore()
|
||||||
const toolbar = useToolbarStore()
|
const toolbar = useToolbarStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const categories = ref<Category[]>([])
|
const categories = ref<Category[]>([])
|
||||||
|
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
try {
|
try {
|
||||||
if (spaceStore.selectedSpaceId !== null) {
|
if (spaceStore.selectedSpaceId !== null) {
|
||||||
let spaceId = spaceStore.selectedSpaceId!!
|
let spaceId = spaceStore.selectedSpaceId!!
|
||||||
categories.value = await categoriesService.fetchCategories(spaceId)
|
await categoryStore.fetchCategories(spaceId)
|
||||||
|
categories.value = categoryStore.categories
|
||||||
}
|
}
|
||||||
} catch (error: Error) {
|
} catch (error: Error) {
|
||||||
toast.add({
|
toast.add({
|
||||||
@@ -39,8 +40,7 @@ const toCreation = () => {
|
|||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await fetchData()
|
await fetchData()
|
||||||
toolbar.registerHandler('createCategory', () => {
|
toolbar.registerHandler('openCategoryCreation', () => {
|
||||||
console.log("create cateogiry")
|
|
||||||
toCreation()
|
toCreation()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -52,13 +52,16 @@ onMounted(async () => {
|
|||||||
|
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div v-for="key in categories.keys()" :key="categories[key].id" @click="router.push(`/categories/${categories[key].id}/edit`)"
|
<div v-for="key in categories.keys()" :key="categories[key].id"
|
||||||
|
@click="router.push(`/categories/${categories[key].id}/edit`)"
|
||||||
class="flex flex-col w-full gap-0 pl-5 items-start justify-items-center font-bold ">
|
class="flex flex-col w-full gap-0 pl-5 items-start justify-items-center font-bold ">
|
||||||
<div class="flex-row w-full items-center justify-between">
|
<div class="flex-row w-full items-center justify-between">
|
||||||
<div class="flex-col items-start">
|
<div class="flex-row items-center gap-2 ">
|
||||||
<div class="flex-row"> {{ categories[key].icon }} {{ categories[key].name }}</div>
|
<span class="text-3xl"> {{ categories[key].icon }}</span>
|
||||||
|
<div class="flex-col !font-bold "> {{ categories[key].name }}
|
||||||
<div class="flex flex-row text-sm">{{ categories[key].description }}</div>
|
<div class="flex flex-row text-sm">{{ categories[key].description }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<i class="pi pi-angle-right !font-extralight"/>
|
<i class="pi pi-angle-right !font-extralight"/>
|
||||||
</div>
|
</div>
|
||||||
<Divider v-if="key+1 !== categories.length" class="!m-0 !py-3"/>
|
<Divider v-if="key+1 !== categories.length" class="!m-0 !py-3"/>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {useRoute} from "vue-router";
|
import {useRoute, useRouter} from "vue-router";
|
||||||
import {computed, onMounted, ref} from "vue";
|
import {computed, onMounted, ref} from "vue";
|
||||||
import {useToolbarStore} from "@/stores/toolbar-store";
|
import {useToolbarStore} from "@/stores/toolbar-store";
|
||||||
import {useToast} from "primevue/usetoast";
|
import {useToast} from "primevue/usetoast";
|
||||||
@@ -8,11 +8,15 @@ import {categoriesService} from "@/services/categories-service";
|
|||||||
import {useSpaceStore} from "@/stores/spaceStore";
|
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";
|
||||||
|
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
const toolbar = useToolbarStore();
|
const toolbar = useToolbarStore();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const spaceStore = useSpaceStore();
|
const spaceStore = useSpaceStore();
|
||||||
|
const categoriesStore = useCategoriesStore();
|
||||||
const categoryId = ref<string | undefined>(route.params.id)
|
const categoryId = ref<string | undefined>(route.params.id)
|
||||||
const mode = computed(() => {
|
const mode = computed(() => {
|
||||||
return categoryId.value ? "edit" : "create"
|
return categoryId.value ? "edit" : "create"
|
||||||
@@ -31,9 +35,7 @@ const options = Object.values(CategoryType).map(type => ({
|
|||||||
|
|
||||||
const fetchCategory = async () => {
|
const fetchCategory = async () => {
|
||||||
try {
|
try {
|
||||||
console.log('here')
|
|
||||||
if (spaceStore.selectedSpaceId && categoryId.value) {
|
if (spaceStore.selectedSpaceId && categoryId.value) {
|
||||||
console.log('here2')
|
|
||||||
let category = await categoriesService.fetchCategory(spaceStore.selectedSpaceId, Number(categoryId.value))
|
let category = await categoriesService.fetchCategory(spaceStore.selectedSpaceId, Number(categoryId.value))
|
||||||
categoryType.value = category.type
|
categoryType.value = category.type
|
||||||
categoryName.value = category.name
|
categoryName.value = category.name
|
||||||
@@ -84,14 +86,20 @@ onMounted(async () => {
|
|||||||
if (mode.value === "edit") {
|
if (mode.value === "edit") {
|
||||||
await fetchCategory()
|
await fetchCategory()
|
||||||
toolbar.registerHandler('deleteCategory', () => {
|
toolbar.registerHandler('deleteCategory', () => {
|
||||||
console.log("delete category")
|
|
||||||
})
|
})
|
||||||
toolbar.registerHandler('updateCategory', () => {
|
toolbar.registerHandler('updateCategory', async () => {
|
||||||
console.log("update category")
|
if (spaceStore.selectedSpaceId) {
|
||||||
|
// await categoriesStore.fetchCategories(spaceStore.selectedSpaceId)
|
||||||
|
router.back()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
toolbar.registerHandler('createCategory', () => {
|
toolbar.registerHandler('createCategory', async () => {
|
||||||
console.log("create category")
|
if (spaceStore.selectedSpaceId) {
|
||||||
|
// await categoriesStore.fetchCategories(spaceStore.selectedSpaceId)
|
||||||
|
router.back()
|
||||||
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -103,7 +111,7 @@ onMounted(async () => {
|
|||||||
|
|
||||||
<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 class=" !justify-items-center !justify-center font-extralight text-9xl w-full focus:outline-0"
|
<input class="!flex !justify-items-center !justify-center font-extralight text-9xl w-full focus:outline-0"
|
||||||
placeholder="Icon" v-model="categoryIcon" @input="handleInput" @paste="handlePaste"
|
placeholder="Icon" v-model="categoryIcon" @input="handleInput" @paste="handlePaste"
|
||||||
@compositionend="handleCompositionEnd" inputmode="text"
|
@compositionend="handleCompositionEnd" inputmode="text"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
|
|||||||
@@ -3,16 +3,17 @@
|
|||||||
|
|
||||||
import {RecurrentOperation} from "@/models/recurrent-operation";
|
import {RecurrentOperation} from "@/models/recurrent-operation";
|
||||||
import {onMounted, ref} from "vue";
|
import {onMounted, ref} from "vue";
|
||||||
import {recurrentsService} from "@/services/recurrents-service";
|
|
||||||
import {useSpaceStore} from "@/stores/spaceStore";
|
import {useSpaceStore} from "@/stores/spaceStore";
|
||||||
import {useToast} from "primevue/usetoast";
|
import {useToast} from "primevue/usetoast";
|
||||||
import {Divider} from "primevue";
|
import {Divider} from "primevue";
|
||||||
import {Category} from "@/models/category";
|
import {Category} from "@/models/category";
|
||||||
import {useRouter} from "vue-router";
|
import {useRouter} from "vue-router";
|
||||||
import {useToolbarStore} from "@/stores/toolbar-store";
|
import {useToolbarStore} from "@/stores/toolbar-store";
|
||||||
|
import {useRecurrentsStore} from "@/stores/recurrent-store";
|
||||||
|
|
||||||
const toolbar = useToolbarStore()
|
const toolbar = useToolbarStore()
|
||||||
const spaceStore = useSpaceStore();
|
const spaceStore = useSpaceStore();
|
||||||
|
const recurrentsStore = useRecurrentsStore();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
@@ -23,10 +24,8 @@ const recurrents = ref<RecurrentOperation[]>([])
|
|||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
try {
|
try {
|
||||||
if (spaceStore.selectedSpaceId) {
|
if (spaceStore.selectedSpaceId) {
|
||||||
console.log('hereeee')
|
await recurrentsStore.fetchRecurrents(spaceStore.selectedSpaceId)
|
||||||
let recurrentsResponse = await recurrentsService.fetchRecurrents(spaceStore.selectedSpaceId)
|
recurrents.value = recurrentsStore.recurrents
|
||||||
recurrents.value = recurrentsResponse
|
|
||||||
console.log(recurrentsResponse)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -34,7 +33,7 @@ const fetchData = async () => {
|
|||||||
toast.add({
|
toast.add({
|
||||||
severity: 'error',
|
severity: 'error',
|
||||||
summary: 'Failed to fetch recurrents.',
|
summary: 'Failed to fetch recurrents.',
|
||||||
detail: error.message
|
detail: e.message
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -53,20 +52,23 @@ onMounted(async () => {
|
|||||||
<div class="card">
|
<div class="card">
|
||||||
<div v-for="key in recurrents.keys()" :key="recurrents[key].id"
|
<div v-for="key in recurrents.keys()" :key="recurrents[key].id"
|
||||||
@click="router.push(`/recurrents/${recurrents[key].id}/edit`)"
|
@click="router.push(`/recurrents/${recurrents[key].id}/edit`)"
|
||||||
class="flex flex-col w-full gap-0 pl-5 items-start justify-items-center font-bold ">
|
class="flex flex-col w-full gap- pl-5 items-start justify-items-center font-bold ">
|
||||||
<div class="flex-row w-full items-center justify-between">
|
<div class="flex-row gap-2 w-full items-center justify-between">
|
||||||
|
<div class="w-full flex items-center justify-between">
|
||||||
<div class="flex-row items-center gap-2 ">
|
<div class="flex-row items-center gap-2 ">
|
||||||
<span class="text-4xl">{{ recurrents[key].category.icon }}</span>
|
<span class="text-4xl">{{ recurrents[key].category.icon }}</span>
|
||||||
<div class="flex-col items-start">
|
<div class="flex-col items-start">
|
||||||
<div class="flex-row"> {{ recurrents[key].name }}</div>
|
<div class="flex-row !font-bold "> {{ recurrents[key].name }}</div>
|
||||||
<div class="flex flex-row text-sm">{{ recurrents[key].category.name }}</div>
|
<div class="flex flex-row text-sm">{{ recurrents[key].category.name }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="items-center flex-col">
|
|
||||||
|
|
||||||
|
<div class="items-end flex-col">
|
||||||
<span class="text-lg !font-semibold">{{ recurrents[key].amount }}₽ </span>
|
<span class="text-lg !font-semibold">{{ recurrents[key].amount }}₽ </span>
|
||||||
<span class="text-sm">каждое {{ recurrents[key].date }} число </span>
|
<span class="text-sm">каждое {{ recurrents[key].date }} число </span>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<i class="pi pi-angle-right !font-extralight"/>
|
<i class="pi pi-angle-right !font-extralight"/>
|
||||||
</div>
|
</div>
|
||||||
<Divider v-if="key+1 !== recurrents.length" class="!m-0 !py-3"/>
|
<Divider v-if="key+1 !== recurrents.length" class="!m-0 !py-3"/>
|
||||||
|
|||||||
@@ -8,33 +8,39 @@ import {categoriesService} from "@/services/categories-service";
|
|||||||
import {useSpaceStore} from "@/stores/spaceStore";
|
import {useSpaceStore} from "@/stores/spaceStore";
|
||||||
import {recurrentsService} from "@/services/recurrents-service";
|
import {recurrentsService} from "@/services/recurrents-service";
|
||||||
import {Category} from "@/models/category";
|
import {Category} from "@/models/category";
|
||||||
|
import router from "@/router";
|
||||||
|
import {useRecurrentsStore} from "@/stores/recurrent-store";
|
||||||
|
import {CreateRecurrentOperationDTO, UpdateRecurrentOperationDTO} from "@/models/recurrent-operation";
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const toolbar = useToolbarStore();
|
const toolbar = useToolbarStore();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const spaceStore = useSpaceStore();
|
const spaceStore = useSpaceStore();
|
||||||
|
const recurrentsStore = useRecurrentsStore();
|
||||||
|
|
||||||
const isCategorySelectorOpened = ref(false);
|
const isCategorySelectorOpened = ref(false);
|
||||||
|
|
||||||
const categories = ref<Category[]>([]);
|
const categories = ref<Category[]>([]);
|
||||||
const recurrentId = ref<string | undefined>(route.params.id)
|
const recurrentId = ref<number | undefined>(route.params.id)
|
||||||
const mode = computed(() => {
|
const mode = computed(() => {
|
||||||
return recurrentId.value ? "edit" : "create"
|
return recurrentId.value ? "edit" : "create"
|
||||||
})
|
})
|
||||||
const recurrentCategory = ref<Category>({})
|
const recurrentCategory = ref<Category>({} as Category)
|
||||||
const recurrentName = ref<string>()
|
const isCategoryError = ref(false)
|
||||||
|
const recurrentName = ref<string>('')
|
||||||
|
const isNameError = ref(false)
|
||||||
const recurrentAmount = ref<number>(0)
|
const recurrentAmount = ref<number>(0)
|
||||||
|
const isAmountError = ref(false)
|
||||||
const recurrentDate = ref<number>(Math.floor(Math.random() * 31))
|
const recurrentDate = ref<number>(Math.floor(Math.random() * 31))
|
||||||
|
const isDateError = ref(false)
|
||||||
|
|
||||||
|
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
try {
|
try {
|
||||||
console.log('here')
|
|
||||||
if (spaceStore.selectedSpaceId) {
|
if (spaceStore.selectedSpaceId) {
|
||||||
categories.value = await categoriesService.fetchCategories(spaceStore.selectedSpaceId)
|
categories.value = await categoriesService.fetchCategories(spaceStore.selectedSpaceId)
|
||||||
if (categories.value.length > 0) {
|
if (categories.value.length > 0) {
|
||||||
if (mode.value === "edit") {
|
if (mode.value === "edit") {
|
||||||
console.log('here2')
|
|
||||||
let recurrent = await recurrentsService.fetchRecurrent(spaceStore.selectedSpaceId, Number(recurrentId.value))
|
let recurrent = await recurrentsService.fetchRecurrent(spaceStore.selectedSpaceId, Number(recurrentId.value))
|
||||||
recurrentCategory.value = recurrent.category
|
recurrentCategory.value = recurrent.category
|
||||||
recurrentName.value = recurrent.name
|
recurrentName.value = recurrent.name
|
||||||
@@ -83,8 +89,81 @@ function handlePaste(e: ClipboardEvent) {
|
|||||||
const num = Number(text)
|
const num = Number(text)
|
||||||
recurrentAmount.value = isNaN(num) ? 0 : num
|
recurrentAmount.value = isNaN(num) ? 0 : num
|
||||||
}
|
}
|
||||||
|
|
||||||
const tgApp = (window as any)?.Telegram?.WebApp;
|
const tgApp = (window as any)?.Telegram?.WebApp;
|
||||||
const insetTop = ref(54)
|
const insetTop = ref(54)
|
||||||
|
const resetForm = () => {
|
||||||
|
isAmountError.value = false
|
||||||
|
isCategoryError.value = false
|
||||||
|
isNameError.value = false
|
||||||
|
isDateError.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const validateForm = (): boolean => {
|
||||||
|
if (!recurrentCategory.value) {
|
||||||
|
isCategoryError.value = true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (recurrentAmount.value <= 0) {
|
||||||
|
isAmountError.value = true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (recurrentName.value.length == 0) {
|
||||||
|
isNameError.value = true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recurrentDate.value < 1 && recurrentDate.value > 31) {
|
||||||
|
isDateError.value = true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
const buildUpdate = (): UpdateRecurrentOperationDTO => {
|
||||||
|
if (validateForm()) {
|
||||||
|
if (mode.value === "edit") {
|
||||||
|
return {
|
||||||
|
categoryId: recurrentCategory.value.id,
|
||||||
|
name: recurrentName.value,
|
||||||
|
amount: recurrentAmount.value,
|
||||||
|
date: recurrentDate.value,
|
||||||
|
} as UpdateRecurrentOperationDTO
|
||||||
|
} else {
|
||||||
|
toast.add({
|
||||||
|
severity: "warn",
|
||||||
|
summary: "You cannot create while edit",
|
||||||
|
detail: "Editing only available when recurrent id is provided.",
|
||||||
|
})
|
||||||
|
throw new Error("Editing only available when recurrent id is provided.")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error("Form is not valid")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const buildCreate = (): CreateRecurrentOperationDTO => {
|
||||||
|
if (validateForm()) {
|
||||||
|
if (mode.value === "create") {
|
||||||
|
return {
|
||||||
|
categoryId: recurrentCategory.value.id,
|
||||||
|
name: recurrentName.value,
|
||||||
|
amount: recurrentAmount.value,
|
||||||
|
date: recurrentDate.value,
|
||||||
|
} as CreateRecurrentOperationDTO
|
||||||
|
} else {
|
||||||
|
toast.add({
|
||||||
|
severity: "warn",
|
||||||
|
summary: "You cannot edit while creating",
|
||||||
|
detail: "Creating only available when no recurrent id is provided.",
|
||||||
|
})
|
||||||
|
throw new Error("Creating only available when creating")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error("Form is not valid")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
if (tgApp && ['ios', 'android'].includes(tgApp.platform)) {
|
if (tgApp && ['ios', 'android'].includes(tgApp.platform)) {
|
||||||
@@ -94,15 +173,37 @@ onMounted(async () => {
|
|||||||
await fetchData()
|
await fetchData()
|
||||||
if (mode.value === "edit") {
|
if (mode.value === "edit") {
|
||||||
|
|
||||||
toolbar.registerHandler('deleteRecurrent', () => {
|
toolbar.registerHandler('deleteRecurrent', async () => {
|
||||||
console.log("delete recurrent")
|
if (spaceStore.selectedSpaceId && recurrentId.value) {
|
||||||
|
await recurrentsService.deleteRecurrent(spaceStore.selectedSpaceId, recurrentId.value)
|
||||||
|
await recurrentsStore.fetchRecurrents(spaceStore.selectedSpaceId)
|
||||||
|
router.back()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
toolbar.registerHandler('updateRecurrent', () => {
|
toolbar.registerHandler('updateRecurrent', async () => {
|
||||||
console.log("update Recurrent")
|
if (spaceStore.selectedSpaceId) {
|
||||||
|
try {
|
||||||
|
await recurrentsService.updateRecurrent(spaceStore.selectedSpaceId, buildUpdate())
|
||||||
|
await recurrentsStore.fetchRecurrents(spaceStore.selectedSpaceId)
|
||||||
|
router.back()
|
||||||
|
} catch (error) {
|
||||||
|
toast.add({
|
||||||
|
severity: "error",
|
||||||
|
summary: "Error while updating recurrent",
|
||||||
|
detail: error.message,
|
||||||
|
life: 3000,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
toolbar.registerHandler('createRecurrent', () => {
|
toolbar.registerHandler('createRecurrent', async () => {
|
||||||
console.log("create Recurrent")
|
if (spaceStore.selectedSpaceId) {
|
||||||
|
await recurrentsService.createRecurrent(spaceStore.selectedSpaceId, buildCreate())
|
||||||
|
await recurrentsStore.fetchRecurrents(spaceStore.selectedSpaceId)
|
||||||
|
router.back()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -141,10 +242,9 @@ onMounted(async () => {
|
|||||||
|
|
||||||
<div class="flex flex-col w-full ">
|
<div class="flex flex-col w-full ">
|
||||||
<div class="flex-col w-full">
|
<div class="flex-col w-full">
|
||||||
|
|
||||||
<InputNumber
|
<InputNumber
|
||||||
v-model="recurrentAmount"
|
v-model="recurrentAmount"
|
||||||
@input="handleInput"
|
@input=" isAmountError = false"
|
||||||
@paste="handlePaste"
|
@paste="handlePaste"
|
||||||
type="text"
|
type="text"
|
||||||
inputmode="numeric"
|
inputmode="numeric"
|
||||||
@@ -153,6 +253,7 @@ onMounted(async () => {
|
|||||||
class="text-7xl font-bold w-full text-center focus:outline-none !p-0 !m-0"
|
class="text-7xl font-bold w-full text-center focus:outline-none !p-0 !m-0"
|
||||||
|
|
||||||
/>
|
/>
|
||||||
|
<span v-if="isAmountError" class="text-sm !text-red-500 font-extralight">Amount couldn't be less then 1</span>
|
||||||
<!-- <span class="absolute right-2 top-1/2 -translate-y-1/2 text-7xl font-bold">₽</span>-->
|
<!-- <span class="absolute right-2 top-1/2 -translate-y-1/2 text-7xl font-bold">₽</span>-->
|
||||||
|
|
||||||
<label class="!justify-items-center !justify-center !font-extralight text-gray-600 text-center">Amount</label>
|
<label class="!justify-items-center !justify-center !font-extralight text-gray-600 text-center">Amount</label>
|
||||||
@@ -162,7 +263,8 @@ onMounted(async () => {
|
|||||||
</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">Recurrent category</label>
|
<label class="!font-semibold text-gray-600 pl-2">Recurrent category</label>
|
||||||
<div class="card !justify-start !items-start !p-4 !pl-5 cursor-pointer" @click="isCategorySelectorOpened = true">
|
<div class="card !justify-start !items-start !p-4 !pl-5 cursor-pointer"
|
||||||
|
@click="isCategorySelectorOpened = true; isCategoryError=false;">
|
||||||
<div class="flex-row w-full gap-2 items-center justify-between">
|
<div class="flex-row w-full gap-2 items-center justify-between">
|
||||||
<div class="flex-row gap-2 items-center">
|
<div class="flex-row gap-2 items-center">
|
||||||
<span class="!text-3xl ">{{ recurrentCategory.icon }}</span>
|
<span class="!text-3xl ">{{ recurrentCategory.icon }}</span>
|
||||||
@@ -174,12 +276,16 @@ onMounted(async () => {
|
|||||||
<i class="pi pi-angle-right !font-extralight"/>
|
<i class="pi pi-angle-right !font-extralight"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<span v-if="isCategoryError" class="text-sm text-red-500 font-extralight">Category should be selected</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">Recurrent name</label>
|
<label class="!font-semibold text-gray-600 pl-2">Recurrent name</label>
|
||||||
<div class="card !justify-start !items-start !p-4 !pl-5 ">
|
<div class="card !justify-start !items-start !p-4 !pl-5 ">
|
||||||
<input class="font-extralight w-full focus:outline-0" placeholder="Name" v-model="recurrentName"/>
|
<input class="font-extralight w-full focus:outline-0" placeholder="Name"
|
||||||
|
@input="recurrentName?.length ==0 ? isNameError = true : isNameError=false" v-model="recurrentName"/>
|
||||||
</div>
|
</div>
|
||||||
|
<span v-if="isNameError" class="text-sm !text-red-500 font-extralight">Name couldn't 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">Recurrent date</label>
|
<label class="!font-semibold text-gray-600 !pl-2">Recurrent date</label>
|
||||||
@@ -188,11 +294,12 @@ onMounted(async () => {
|
|||||||
<div v-for="i in 31"
|
<div v-for="i in 31"
|
||||||
class="!w-12 !h-12 !items-center !justify-items-center !justify-center rounded-full cursor-pointer flex"
|
class="!w-12 !h-12 !items-center !justify-items-center !justify-center rounded-full cursor-pointer flex"
|
||||||
:class="recurrentDate == i ? 'bg-green-200' : 'bg-gray-100'"
|
:class="recurrentDate == i ? 'bg-green-200' : 'bg-gray-100'"
|
||||||
@click="recurrentDate=i">
|
@click="recurrentDate=i; isDateError=false">
|
||||||
{{ i }}
|
{{ i }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<span v-if="isDateError" class="text-sm text-red-500 font-extralight">Date couldn't be empty or less than 1 and greater than 31.</span>
|
||||||
<label class="!font-extralight text-gray-600 !pl-2">recurrent every N day of month</label>
|
<label class="!font-extralight text-gray-600 !pl-2">recurrent every N day of month</label>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ onMounted(fetchData);
|
|||||||
:options="{ color: '#111', bgColor: '#fff' }"
|
:options="{ color: '#111', bgColor: '#fff' }"
|
||||||
@onrefresh="
|
@onrefresh="
|
||||||
() => {
|
() => {
|
||||||
console.log('refreshed');
|
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ const routes: RouteRecordRaw[] = [
|
|||||||
icon: '',
|
icon: '',
|
||||||
onClickId: 'openSpacePicker',
|
onClickId: 'openSpacePicker',
|
||||||
},
|
},
|
||||||
{id: 'createRecurrent', text: '', icon: 'pi pi-save', onClickId: 'createCategory'},
|
{id: 'createRecurrent', text: '', icon: 'pi pi-save', onClickId: 'createRecurrent'},
|
||||||
],
|
],
|
||||||
navStack: 'settings',
|
navStack: 'settings',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
|
|
||||||
import {User} from "@/models/user";
|
import {User} from "@/models/user";
|
||||||
import {RecurrentOperation} from "@/models/recurrent-operation";
|
import {
|
||||||
|
CreateRecurrentOperationDTO,
|
||||||
|
RecurrentOperation,
|
||||||
|
UpdateRecurrentOperationDTO
|
||||||
|
} from "@/models/recurrent-operation";
|
||||||
import {categoriesService} from "@/services/categories-service";
|
import {categoriesService} from "@/services/categories-service";
|
||||||
|
|
||||||
async function fetchRecurrents(spaceId: number): Promise<RecurrentOperation[]> {
|
async function fetchRecurrents(spaceId: number): Promise<RecurrentOperation[]> {
|
||||||
@@ -17,7 +20,7 @@ async function fetchRecurrents(spaceId: number): Promise<RecurrentOperation[]> {
|
|||||||
username: `username_${i}`,
|
username: `username_${i}`,
|
||||||
firstName: `firstName ${i}`,
|
firstName: `firstName ${i}`,
|
||||||
} as User,
|
} as User,
|
||||||
createdAt: Date.now(),
|
createdAt: new Date(),
|
||||||
} as RecurrentOperation)
|
} as RecurrentOperation)
|
||||||
}
|
}
|
||||||
return recurrents;
|
return recurrents;
|
||||||
@@ -35,10 +38,23 @@ async function fetchRecurrent(spaceId: number, categoryId: number): Promise<Recu
|
|||||||
username: `username_${1}`,
|
username: `username_${1}`,
|
||||||
firstName: `firstName ${1}`,
|
firstName: `firstName ${1}`,
|
||||||
} as User,
|
} as User,
|
||||||
createdAt: Date.now(),
|
createdAt: new Date(),
|
||||||
} as RecurrentOperation
|
} as RecurrentOperation
|
||||||
}
|
}
|
||||||
|
|
||||||
export const recurrentsService = {
|
async function createRecurrent(spaceId:number, recurrent: CreateRecurrentOperationDTO): Promise<number> {
|
||||||
fetchRecurrents, fetchRecurrent
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateRecurrent(spaceId:number, recurrent: UpdateRecurrentOperationDTO): Promise<number> {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteRecurrent(spaceId: number,recurrentId: number): Promise<void> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const recurrentsService = {
|
||||||
|
fetchRecurrents, fetchRecurrent, createRecurrent, updateRecurrent, deleteRecurrent,
|
||||||
}
|
}
|
||||||
29
src/stores/categories-store.ts
Normal file
29
src/stores/categories-store.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { categoriesService } from '@/services/categories-service'
|
||||||
|
import { Category } from '@/models/category'
|
||||||
|
|
||||||
|
export const useCategoriesStore = defineStore('categories', () => {
|
||||||
|
const categories = ref<Category[]>([])
|
||||||
|
const isLoading = ref(false)
|
||||||
|
|
||||||
|
const fetchCategories = async (spaceId: number) => {
|
||||||
|
isLoading.value = true
|
||||||
|
try {
|
||||||
|
categories.value = await categoriesService.fetchCategories(spaceId)
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const addCategory = (category: Category) => {
|
||||||
|
categories.value.push(category)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
categories,
|
||||||
|
isLoading,
|
||||||
|
fetchCategories,
|
||||||
|
addCategory
|
||||||
|
}
|
||||||
|
})
|
||||||
29
src/stores/recurrent-store.ts
Normal file
29
src/stores/recurrent-store.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import {RecurrentOperation} from "@/models/recurrent-operation";
|
||||||
|
import {recurrentsService} from "@/services/recurrents-service";
|
||||||
|
|
||||||
|
export const useRecurrentsStore = defineStore('recurrents', () => {
|
||||||
|
const recurrents = ref<RecurrentOperation[]>([])
|
||||||
|
const isLoading = ref(false)
|
||||||
|
|
||||||
|
const fetchRecurrents = async (spaceId: number) => {
|
||||||
|
isLoading.value = true
|
||||||
|
try {
|
||||||
|
recurrents.value = await recurrentsService.fetchRecurrents(spaceId)
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const addRecurrent = (recurrent: RecurrentOperation) => {
|
||||||
|
recurrents.value.push(recurrent)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
recurrents,
|
||||||
|
isLoading,
|
||||||
|
fetchRecurrents,
|
||||||
|
addRecurrent
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -4,7 +4,6 @@ import { fileURLToPath, URL } from 'node:url'
|
|||||||
|
|
||||||
export default defineConfig(async ({mode}) => {
|
export default defineConfig(async ({mode}) => {
|
||||||
const env = loadEnv(mode, process.cwd(), '')
|
const env = loadEnv(mode, process.cwd(), '')
|
||||||
console.log('🚀 Running Vite in mode:', mode)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
plugins: [
|
plugins: [
|
||||||
|
|||||||
Reference in New Issue
Block a user