feat: Introduce DashboardWeek and WeekCategory models to display pre-calculated weekly expense data in dashboard charts.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue';
|
||||
import Chart from 'primevue/chart';
|
||||
import { DashboardCategory } from '@/models/dashboard';
|
||||
import { DashboardCategory, DashboardWeek } from '@/models/dashboard';
|
||||
import { Transaction } from '@/models/transaction';
|
||||
import { TransactionType } from '@/models/enums';
|
||||
import { formatAmount } from '@/utils/utils';
|
||||
@@ -13,6 +13,7 @@ dayjs.extend(isoWeek);
|
||||
const props = defineProps<{
|
||||
categories: DashboardCategory[];
|
||||
transactions: Transaction[];
|
||||
weeks: DashboardWeek[];
|
||||
}>();
|
||||
|
||||
const chartType = ref<'category' | 'weekly'>('category');
|
||||
@@ -84,56 +85,14 @@ const getCategoryColor = (index: number) => {
|
||||
};
|
||||
|
||||
// --- Weekly Chart Logic ---
|
||||
interface WeekData {
|
||||
label: string;
|
||||
start: dayjs.Dayjs;
|
||||
end: dayjs.Dayjs;
|
||||
amount: number;
|
||||
transactions: Transaction[];
|
||||
}
|
||||
|
||||
const weeklyData = computed(() => {
|
||||
const weeks: WeekData[] = [];
|
||||
// Generate last 4 weeks
|
||||
for (let i = 3; i >= 0; i--) {
|
||||
const startOfWeek = dayjs().subtract(i, 'week').startOf('isoWeek');
|
||||
const endOfWeek = dayjs().subtract(i, 'week').endOf('isoWeek');
|
||||
weeks.push({
|
||||
label: `${startOfWeek.format('D MMM')} - ${endOfWeek.format('D MMM')}`,
|
||||
start: startOfWeek,
|
||||
end: endOfWeek,
|
||||
amount: 0,
|
||||
transactions: []
|
||||
});
|
||||
}
|
||||
|
||||
// Filter expense transactions from the transactions prop
|
||||
const expenseTransactions = props.transactions;
|
||||
|
||||
expenseTransactions.forEach(t => {
|
||||
const tDate = dayjs(t.date);
|
||||
const week = weeks.find(w => tDate.isAfter(w.start.subtract(1, 'second')) && tDate.isBefore(w.end.add(1, 'second')));
|
||||
if (week) {
|
||||
week.amount += t.amount;
|
||||
week.transactions.push(t);
|
||||
}
|
||||
});
|
||||
|
||||
// Sort transactions by amount descending
|
||||
weeks.forEach(week => {
|
||||
week.transactions.sort((a, b) => b.amount - a.amount);
|
||||
});
|
||||
|
||||
return weeks;
|
||||
});
|
||||
|
||||
const weeklyChartData = computed(() => {
|
||||
return {
|
||||
labels: weeklyData.value.map(w => w.label),
|
||||
labels: props.weeks.map(w => `${dayjs(w.startDate).format('D MMM')} - ${dayjs(w.endDate).format('D MMM')}`),
|
||||
datasets: [
|
||||
{
|
||||
label: 'Expenses',
|
||||
data: weeklyData.value.map(w => w.amount),
|
||||
data: props.weeks.map(w => w.expenseSum),
|
||||
backgroundColor: '#3b82f6',
|
||||
borderRadius: 8
|
||||
}
|
||||
@@ -232,27 +191,28 @@ const weeklyChartOptions = computed(() => {
|
||||
|
||||
<template v-else>
|
||||
<div class="flex flex-col gap-4">
|
||||
<div v-for="week in weeklyData" :key="week.label" class="flex flex-col gap-2">
|
||||
<div v-for="week in props.weeks" :key="week.startDate.toString()" class="flex flex-col gap-2">
|
||||
<div class="flex items-center justify-between p-2 bg-surface-50 dark:bg-surface-800 rounded-lg">
|
||||
<span class="font-medium text-surface-700 dark:text-surface-200">{{ week.label }}</span>
|
||||
<span class="font-semibold text-surface-900 dark:text-surface-0">{{ formatAmount(week.amount) }}
|
||||
<span class="font-medium text-surface-700 dark:text-surface-200">{{
|
||||
dayjs(week.startDate).format('D MMM') }} - {{ dayjs(week.endDate).format('D MMM') }}</span>
|
||||
<span class="font-semibold text-surface-900 dark:text-surface-0">{{ formatAmount(week.expenseSum) }}
|
||||
₽</span>
|
||||
</div>
|
||||
|
||||
<!-- Transactions List -->
|
||||
<!-- Categories List -->
|
||||
<div
|
||||
class="flex flex-col gap-1 pl-2 border-l-2 border-surface-100 dark:border-surface-700 ml-2 h-fit">
|
||||
<div v-for="tx in week.transactions.slice(0, 5)" :key="tx.id"
|
||||
<div v-for="cat in week.categories.slice(0, 5)" :key="cat.categoryId"
|
||||
class="flex items-center justify-between py-1 px-2 text-sm hover:bg-surface-50 dark:hover:bg-surface-800 rounded transition-colors">
|
||||
<div class="flex items-center gap-2 overflow-hidden">
|
||||
<span class="text-lg">{{ tx.category.icon }}</span>
|
||||
<span class="text-surface-600 dark:text-surface-300 truncate">{{ tx.category.name }}</span>
|
||||
<span class="text-lg">{{ cat.categoryIcon }}</span>
|
||||
<span class="text-surface-600 dark:text-surface-300 truncate">{{ cat.categoryName }}</span>
|
||||
</div>
|
||||
<span class="font-medium text-surface-900 dark:text-surface-100 whitespace-nowrap">{{
|
||||
formatAmount(tx.amount) }} ₽</span>
|
||||
cat.sum ? formatAmount(cat.sum) : 0 }} ₽</span>
|
||||
</div>
|
||||
<div v-if="week.transactions.length > 5" class="text-xs text-surface-400 pl-2 pt-1">
|
||||
+{{ week.transactions.length - 5 }} more
|
||||
<div v-if="week.categories.length > 5" class="text-xs text-surface-400 pl-2 pt-1">
|
||||
+{{ week.categories.length - 5 }} more
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -161,7 +161,8 @@ const userName = computed(() => {
|
||||
<!-- Charts & Upcoming -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-1 gap-4">
|
||||
<!-- Charts -->
|
||||
<DashboardCharts :categories="dashboardData.categories" :transactions="dashboardTransactions" />
|
||||
<DashboardCharts :categories="dashboardData.categories" :transactions="dashboardTransactions"
|
||||
:weeks="dashboardData.weeks" />
|
||||
|
||||
<!-- Upcoming Transactions -->
|
||||
<div class=" ">
|
||||
|
||||
@@ -8,6 +8,21 @@ export interface DashboardData {
|
||||
categories: DashboardCategory[],
|
||||
upcomingTransactions: Transaction[],
|
||||
recentTransactions: Transaction[],
|
||||
weeks: DashboardWeek[],
|
||||
}
|
||||
|
||||
export interface DashboardWeek {
|
||||
startDate: Date,
|
||||
endDate: Date,
|
||||
expenseSum: number,
|
||||
categories: WeekCategory[],
|
||||
}
|
||||
|
||||
export interface WeekCategory {
|
||||
categoryId: number,
|
||||
categoryName: string,
|
||||
categoryIcon: string
|
||||
sum: number,
|
||||
}
|
||||
|
||||
export interface DashboardCategory {
|
||||
@@ -17,3 +32,4 @@ export interface DashboardCategory {
|
||||
changeDiff: number,
|
||||
changeDiffPercentage: number,
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user