added vue-bootstrap
added income/expense input added Frequency enum Signed-off-by: Pascal Syma <pascal@syma.dev>
This commit is contained in:
+3
-3
@@ -2,11 +2,11 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<title>expense</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<body class="py-4">
|
||||
<div id="app" class="container"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Generated
+121
@@ -166,6 +166,66 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@nuxt/opencollective": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@nuxt/opencollective/-/opencollective-0.3.2.tgz",
|
||||
"integrity": "sha512-XG7rUdXG9fcafu9KTDIYjJSkRO38EwjlKYIb5TQ/0WDbiTUTtUtgncMscKOYzfsY86kGs05pAuMOR+3Fi0aN3A==",
|
||||
"requires": {
|
||||
"chalk": "^4.1.0",
|
||||
"consola": "^2.15.0",
|
||||
"node-fetch": "^2.6.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"requires": {
|
||||
"color-convert": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
|
||||
"integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
|
||||
"requires": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"requires": {
|
||||
"color-name": "~1.1.4"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"requires": {
|
||||
"has-flag": "^4.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@popperjs/core": {
|
||||
"version": "2.9.2",
|
||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.9.2.tgz",
|
||||
"integrity": "sha512-VZMYa7+fXHdwIq1TDhSXoVmSPEGM/aa+6Aiq3nVVJ9bXr24zScr+NlKFKC3iPljA7ho/GAZr+d2jOf5GIRC30Q=="
|
||||
},
|
||||
"@types/json5": {
|
||||
"version": "0.0.29",
|
||||
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
|
||||
@@ -2018,6 +2078,23 @@
|
||||
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
|
||||
"dev": true
|
||||
},
|
||||
"bootstrap": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.0.tgz",
|
||||
"integrity": "sha512-Io55IuQY3kydzHtbGvQya3H+KorS/M9rSNyfCGCg9WZ4pyT/lCxIlpJgG1GXW/PswzC84Tr2fBYi+7+jFVQQBw=="
|
||||
},
|
||||
"bootstrap-vue": {
|
||||
"version": "2.21.2",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap-vue/-/bootstrap-vue-2.21.2.tgz",
|
||||
"integrity": "sha512-0Exe+4MZysqhZNXIKf4TzkvXaupxh9EHsoCRez0o5Dc0J7rlafayOEwql63qXv74CgZO8E4U8ugRNJko1vMvNw==",
|
||||
"requires": {
|
||||
"@nuxt/opencollective": "^0.3.2",
|
||||
"bootstrap": ">=4.5.3 <5.0.0",
|
||||
"popper.js": "^1.16.1",
|
||||
"portal-vue": "^2.1.7",
|
||||
"vue-functional-data-merge": "^3.1.0"
|
||||
}
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
@@ -2901,6 +2978,11 @@
|
||||
"integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==",
|
||||
"dev": true
|
||||
},
|
||||
"consola": {
|
||||
"version": "2.15.3",
|
||||
"resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz",
|
||||
"integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw=="
|
||||
},
|
||||
"console-browserify": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz",
|
||||
@@ -5319,6 +5401,15 @@
|
||||
"jest-regex-util": "^22.4.3"
|
||||
}
|
||||
},
|
||||
"exports-loader": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/exports-loader/-/exports-loader-2.0.0.tgz",
|
||||
"integrity": "sha512-k/VFrVEUmotfkk8vZ+njG5NEXpr5Ee+BonV+AYINV2hNo3o+/UB8nEuCUQk2k6IyWIoobmXoTFO0igxrQcMV4Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"source-map": "^0.6.1"
|
||||
}
|
||||
},
|
||||
"express": {
|
||||
"version": "4.17.1",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
|
||||
@@ -7867,6 +7958,11 @@
|
||||
"merge-stream": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"jquery": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz",
|
||||
"integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw=="
|
||||
},
|
||||
"js-base64": {
|
||||
"version": "2.6.4",
|
||||
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz",
|
||||
@@ -8707,6 +8803,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
|
||||
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
|
||||
},
|
||||
"node-forge": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
|
||||
@@ -9405,6 +9506,16 @@
|
||||
"integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==",
|
||||
"dev": true
|
||||
},
|
||||
"popper.js": {
|
||||
"version": "1.16.1",
|
||||
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz",
|
||||
"integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ=="
|
||||
},
|
||||
"portal-vue": {
|
||||
"version": "2.1.7",
|
||||
"resolved": "https://registry.npmjs.org/portal-vue/-/portal-vue-2.1.7.tgz",
|
||||
"integrity": "sha512-+yCno2oB3xA7irTt0EU5Ezw22L2J51uKAacE/6hMPMoO/mx3h4rXFkkBkT4GFsMDv/vEe8TNKC3ujJJ0PTwb6g=="
|
||||
},
|
||||
"portfinder": {
|
||||
"version": "1.0.28",
|
||||
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
|
||||
@@ -14425,6 +14536,11 @@
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-2.6.12.tgz",
|
||||
"integrity": "sha512-uhmLFETqPPNyuLLbsKz6ioJ4q7AZHzD8ZVFNATNyICSZouqP2Sz0rotWQC8UNBF6VGSCs5abnKJoStA6JbCbfg=="
|
||||
},
|
||||
"vue-enums": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-enums/-/vue-enums-1.0.0.tgz",
|
||||
"integrity": "sha512-fCLmWRSzl6O7e9BkQ+aFdrWpvIxLlNIWswjvvCLkzsCQ4/nSCVrRd7Tr+9/651d1FGOe5v3fuPIFVP6Cjsv+0Q=="
|
||||
},
|
||||
"vue-eslint-parser": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-2.0.3.tgz",
|
||||
@@ -14456,6 +14572,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"vue-functional-data-merge": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-functional-data-merge/-/vue-functional-data-merge-3.1.0.tgz",
|
||||
"integrity": "sha512-leT4kdJVQyeZNY1kmnS1xiUlQ9z1B/kdBFCILIjYYQDqZgLqCLa0UhjSSeRX6c3mUe6U5qYeM8LrEqkHJ1B4LA=="
|
||||
},
|
||||
"vue-hot-reload-api": {
|
||||
"version": "2.3.4",
|
||||
"resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz",
|
||||
|
||||
+8
-1
@@ -13,7 +13,13 @@
|
||||
"build": "node build/build.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^2.5.2"
|
||||
"@popperjs/core": "^2.9.2",
|
||||
"bootstrap": "^4.6.0",
|
||||
"bootstrap-vue": "^2.21.2",
|
||||
"jquery": "^3.6.0",
|
||||
"popper.js": "^1.16.1",
|
||||
"vue": "^2.5.2",
|
||||
"vue-enums": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^7.1.2",
|
||||
@@ -41,6 +47,7 @@
|
||||
"eslint-plugin-promise": "^3.4.0",
|
||||
"eslint-plugin-standard": "^3.0.1",
|
||||
"eslint-plugin-vue": "^4.0.0",
|
||||
"exports-loader": "^2.0.0",
|
||||
"extract-text-webpack-plugin": "^3.0.0",
|
||||
"file-loader": "^1.1.4",
|
||||
"friendly-errors-webpack-plugin": "^1.6.1",
|
||||
|
||||
+81
-10
@@ -1,28 +1,99 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<img src="./assets/logo.png">
|
||||
<HelloWorld/>
|
||||
<div id="app" class="container">
|
||||
<b-row class="results">
|
||||
<b-col sm="12" offset-md="1" md="10">
|
||||
<b-card header="Result" title="Special title treatment">
|
||||
<b-card-text>With supporting text below as a natural lead-in to additional content.</b-card-text>
|
||||
<p>Income: {{ calculated.yearly.in | currency }}</p>
|
||||
<p>Expenses: {{ calculated.yearly.out | currency }}</p>
|
||||
<p>Profit: <span :class="calculated.yearly.sum < 0 ? 'text-danger' : 'text-success'">{{ calculated.yearly.sum | currency }}</span></p>
|
||||
<!-- <b-button variant="primary" size="lg" @click="calculate">Calculate</b-button>-->
|
||||
</b-card>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<b-row class="inputs">
|
||||
<Input title="Income" color="success" :entries="income" />
|
||||
<Input title="Expenses" color="danger" :entries="expenses" />
|
||||
</b-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import HelloWorld from './components/HelloWorld'
|
||||
import Input from './components/Input'
|
||||
import Frequency from './enums/Frequency'
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
Input,
|
||||
HelloWorld
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
income: [],
|
||||
expenses: [],
|
||||
calculated: {
|
||||
yearly: {
|
||||
in: 0,
|
||||
out: 0,
|
||||
sum: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const storage = localStorage.getItem('expenses')
|
||||
if (storage) {
|
||||
try {
|
||||
const storageObj = JSON.parse(storage)
|
||||
if (storageObj.expenses && storageObj.income) {
|
||||
this.$set(this, 'expenses', storageObj.expenses)
|
||||
this.$set(this, 'income', storageObj.income)
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
|
||||
this.calculate()
|
||||
},
|
||||
watch: {
|
||||
income: {
|
||||
deep: true,
|
||||
handler: 'calculate'
|
||||
},
|
||||
expenses: {
|
||||
deep: true,
|
||||
handler: 'calculate'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
calculate () {
|
||||
const storage = JSON.stringify({expenses: this.expenses, income: this.income})
|
||||
localStorage.setItem('expenses', storage)
|
||||
|
||||
let calc = {
|
||||
in: 0,
|
||||
out: 0,
|
||||
sum: 0
|
||||
}
|
||||
|
||||
calc.in = [...this.income.map(i => Frequency.byId(i.frequency).interval * parseFloat(i.amount)), ...this.income.filter(i => i.frequency === 0).map(i => parseFloat(i.amount))].reduce((c, v) => c + v, 0)
|
||||
calc.out = [...this.expenses.map(i => Frequency.byId(i.frequency).interval * parseFloat(i.amount)), ...this.expenses.filter(i => i.frequency === 0).map(i => parseFloat(i.amount))].reduce((c, v) => c + v, 0)
|
||||
|
||||
calc.sum = calc.in - calc.out
|
||||
|
||||
this.$set(this.calculated, 'yearly', calc)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
#app {
|
||||
font-family: 'Avenir', Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-align: center;
|
||||
color: #2c3e50;
|
||||
margin-top: 60px;
|
||||
body {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.inputs {
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
<template>
|
||||
<b-col md="6">
|
||||
<b-card no-body>
|
||||
<b-card-header :header-bg-variant="color" header-text-variant="white" class="container-fluid">
|
||||
<b-row>
|
||||
<b-col md="10">
|
||||
<h3 class="w-75 p-3">{{ title }}</h3>
|
||||
</b-col>
|
||||
<b-col md="2" class="float-right align-self-center">
|
||||
<b-button @click="add()" variant="primary" size="lg"><b-icon-plus /></b-button>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</b-card-header>
|
||||
<b-card-body>
|
||||
<b-table :fields="fields" :items="data" responsive="sm" v-model="currentItems">
|
||||
<template #cell(index)="data">
|
||||
{{ data.index + 1 }}
|
||||
</template>
|
||||
|
||||
<template #cell(options)="data">
|
||||
<b-button-group size="sm">
|
||||
<b-button @click="toggleDetails(data)" v-b-tooltip.hover :title="data.detailsShowing ? 'Cancel' : 'Edit'" :variant="data.detailsShowing ? 'outline-danger' : 'primary'">
|
||||
<b-icon-x-square v-if="data.detailsShowing" />
|
||||
<b-icon-pencil-square v-else />
|
||||
</b-button>
|
||||
<b-button @click="askDelete(data)" v-b-tooltip.hover title="Remove" variant="danger"><b-icon-trash /></b-button>
|
||||
</b-button-group>
|
||||
</template>
|
||||
|
||||
<template #cell()="data">
|
||||
{{ data.value }}
|
||||
</template>
|
||||
|
||||
<template #cell(amount)="data">
|
||||
{{ data.item.amount | currency }}
|
||||
</template>
|
||||
|
||||
<template #cell(frequency)="data">
|
||||
{{ $enums.Frequency.byId(data.item.frequency).name }}
|
||||
</template>
|
||||
|
||||
<template #row-details="row">
|
||||
<b-card>
|
||||
<b-form @submit.prevent="save(row)">
|
||||
<b-form-group
|
||||
id="name-group"
|
||||
label="Name:"
|
||||
label-for="name">
|
||||
<b-form-input
|
||||
id="name"
|
||||
v-model="editingCache.name"
|
||||
type="text"
|
||||
placeholder="Name"
|
||||
required></b-form-input>
|
||||
</b-form-group>
|
||||
|
||||
<b-form-group
|
||||
id="amount-group"
|
||||
label="Amount:"
|
||||
label-for="amount">
|
||||
<b-input-group append="€" class="mb-2 mr-sm-2 mb-sm-0">
|
||||
<b-form-input
|
||||
id="amount"
|
||||
v-model="editingCache.amount"
|
||||
type="number"
|
||||
placeholder="0,00"
|
||||
step="0.01"
|
||||
min="0.01"
|
||||
required></b-form-input>
|
||||
</b-input-group>
|
||||
</b-form-group>
|
||||
|
||||
<b-form-group
|
||||
id="frequency-group"
|
||||
label="Frequency:"
|
||||
label-for="frequency">
|
||||
<b-form-select
|
||||
id="frequency"
|
||||
v-model="editingCache.frequency"
|
||||
type="text"
|
||||
:options="$enums.Frequency.options()"
|
||||
required></b-form-select>
|
||||
</b-form-group>
|
||||
|
||||
<b-button type="submit" variant="success"><b-icon-check /> Save</b-button>
|
||||
</b-form>
|
||||
</b-card>
|
||||
</template>
|
||||
</b-table>
|
||||
</b-card-body>
|
||||
</b-card>
|
||||
</b-col>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from 'vue'
|
||||
import Frequency from '../enums/Frequency'
|
||||
|
||||
export default {
|
||||
name: 'Input',
|
||||
enums: {
|
||||
Frequency
|
||||
},
|
||||
props: [
|
||||
'title',
|
||||
'color',
|
||||
'entries'
|
||||
],
|
||||
data () {
|
||||
return {
|
||||
fields: [
|
||||
{
|
||||
key: 'index',
|
||||
label: '#'
|
||||
},
|
||||
'name',
|
||||
'amount',
|
||||
'frequency',
|
||||
{
|
||||
key: 'options',
|
||||
label: ''
|
||||
}
|
||||
],
|
||||
data: [],
|
||||
currentItems: [],
|
||||
editingCache: undefined,
|
||||
editing: undefined
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.$set(this, 'data', this.$props.entries)
|
||||
},
|
||||
methods: {
|
||||
add () {
|
||||
this.data.push({
|
||||
name: '',
|
||||
amount: 1.00,
|
||||
frequency: 0
|
||||
})
|
||||
|
||||
this.toggleDetails({index: this.data.length - 1, toggleDetails: () => {}})
|
||||
},
|
||||
askDelete (row) {
|
||||
// ask before deletion
|
||||
this.$bvModal.msgBoxConfirm(`Please confirm that you want to delete '${row.item.name}'?`, {
|
||||
title: 'Are you sure?',
|
||||
size: 'sm',
|
||||
buttonSize: 'sm',
|
||||
okVariant: 'danger',
|
||||
okTitle: 'Yes',
|
||||
cancelTitle: 'No',
|
||||
footerClass: 'p-2',
|
||||
hideHeaderClose: false,
|
||||
centered: true
|
||||
})
|
||||
.then(confirmedDelete => {
|
||||
if (!confirmedDelete) return
|
||||
this.data.splice(row.index, 1)
|
||||
})
|
||||
},
|
||||
save (row) {
|
||||
// override active data with from cache
|
||||
this.$set(this.data, row.index, this.editingCache)
|
||||
this.toggleDetails(row)
|
||||
},
|
||||
toggleDetails (row) {
|
||||
// close all open details
|
||||
this.currentItems.forEach((item, i) => {
|
||||
if (i === row.index) return
|
||||
this.$set(item, '_showDetails', false)
|
||||
})
|
||||
|
||||
// create (or reset) local copy for form data
|
||||
if (row.detailsShowing) {
|
||||
this.editingCache = undefined
|
||||
} else {
|
||||
this.editingCache = Vue.util.extend({}, row.item)
|
||||
}
|
||||
|
||||
row.toggleDetails()
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
data: {
|
||||
deep: true,
|
||||
handler () {
|
||||
this.$emit('input', this.data)
|
||||
}
|
||||
},
|
||||
entries: {
|
||||
deep: true,
|
||||
handler () {
|
||||
this.$set(this, 'data', this.$props.entries)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* highlight selected row */
|
||||
.b-table-has-details {
|
||||
background: var(--dark);
|
||||
color: var(--white);
|
||||
}
|
||||
.b-table-has-details + tr {
|
||||
background: var(--dark);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,36 @@
|
||||
class Frequency {
|
||||
constructor (name, interval) {
|
||||
this.name = name
|
||||
this.interval = interval
|
||||
}
|
||||
}
|
||||
|
||||
Frequency.ONCE = new Frequency('Once', 0)
|
||||
Frequency.YEARLY = new Frequency('Yearly', 1)
|
||||
Frequency.BIMONTHLY = new Frequency('Bi-Monthly', 6)
|
||||
Frequency.MONTHLY = new Frequency('Monthly', 12)
|
||||
Frequency.BIWEEKLY = new Frequency('Bi-Weekly', 26)
|
||||
Frequency.WEEKLY = new Frequency('Weekly', 52)
|
||||
Frequency.DAILY = new Frequency('Daily', 52 * 7)
|
||||
|
||||
Frequency.byId = id => {
|
||||
try { return Frequency[Object.keys(Frequency)[id]] } catch (e) { return Frequency.ONCE }
|
||||
}
|
||||
|
||||
Frequency.values = () => {
|
||||
let keys = Object.keys(Frequency)
|
||||
keys.splice(-3, 3)
|
||||
|
||||
return keys.map(k => Frequency[k])
|
||||
}
|
||||
|
||||
Frequency.options = () => {
|
||||
return Frequency.values().map((f, i) => {
|
||||
return {
|
||||
value: i,
|
||||
text: f.name
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default Frequency
|
||||
+25
@@ -1,7 +1,32 @@
|
||||
// The Vue build version to load with the `import` command
|
||||
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
|
||||
import Vue from 'vue'
|
||||
import enums from 'vue-enums'
|
||||
import App from './App'
|
||||
import { BootstrapVue, IconsPlugin } from 'bootstrap-vue'
|
||||
|
||||
import 'bootstrap/dist/js/bootstrap'
|
||||
import 'bootstrap/dist/css/bootstrap.min.css'
|
||||
import 'bootstrap-vue/dist/bootstrap-vue.css'
|
||||
|
||||
Vue.use(enums, {namespace: '$enums'})
|
||||
|
||||
// Make BootstrapVue available throughout your project
|
||||
Vue.use(BootstrapVue)
|
||||
// Optionally install the BootstrapVue icon components plugin
|
||||
Vue.use(IconsPlugin)
|
||||
|
||||
Vue.filter('currency', function (value) {
|
||||
if (typeof value !== 'number') {
|
||||
try {
|
||||
value = parseFloat(value)
|
||||
} catch (e) {
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
return `${value.toFixed(2)} €`
|
||||
})
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
|
||||
Reference in New Issue
Block a user