Skip to content

Commit

Permalink
feat: budget only for current month
Browse files Browse the repository at this point in the history
  • Loading branch information
begprod committed Aug 6, 2024
1 parent 9866a69 commit 09ec37d
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 16 deletions.
26 changes: 17 additions & 9 deletions src/components/BaseExpensesList/BaseExpensesList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,20 @@
<div class="flex">
<div class="mr-2 font-bold">Monthly budget:</div>
<div data-testid="monthly-budget">
{{ getAllDaysByMonthId(month.id).length * dailyBudget }}
{{
getAllDaysByMonthId(month.id).length * getMonthlyDailyBudget[month.id].dailyBudget
}}
</div>
</div>
<div class="font-bold" data-testid="monthly-percents">
{{ countProgressPercentage(month.id) }}%
{{ countProgressPercentage(month.id, getMonthlyDailyBudget[month.id].dailyBudget) }}%
</div>
</div>
<BaseProgressBar :percentage="countProgressPercentage(month.id)" />
<BaseProgressBar
:percentage="
countProgressPercentage(month.id, getMonthlyDailyBudget[month.id].dailyBudget)
"
/>
</div>
</div>
</template>
Expand Down Expand Up @@ -54,13 +60,15 @@
<div
class="text-xs lg:text-sm"
:class="{
'text-emerald-500': getDailyExpenses(day.id) <= dailyBudget,
'text-rose-500': getDailyExpenses(day.id) > dailyBudget,
'text-emerald-500':
getDailyExpenses(day.id) <= getMonthlyDailyBudget[month.id].dailyBudget,
'text-rose-500':
getDailyExpenses(day.id) > getMonthlyDailyBudget[month.id].dailyBudget,
hidden: getDailyExpenses(day.id) === 0,
}"
data-testid="daily-expenses"
>
{{ getDailyExpenses(day.id) }} / {{ dailyBudget }}
{{ getDailyExpenses(day.id) }} / {{ getMonthlyDailyBudget[month.id].dailyBudget }}
</div>
</div>
</template>
Expand Down Expand Up @@ -134,7 +142,7 @@ const expensesStore = useExpensesStore();
const { isAddExpenseInputVisible } = storeToRefs(commonStore);
const { expenses } = storeToRefs(expensesStore);
const { getActiveCurrency, dailyBudget } = storeToRefs(settingsStore);
const { getMonthlyDailyBudget, getActiveCurrency } = storeToRefs(settingsStore);
const { getCurrentMonths } = storeToRefs(calendarStore);
const { hideAddExpenseInput } = commonStore;
const { getAllDaysByMonthId, getDaysByMonthIdWidthOutFutureDays } = calendarStore;
Expand All @@ -144,15 +152,15 @@ const expense = ref('');
const isExpenseFieldHasError = ref(false);
const expenseSchema = number().integer().required().min(1);
const countProgressPercentage = (monthId: IMonth['id'] | undefined) => {
const countProgressPercentage = (monthId: IMonth['id'] | undefined, dailyBudget: number) => {
if (monthId === undefined) {
return 0;
}
const monthExpensesCounter = getMonthlyExpenses(monthId);
return Math.round(
(monthExpensesCounter / (getAllDaysByMonthId(monthId).length * dailyBudget.value)) * 100,
(monthExpensesCounter / (getAllDaysByMonthId(monthId).length * dailyBudget)) * 100,
);
};
Expand Down
5 changes: 5 additions & 0 deletions src/components/layouts/BaseLayout/BaseLayout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
</template>
<script setup lang="ts">
import { onBeforeMount } from 'vue';
import { storeToRefs } from 'pinia';
import BaseHeader from '@/components/layouts/partials/BaseHeader/BaseHeader.vue';
import BaseFooter from '@/components/layouts/partials/BaseFooter/BaseFooter.vue';
Expand All @@ -35,4 +36,8 @@ const { setToast } = commonStore;
const clearToast = () => {
setToast({ type: 'default', message: '', duration: 0 });
};
onBeforeMount(() => {
clearToast();
});
</script>
1 change: 0 additions & 1 deletion src/stores/calendar/calendar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ export const useCalendarStore = defineStore('calendar', {
state: (): ICalendarStore => ({
months: [],
days: [],
shouldGenerateNextMonth: false,
}),

getters: {
Expand Down
33 changes: 32 additions & 1 deletion src/stores/settings/settings.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { IMonth } from '@/types';
import type { ISettingsStore, ICurrency } from '@/types';
import { defineStore } from 'pinia';
import { useLocalStorage } from '@vueuse/core';
import { generateMonths } from '@/helpers';

export const useSettingsStore = defineStore('settings', {
state: (): ISettingsStore => ({
Expand Down Expand Up @@ -32,15 +34,35 @@ export const useSettingsStore = defineStore('settings', {
},
]),
dailyBudget: useLocalStorage('budget.it:daily', 500),
monthlyDailyBudget: useLocalStorage('budget.it:monthlyDailyBudget', {}),
}),

getters: {
getMonthlyDailyBudget(state): Record<string, { dailyBudget: number; isCurrent: boolean }> {
return state.monthlyDailyBudget;
},
getActiveCurrency(state): ICurrency {
return state.currencies.filter((currency: ICurrency) => currency.isActive)[0];
},
},

actions: {
initMonthlyDailyBudgetObject() {
if (Object.keys(this.monthlyDailyBudget).length !== 0) {
return;
}

const monthsList = generateMonths(5);
const nextMonth = generateMonths(0, 1);
const allMonths = [...nextMonth, ...monthsList];

allMonths.forEach((month: IMonth) => {
this.monthlyDailyBudget[month.id] = {
dailyBudget: this.dailyBudget,
isCurrent: month.isCurrent,
};
});
},
setActiveCurrency(name: ICurrency['name']) {
this.currencies = this.currencies.map((currency: ICurrency) => {
currency.isActive = currency.name === name;
Expand All @@ -49,7 +71,16 @@ export const useSettingsStore = defineStore('settings', {
});
},
setDailyBudget(value: number) {
this.dailyBudget = value;
const currentMonth = Object.keys(this.monthlyDailyBudget).find(
(key: string) => this.monthlyDailyBudget[key].isCurrent,
);

if (!currentMonth) {
throw new Error('Current month not found');
}

this.dailyBudget = Number(value);
this.monthlyDailyBudget[currentMonth].dailyBudget = Number(value);
},
addNewCurrency(name: ICurrency['name']) {
this.currencies.push({
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export interface IExpense {
export interface ISettingsStore {
currencies: RemovableRef<Array<ICurrency>>;
dailyBudget: RemovableRef<number>;
monthlyDailyBudget: RemovableRef<Record<string, { dailyBudget: number; isCurrent: boolean }>>;
}

export interface ICurrency {
Expand Down
18 changes: 13 additions & 5 deletions src/views/SettingsView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<div class="mb-7 pt-4 text-2xl text-slate-700 font-bold select-none">Settings</div>

<div class="mb-10">
<div class="mb-3 text-slate-500 select-none">Daily budget</div>
<div class="mb-3 text-slate-500 select-none">Current month daily budget</div>

<BaseFormBar @submit="submitDailyBudget(dailyBudgetInput.value)">
<template #input>
Expand Down Expand Up @@ -80,7 +80,7 @@
</template>

<script setup lang="ts">
import { reactive, watch } from 'vue';
import { reactive, watch, onBeforeMount } from 'vue';
import { storeToRefs } from 'pinia';
import { number, string } from 'yup';
import { PlusIcon, CheckIcon } from '@heroicons/vue/24/outline';
Expand All @@ -96,9 +96,13 @@ const commonStore = useCommonStore();
const settingsStore = useSettingsStore();
const { setToast } = commonStore;
const { setDailyBudget, addNewCurrency, dailyBudget } = settingsStore;
const { initMonthlyDailyBudgetObject, setDailyBudget, addNewCurrency, dailyBudget } = settingsStore;
const { currencies } = storeToRefs(settingsStore);
onBeforeMount(() => {
initMonthlyDailyBudgetObject();
});
const dailyBudgetInput = reactive({
value: dailyBudget,
isError: false,
Expand All @@ -125,10 +129,14 @@ const submitDailyBudget = (budget: number) => {
dailyBudgetInput.isError = false;
setToast({ type: 'success', message: 'Daily budget updated', duration: 5 });
} catch (error) {
} catch (error: any) {
dailyBudgetInput.isError = true;
setToast({ type: 'error', message: 'Enter an integer greater than 9', duration: 5 });
setToast({
type: 'error',
message: error.message || 'Enter an integer greater than 9',
duration: 5,
});
}
};
Expand Down

0 comments on commit 09ec37d

Please sign in to comment.