Skip to content

Commit

Permalink
Added tag management, some fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
isKONSTANTIN committed Aug 2, 2024
1 parent 1bb589f commit 415f22c
Show file tree
Hide file tree
Showing 18 changed files with 946 additions and 71 deletions.
11 changes: 6 additions & 5 deletions components/analytics/pie.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

<div class="text-sm breadcrumbs pl-3 mt-2 bg-base-200 rounded-xl">
<ul>
<li><a @click="resetView(); buildChart();">Root</a></li>
<li><a @click="resetView(); buildChart();">{{$t("tagsPage.root")}}</a></li>
<li v-if="view.length > 0" v-for="item in view"><a @click="cutUnder(item); buildChart();"> {{tagsMap.get(item).tag.name}} </a></li>
</ul>
</div>
Expand Down Expand Up @@ -81,7 +81,7 @@ const tagsMap = $transactionsTagsApi.getTagsTreeMap();
const view = ref([]);
const tags = $transactionsTagsApi.getTags();
const analytics = ref();
const analytics = ref([]);
const pushToView = (tagId) => {
view.value.push(tagId);
Expand Down Expand Up @@ -121,7 +121,7 @@ const chartMap = ref({});
const getDays = () => {
return {
first: mode.value ? new Date(date.value.year, date.value.month, 1) : new Date(date.value, 0, 1),
last: mode.value ? new Date(date.value.year, date.value.month + 1, 1) : new Date(date.value + 1, 0, 1)
last: mode.value ? new Date(date.value.year, date.value.month + 1, 0, 23,59,59, 999) : new Date(date.value + 1, 0, 0, 23,59,59, 999)
}
}
Expand Down Expand Up @@ -159,7 +159,7 @@ const formatter = (value) => {
return (props.sign > 0 ? "" : "-") + formatAmount(value);
}
const childsSum = (allData, tagObject, currencyId, sign) => {
const childsSum = (allData, tagObject, sign) => {
let sum = 0;
tagObject.childs.forEach(t => {
Expand All @@ -169,6 +169,7 @@ const childsSum = (allData, tagObject, currencyId, sign) => {
if (t.childs && t.childs.length > 0) {
sum += childsSum(allData, t, sign);
}
})
return sum;
Expand Down Expand Up @@ -243,7 +244,7 @@ const buildChart = () => {
if (tagDelta * sign < 0)
tagDelta = 0;
const sum = tagDelta + (isParent ? 0 : childsSum(allData, tag, currency.value, sign));
const sum = tagDelta + (isParent ? 0 : childsSum(allData, tag, sign));
if (sum === 0)
return;
Expand Down
143 changes: 143 additions & 0 deletions components/analytics/tagsAnalytics.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
<template>
<div v-if="data.length > 0" class="flex flex-wrap gap-2 h-min" :class="{'panel' : props.needPanelStyle}">
<div v-for="d of data" :key="d.id" class="flex flex-col border rounded-xl p-3 pb-2 pt-1 gap-1 lg:w-full flex-1 justify-between" :class="'border-' + d.status">
<div class="flex gap-1 items-center justify-center 2xl:flex-wrap">
<p class="font-bold text-sm truncate">
{{tagsMap.get(d.tagId).name}}
</p>

<div class="badge badge-outline badge-sm">
{{ currenciesMap.get(d.currencyId).symbol }}
</div>
</div>

<div class="text-center flex flex-col">
<p class="font-bold text-sm text-nowrap 2xl:text-wrap">
{{ formatAmount(Math.abs(d.delta), d.currencyId) }} / {{ formatAmount(Math.abs(d.expected), d.currencyId) }}
</p>
<progress class="progress w-full"
:class="'progress-' + d.status"
:value="d.percent"
max="1"
/>
</div>
</div>
</div>
<div v-else class="w-full template-border flex items-center justify-center text-center rounded-xl h-min p-4">
<p class="font-bold opacity-50">{{ props.emptyMessage || $t("mainPage.tags.emptyMessage") }}</p>
</div>
</template>

<script setup>
const { t, locale } = useI18n();
const props = defineProps({
date: {
type: Date,
required: false,
default: new Date()
},
onlyRoot: {
type: Boolean,
required: false,
default: false
},
onlyExpanses: {
type: Boolean,
required: false,
default: false
},
hideLowPercent: {
type: Boolean,
required: false,
default: false
},
emptyMessage: {
type: String,
required: false
},
needPanelStyle: {
type: Boolean,
required: false,
default: true
}
})
const { $analyticsApi, $transactionsTagsApi, $tagsManagementApi, $currenciesApi, $serverConfigs, $transactionsApi } = useNuxtApp();
const data = ref([]);
const tagsTree = $transactionsTagsApi.getTagsTree();
const tagsMap = $transactionsTagsApi.getTagsMap();
const currenciesMap = $currenciesApi.getCurrenciesMap();
const managementMap = $tagsManagementApi.getManagementsMap();
const formatAmount = (delta, currencyId) => {
const currency = currenciesMap.value.get(currencyId);
const formatter = Intl.NumberFormat(locale.value, {
minimumFractionDigits: 0,
maximumFractionDigits: currency.decimals
});
return formatter.format(delta);
}
const fetchData = async () => {
const fetched = await $analyticsApi.getTagAnalytics(props.date);
const newData = [];
for (const entry of fetched) {
const expected = managementMap.value.get(entry.managementId).amount
if (expected > 0 && props.onlyExpanses || props.onlyRoot && !tagsTree.value.find(t => t.tag.tagId === entry.tagId))
continue;
let percent = Math.max(Math.min(entry.delta / expected, 1), 0);
if (expected > 0)
percent = 1 - percent;
let status = "success";
if (percent >= 0.85) {
status = "error"
}else if (percent >= 0.5) {
status = "warning"
}
if (props.hideLowPercent && percent < 0.1)
continue;
newData.push({
id: entry.managementId,
tagId: entry.tagId,
currencyId: entry.currencyId,
delta: entry.delta,
expected: expected,
percent: percent,
status: status,
});
}
data.value = newData.sort((a, b) => b.percent - a.percent);
}
$transactionsApi.registerUpdateListener(() => {
fetchData();
})
watch([() => props.date, () => props.onlyRoot], () => {
fetchData();
})
</script>

<style scoped>
.panel {
@apply p-2;
}
</style>
2 changes: 1 addition & 1 deletion components/analytics/tagsByMonths.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const tagsMap = $transactionsTagsApi.getTagsMap();
const filter = ref();
const chartSeries = ref([]);
const type = ref('area');
const type = ref('bar');
const chartOptions = ref({});
Expand Down
159 changes: 159 additions & 0 deletions components/misc/tagsManagementSummary.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
<template>
<div class="flex gap-2 w-full flex-col sm:flex-row">
<div class="stats shadow w-full" v-if="expectIncome.length > 0">
<div class="stat" v-for="m in expectIncome.filter(m => m.dateType == 0)">
<div class="stat-title">{{ currenciesMap.get(m.currencyId).code }}</div>
<div class="stat-value text-success"> +{{ formatDelta(m.amount, m.currencyId) }} </div>
<div class="stat-desc">
{{ capitalizeFirstLetter($t("tagsPage.table.management.dateTypes.perMonth")) }}

<template v-if="m.showMax">
<br>
{{ $t("tagsPage.tagsSummary.maxContribution") }}: {{ tagsMap.get(m.maxTag).name.toLocaleLowerCase() }}, {{ formatDelta(m.maxAmount, m.currencyId) }}
</template>
</div>
</div>

<div class="stat" v-for="m in expectIncome.filter(m => m.dateType == 1)">
<div class="stat-title">{{ currenciesMap.get(m.currencyId).code }}</div>
<div class="stat-value text-success"> +{{ formatDelta(m.amount, m.currencyId) }} </div>
<div class="stat-desc">
{{ capitalizeFirstLetter($t("tagsPage.table.management.dateTypes.perQuartal")) }}

<template v-if="m.showMax">
<br>
{{ $t("tagsPage.tagsSummary.maxContribution") }}: {{ tagsMap.get(m.maxTag).name.toLocaleLowerCase() }}, {{ formatDelta(m.maxAmount, m.currencyId) }}
</template>
</div>
</div>
</div>
<div v-else class="w-full template-border flex items-center justify-center text-center rounded-xl min-h-24">
<p class="font-bold opacity-50">{{ $t("tagsPage.tagsSummary.noData.income") }}</p>
</div>

<div class="stats shadow w-full" v-if="expectExpanses.length > 0">
<div class="stat" v-for="m in expectExpanses.filter(m => m.dateType == 0)">
<div class="stat-title">{{ currenciesMap.get(m.currencyId).code }}</div>
<div class="stat-value text-error"> {{ formatDelta(m.amount, m.currencyId) }} </div>
<div class="stat-desc">
{{ capitalizeFirstLetter($t("tagsPage.table.management.dateTypes.perMonth")) }}

<template v-if="m.showMax">
<br>
{{ $t("tagsPage.tagsSummary.maxContribution") }}: {{ tagsMap.get(m.maxTag).name.toLocaleLowerCase() }}, {{ formatDelta(m.maxAmount, m.currencyId) }}
</template>
</div>
</div>

<div class="stat" v-for="m in expectExpanses.filter(m => m.dateType == 1)">
<div class="stat-title">{{ currenciesMap.get(m.currencyId).code }}</div>
<div class="stat-value text-error"> {{ formatDelta(m.amount, m.currencyId) }} </div>
<div class="stat-desc">
{{ capitalizeFirstLetter($t("tagsPage.table.management.dateTypes.perQuartal")) }}

<template v-if="m.showMax">
<br>
{{ $t("tagsPage.tagsSummary.maxContribution") }}: {{ tagsMap.get(m.maxTag).name.toLocaleLowerCase() }}, {{ formatDelta(m.maxAmount, m.currencyId) }}
</template>
</div>
</div>
</div>
<div v-else class="w-full template-border flex items-center justify-center text-center rounded-xl min-h-24">
<p class="font-bold opacity-50">{{ $t("tagsPage.tagsSummary.noData.expanse") }}</p>
</div>
</div>
</template>

<script setup>
const { t, locale } = useI18n();
const { $transactionsTagsApi, $tagsManagementApi, $currenciesApi } = useNuxtApp();
const managements = $tagsManagementApi.getManagements();
const currenciesMap = $currenciesApi.getCurrenciesMap();
const tagsMap = $transactionsTagsApi.getTagsMap();
const expectIncome = ref([]);
const expectExpanses = ref([]);
const formatDelta = (delta, currencyId) => {
const currency = currenciesMap.value.get(currencyId);
const formatter = Intl.NumberFormat(locale.value, {
style: 'currency',
currency: currency.code,
minimumFractionDigits: 2,
maximumFractionDigits: currency.decimals
});
return formatter.format(delta).replace(currency.code + " ", currency.symbol).replace(" " + currency.code, " " + currency.symbol);
}
const capitalizeFirstLetter = (string) => {
return string.charAt(0).toUpperCase() + string.slice(1);
}
const calculate = () => {
expectIncome.value = [];
expectExpanses.value = [];
managements.value.forEach((value) => {
if (value.amount > 0) {
const income = expectIncome.value.find((m) => m.currencyId == value.currencyId && m.dateType == value.dateType);
if (income) {
income.showMax = true;
income.amount += value.amount;
if (value.amount > income.maxAmount) {
income.maxAmount = value.amount;
income.maxTag = value.tagId;
}
}else {
expectIncome.value.push({
maxTag: value.tagId,
maxAmount: value.amount,
showMax: false,
amount: value.amount,
currencyId: value.currencyId,
dateType: value.dateType,
});
}
}else {
const expanse = expectExpanses.value.find((m) => m.currencyId == value.currencyId && m.dateType == value.dateType);
if (expanse) {
expanse.showMax = true;
expanse.amount += value.amount;
if (value.amount < expanse.maxAmount) {
expanse.maxAmount = value.amount;
expanse.maxTag = value.tagId;
}
}else {
expectExpanses.value.push({
maxTag: value.tagId,
maxAmount: value.amount,
showMax: false,
amount: value.amount,
currencyId: value.currencyId,
dateType: value.dateType,
});
}
}
})
}
watch(managements, () => {
calculate();
}, {deep: true})
calculate();
</script>

<style scoped>
</style>
Loading

0 comments on commit 415f22c

Please sign in to comment.