173 lines
6.5 KiB
Vue
173 lines
6.5 KiB
Vue
<script setup lang="ts">
|
||
import {computed, onMounted, onUnmounted, ref} from "vue";
|
||
import BudgetTransactionView from "@/components/budgets/BudgetTransactionView.vue";
|
||
import IconField from "primevue/iconfield";
|
||
import InputIcon from "primevue/inputicon";
|
||
import InputText from "primevue/inputtext";
|
||
|
||
import {getTransactions, getTransactionTypes} from "@/services/transactionService";
|
||
import {Transaction} from "@/models/Transaction";
|
||
import ProgressSpinner from "primevue/progressspinner";
|
||
import {getUsers} from "@/services/userService";
|
||
import Button from "primevue/button";
|
||
import { EventBus } from '@/utils/eventBus';
|
||
|
||
const loading = ref(false);
|
||
const searchText = ref("");
|
||
const transactions = ref<Transaction[]>([]);
|
||
const limit = 20; // Количество транзакций на одну загрузку
|
||
const offset = ref(0); // Начальное смещение
|
||
const allLoaded = ref(false); // Флаг для отслеживания окончания данных
|
||
|
||
// Функция для получения транзакций с параметрами limit и offset
|
||
const fetchTransactions = async (reload) => {
|
||
console.log("here")
|
||
console.log(allLoaded.value)
|
||
// if (loading.value || allLoaded.value) return; // Останавливаем загрузку, если уже загружается или данные загружены полностью
|
||
loading.value = true;
|
||
|
||
try {
|
||
console.log(reload);
|
||
const response = await getTransactions('INSTANT', null, null, selectedUserId.value ? selectedUserId.value : null, null, reload ? offset.value : limit, reload ? 0 : offset.value);
|
||
const newTransactions = response.data;
|
||
|
||
// Проверка на конец данных
|
||
if (newTransactions.length < limit) {
|
||
allLoaded.value = true; // Если данных меньше limit, значит, достигнут конец
|
||
}
|
||
|
||
// Добавляем новые транзакции к текущему списку
|
||
|
||
reload ? transactions.value = newTransactions : transactions.value.push(...newTransactions)
|
||
offset.value += limit; // Обновляем смещение для следующей загрузки
|
||
} catch (error) {
|
||
console.error("Error fetching transactions:", error);
|
||
}
|
||
|
||
loading.value = false;
|
||
};
|
||
const switchUserFilter = async (user) => {
|
||
if (selectedUserId.value == user.id) {
|
||
selectedUserId.value = null
|
||
} else if (selectedUserId.value == null) {
|
||
selectedUserId.value = user.id;
|
||
} else {
|
||
selectedUserId.value = user.id;
|
||
}
|
||
|
||
await getTransactions('INSTANT', null, null, selectedUserId.value, null, offset.value, 0)
|
||
.then(it => transactions.value = it.data)
|
||
|
||
}
|
||
|
||
|
||
|
||
const tgname = computed(() => {
|
||
if (window.Telegram.WebApp) {
|
||
const tg = window.Telegram.WebApp;
|
||
return tg.initDataUnsafe.user;
|
||
}
|
||
});
|
||
|
||
// Отфильтрованные транзакции по поисковому запросу
|
||
const filteredTransactions = computed(() => {
|
||
// Проверяем, есть ли текст поиска
|
||
const search = searchText.value.trim().toLowerCase();
|
||
|
||
if (!search) {
|
||
// Если текст поиска пуст, возвращаем все транзакции
|
||
return transactions.value;
|
||
}
|
||
|
||
// Проверяем наличие данных
|
||
if (!transactions.value || !Array.isArray(transactions.value)) {
|
||
console.warn("Transactions is not a valid array");
|
||
return [];
|
||
}
|
||
|
||
// Фильтруем транзакции по тексту поиска
|
||
return transactions.value.filter(transaction => {
|
||
return transaction.comment.toLowerCase().includes(search) ||
|
||
transaction.category.name.toLowerCase().includes(search);
|
||
});
|
||
});
|
||
|
||
|
||
// Обработчик прокрутки для ленивой загрузки
|
||
// const handleScroll = () => {
|
||
// const bottomReached = window.innerHeight + window.scrollY >= document.documentElement.scrollHeight - 2000;
|
||
// if (bottomReached && !loading.value) {
|
||
// fetchTransactions(); // Загружаем следующую страницу
|
||
// }
|
||
// };
|
||
|
||
const users = ref([])
|
||
const selectedUserId = ref(null)
|
||
const fetchUsers = async () => {
|
||
users.value = await getUsers();
|
||
}
|
||
|
||
const selectedTransactionType = ref(null)
|
||
const types = ref([])
|
||
onMounted(async () => {
|
||
EventBus.on('transactions-updated', fetchTransactions);
|
||
await fetchTransactions(); // Первоначальная загрузка данных
|
||
await fetchUsers();
|
||
await getTransactionTypes().then( it => types.value = it.data);
|
||
// window.addEventListener("scroll", handleScroll); // Добавляем обработчик прокрутки
|
||
});
|
||
|
||
onUnmounted( async () => {
|
||
EventBus.off('transactions-updated', fetchTransactions);
|
||
})
|
||
|
||
</script>
|
||
|
||
<template>
|
||
<div class="px-4 bg-gray-100 h-full">
|
||
<h2 class="text-4xl mb-6 font-bold">Transaction list</h2>
|
||
<div class="flex flex-col gap-2">
|
||
<IconField>
|
||
<InputIcon class="pi pi-search"/>
|
||
<InputText v-model="searchText" placeholder="Search"></InputText>
|
||
</IconField>
|
||
<div class="flex flex-row gap-2">
|
||
<!-- <span v-for="user in users">{{user.id}}</span>-->
|
||
<button v-for="user in users" @click="switchUserFilter(user)"
|
||
class="rounded-xl border p-1 bg-white border-gray-300 mb-2 min-w-fit px-2"
|
||
:class="selectedUserId == user.id ? '!bg-blue-100' : ''">
|
||
|
||
<p><span class="text-sm font-bold">{{ user.firstName }}</span></p>
|
||
</button>
|
||
|
||
|
||
<!-- <button v-for="type in types" class="rounded-xl border p-1 bg-white border-gray-300 mb-2 min-w-fit px-2">-->
|
||
<!-- <p><span class="text-sm font-bold">{{ type.name }}</span></p>-->
|
||
<!-- </button>-->
|
||
</div>
|
||
<div class="flex flex-col gap-2">
|
||
|
||
<BudgetTransactionView
|
||
v-for="transaction in filteredTransactions"
|
||
:key="transaction.id"
|
||
:transaction="transaction"
|
||
:is-list="true"
|
||
@transaction-updated="fetchTransactions(true)"
|
||
@delete-transaction="fetchTransactions(true)"
|
||
/>
|
||
<div class="flex items-center justify-center px-2 py-1 mb-5">
|
||
<Button @click="fetchTransactions(false)">Загрузить следующие...</Button>
|
||
</div>
|
||
<!-- Показать спиннер загрузки, если идет загрузка -->
|
||
<ProgressSpinner v-if="loading" class="mb-4" style="width: 50px; height: 50px;"
|
||
strokeWidth="8"
|
||
fill="transparent"
|
||
animationDuration=".5s"/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<style scoped>
|
||
</style>
|