238 lines
6.3 KiB
Vue
238 lines
6.3 KiB
Vue
<template>
|
|
<div class="p-3">
|
|
<div
|
|
v-if="
|
|
!isLoading &&
|
|
data !== null &&
|
|
accounts.length > 0 &&
|
|
categories.length > 0
|
|
"
|
|
>
|
|
<div class="d-flex">
|
|
<Filters
|
|
v-model:account="account"
|
|
v-model:date-from="dateFrom"
|
|
v-model:date-to="dateTo"
|
|
:accounts="accounts"
|
|
@update="refresh"
|
|
/>
|
|
|
|
<div class="ms-auto">
|
|
<BButton @click="toggleMode()" variant="none">
|
|
<i class="fa-solid fa-gear"></i>
|
|
</BButton>
|
|
</div>
|
|
</div>
|
|
|
|
<Draggable v-model="config" class="row" handle=".handle" @change="refresh()">
|
|
<transition-group>
|
|
<div
|
|
v-for="(item, key) in config"
|
|
:key="key"
|
|
class="component mb-4 col-12"
|
|
:class="componentClasses(item)"
|
|
>
|
|
<div
|
|
v-if="mode === 'edit'"
|
|
class="mb-3 d-flex justify-content-beetween"
|
|
>
|
|
<BButton variant="none" size="sm" class="handle">
|
|
<i class="fa-solid fa-up-down-left-right"></i>
|
|
</BButton>
|
|
<BButtonGroup size="sm" class="d-sm-none d-md-block">
|
|
<BButton
|
|
v-for="i in [
|
|
{size: 3, label: '1'},
|
|
{size: 6, label: '2'},
|
|
{size: 9, label: '3'},
|
|
{size: 12, label: '4'},
|
|
]"
|
|
:variant="i.size == config[key].size ? 'primary' : 'secondary'"
|
|
@click="config[key].size = i.size"
|
|
>{{ i.label }}</BButton>
|
|
</BButtonGroup>
|
|
</div>
|
|
|
|
<Capital
|
|
v-if="item.component === 'Capital'"
|
|
:data="data"
|
|
:date-from="dateFrom"
|
|
:date-to="dateTo"
|
|
/>
|
|
<SavingAccounts
|
|
v-if="item.component === 'SavingAccounts'"
|
|
:data="savingAccounts"
|
|
/>
|
|
<Distribution
|
|
v-if="item.component === 'Distribution'"
|
|
:data="data"
|
|
:categories="categories"
|
|
:date-from="dateFrom"
|
|
:date-to="dateTo"
|
|
/>
|
|
<DiffCreditDebit
|
|
v-if="item.component === 'DiffCreditDebit'"
|
|
:data="data"
|
|
:date-from="dateFrom"
|
|
:date-to="dateTo"
|
|
/>
|
|
<MonthThresholds
|
|
v-if="item.component === 'MonthThresholds'"
|
|
:data="monthThresholdsData()"
|
|
:date-from="dateFrom"
|
|
:date-to="dateTo"
|
|
/>
|
|
</div>
|
|
</transition-group>
|
|
</Draggable>
|
|
</div>
|
|
<div v-else>Chargement...</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import {ref, reactive, onMounted, watch} from 'vue'
|
|
import {compute as monthThresholds} from '../chart/monthThreshold'
|
|
import {getStorage, saveStorage} from '../lib/storage'
|
|
import {BButtonGroup, BButton} from 'bootstrap-vue-next'
|
|
import Filters from './../components/dashboard/Filters.vue'
|
|
import Capital from './../components/dashboard/Capital.vue'
|
|
import SavingAccounts from './../components/dashboard/SavingAccounts.vue'
|
|
import Distribution from './../components/dashboard/Distribution.vue'
|
|
import MonthThresholds from './../components/dashboard/MonthThresholds.vue'
|
|
import DiffCreditDebit from './../components/dashboard/DiffCreditDebit.vue'
|
|
import { VueDraggableNext as Draggable } from 'vue-draggable-next'
|
|
|
|
const data = ref(null)
|
|
const isLoading = ref(true)
|
|
|
|
const accounts = ref([])
|
|
const categories = ref([])
|
|
const savingAccounts = ref([])
|
|
|
|
const mode = ref('view')
|
|
|
|
const account = ref(getStorage(`dashboard:account`))
|
|
const dateFrom = ref(getStorage(`dashboard:dateFrom`))
|
|
const dateTo = ref(getStorage(`dashboard:dateTo`))
|
|
const config = reactive(
|
|
getStorage(`dashboard:config`, [
|
|
{component: 'Capital', size: 8},
|
|
{component: 'SavingAccounts', size: 4},
|
|
{component: 'Distribution', size: 12},
|
|
{component: 'DiffCreditDebit', size: 12},
|
|
{component: 'MonthThresholds', size: 12},
|
|
]),
|
|
)
|
|
|
|
let winWidth = 0
|
|
const _monthThresholdsData = ref(null)
|
|
const monthThresholdsData = () => {
|
|
if (_monthThresholdsData.value !== null) {
|
|
return _monthThresholdsData.value
|
|
}
|
|
|
|
_monthThresholdsData.value = monthThresholds(
|
|
data.value,
|
|
categories.value,
|
|
dateFrom.value,
|
|
dateTo.value,
|
|
)
|
|
|
|
return _monthThresholdsData.value
|
|
}
|
|
|
|
const toggleMode = () => {
|
|
mode.value = mode.value === 'edit' ? 'view' : 'edit'
|
|
}
|
|
|
|
const componentClasses = (item) => {
|
|
const data = [`col-md-${item.size}`]
|
|
|
|
if (mode.value === 'edit') {
|
|
data.push('editable')
|
|
}
|
|
|
|
return data
|
|
}
|
|
|
|
watch(dateFrom, (v) => saveStorage(`dashboard:dateFrom`, v))
|
|
watch(dateTo, (v) => saveStorage(`dashboard:dateTo`, v))
|
|
watch(account, (v) => saveStorage(`dashboard:account`, v))
|
|
watch(config, (v) => {
|
|
saveStorage(`dashboard:config`, v)
|
|
refresh()
|
|
})
|
|
|
|
window.addEventListener('resize', () => {
|
|
if (Math.abs(window.innerWidth - winWidth) < 20) {
|
|
return
|
|
}
|
|
|
|
winWidth = window.innerWidth
|
|
isLoading.value = true
|
|
window.setTimeout(() => {
|
|
isLoading.value = false
|
|
}, 500)
|
|
})
|
|
|
|
const refresh = () => {
|
|
let query = {
|
|
order: 'date',
|
|
sort: 'asc',
|
|
limit: 0,
|
|
}
|
|
|
|
isLoading.value = true
|
|
_monthThresholdsData.value = null
|
|
|
|
if (account.value) {
|
|
query['bank_account_id__eq'] = account.value
|
|
}
|
|
|
|
fetch(`/api/transaction?${new URLSearchParams(query)}`)
|
|
.then((response) => response.json())
|
|
.then((value) => {
|
|
data.value = value.rows.filter(
|
|
(row) => !row.category || row.category.ignore_transactions === false,
|
|
)
|
|
isLoading.value = false
|
|
})
|
|
}
|
|
|
|
onMounted(() => {
|
|
winWidth = window.innerWidth
|
|
|
|
refresh()
|
|
|
|
fetch('/api/category?order=label&sort=asc&ignore_transactions__eq=0')
|
|
.then((response) => response.json())
|
|
.then((data) => {
|
|
categories.value = data.rows
|
|
categories.value.push({id: -1, label: 'Sans catégorie', color: '#cccccc'})
|
|
})
|
|
|
|
fetch('/api/bank_account')
|
|
.then((response) => response.json())
|
|
.then((data) => {
|
|
accounts.value = data.rows
|
|
})
|
|
|
|
fetch('/api/saving_account')
|
|
.then((response) => response.json())
|
|
.then((data) => {
|
|
savingAccounts.value = data.rows
|
|
})
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.config {
|
|
width: 200px;
|
|
max-width: 100%;
|
|
}
|
|
|
|
.handle {
|
|
cursor: grab;
|
|
}
|
|
</style>
|