Compare commits
4 Commits
70f4107840
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| fb60c69846 | |||
| a5f4d75306 | |||
| fbb3909531 | |||
| 853d5111e2 |
@@ -176,13 +176,13 @@ onMounted(async () => {
|
|||||||
<div class="flex flex-row !w-full justify-between items-center">
|
<div class="flex flex-row !w-full justify-between items-center">
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<span>Google Drive</span>
|
<span>Google Drive</span>
|
||||||
<span class="text-xs text-gray-500" v-if="userStore.user?.isGoogleDriveLinked">Connected</span>
|
<span class="text-xs text-gray-500" v-if="userStore.user?.isGoogleDriveConnected">Connected</span>
|
||||||
<span class="text-xs text-gray-500" v-else>Not connected</span>
|
<span class="text-xs text-gray-500" v-else>Not connected</span>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
:label="userStore.user?.isGoogleDriveLinked ? 'Reconnect' : 'Connect'"
|
:label="userStore.user?.isGoogleDriveConnected? 'Reconnect' : 'Connect'"
|
||||||
:icon="userStore.user?.isGoogleDriveLinked ? 'pi pi-refresh' : 'pi pi-google'"
|
:icon="userStore.user?.isGoogleDriveConnected ? 'pi pi-refresh' : 'pi pi-google'"
|
||||||
:severity="userStore.user?.isGoogleDriveLinked ? 'secondary' : 'primary'"
|
:severity="userStore.user?.isGoogleDriveConnected ? 'secondary' : 'primary'"
|
||||||
size="small"
|
size="small"
|
||||||
@click="linkGoogleDrive"
|
@click="linkGoogleDrive"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -173,6 +173,31 @@ const fetchData = async (fetchPlanned: boolean = true, fetchInstant: boolean = t
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const downloadTransactions = async () => {
|
||||||
|
if (!spaceStore.selectedSpaceId) return
|
||||||
|
try {
|
||||||
|
await transactionService.exportTransactions(spaceStore.selectedSpaceId, {
|
||||||
|
query: searchQuery.value || null,
|
||||||
|
categoriesIds: selectedCategoryIds.value.length > 0 ? selectedCategoryIds.value : null,
|
||||||
|
dateFrom: filterDateFrom.value ? toDateOnly(filterDateFrom.value) : null,
|
||||||
|
dateTo: filterDateTo.value ? toDateOnly(filterDateTo.value) : null,
|
||||||
|
} as TransactionFilters)
|
||||||
|
toast.add({
|
||||||
|
severity: 'success',
|
||||||
|
summary: 'Success',
|
||||||
|
detail: 'Transactions exported successfully',
|
||||||
|
life: 3000,
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
toast.add({
|
||||||
|
severity: 'error',
|
||||||
|
summary: 'Failed to export transactions.',
|
||||||
|
detail: String(e),
|
||||||
|
life: 3000,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await fetchCategories()
|
await fetchCategories()
|
||||||
await fetchData()
|
await fetchData()
|
||||||
@@ -194,6 +219,7 @@ onMounted(async () => {
|
|||||||
<InputIcon class="pi pi-search"> </InputIcon>
|
<InputIcon class="pi pi-search"> </InputIcon>
|
||||||
<InputText v-model="searchQuery" placeholder="Search" class="!w-full !bg-white !text-left" />
|
<InputText v-model="searchQuery" placeholder="Search" class="!w-full !bg-white !text-left" />
|
||||||
</IconField>
|
</IconField>
|
||||||
|
<Button icon="pi pi-download" @click="downloadTransactions" text rounded aria-label="Download" />
|
||||||
<Button icon="pi pi-filter" @click="isFilterSheetVisible = true" text rounded aria-label="Filter" />
|
<Button icon="pi pi-filter" @click="isFilterSheetVisible = true" text rounded aria-label="Filter" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-row justify-between">
|
<div class="flex flex-row justify-between">
|
||||||
|
|||||||
@@ -5,5 +5,5 @@ export interface User {
|
|||||||
tgId: number
|
tgId: number
|
||||||
tdUserName: string;
|
tdUserName: string;
|
||||||
roles: string[];
|
roles: string[];
|
||||||
isGoogleDriveLinked?: boolean;
|
isGoogleDriveConnected?: boolean;
|
||||||
}
|
}
|
||||||
@@ -80,6 +80,36 @@ async function deleteTransaction(spaceId: number, txId: number): Promise<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TransactionService = {
|
async function exportTransactions(spaceId: number, filters: TransactionFilters): Promise<void> {
|
||||||
getTransactions, getTransaction, createTransaction, updateTransaction, deleteTransaction,
|
try {
|
||||||
|
let response = await api.post(`/spaces/${spaceId}/transactions/_export`, filters, {
|
||||||
|
responseType: 'blob'
|
||||||
|
});
|
||||||
|
|
||||||
|
const contentDisposition = response.headers['content-disposition'];
|
||||||
|
let fileName = `transactions_${spaceId}_${toDateOnly(new Date())}.csv`;
|
||||||
|
|
||||||
|
if (contentDisposition) {
|
||||||
|
const fileNameMatch = contentDisposition.match(/filename\*?=['"]?(?:UTF-8'')?([^; '"]+)['"]?/i);
|
||||||
|
if (fileNameMatch && fileNameMatch[1]) {
|
||||||
|
fileName = decodeURIComponent(fileNameMatch[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = window.URL.createObjectURL(response.data);
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = url;
|
||||||
|
link.setAttribute('download', fileName);
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
link.remove();
|
||||||
|
window.URL.revokeObjectURL(url);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TransactionService = {
|
||||||
|
getTransactions, getTransaction, createTransaction, updateTransaction, deleteTransaction, exportTransactions
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user