mirror of
https://github.com/chenasraf/cospend-nc.git
synced 2026-05-17 17:38:10 +00:00
add my cumulated balance in nav footer
Signed-off-by: Julien Veyssier <julien-nc@posteo.net>
This commit is contained in:
@@ -78,9 +78,6 @@ class PageController extends Controller {
|
||||
$this->initialStateService->provideInitialState('pathBillId', $billId ?? 0);
|
||||
$this->eventDispatcher->dispatchTyped(new RenderReferenceEvent());
|
||||
$response = new TemplateResponse('cospend', 'main');
|
||||
$csp = new ContentSecurityPolicy();
|
||||
$csp->allowEvalScript();
|
||||
$response->setContentSecurityPolicy($csp);
|
||||
return $response;
|
||||
}
|
||||
|
||||
|
||||
40
package-lock.json
generated
40
package-lock.json
generated
@@ -4888,9 +4888,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.12.tgz",
|
||||
"integrity": "sha512-LfPFB0zOeCeCNQV3i+67rcoVvoN5n0NVuR2vLG0O5ySQMgchuZlC4lgz546ZOJyDtj5KIgOxy+lacOimfqZAIA==",
|
||||
"version": "20.16.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.13.tgz",
|
||||
"integrity": "sha512-GjQ7im10B0labo8ZGXDGROUl9k0BNyDgzfGpb4g/cl+4yYDWVKcozANF4FGr4/p0O/rAkQClM6Wiwkije++1Tg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.19.2"
|
||||
@@ -7337,9 +7337,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.5.40",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.40.tgz",
|
||||
"integrity": "sha512-LYm78o6if4zTasnYclgQzxEcgMoIcybWOhkATWepN95uwVVWV0/IW10v+2sIeHE+bIYWipLneTftVyQm45UY7g==",
|
||||
"version": "1.5.41",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.41.tgz",
|
||||
"integrity": "sha512-dfdv/2xNjX0P8Vzme4cfzHqnPm5xsZXwsolTYr0eyW18IUmNyG08vL+fttvinTfhKfIKdRoqkDIC9e9iWQCNYQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/elliptic": {
|
||||
@@ -8152,9 +8152,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-vue": {
|
||||
"version": "9.29.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.29.0.tgz",
|
||||
"integrity": "sha512-hamyjrBhNH6Li6R1h1VF9KHfshJlKgKEg3ARbGTn72CMNDSMhWbgC7NdkRDEh25AFW+4SDATzyNM+3gWuZii8g==",
|
||||
"version": "9.29.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.29.1.tgz",
|
||||
"integrity": "sha512-MH/MbVae4HV/tM8gKAVWMPJbYgW04CK7SuzYRrlNERpxbO0P3+Zdsa2oAcFBW6xNu7W6lIkGOsFAMCRTYmrlWQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
@@ -13730,9 +13730,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/sass": {
|
||||
"version": "1.80.1",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.80.1.tgz",
|
||||
"integrity": "sha512-9lBwDZ7j3y/1DKj5Ec249EVGo5CVpwnzIyIj+cqlCjKkApLnzsJ/l9SnV4YnORvW9dQwQN+gQvh/mFZ8CnDs7Q==",
|
||||
"version": "1.80.3",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.80.3.tgz",
|
||||
"integrity": "sha512-ptDWyVmDMVielpz/oWy3YP3nfs7LpJTHIJZboMVs8GEC9eUmtZTZhMHlTW98wY4aEorDfjN38+Wr/XjskFWcfA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@parcel/watcher": "^2.4.1",
|
||||
@@ -14601,9 +14601,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/stylelint-scss": {
|
||||
"version": "6.8.0",
|
||||
"resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-6.8.0.tgz",
|
||||
"integrity": "sha512-6gjsCZ30UUF6ivjZB2Z+1lb6k0+JFa1uR2MgGbYu76xRjEfvNTpSS1nQim1Gom1ijFF9GzauOiq1Kr7zKptQOw==",
|
||||
"version": "6.8.1",
|
||||
"resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-6.8.1.tgz",
|
||||
"integrity": "sha512-al+5eRb72bKrFyVAY+CLWKUMX+k+wsDCgyooSfhISJA2exqnJq1PX1iIIpdrvhu3GtJgNJZl9/BIW6EVSMCxdg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
@@ -14611,7 +14611,7 @@
|
||||
"css-tree": "^3.0.0",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"known-css-properties": "^0.34.0",
|
||||
"mdn-data": "^2.0.30",
|
||||
"mdn-data": "^2.11.1",
|
||||
"postcss-media-query-parser": "^0.2.3",
|
||||
"postcss-resolve-nested-selector": "^0.1.6",
|
||||
"postcss-selector-parser": "^6.1.2",
|
||||
@@ -14624,6 +14624,14 @@
|
||||
"stylelint": "^16.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/stylelint-scss/node_modules/mdn-data": {
|
||||
"version": "2.11.1",
|
||||
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.11.1.tgz",
|
||||
"integrity": "sha512-Hdx3wmyqPFrhd6YHVuSkUK2eIGAcxR0xlndcgZqjA68yMJTbfXrjJwbgsBOsNjI7LnBIVUQnmyMVSdi/ob0GpQ==",
|
||||
"dev": true,
|
||||
"license": "CC0-1.0",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/stylelint/node_modules/balanced-match": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz",
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
{{ activity.subject }}
|
||||
</span>
|
||||
<span
|
||||
v-tooltip.top="{ content: formattedTime }"
|
||||
:title="formattedTime"
|
||||
class="time">
|
||||
{{ relativeTime }}
|
||||
</span>
|
||||
|
||||
@@ -67,6 +67,17 @@
|
||||
<PendingInvitationsModal v-if="!pageIsPublic && showPendingInvitations"
|
||||
:invitations="pendingInvitations"
|
||||
@close="showPendingInvitations = false" />
|
||||
<NcAppNavigationItem v-if="!pageIsPublic && showMyBalance && myBalance !== null"
|
||||
:name="t('cospend', 'My balance')">
|
||||
<template #icon>
|
||||
<ColoredAvatar :user="currentUserId" />
|
||||
</template>
|
||||
<template #counter>
|
||||
<NcCounterBubble>
|
||||
<span :class="balanceClass">{{ myBalance }}</span>
|
||||
</NcCounterBubble>
|
||||
</template>
|
||||
</NcAppNavigationItem>
|
||||
<NcAppNavigationItem v-if="!pageIsPublic && pendingInvitations.length > 0"
|
||||
:name="t('cospend', 'Pending share invitations')"
|
||||
@click="showPendingInvitations = true">
|
||||
@@ -128,6 +139,7 @@ import AppNavigationProjectItem from './AppNavigationProjectItem.vue'
|
||||
import NewProjectModal from './NewProjectModal.vue'
|
||||
import PendingInvitationsModal from './PendingInvitationsModal.vue'
|
||||
import AppNavigationUnreachableProjectItem from './AppNavigationUnreachableProjectItem.vue'
|
||||
import ColoredAvatar from './avatar/ColoredAvatar.vue'
|
||||
|
||||
import cospend from '../state.js'
|
||||
import * as constants from '../constants.js'
|
||||
@@ -135,10 +147,12 @@ import { strcmp, importCospendProject, importSWProject } from '../utils.js'
|
||||
|
||||
import { emit } from '@nextcloud/event-bus'
|
||||
import { showSuccess } from '@nextcloud/dialogs'
|
||||
import { getCurrentUser } from '@nextcloud/auth'
|
||||
|
||||
export default {
|
||||
name: 'CospendNavigation',
|
||||
components: {
|
||||
ColoredAvatar,
|
||||
AppNavigationUnreachableProjectItem,
|
||||
PendingInvitationsModal,
|
||||
NewProjectModal,
|
||||
@@ -202,9 +216,29 @@ export default {
|
||||
showArchivedProjects: false,
|
||||
showPendingInvitations: false,
|
||||
projectFilterQuery: '',
|
||||
currentUserId: getCurrentUser()?.uid,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
showMyBalance() {
|
||||
return cospend.showMyBalance
|
||||
},
|
||||
myBalance() {
|
||||
return Object.values(this.projects)
|
||||
.filter(p => p.archived_ts === null)
|
||||
.map(p => {
|
||||
const me = p.members.find(m => m.userid === this.currentUserId)
|
||||
return me ? me.balance : null
|
||||
})
|
||||
.filter(b => b !== null)
|
||||
.reduce((acc, balance) => acc + balance, 0)
|
||||
},
|
||||
balanceClass() {
|
||||
return {
|
||||
balancePositive: this.myBalance >= 0.01,
|
||||
balanceNegative: this.myBalance <= -0.01,
|
||||
}
|
||||
},
|
||||
filteredProjectIds() {
|
||||
const projectIds = this.showArchivedProjects ? this.archivedProjectIds : this.nonArchivedProjectIds
|
||||
return this.projectFilterQuery === ''
|
||||
|
||||
@@ -182,9 +182,14 @@
|
||||
</h3>
|
||||
<NcCheckboxRadioSwitch
|
||||
:checked.sync="useTime"
|
||||
@update:checked="onUseTimeChange">
|
||||
@update:checked="onCheckboxChange($event, 'useTime')">
|
||||
{{ t('cospend', 'Use time in dates') }}
|
||||
</NcCheckboxRadioSwitch>
|
||||
<NcCheckboxRadioSwitch
|
||||
:checked.sync="showMyBalance"
|
||||
@update:checked="onCheckboxChange($event, 'showMyBalance')">
|
||||
{{ t('cospend', 'Show my cumulated balance') }}
|
||||
</NcCheckboxRadioSwitch>
|
||||
</NcAppSettingsSection>
|
||||
</NcAppSettingsDialog>
|
||||
</div>
|
||||
@@ -227,6 +232,7 @@ export default {
|
||||
memberOrder: cospend.memberOrder || 'name',
|
||||
maxPrecision: cospend.maxPrecision || 2,
|
||||
useTime: cospend.useTime ?? true,
|
||||
showMyBalance: cospend.showMyBalance ?? false,
|
||||
importingProject: false,
|
||||
importingSWProject: false,
|
||||
cospendVersion: OC.getCapabilities()?.cospend?.version || '??',
|
||||
@@ -280,9 +286,9 @@ export default {
|
||||
cospend.maxPrecision = this.maxPrecision
|
||||
this.$emit('update-max-precision')
|
||||
},
|
||||
onUseTimeChange(checked) {
|
||||
emit('save-option', { key: 'useTime', value: checked ? '1' : '0' })
|
||||
cospend.useTime = checked
|
||||
onCheckboxChange(checked, key) {
|
||||
emit('save-option', { key, value: checked ? '1' : '0' })
|
||||
cospend[key] = checked
|
||||
},
|
||||
onImportClick() {
|
||||
importCospendProject(() => {
|
||||
|
||||
@@ -388,17 +388,15 @@
|
||||
</td>
|
||||
<td v-for="mid in stats.allMemberIds"
|
||||
:key="value.memberid + '-' + mid"
|
||||
v-tooltip.top="{
|
||||
content: value.memberid === 0
|
||||
? t('cospend', 'Total owed by {name}', { name: myGetSmartMemberName(mid) })
|
||||
: myGetSmartMemberName(value.memberid) + ' → ' + myGetSmartMemberName(mid)
|
||||
}"
|
||||
:title="value.memberid === 0
|
||||
? t('cospend', 'Total owed by {name}', { name: myGetSmartMemberName(mid) })
|
||||
: myGetSmartMemberName(value.memberid) + ' → ' + myGetSmartMemberName(mid)"
|
||||
:style="'border: 2px solid ' + (value.memberid === 0 ? 'lightgrey' : '#' + myGetMemberColor(value.memberid)) + ';'">
|
||||
{{ value[mid].toFixed(2) }}
|
||||
{{ selectedCurrencyName }}
|
||||
</td>
|
||||
<td v-if="value.memberid !== 0"
|
||||
v-tooltip.top="{ content: t('cospend', 'Total paid by {name}', { name: myGetSmartMemberName(value.memberid) }) }"
|
||||
:title="t('cospend', 'Total paid by {name}', { name: myGetSmartMemberName(value.memberid) })"
|
||||
style="border: 2px solid lightgrey;">
|
||||
{{ value.total.toFixed(2) }}
|
||||
{{ selectedCurrencyName }}
|
||||
|
||||
16
src/main.js
16
src/main.js
@@ -14,10 +14,7 @@ import './bootstrap.js'
|
||||
import App from './App.vue'
|
||||
import { showError } from '@nextcloud/dialogs'
|
||||
import '@nextcloud/dialogs/style.css'
|
||||
// import { getRequestToken } from '@nextcloud/auth'
|
||||
// import { generateFilePath } from '@nextcloud/router'
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
import Tooltip from '@nextcloud/vue/dist/Directives/Tooltip.js'
|
||||
import vueAwesomeCountdown from 'vue-awesome-countdown'
|
||||
import VueClipboard from 'vue-clipboard2'
|
||||
import SmartTable from 'vuejs-smart-table'
|
||||
@@ -29,7 +26,6 @@ import '../css/cospend.scss'
|
||||
Vue.use(vueAwesomeCountdown, 'vac')
|
||||
Vue.use(VueClipboard)
|
||||
Vue.use(SmartTable)
|
||||
Vue.directive('tooltip', Tooltip)
|
||||
|
||||
function restoreOptions() {
|
||||
network.getOptionValues().then((response) => {
|
||||
@@ -47,16 +43,12 @@ function getOptionValuesSuccess(response) {
|
||||
for (const k in optionsValues) {
|
||||
if (k === 'selectedProject') {
|
||||
cospend.restoredCurrentProjectId = optionsValues[k]
|
||||
} else if (k === 'outputDirectory') {
|
||||
cospend.outputDirectory = optionsValues[k]
|
||||
} else if (k === 'sortOrder') {
|
||||
cospend.sortOrder = optionsValues[k]
|
||||
} else if (k === 'memberOrder') {
|
||||
cospend.memberOrder = optionsValues[k]
|
||||
} else if (k === 'maxPrecision') {
|
||||
cospend.maxPrecision = optionsValues[k]
|
||||
} else if (k === 'useTime') {
|
||||
cospend.useTime = optionsValues[k] !== '0'
|
||||
} else if (k === 'showMyBalance') {
|
||||
cospend.showMyBalance = optionsValues[k] !== '0'
|
||||
} else {
|
||||
cospend[k] = optionsValues[k]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ const cospend = {
|
||||
memberOrder: 'name',
|
||||
useTime: true,
|
||||
activity_enabled: false,
|
||||
showMyBalance: false,
|
||||
}
|
||||
|
||||
export default cospend
|
||||
|
||||
Reference in New Issue
Block a user