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({
|
export const AppState = reactive({
|
||||||
user: {},
|
user: {},
|
||||||
account: {},
|
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>
|
<template>
|
||||||
<div class="component flex flex-wrap md:flex-nowrap justify-between bg-stone-800 mb-2">
|
<div class="component flex flex-wrap md:flex-nowrap justify-between bg-stone-800 mb-2">
|
||||||
<div class="pr-4">
|
<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>
|
||||||
<div class="pr-4">
|
<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>
|
||||||
<div class="pr-4">
|
<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>
|
||||||
<div class="pr-4">
|
<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">
|
<select v-model="transData.categoryId" class="text-slate-50 bg-stone-800 w-36 hover:bg-green-300 hover:text-stone-900">
|
||||||
<option value="" selected>{{transaction.category}}</option>
|
<option :value="transData.categoryId" selected>{{categories.find((c) => c._id == transData.categoryId)?.name}}</option>
|
||||||
<option v-for="c in 10" value="meow">meow</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>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="pr-4">
|
<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>
|
||||||
<div>
|
<div>
|
||||||
<button class="text-slate-50 bg-stone-800 w-16 hover:bg-green-300 hover:text-stone-900" @click="update">
|
<button class="text-slate-50 bg-stone-800 w-16 hover:bg-green-300 hover:text-stone-900" @click="update">
|
||||||
Save
|
Save
|
||||||
</button>
|
</button>
|
||||||
{{transaction}}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -31,6 +38,8 @@
|
|||||||
<script>
|
<script>
|
||||||
// import { logger } from '../utils/Logger'
|
// import { logger } from '../utils/Logger'
|
||||||
import { transactionsService } from '../services/TransactionsService'
|
import { transactionsService } from '../services/TransactionsService'
|
||||||
|
import { getDollars } from '../utils/Dollars'
|
||||||
|
import { computed, reactive, onMounted, ref, watchEffect } from "vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
// TODO there's probably something wrong with this...
|
// TODO there's probably something wrong with this...
|
||||||
@@ -38,15 +47,28 @@ export default {
|
|||||||
transaction: {
|
transaction: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
|
},
|
||||||
|
categories: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setup(props){
|
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 {
|
return {
|
||||||
|
transData,
|
||||||
async update() {
|
async update() {
|
||||||
console.log(props.transaction)
|
// console.log(props.transaction)
|
||||||
// send off request to update transaction
|
// send off request to update transaction
|
||||||
try {
|
try {
|
||||||
await transactionsService.update(props.transaction)
|
// use the editable object instead
|
||||||
|
await transactionsService.update(transData.value)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
}
|
}
|
||||||
@@ -56,6 +78,18 @@ export default {
|
|||||||
}
|
}
|
||||||
</script>
|
</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 -->
|
<!-- // TODO undo this -->
|
||||||
<style lang="postcss" scoped>
|
<style lang="postcss" scoped>
|
||||||
|
|||||||
@@ -3,16 +3,35 @@
|
|||||||
<p class="hover:text-green-300 cursor-pointer">Add Category</p>
|
<p class="hover:text-green-300 cursor-pointer">Add Category</p>
|
||||||
<div class="flex md:mx-40 flex-col md:flex-row">
|
<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-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>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { computed, onMounted } from 'vue'
|
||||||
|
import { AppState } from '../AppState'
|
||||||
|
import { categoriesService } from '../services/CategoriesService'
|
||||||
|
import { logger } from '../utils/Logger'
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
setup(){
|
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>
|
</script>
|
||||||
@@ -20,4 +39,25 @@ export default {
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<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="component">
|
||||||
<div class="flex mt-6 md:mx-40 flex-col">
|
<div class="flex mt-6 md:mx-40 flex-col">
|
||||||
<h1>Transactions Container</h1>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { computed, onMounted } from 'vue'
|
import { computed, onMounted } from 'vue'
|
||||||
import { AppState } from '../AppState'
|
import { AppState } from '../AppState'
|
||||||
|
import { categoriesService } from '../services/CategoriesService'
|
||||||
import { transactionsService } from '../services/TransactionsService'
|
import { transactionsService } from '../services/TransactionsService'
|
||||||
import { logger } from '../utils/Logger'
|
import { logger } from '../utils/Logger'
|
||||||
|
|
||||||
@@ -18,13 +19,15 @@ export default {
|
|||||||
setup(){
|
setup(){
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
try {
|
try {
|
||||||
|
await categoriesService.getAll()
|
||||||
await transactionsService.getAll()
|
await transactionsService.getAll()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.log(error)
|
logger.log(error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return {
|
return {
|
||||||
transactions: computed(() => AppState.transactions)
|
transactions: computed(() => AppState.transactions),
|
||||||
|
categories: computed(() => AppState.categories)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ const routes = [
|
|||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
name: 'Overview',
|
name: 'Overview',
|
||||||
component: loadPage('OverviewPage')
|
component: loadPage('OverviewPage'),
|
||||||
|
beforeEnter: authGuard
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/transactions',
|
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 { AppState } from "../AppState"
|
||||||
import { logger } from "../utils/Logger"
|
import { logger } from "../utils/Logger"
|
||||||
import { api } from "./AxiosService"
|
import { api } from "./AxiosService"
|
||||||
|
import { getCents } from '../utils/Dollars'
|
||||||
|
|
||||||
|
|
||||||
// TODO build the service to get some real data
|
// TODO build the service to get some real data
|
||||||
@@ -20,9 +21,10 @@ class TransactionsService {
|
|||||||
|
|
||||||
// TODO test this
|
// TODO test this
|
||||||
async update(transaction) {
|
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)
|
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
|
// 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(
|
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},
|
accountId: {type: Schema.Types.ObjectId, required: true},
|
||||||
|
|
||||||
/** @property {String} [name] -name of the category */
|
/** @property {String} [name] -name of the category */
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ async create(newTransaction) {
|
|||||||
return dbTransaction
|
return dbTransaction
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO need to populate categories
|
||||||
async getAll(accountId) {
|
async getAll(accountId) {
|
||||||
if (!accountId) {
|
if (!accountId) {
|
||||||
throw new BadRequest("User not logged in")
|
throw new BadRequest("User not logged in")
|
||||||
@@ -19,8 +20,6 @@ async getAll(accountId) {
|
|||||||
return allTransactions
|
return allTransactions
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO test this
|
|
||||||
// TODO fix this
|
|
||||||
async update(accountId, transactionId, update) {
|
async update(accountId, transactionId, update) {
|
||||||
if (!transactionId) {
|
if (!transactionId) {
|
||||||
throw new BadRequest('Bad transaction id')
|
throw new BadRequest('Bad transaction id')
|
||||||
|
|||||||
Reference in New Issue
Block a user