categories search
This commit is contained in:
@@ -1,10 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {useSpaceStore} from "@/stores/spaceStore";
|
import {useSpaceStore} from "@/stores/spaceStore";
|
||||||
import {computed, onMounted, ref} from "vue";
|
import {onMounted, ref} from "vue";
|
||||||
import {Checkbox, Divider} from "primevue";
|
import {Checkbox, Divider} from "primevue";
|
||||||
import {useToast} from "primevue/usetoast";
|
import {useToast} from "primevue/usetoast";
|
||||||
import {Transaction} from "@/models/transaction";
|
import {Transaction, UpdateTransactionDTO} from "@/models/transaction";
|
||||||
import {TransactionService} from "@/services/transactions-service";
|
import {TransactionFilters, TransactionService} from "@/services/transactions-service";
|
||||||
import {formatAmount, formatDate} from "@/utils/utils";
|
import {formatAmount, formatDate} from "@/utils/utils";
|
||||||
import {useRouter} from "vue-router";
|
import {useRouter} from "vue-router";
|
||||||
import {TransactionKind} from "@/models/enums";
|
import {TransactionKind} from "@/models/enums";
|
||||||
@@ -15,39 +15,105 @@ const router = useRouter();
|
|||||||
const spaceStore = useSpaceStore()
|
const spaceStore = useSpaceStore()
|
||||||
const toolbar = useToolbarStore()
|
const toolbar = useToolbarStore()
|
||||||
const transactionService = TransactionService
|
const transactionService = TransactionService
|
||||||
const transactions = ref<Transaction[]>([])
|
|
||||||
const groupedTransactions = computed(() => {
|
|
||||||
const planned: Transaction[] = []
|
|
||||||
const instant: Transaction[] = []
|
|
||||||
|
|
||||||
for (const tx of transactions.value) {
|
const showIsDone = ref(false)
|
||||||
if (tx.kind === TransactionKind.PLANNING) planned.push(tx)
|
|
||||||
else if (tx.kind === TransactionKind.INSTANT) instant.push(tx)
|
|
||||||
}
|
|
||||||
|
|
||||||
return { planned, instant }
|
const setTransactionDone = async (transaction: Transaction): Promise<void> => {
|
||||||
})
|
const updateTransaction = {
|
||||||
|
type: transaction.type,
|
||||||
const plannedTransactions = computed(() => groupedTransactions.value.planned)
|
kind: transaction.kind,
|
||||||
const instantTransactions = computed(() => groupedTransactions.value.instant)
|
categoryId: transaction.category.id,
|
||||||
|
comment: transaction.comment,
|
||||||
|
amount: transaction.amount,
|
||||||
const fetchData = async () => {
|
fees: 0,
|
||||||
if (spaceStore.selectedSpaceId) {
|
isDone: true,
|
||||||
|
date: new Date(transaction.date),
|
||||||
|
} as UpdateTransactionDTO
|
||||||
try {
|
try {
|
||||||
console.log('hereeeee ')
|
await transactionService.updateTransaction(spaceStore.selectedSpaceId as number, transaction.id, updateTransaction)
|
||||||
transactions.value = await transactionService.getTransactions(spaceStore.selectedSpaceId);
|
} catch (error) {
|
||||||
} catch (e) {
|
|
||||||
toast.add({
|
toast.add({
|
||||||
severity: "error",
|
severity: 'error',
|
||||||
summary: "Failed to load transactions.",
|
summary: 'Failed to update transactions.',
|
||||||
detail: e,
|
detail: String(error),
|
||||||
life: 3000,
|
life: 3000,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const plannedTransactions = ref<Transaction[]>([])
|
||||||
|
const plannedOffset = ref(0)
|
||||||
|
const plannedLimit = ref(10)
|
||||||
|
const plannedLastBatch = ref(false)
|
||||||
|
|
||||||
|
const instantTransactions = ref<Transaction[]>([])
|
||||||
|
const instantOffset = ref(0)
|
||||||
|
const instantLimit = ref(10)
|
||||||
|
const instantLastBatch = ref(false)
|
||||||
|
|
||||||
|
const fetchMorePlanned = async () => {
|
||||||
|
plannedOffset.value += plannedLimit.value
|
||||||
|
await fetchData(true, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fetchMoreInstant = async () => {
|
||||||
|
instantOffset.value += instantLimit.value
|
||||||
|
await fetchData(false, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchData = async (fetchPlanned: boolean = true, fetchInstant: boolean = true, replace: boolean = false) => {
|
||||||
|
if (!spaceStore.selectedSpaceId) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Готовим промисы
|
||||||
|
const plannedPromise: Promise<Transaction[]> =
|
||||||
|
fetchPlanned
|
||||||
|
? transactionService.getTransactions(spaceStore.selectedSpaceId, {
|
||||||
|
kind: TransactionKind.PLANNING,
|
||||||
|
isDone: showIsDone.value ? undefined : false,
|
||||||
|
offset: plannedOffset.value,
|
||||||
|
limit: plannedLimit.value,
|
||||||
|
} as TransactionFilters) // никаких `as TransactionFilters`, если поля опциональные
|
||||||
|
: Promise.resolve(plannedTransactions.value)
|
||||||
|
|
||||||
|
const instantPromise: Promise<Transaction[]> =
|
||||||
|
fetchInstant
|
||||||
|
? transactionService.getTransactions(spaceStore.selectedSpaceId, {
|
||||||
|
kind: TransactionKind.INSTANT,
|
||||||
|
offset: instantOffset.value,
|
||||||
|
limit: instantLimit.value,
|
||||||
|
} as TransactionFilters)
|
||||||
|
: Promise.resolve(instantTransactions.value)
|
||||||
|
|
||||||
|
const [planned, instant] = await Promise.all([plannedPromise, instantPromise])
|
||||||
|
|
||||||
|
if (replace) {
|
||||||
|
|
||||||
|
// Если хочешь просто перезаписывать
|
||||||
|
plannedTransactions.value = planned
|
||||||
|
instantTransactions.value = instant
|
||||||
|
} else {
|
||||||
|
// Если хочешь "подгружать ещё" (пагинация, load more):
|
||||||
|
if (fetchPlanned) {
|
||||||
|
plannedTransactions.value = [...plannedTransactions.value, ...planned]
|
||||||
|
if (planned.length < plannedLimit.value) plannedLastBatch.value = true
|
||||||
|
}
|
||||||
|
if (fetchInstant) {
|
||||||
|
instantTransactions.value = [...instantTransactions.value, ...instant]
|
||||||
|
if (instant.length < instantLimit.value) instantLastBatch.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
toast.add({
|
||||||
|
severity: 'error',
|
||||||
|
summary: 'Failed to load transactions.',
|
||||||
|
detail: String(e),
|
||||||
|
life: 3000,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await fetchData()
|
await fetchData()
|
||||||
toolbar.registerHandler('openTransactionCreation', () => {
|
toolbar.registerHandler('openTransactionCreation', () => {
|
||||||
@@ -63,21 +129,30 @@ onMounted(async () => {
|
|||||||
</div>
|
</div>
|
||||||
<div v-else class="flex flex-col gap-6 pb-10">
|
<div v-else class="flex flex-col gap-6 pb-10">
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
|
<div class="flex flex-row justify-between">
|
||||||
<span class="text-xl !font-semibold !pl-2">Planned transactions</span>
|
<span class="text-xl !font-semibold !pl-2">Planned transactions</span>
|
||||||
|
<div class="flex flex-row gap-2 items-center">
|
||||||
|
<Checkbox v-model="showIsDone" binary value=" Показывать выполненные" @change="fetchData(true, false, true)"/>
|
||||||
|
Показывать выполненные
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="flex card">
|
<div class="flex card">
|
||||||
<span v-if="plannedTransactions.length==0">Looks like you haven't plan any transactions yet. <router-link
|
<span v-if="plannedTransactions.length==0">Looks like you haven't plan any transactions yet. <router-link
|
||||||
to="/transactions/create" class="!text-blue-400">Try to create some.</router-link></span>
|
to="/transactions/create" class="!text-blue-400">Try to create some.</router-link></span>
|
||||||
<div v-else v-for="key in plannedTransactions.keys()" :key="plannedTransactions[key].id"
|
<div v-else v-for="key in plannedTransactions.keys()" :key="plannedTransactions[key].id"
|
||||||
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 flex-row w-full items-center gap-4">
|
<div class="flex flex-row w-full items-center gap-4">
|
||||||
<Checkbox v-model="plannedTransactions[key].isDone" binary class="text-3xl">
|
<Checkbox v-model="plannedTransactions[key].isDone" binary class="text-3xl"
|
||||||
|
@change="setTransactionDone(plannedTransactions[key])">
|
||||||
{{ plannedTransactions[key].category.icon }}
|
{{ plannedTransactions[key].category.icon }}
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
<div class="flex !flex-row !justify-between !w-full"
|
<div class="flex !flex-row !justify-between !w-full"
|
||||||
@click="router.push(`/transactions/${plannedTransactions[key].id}/edit`)">
|
@click="router.push(`/transactions/${plannedTransactions[key].id}/edit`)">
|
||||||
<div class="flex flex-row items-center gap-2">
|
<div class="flex flex-row items-center gap-2">
|
||||||
<div class="flex flex-col !font-bold "> {{ plannedTransactions[key].comment }}
|
<div class="flex flex-col !font-bold "> {{ plannedTransactions[key].comment }}
|
||||||
<div class="flex flex-row text-sm">{{ plannedTransactions[key].category.name }}</div>
|
<div class="flex flex-row text-sm">{{ plannedTransactions[key].category.icon }}
|
||||||
|
{{ plannedTransactions[key].category.name }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-row gap-2 items-center !w-fit">
|
<div class="flex flex-row gap-2 items-center !w-fit">
|
||||||
@@ -92,6 +167,7 @@ onMounted(async () => {
|
|||||||
<Divider v-if="key+1 !== plannedTransactions.length" class="!m-0 !py-3"/>
|
<Divider v-if="key+1 !== plannedTransactions.length" class="!m-0 !py-3"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<button v-if="!plannedLastBatch" class="card w-fit " @click="fetchMorePlanned">Load more...</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
<span class="text-xl !font-semibold !pl-2">Instant transactions</span>
|
<span class="text-xl !font-semibold !pl-2">Instant transactions</span>
|
||||||
@@ -103,10 +179,14 @@ onMounted(async () => {
|
|||||||
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 flex-row w-full items-center justify-between">
|
<div class="flex flex-row w-full items-center justify-between">
|
||||||
<div class="flex flex-row items-center gap-2 ">
|
<div class="flex flex-row items-center gap-2 ">
|
||||||
<span v-if="instantTransactions[key].category" class="text-3xl"> {{ instantTransactions[key].category.icon }}</span>
|
<span v-if="instantTransactions[key].category" class="text-3xl"> {{
|
||||||
|
instantTransactions[key].category.icon
|
||||||
|
}}</span>
|
||||||
<i v-else class="pi pi-question !text-3xl"/>
|
<i v-else class="pi pi-question !text-3xl"/>
|
||||||
<div class="flex flex-col !font-bold "> {{ instantTransactions[key].comment }}
|
<div class="flex flex-col !font-bold "> {{ instantTransactions[key].comment }}
|
||||||
<div v-if="instantTransactions[key].category" class="flex flex-row text-sm">{{ instantTransactions[key].category.name }}</div>
|
<div v-if="instantTransactions[key].category" class="flex flex-row text-sm">
|
||||||
|
{{ instantTransactions[key].category.name }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-row gap-2 items-center">
|
<div class="flex flex-row gap-2 items-center">
|
||||||
@@ -120,6 +200,8 @@ onMounted(async () => {
|
|||||||
<Divider v-if="key+1 !== instantTransactions.length" class="!m-0 !py-3"/>
|
<Divider v-if="key+1 !== instantTransactions.length" class="!m-0 !py-3"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<button v-if="!instantLastBatch" class="card w-fit " @click="fetchMoreInstant">Load more...</button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -12,10 +12,19 @@ function toDateOnly(d: Date): string {
|
|||||||
return `${y}-${m}-${day}`;
|
return `${y}-${m}-${day}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TransactionFilters{
|
||||||
|
type : TransactionType | null
|
||||||
|
kind: TransactionKind | null
|
||||||
|
dateFrom: string | Date | null
|
||||||
|
dateTo: string | Date | null
|
||||||
|
isDone: boolean | null
|
||||||
|
offset: number | null
|
||||||
|
limit: number | null
|
||||||
|
}
|
||||||
|
|
||||||
async function getTransactions(spaceId: number): Promise<Transaction[]> {
|
async function getTransactions(spaceId: number, filters: TransactionFilters): Promise<Transaction[]> {
|
||||||
try {
|
try {
|
||||||
let response = await api.get(`/spaces/${spaceId}/transactions`);
|
let response = await api.post(`/spaces/${spaceId}/transactions/_search`, filters );
|
||||||
return response.data;
|
return response.data;
|
||||||
}catch (error) {
|
}catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
|||||||
Reference in New Issue
Block a user