Compare commits
2 Commits
0e6caca9ab
...
d1793be3e1
| Author | SHA1 | Date | |
|---|---|---|---|
| d1793be3e1 | |||
| 191960da2d |
@@ -2,6 +2,7 @@
|
|||||||
import IconX from '@/components/icons/IconX.vue'
|
import IconX from '@/components/icons/IconX.vue'
|
||||||
import IconPlus from '@/components/icons/IconPlusCircle.vue'
|
import IconPlus from '@/components/icons/IconPlusCircle.vue'
|
||||||
import { useBoardStore } from '@/stores/boardStore'
|
import { useBoardStore } from '@/stores/boardStore'
|
||||||
|
import { Spending } from '@/services/Spending'
|
||||||
|
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import InputField from './InputField.vue'
|
import InputField from './InputField.vue'
|
||||||
@@ -31,13 +32,11 @@ const forceValidate = ref(false)
|
|||||||
function submit() {
|
function submit() {
|
||||||
forceValidate.value = true
|
forceValidate.value = true
|
||||||
if (spendingAmountError.value == '' && spendingNameError.value == '') {
|
if (spendingAmountError.value == '' && spendingNameError.value == '') {
|
||||||
store
|
const user = store.getCurrentBoard()?.getUsers().find(u => u.name === props.userName)
|
||||||
.getCurrentBoard()
|
if (user) {
|
||||||
.addSpendingByUserName(
|
const spending = new Spending(spendingNameInput.value, spendingAmount.value * 100)
|
||||||
props.userName ?? '',
|
store.getCurrentBoard()?.addSpending(user, spending)
|
||||||
spendingNameInput.value,
|
}
|
||||||
spendingAmount.value * 100,
|
|
||||||
)
|
|
||||||
spendingNameInput.value = ''
|
spendingNameInput.value = ''
|
||||||
spendingAmountInput.value = ''
|
spendingAmountInput.value = ''
|
||||||
isOpen.value = false
|
isOpen.value = false
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import InputField from './InputField.vue'
|
import InputField from './InputField.vue'
|
||||||
import { useBoardStore } from '@/stores/boardStore'
|
import { useBoardStore } from '@/stores/boardStore'
|
||||||
|
import { useUserStore } from '@/stores/userStore'
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
const route = useRouter()
|
const route = useRouter()
|
||||||
const store = useBoardStore()
|
const boardStore = useBoardStore()
|
||||||
|
const userStore = useUserStore()
|
||||||
|
|
||||||
const boardNameInput = ref('')
|
const boardNameInput = ref('')
|
||||||
const boardNameError = computed(() => {
|
const boardNameError = computed(() => {
|
||||||
@@ -17,14 +19,14 @@ const forceValidate = ref(false)
|
|||||||
function submit() {
|
function submit() {
|
||||||
forceValidate.value = true
|
forceValidate.value = true
|
||||||
if (boardNameError.value == '') {
|
if (boardNameError.value == '') {
|
||||||
const newBoard = store.createBoard(boardNameInput.value)
|
const newBoard = boardStore.createBoard(userStore.getLogedInUser()!, boardNameInput.value)
|
||||||
route.push('/boards/' + newBoard.guid)
|
route.push('/boards/' + newBoard.guid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<form class="bg-base-200 border-base-300 rounded-box w-xs border p-4" @submit.prevent="submit">
|
<form class="bg-base-100 border border-base-200 rounded-box shadow-md w-xs p-4" @submit.prevent="submit">
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
<h3 class="font-bold">Neue Liste Erstellen</h3>
|
<h3 class="font-bold">Neue Liste Erstellen</h3>
|
||||||
|
|
||||||
|
|||||||
@@ -4,23 +4,41 @@ import { v4 as uuidv4 } from 'uuid'
|
|||||||
|
|
||||||
export class Board {
|
export class Board {
|
||||||
name: string
|
name: string
|
||||||
users: Array<User>
|
users: Set<User>
|
||||||
|
spendings: Array<Spending>
|
||||||
creationDate: Date
|
creationDate: Date
|
||||||
guid: string
|
guid: string
|
||||||
|
|
||||||
constructor(name: string) {
|
constructor(name: string) {
|
||||||
this.name = name
|
this.name = name
|
||||||
this.users = Array<User>()
|
this.users = new Set<User>()
|
||||||
|
this.spendings = new Array<Spending>()
|
||||||
this.creationDate = new Date()
|
this.creationDate = new Date()
|
||||||
this.guid = uuidv4()
|
this.guid = uuidv4()
|
||||||
}
|
}
|
||||||
|
|
||||||
addUser(user: User): void {
|
addUser(user: User): void {
|
||||||
this.users.push(user)
|
this.users.add(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
addSpendingByUserName(userName: string, spendingName: string, amountCt: number) {
|
addSpending(user: User, spending: Spending): void {
|
||||||
const user = this.users.filter((u) => u.name === userName)[0]
|
spending.setSpender(user)
|
||||||
user?.addSpending(new Spending(spendingName, amountCt))
|
this.users.add(user)
|
||||||
|
this.spendings.push(spending)
|
||||||
|
}
|
||||||
|
|
||||||
|
getUsers(): User[] {
|
||||||
|
return Array.from(this.users)
|
||||||
|
}
|
||||||
|
|
||||||
|
getUserSpendingTotals(): Map<string, number> {
|
||||||
|
const totals = new Map<string, number>()
|
||||||
|
for (const spending of this.spendings) {
|
||||||
|
if (spending.spender) {
|
||||||
|
const current = totals.get(spending.spender.name) || 0
|
||||||
|
totals.set(spending.spender.name, current + spending.amountCt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return totals
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,8 @@
|
|||||||
import type { Spending } from './Spending'
|
|
||||||
|
|
||||||
export class User {
|
export class User {
|
||||||
name: string
|
name: string
|
||||||
spendings: Array<Spending>
|
|
||||||
|
|
||||||
constructor(name: string) {
|
constructor(name: string) {
|
||||||
this.name = name
|
this.name = name
|
||||||
this.spendings = Array<Spending>()
|
|
||||||
}
|
|
||||||
|
|
||||||
addSpending(spending: Spending): void {
|
|
||||||
spending.setSpender(this)
|
|
||||||
this.spendings.push(spending)
|
|
||||||
}
|
|
||||||
|
|
||||||
getTotalSpending(): number {
|
|
||||||
return this.spendings.map((w) => w.amountCt).reduce((acc, num) => acc + num, 0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getInitials(): string {
|
getInitials(): string {
|
||||||
|
|||||||
@@ -2,41 +2,23 @@ import { defineStore } from 'pinia'
|
|||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import { Board } from '@/services/Board'
|
import { Board } from '@/services/Board'
|
||||||
import { User } from '@/services/User'
|
import { User } from '@/services/User'
|
||||||
import { Spending } from '@/services/Spending'
|
|
||||||
|
|
||||||
export const useBoardStore = defineStore('boardStore', () => {
|
export const useBoardStore = defineStore('boardStore', () => {
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const boards = new Map<string, Board>()
|
const boards = new Map<string, Board>()
|
||||||
let testBoard: Board | undefined
|
|
||||||
|
|
||||||
function createBoard(name: string): Board {
|
function createBoard(owner: User, name: string): Board {
|
||||||
const newBoard = new Board(name)
|
const newBoard = new Board(name)
|
||||||
|
newBoard.addUser(owner)
|
||||||
boards.set(newBoard.guid, newBoard)
|
boards.set(newBoard.guid, newBoard)
|
||||||
return newBoard
|
return newBoard
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBoard(guid: string): Board {
|
function getBoard(guid: string): Board | undefined {
|
||||||
const board = boards.get(guid)
|
return boards.get(guid)
|
||||||
if (board != undefined) {
|
|
||||||
return board
|
|
||||||
} else {
|
|
||||||
if (testBoard === undefined) {
|
|
||||||
testBoard = new Board('Grill and Chill')
|
|
||||||
const elias = new User('Elias')
|
|
||||||
elias.addSpending(new Spending('Burger', 1230))
|
|
||||||
elias.addSpending(new Spending('Kaffee', 510))
|
|
||||||
testBoard.addUser(elias)
|
|
||||||
const max = new User('Max')
|
|
||||||
max.addSpending(new Spending('Omlett', 1822))
|
|
||||||
max.addSpending(new Spending('Kaffee', 3073))
|
|
||||||
testBoard.addUser(max)
|
|
||||||
return testBoard
|
|
||||||
}
|
|
||||||
return testBoard
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCurrentBoard(): Board {
|
function getCurrentBoard(): Board | undefined {
|
||||||
if (typeof route.params.boardId === 'string') {
|
if (typeof route.params.boardId === 'string') {
|
||||||
return getBoard(route.params.boardId)
|
return getBoard(route.params.boardId)
|
||||||
} else {
|
} else {
|
||||||
@@ -44,5 +26,11 @@ export const useBoardStore = defineStore('boardStore', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { createBoard, getBoard, getCurrentBoard }
|
function getBoardsForUser(user: User): Board[] {
|
||||||
|
return Array.from(boards.values()).filter(board =>
|
||||||
|
board.getUsers().some(u => u.name === user.name)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return { createBoard, getBoard, getCurrentBoard, getBoardsForUser }
|
||||||
})
|
})
|
||||||
|
|||||||
41
frontend/src/stores/userStore.ts
Normal file
41
frontend/src/stores/userStore.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { User } from '@/services/User'
|
||||||
|
|
||||||
|
export const useUserStore = defineStore('userStore', () => {
|
||||||
|
const users = ref<Array<User>>([])
|
||||||
|
const useSampleUsers = ref(true)
|
||||||
|
|
||||||
|
function addUser(user: User) {
|
||||||
|
users.value.push(user)
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeUser(userName: string) {
|
||||||
|
users.value = users.value.filter((user: User) => user.name !== userName)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUser(userName: string) {
|
||||||
|
return getAllUsers().find((user: User) => user.name === userName)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLoggedInUser() {
|
||||||
|
return getAllUsers().find((user: User) => user.name === "Elias")
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAllUsers() {
|
||||||
|
if (useSampleUsers.value) {
|
||||||
|
// Return sample users
|
||||||
|
return [
|
||||||
|
new User('Elias'),
|
||||||
|
new User('Daniel'),
|
||||||
|
new User('Max'),
|
||||||
|
new User('Alice Example'),
|
||||||
|
new User('Bob Demo'),
|
||||||
|
new User('Charlie Test')
|
||||||
|
]
|
||||||
|
}
|
||||||
|
return users.value
|
||||||
|
}
|
||||||
|
|
||||||
|
return { addUser, removeUser, getUser, getAllUsers, useSampleUsers, getLogedInUser: getLoggedInUser }
|
||||||
|
})
|
||||||
@@ -11,12 +11,12 @@ const board = ref(store.getCurrentBoard())
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ItemList title="Informationen">
|
<ItemList title="Informationen">
|
||||||
<ItemListElement title="Name" :subtitle="board.name" />
|
<ItemListElement title="Name" :subtitle="board?.name" />
|
||||||
<ItemListElement title="Guid" :subtitle="board.guid" />
|
<ItemListElement title="Guid" :subtitle="board?.guid" />
|
||||||
<ItemListElement
|
<ItemListElement
|
||||||
title="Erstellt am"
|
title="Erstellt am"
|
||||||
:subtitle="
|
:subtitle="
|
||||||
board.creationDate.toLocaleDateString('de-DE', {
|
board?.creationDate.toLocaleDateString('de-DE', {
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
month: '2-digit',
|
month: '2-digit',
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
|
|||||||
@@ -1,9 +1,44 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import ItemList from '@/components/ItemList.vue'
|
import ItemList from '@/components/ItemList.vue'
|
||||||
|
import ItemListElement from '@/components/ItemListElement.vue'
|
||||||
import { useBoardStore } from '@/stores/boardStore'
|
import { useBoardStore } from '@/stores/boardStore'
|
||||||
|
import { useUserStore } from '@/stores/userStore'
|
||||||
|
import { computed, ref } from 'vue'
|
||||||
|
|
||||||
|
const boardStore = useBoardStore()
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const selectedUserName = ref('')
|
||||||
|
|
||||||
|
const availableUsers = computed(() => {
|
||||||
|
const allUsers = userStore.getAllUsers()
|
||||||
|
const boardUsers = boardStore.getCurrentBoard()?.getUsers()
|
||||||
|
const boardUserNames = new Set(boardUsers?.map(u => u.name))
|
||||||
|
return allUsers.filter(u => !boardUserNames.has(u.name))
|
||||||
|
})
|
||||||
|
|
||||||
|
function addUser() {
|
||||||
|
if (selectedUserName.value) {
|
||||||
|
const user = userStore.getAllUsers().find(u => u.name === selectedUserName.value)
|
||||||
|
if (user) {
|
||||||
|
boardStore.getCurrentBoard()?.addUser(user)
|
||||||
|
selectedUserName.value = '' // reset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ItemList title="Einstellungen"> </ItemList>
|
<ItemList title="Einstellungen">
|
||||||
|
<ItemListElement title="Benutzer hinzufügen">
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<select v-model="selectedUserName" class="select select-bordered">
|
||||||
|
<option value="">Benutzer auswählen</option>
|
||||||
|
<option v-for="user in availableUsers" :key="user.name" :value="user.name">
|
||||||
|
{{ user.name }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
<button class="btn btn-primary" @click="addUser" :disabled="!selectedUserName">Hinzufügen</button>
|
||||||
|
</div>
|
||||||
|
</ItemListElement>
|
||||||
|
</ItemList>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { useBoardStore } from '@/stores/boardStore'
|
|||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
|
|
||||||
const store = useBoardStore()
|
const store = useBoardStore()
|
||||||
const spendings = ref(store.getCurrentBoard().users.flatMap((u) => u.spendings))
|
const spendings = ref(store.getCurrentBoard()?.spendings)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ import { useBoardStore } from '@/stores/boardStore'
|
|||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
|
|
||||||
const store = useBoardStore()
|
const store = useBoardStore()
|
||||||
const users = ref(store.getCurrentBoard().users)
|
const users = ref(store.getCurrentBoard()?.getUsers())
|
||||||
|
const totals = ref(store.getCurrentBoard()?.getUserSpendingTotals())
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -17,7 +18,7 @@ const users = ref(store.getCurrentBoard().users)
|
|||||||
:key="user.name"
|
:key="user.name"
|
||||||
:icon="user.getInitials()"
|
:icon="user.getInitials()"
|
||||||
:title="user.name"
|
:title="user.name"
|
||||||
:subtitle="(user.getTotalSpending() / 100).toFixed(2) + '€'"
|
:subtitle="((totals?.get(user.name) || 0) / 100).toFixed(2) + '€'"
|
||||||
subtitle-class="text-green-700"
|
subtitle-class="text-green-700"
|
||||||
>
|
>
|
||||||
<AddSpendingModal :user-name="user.name" />
|
<AddSpendingModal :user-name="user.name" />
|
||||||
|
|||||||
@@ -1,9 +1,33 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import CreateNewList from '../components/CreateNewList.vue'
|
import CreateNewList from '../components/CreateNewList.vue'
|
||||||
|
import ItemList from '@/components/ItemList.vue'
|
||||||
|
import ItemListElement from '@/components/ItemListElement.vue'
|
||||||
|
import { useUserStore } from '@/stores/userStore'
|
||||||
|
import { useBoardStore } from '@/stores/boardStore'
|
||||||
|
import { computed } from 'vue'
|
||||||
|
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const boardStore = useBoardStore()
|
||||||
|
|
||||||
|
const loggedInUser = computed(() => userStore.getLogedInUser())
|
||||||
|
const userBoards = computed(() => {
|
||||||
|
const user = loggedInUser.value
|
||||||
|
return user ? boardStore.getBoardsForUser(user) : []
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="grid h-full place-content-center">
|
<div class="grid h-full justify-center pt-4">
|
||||||
|
<div class="flex flex-col gap-4">
|
||||||
|
<ItemList v-if="userBoards.length > 0" title="Meine Listen">
|
||||||
|
<router-link v-for="board in userBoards" :key="board.guid" :to="'/boards/' + board.guid">
|
||||||
|
<ItemListElement
|
||||||
|
:title="board.name"
|
||||||
|
:subtitle="board.getUsers().length + ' Mitglieder'"
|
||||||
|
/>
|
||||||
|
</router-link>
|
||||||
|
</ItemList>
|
||||||
<CreateNewList></CreateNewList>
|
<CreateNewList></CreateNewList>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user