no longer manipulating prop. still can't get formatting to twork
This commit is contained in:
@@ -4,5 +4,6 @@ import { reactive } from 'vue'
|
||||
export const AppState = reactive({
|
||||
user: {},
|
||||
account: {},
|
||||
transactions: []
|
||||
transactions: [],
|
||||
categories: []
|
||||
})
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
<template>
|
||||
<div class="component flex flex-wrap md:flex-nowrap justify-between bg-stone-800 mb-2">
|
||||
<div class="pr-4">
|
||||
<input type="date" v-model="transData.date" class="text-slate-50 bg-stone-800 w-32 hover:bg-green-300 hover:text-stone-900">
|
||||
</div>
|
||||
<div class="pr-4">
|
||||
<!-- TODO this is bad! don't manipulate the prop -->
|
||||
<!-- Look at cars in gregslist? -->
|
||||
<!-- use editable object -->
|
||||
<span class="flex">
|
||||
$
|
||||
<input type="number" v-model="transData.amount" :placeholder="transData.amount" class="w-24 bg-stone-800 text-slate-50 hover:bg-green-300 hover:text-stone-900">
|
||||
</span>
|
||||
</div>
|
||||
<div class="pr-4">
|
||||
<input type="text" v-model="transData.payee" :placeholder="transData.payee" class="text-slate-50 bg-stone-800 w-32 hover:bg-green-300 hover:text-stone-900">
|
||||
</div>
|
||||
<div class="pr-4">
|
||||
<select v-model="transData.categoryId" class="text-slate-50 bg-stone-800 w-36 hover:bg-green-300 hover:text-stone-900">
|
||||
<option :value="transData.categoryId" selected>{{categories.find((c) => c._id == transData.categoryId)?.name}}</option>
|
||||
<!-- cat?.name - null coalescence - returns value iff object is valid -->
|
||||
<!-- TODO there's an error here but it works??? -->
|
||||
<option v-for="c in categories" :value="c._id">{{c.name}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="pr-4">
|
||||
<input type="text" v-model="transData.comment" :placeholder="transData.comment" class="text-slate-50 bg-stone-800 w-48 hover:bg-green-300 hover:text-stone-900">
|
||||
</div>
|
||||
<div>
|
||||
<button class="text-slate-50 bg-stone-800 w-16 hover:bg-green-300 hover:text-stone-900" @click="update">
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
// import { logger } from '../utils/Logger'
|
||||
import { transactionsService } from '../services/TransactionsService'
|
||||
import { getDollars } from '../utils/Dollars'
|
||||
import { computed, reactive, onMounted, ref, watchEffect } from "vue";
|
||||
|
||||
export default {
|
||||
// TODO there's probably something wrong with this...
|
||||
props: {
|
||||
transaction: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
categories: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
setup(props){
|
||||
// create editable object and use watchEffect
|
||||
const transData = ref({})
|
||||
watchEffect(() => {
|
||||
transData.value = props.transaction
|
||||
// whatever this doesn't work because WHYNOT
|
||||
// transData.dollars = props.transaction.amount / 100
|
||||
})
|
||||
return {
|
||||
transData,
|
||||
async update() {
|
||||
// console.log(props.transaction)
|
||||
// send off request to update transaction
|
||||
try {
|
||||
// use the editable object instead
|
||||
await transactionsService.update(transData.value)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!--
|
||||
setup(props) {
|
||||
const carData = ref({});
|
||||
// NOTE the watcheffect runs when a piece of data inside it changes
|
||||
// in this case props.edit car was accessed so if props.editCar changes it runs again
|
||||
watchEffect(() => {
|
||||
logger.log(props.editCar);
|
||||
carData.value = props.editCar;
|
||||
});
|
||||
return {
|
||||
carData, -->
|
||||
|
||||
|
||||
<!-- // TODO undo this -->
|
||||
<style lang="postcss" scoped>
|
||||
input {
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
input::placeholder {
|
||||
@apply text-slate-50;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
input:hover::placeholder {
|
||||
@apply text-stone-900;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
input:hover {
|
||||
color-scheme: light;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,28 @@
|
||||
<template>
|
||||
<div class="component">
|
||||
<p>{{category}}</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
import { computed, reactive, onMounted, ref, watchEffect } from "vue";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
category: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
setup(props){
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,28 +1,35 @@
|
||||
<template>
|
||||
<div class="component flex flex-wrap md:flex-nowrap justify-between bg-stone-800 mb-2">
|
||||
<div class="pr-4">
|
||||
<input type="date" v-model="transaction.date" class="text-slate-50 bg-stone-800 w-32 hover:bg-green-300 hover:text-stone-900">
|
||||
<input type="date" v-model="transData.date" class="text-slate-50 bg-stone-800 w-32 hover:bg-green-300 hover:text-stone-900">
|
||||
</div>
|
||||
<div class="pr-4">
|
||||
<input type="number" v-model="transaction.amount" :placeholder="transaction.amount" class="w-24 bg-stone-800 text-slate-50 hover:bg-green-300 hover:text-stone-900">
|
||||
<!-- TODO this is bad! don't manipulate the prop -->
|
||||
<!-- Look at cars in gregslist? -->
|
||||
<!-- use editable object -->
|
||||
<span class="flex">
|
||||
$
|
||||
<input type="number" v-model="transData.amount" :placeholder="transData.amount" class="w-24 bg-stone-800 text-slate-50 hover:bg-green-300 hover:text-stone-900">
|
||||
</span>
|
||||
</div>
|
||||
<div class="pr-4">
|
||||
<input type="text" v-model="transaction.payee" :placeholder="transaction.payee" class="text-slate-50 bg-stone-800 w-32 hover:bg-green-300 hover:text-stone-900">
|
||||
<input type="text" v-model="transData.payee" :placeholder="transData.payee" class="text-slate-50 bg-stone-800 w-32 hover:bg-green-300 hover:text-stone-900">
|
||||
</div>
|
||||
<div class="pr-4">
|
||||
<select v-model="transaction.category" class="text-slate-50 bg-stone-800 w-36 hover:bg-green-300 hover:text-stone-900">
|
||||
<option value="" selected>{{transaction.category}}</option>
|
||||
<option v-for="c in 10" value="meow">meow</option>
|
||||
<select v-model="transData.categoryId" class="text-slate-50 bg-stone-800 w-36 hover:bg-green-300 hover:text-stone-900">
|
||||
<option :value="transData.categoryId" selected>{{categories.find((c) => c._id == transData.categoryId)?.name}}</option>
|
||||
<!-- cat?.name - null coalescence - returns value iff object is valid -->
|
||||
<!-- TODO there's an error here but it works??? -->
|
||||
<option v-for="c in categories" :value="c._id">{{c.name}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="pr-4">
|
||||
<input type="text" v-model="transaction.comment" :placeholder="transaction.comment" class="text-slate-50 bg-stone-800 w-48 hover:bg-green-300 hover:text-stone-900">
|
||||
<input type="text" v-model="transData.comment" :placeholder="transData.comment" class="text-slate-50 bg-stone-800 w-48 hover:bg-green-300 hover:text-stone-900">
|
||||
</div>
|
||||
<div>
|
||||
<button class="text-slate-50 bg-stone-800 w-16 hover:bg-green-300 hover:text-stone-900" @click="update">
|
||||
Save
|
||||
</button>
|
||||
{{transaction}}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -31,6 +38,8 @@
|
||||
<script>
|
||||
// import { logger } from '../utils/Logger'
|
||||
import { transactionsService } from '../services/TransactionsService'
|
||||
import { getDollars } from '../utils/Dollars'
|
||||
import { computed, reactive, onMounted, ref, watchEffect } from "vue";
|
||||
|
||||
export default {
|
||||
// TODO there's probably something wrong with this...
|
||||
@@ -38,15 +47,28 @@ export default {
|
||||
transaction: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
categories: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
setup(props){
|
||||
// create editable object and use watchEffect
|
||||
const transData = ref({})
|
||||
watchEffect(() => {
|
||||
transData.value = props.transaction
|
||||
// whatever this doesn't work because WHYNOT
|
||||
// transData.dollars = props.transaction.amount / 100
|
||||
})
|
||||
return {
|
||||
transData,
|
||||
async update() {
|
||||
console.log(props.transaction)
|
||||
// console.log(props.transaction)
|
||||
// send off request to update transaction
|
||||
try {
|
||||
await transactionsService.update(props.transaction)
|
||||
// use the editable object instead
|
||||
await transactionsService.update(transData.value)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
@@ -56,6 +78,18 @@ export default {
|
||||
}
|
||||
</script>
|
||||
|
||||
<!--
|
||||
setup(props) {
|
||||
const carData = ref({});
|
||||
// NOTE the watcheffect runs when a piece of data inside it changes
|
||||
// in this case props.edit car was accessed so if props.editCar changes it runs again
|
||||
watchEffect(() => {
|
||||
logger.log(props.editCar);
|
||||
carData.value = props.editCar;
|
||||
});
|
||||
return {
|
||||
carData, -->
|
||||
|
||||
|
||||
<!-- // TODO undo this -->
|
||||
<style lang="postcss" scoped>
|
||||
|
||||
@@ -3,16 +3,35 @@
|
||||
<p class="hover:text-green-300 cursor-pointer">Add Category</p>
|
||||
<div class="flex md:mx-40 flex-col md:flex-row">
|
||||
<div class="md:w-4/12 md:order-last">analysis container</div>
|
||||
<div class="md:w-8/12">category container</div>
|
||||
<div class="md:w-8/12">category container
|
||||
<p v-for="c in categories" :key="c._id">{{c.name}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
import { computed, onMounted } from 'vue'
|
||||
import { AppState } from '../AppState'
|
||||
import { categoriesService } from '../services/CategoriesService'
|
||||
import { logger } from '../utils/Logger'
|
||||
|
||||
|
||||
export default {
|
||||
setup(){
|
||||
return {}
|
||||
onMounted(async () => {
|
||||
try {
|
||||
// console.log(AppState.categories)
|
||||
await categoriesService.getAll()
|
||||
// console.log(AppState.categories)
|
||||
} catch (error) {
|
||||
logger.log(error)
|
||||
}
|
||||
})
|
||||
return {
|
||||
categories: computed(() => AppState.categories)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -20,4 +39,25 @@ export default {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
||||
<!--
|
||||
import { computed, onMounted } from 'vue'
|
||||
import { AppState } from '../AppState'
|
||||
import { transactionsService } from '../services/TransactionsService'
|
||||
import { logger } from '../utils/Logger'
|
||||
|
||||
export default {
|
||||
setup(){
|
||||
onMounted(async () => {
|
||||
try {
|
||||
await transactionsService.getAll()
|
||||
} catch (error) {
|
||||
logger.log(error)
|
||||
}
|
||||
})
|
||||
return {
|
||||
transactions: computed(() => AppState.transactions)
|
||||
}
|
||||
}
|
||||
} -->
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="component">
|
||||
<div class="flex mt-6 md:mx-40 flex-col">
|
||||
<h1>Transactions Container</h1>
|
||||
<Transaction v-for="t in transactions" :key="t._id" :transaction="t" />
|
||||
<Transaction v-for="t in transactions" :key="t._id" :transaction="t" :categories="categories" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -11,6 +11,7 @@
|
||||
<script>
|
||||
import { computed, onMounted } from 'vue'
|
||||
import { AppState } from '../AppState'
|
||||
import { categoriesService } from '../services/CategoriesService'
|
||||
import { transactionsService } from '../services/TransactionsService'
|
||||
import { logger } from '../utils/Logger'
|
||||
|
||||
@@ -18,13 +19,15 @@ export default {
|
||||
setup(){
|
||||
onMounted(async () => {
|
||||
try {
|
||||
await categoriesService.getAll()
|
||||
await transactionsService.getAll()
|
||||
} catch (error) {
|
||||
logger.log(error)
|
||||
}
|
||||
})
|
||||
return {
|
||||
transactions: computed(() => AppState.transactions)
|
||||
transactions: computed(() => AppState.transactions),
|
||||
categories: computed(() => AppState.categories)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@ const routes = [
|
||||
{
|
||||
path: '/',
|
||||
name: 'Overview',
|
||||
component: loadPage('OverviewPage')
|
||||
component: loadPage('OverviewPage'),
|
||||
beforeEnter: authGuard
|
||||
},
|
||||
{
|
||||
path: '/transactions',
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import { AppState } from "../AppState"
|
||||
import { logger } from "../utils/Logger"
|
||||
import { api } from "./AxiosService"
|
||||
|
||||
|
||||
class CategoriesService {
|
||||
async getAll() {
|
||||
const res = await api.get('api/categories')
|
||||
// console.log(res.data)
|
||||
AppState.categories = res.data
|
||||
}
|
||||
}
|
||||
|
||||
export const categoriesService = new CategoriesService()
|
||||
@@ -1,6 +1,7 @@
|
||||
import { AppState } from "../AppState"
|
||||
import { logger } from "../utils/Logger"
|
||||
import { api } from "./AxiosService"
|
||||
import { getCents } from '../utils/Dollars'
|
||||
|
||||
|
||||
// TODO build the service to get some real data
|
||||
@@ -20,9 +21,10 @@ class TransactionsService {
|
||||
|
||||
// TODO test this
|
||||
async update(transaction) {
|
||||
console.log(transaction._id)
|
||||
// transaction.amount = getCents(transaction.dollars)
|
||||
// console.log(transaction._id)
|
||||
const res = await api.put('api/transactions/' + transaction._id, transaction)
|
||||
console.log('transactionUpdate: ' + res.data)
|
||||
// console.log('transactionUpdate: ' + res.data)
|
||||
// AppState.transactions.find((t) => t._id == transactionId) = res.data
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
export function getDollars(cents) {
|
||||
// return `$${Math.floor(cents / 100)}.${cents % 100}`
|
||||
return cents / 100
|
||||
}
|
||||
|
||||
export function getCents(dollars) {
|
||||
return Math.round(dollars * 100)
|
||||
}
|
||||
@@ -5,7 +5,7 @@ const Schema = mongoose.Schema
|
||||
|
||||
export const CategorySchema = new Schema(
|
||||
{
|
||||
/** @property {ObjectId} [accountId] -ID of the account this transaction belongs to */
|
||||
/** @property {ObjectId} [accountId] -ID of the account this category belongs to */
|
||||
accountId: {type: Schema.Types.ObjectId, required: true},
|
||||
|
||||
/** @property {String} [name] -name of the category */
|
||||
|
||||
@@ -11,6 +11,7 @@ async create(newTransaction) {
|
||||
return dbTransaction
|
||||
}
|
||||
|
||||
// TODO need to populate categories
|
||||
async getAll(accountId) {
|
||||
if (!accountId) {
|
||||
throw new BadRequest("User not logged in")
|
||||
@@ -19,8 +20,6 @@ async getAll(accountId) {
|
||||
return allTransactions
|
||||
}
|
||||
|
||||
// TODO test this
|
||||
// TODO fix this
|
||||
async update(accountId, transactionId, update) {
|
||||
if (!transactionId) {
|
||||
throw new BadRequest('Bad transaction id')
|
||||
|
||||
Reference in New Issue
Block a user