new datastructure
This commit is contained in:
parent
b0c561661b
commit
d3376b33d8
@ -1,6 +1,7 @@
|
||||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="vaben">
|
||||
<words>
|
||||
<w>mealplan</w>
|
||||
<w>pinia</w>
|
||||
<w>selfhosted</w>
|
||||
<w>unapplied</w>
|
||||
|
@ -53,7 +53,7 @@
|
||||
|
||||
<!-- shopping list table -->
|
||||
|
||||
<b-row v-for="c in shopping_list_store.category_food_entries" v-bind:key="c.id" class="pr-4 pl-4">
|
||||
<b-row v-for="c in shopping_list_store.get_entries_by_group" v-bind:key="c.id" class="pr-4 pl-4">
|
||||
<b-col cols="12">
|
||||
<b-button-group class="w-100 mt-1">
|
||||
<b-button variant="light" block class="btn btn-block text-left">
|
||||
@ -750,7 +750,7 @@ export default {
|
||||
handler() {
|
||||
this.$cookies.set(SETTINGS_COOKIE_NAME, {ui: this.ui, settings: {entrymode: this.entrymode}}, "100y")
|
||||
if (this.entrymode) {
|
||||
document.getElementById('shoppinglist').scrollTop = 0
|
||||
//document.getElementById('shoppinglist').scrollTop = 0
|
||||
this.$nextTick(function () {
|
||||
this.setFocus()
|
||||
})
|
||||
|
@ -3,21 +3,18 @@
|
||||
<div id="app">
|
||||
<div>
|
||||
|
||||
|
||||
|
||||
<b-button-group class="w-100 mb-1" >
|
||||
<b-button variant="dark" block class="btn btn-block btn-sm text-left " >100 g Möhren Test <br/><small class="text-muted">Info</small></b-button>
|
||||
<b-button variant="success"><i class="fas fa-check"></i></b-button>
|
||||
</b-button-group>
|
||||
<br/>
|
||||
<b-button-group class="w-100">
|
||||
<b-button variant="dark" block class="btn btn-block text-left" >150 ml Heißwassermöhrenbrühe<br/><small class="text-muted">Info</small></b-button>
|
||||
<b-button variant="success"><i class="fas fa-check"></i></b-button>
|
||||
</b-button-group>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<generic-multiselect
|
||||
:model="Models.SHOPPING_CATEGORY"
|
||||
:multiple="false"
|
||||
></generic-multiselect>
|
||||
<generic-multiselect
|
||||
:model="Models.SHOPPING_CATEGORY"
|
||||
:multiple="false"
|
||||
></generic-multiselect>
|
||||
<generic-multiselect
|
||||
:model="Models.SHOPPING_CATEGORY"
|
||||
:multiple="false"
|
||||
></generic-multiselect>
|
||||
----
|
||||
|
||||
<markdown-editor-component></markdown-editor-component>
|
||||
@ -48,7 +45,7 @@ Vue.use(BootstrapVue)
|
||||
export default {
|
||||
name: "TestView",
|
||||
mixins: [ApiMixin],
|
||||
components: {MarkdownEditorComponent},
|
||||
components: {GenericMultiselect, MarkdownEditorComponent},
|
||||
computed: {},
|
||||
data() {
|
||||
return {}
|
||||
|
@ -2,7 +2,7 @@
|
||||
<div id="shopping_line_item">
|
||||
|
||||
<b-button-group class="w-100" v-if="useShoppingListStore().show_checked_entries || !is_checked">
|
||||
<b-button :class="{'btn-dark': !is_checked, 'btn-success': is_checked}" block class="btn btn-block text-left" @click="detail_modal_visible = true">
|
||||
<b-button :class="{'btn-dark': (!is_checked && !is_delayed), 'btn-success': is_checked, 'btn-warning': is_delayed}" block class="btn btn-block text-left" @click="detail_modal_visible = true">
|
||||
<div class="d-flex ">
|
||||
<div class="d-flex flex-column pr-2" v-if="Object.keys(amounts).length> 0">
|
||||
<span v-for="a in amounts" v-bind:key="a.id">{{ a.amount }} {{ a.unit }}<br/></span>
|
||||
@ -17,7 +17,7 @@
|
||||
|
||||
|
||||
</b-button>
|
||||
<b-button variant="success" @click="useShoppingListStore().setFoodCheckedState(food, !is_checked)" :class="{'btn-success': !is_checked, 'btn-warning': is_checked}">
|
||||
<b-button variant="success" @click="useShoppingListStore().setEntriesCheckedState(entries, !is_checked)" :class="{'btn-success': !is_checked, 'btn-warning': is_checked}">
|
||||
<i class="fas" :class="{'fa-check': !is_checked, 'fa-times': is_checked}"></i>
|
||||
</b-button>
|
||||
</b-button-group>
|
||||
@ -31,7 +31,7 @@
|
||||
</template>
|
||||
|
||||
<template #default>
|
||||
<h6 class="mt-2">Actions</h6> <!-- TODO localize -->
|
||||
<h6 class="mt-2">{{ $t('Quick actions')}}</h6>
|
||||
<b-form-select
|
||||
class="form-control mb-2"
|
||||
:options="useShoppingListStore().supermarket_categories"
|
||||
@ -39,11 +39,11 @@
|
||||
value-field="id"
|
||||
v-model="food.supermarket_category"
|
||||
@change="detail_modal_visible = false; updateFoodCategory(food)"
|
||||
></b-form-select> <!-- TODO change to lookup input or something else that works with dicts -->
|
||||
></b-form-select>
|
||||
|
||||
<b-button variant="success" block @click="detail_modal_visible = false;"> {{ $t("Edit_Food") }}</b-button> <!-- TODO implement -->
|
||||
|
||||
<b-button variant="info" block @click="detail_modal_visible = false;useShoppingListStore().delayFood(food)">{{ $t('Delay') }}</b-button>
|
||||
<b-button variant="info" block @click="detail_modal_visible = false;useShoppingListStore().delayEntries(entries)">{{ $t('Delay') }}</b-button>
|
||||
|
||||
|
||||
<h6 class="mt-2">{{ $t('Entries') }}</h6>
|
||||
@ -118,6 +118,14 @@ export default {
|
||||
}
|
||||
return true
|
||||
},
|
||||
is_delayed: function () {
|
||||
for (let i in this.entries) {
|
||||
if ( Date.parse(this.entries[i].delay_until) > new Date(Date.now())) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
},
|
||||
food: function () {
|
||||
return this.entries[Object.keys(this.entries)[0]]['food']
|
||||
},
|
||||
@ -210,7 +218,7 @@ export default {
|
||||
|
||||
updateFoodCategory: function (food) {
|
||||
|
||||
if (typeof food.supermarket_category === "number"){
|
||||
if (typeof food.supermarket_category === "number"){ // not the best solution, but as long as generic multiselect does not support caching, I don't want to use a proper model
|
||||
food.supermarket_category = this.useShoppingListStore().supermarket_categories.filter(sc => sc.id === food.supermarket_category)[0]
|
||||
}
|
||||
|
||||
|
@ -2,15 +2,18 @@ import {ApiApiFactory} from "@/utils/openapi/api"
|
||||
import {StandardToasts} from "@/utils/utils"
|
||||
import {defineStore} from "pinia"
|
||||
import Vue from "vue"
|
||||
import _ from 'lodash';
|
||||
|
||||
const _STORE_ID = "shopping_list_store"
|
||||
const _LOCAL_STORAGE_KEY = "SHOPPING_LIST_CLIENT_SETTINGS"
|
||||
/*
|
||||
* test store to play around with pinia and see if it can work for my usecases
|
||||
* dont trust that all shopping list entries are in store as there is no cache validation logic, its just a shared data holder
|
||||
* test store to play around with pinia and see if it can work for my use cases
|
||||
* don't trust that all shopping list entries are in store as there is no cache validation logic, its just a shared data holder
|
||||
* */
|
||||
export const useShoppingListStore = defineStore(_STORE_ID, {
|
||||
state: () => ({
|
||||
entries: {},
|
||||
|
||||
category_food_entries: {},
|
||||
supermarket_categories: [],
|
||||
|
||||
@ -18,9 +21,25 @@ export const useShoppingListStore = defineStore(_STORE_ID, {
|
||||
|
||||
currently_updating: false,
|
||||
settings: null,
|
||||
|
||||
|
||||
GROUP_CATEGORY: 'food.supermarket_category.name',
|
||||
GROUP_CREATED_BY: 'created_by.display_name',
|
||||
GROUP_RECIPE: 'recipe_mealplan.recipe_name',
|
||||
GROUP_MEALPLAN: 'recipe_mealplan.mealplan', //TODO give this some name from the API
|
||||
|
||||
selected_group: 'food.supermarket_category.name',
|
||||
}),
|
||||
getters: {
|
||||
|
||||
get_entries_by_group: function () {
|
||||
let structure = {}
|
||||
for (let i in this.entries) {
|
||||
structure = this.updateEntryInStructure(structure, this.entries[i], this.selected_group)
|
||||
}
|
||||
return structure
|
||||
},
|
||||
|
||||
client_settings: function () {
|
||||
if (this.settings === null) {
|
||||
this.settings = this.loadClientSettings()
|
||||
@ -41,7 +60,7 @@ export const useShoppingListStore = defineStore(_STORE_ID, {
|
||||
let apiClient = new ApiApiFactory()
|
||||
apiClient.listShoppingListEntrys().then((r) => {
|
||||
r.data.forEach((e) => {
|
||||
this.updateEntryInStructure(e)
|
||||
Vue.set(this.entries, e.id, e)
|
||||
})
|
||||
this.currently_updating = false
|
||||
}).catch((err) => {
|
||||
@ -61,7 +80,7 @@ export const useShoppingListStore = defineStore(_STORE_ID, {
|
||||
// TODO shared handled in backend?
|
||||
|
||||
return apiClient.createShoppingListEntry(object).then((r) => {
|
||||
this.updateEntryInStructure(r.data)
|
||||
Vue.set(this.entries, r.data.id, r.data)
|
||||
}).catch((err) => {
|
||||
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err)
|
||||
})
|
||||
@ -69,7 +88,7 @@ export const useShoppingListStore = defineStore(_STORE_ID, {
|
||||
updateObject(object) {
|
||||
let apiClient = new ApiApiFactory()
|
||||
return apiClient.updateShoppingListEntry(object.id, object).then((r) => {
|
||||
this.updateEntryInStructure(r.data)
|
||||
Vue.set(this.entries, r.data.id, r.data)
|
||||
}).catch((err) => {
|
||||
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err)
|
||||
})
|
||||
@ -114,28 +133,41 @@ export const useShoppingListStore = defineStore(_STORE_ID, {
|
||||
}
|
||||
return -1
|
||||
},
|
||||
updateEntryInStructure(entry) {
|
||||
let category = this.getFoodCategory(entry.food)
|
||||
if (!(category in this.category_food_entries)) {
|
||||
Vue.set(this.category_food_entries, category, {'id': category, 'name': entry.food.supermarket_category.name, 'foods': {}})
|
||||
/**
|
||||
* function to set entry to its proper place in the data structure to perform grouping
|
||||
* @param {{}} structure datastructure
|
||||
* @param {*} entry entry to place
|
||||
* @param {*} group group to place entry into (must be of ShoppingListStore.GROUP_XXX/dot notation of entry property)
|
||||
* @returns updated datastructure including entry
|
||||
*/
|
||||
updateEntryInStructure(structure, entry, group) {
|
||||
let grouping_key = _.get(entry, group, -1)
|
||||
// todo handele parent
|
||||
if (grouping_key === undefined || grouping_key === null) {
|
||||
grouping_key = -1
|
||||
}
|
||||
if (!(entry.food.id in this.category_food_entries[category]['foods'])) {
|
||||
Vue.set(this.category_food_entries[category]['foods'], entry.food.id, {'id': entry.food.id, 'name': entry.food.name, 'entries': {}})
|
||||
}
|
||||
Vue.set(this.category_food_entries[category]['foods'][entry.food.id]['entries'], entry.id, entry)
|
||||
},
|
||||
setFoodCheckedState(food, checked) {
|
||||
/**
|
||||
* function to handle user checking or unchecking a food
|
||||
*/
|
||||
|
||||
let entries = this.category_food_entries[this.getFoodCategory(food)]['foods'][food.id]['entries']
|
||||
if (!(grouping_key in structure)) {
|
||||
Vue.set(structure, grouping_key, {'name': grouping_key, 'foods': {}})
|
||||
}
|
||||
if (!(entry.food.id in structure[grouping_key]['foods'])) {
|
||||
Vue.set(structure[grouping_key]['foods'], entry.food.id, {'id': entry.food.id, 'name': entry.food.name, 'entries': {}})
|
||||
}
|
||||
Vue.set(structure[grouping_key]['foods'][entry.food.id]['entries'], entry.id, entry)
|
||||
return structure
|
||||
},
|
||||
/**
|
||||
* function to handle user checking or unchecking a set of entries
|
||||
* @param {{}} entries set of entries
|
||||
* @param checked boolean to set checked state of entry to
|
||||
*/
|
||||
setEntriesCheckedState(entries, checked) {
|
||||
for (let i in entries) {
|
||||
entries[i].checked = checked
|
||||
this.updateObject(entries[i])
|
||||
this.entries[i].checked = checked
|
||||
this.updateObject(this.entries[i])
|
||||
}
|
||||
},
|
||||
delayFood(food) {
|
||||
delayEntries(entries) {
|
||||
/**
|
||||
* function to handle user "delaying" shopping entry
|
||||
* takes a food object as an argument and delays all entries associated with the food
|
||||
@ -143,12 +175,11 @@ export const useShoppingListStore = defineStore(_STORE_ID, {
|
||||
let delay = 4 //TODO get delay from settings
|
||||
let delay_date = new Date(Date.now() + delay * (60 * 60 * 1000))
|
||||
|
||||
let entries = this.category_food_entries[this.getFoodCategory(food)]['foods'][food.id]['entries']
|
||||
for (let i in entries) {
|
||||
entries[i].delayed_until = delay_date
|
||||
this.updateObject(entries[i])
|
||||
console.log('DELAYING ', i, ' until ', delay_date)
|
||||
this.entries[i].delay_until = delay_date
|
||||
this.updateObject(this.entries[i])
|
||||
}
|
||||
|
||||
},
|
||||
deleteFood(food) {
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user