cat editor: add 'add product' dialog
This commit is contained in:
72
cateditor/src/components/AddProductDialog.vue
Normal file
72
cateditor/src/components/AddProductDialog.vue
Normal file
@ -0,0 +1,72 @@
|
||||
<template>
|
||||
<div class="text-xs-center">
|
||||
<v-dialog v-model="show" width="250">
|
||||
<v-card>
|
||||
|
||||
<v-card class="subheading font-weight-bold ma-0 pa-0 white--text" color="keen_dark_grey">
|
||||
<v-card-title class="ma-0 pa-2 pl-3">
|
||||
Add Materials
|
||||
<v-spacer></v-spacer>
|
||||
<v-icon color="white" @click="show = false">clear</v-icon>
|
||||
</v-card-title>
|
||||
</v-card>
|
||||
|
||||
<v-card-text>
|
||||
<p>Enter lots of material numbers to add to the catalog</p>
|
||||
<v-textarea
|
||||
v-model="text"
|
||||
autofocus
|
||||
label="Material numbers"
|
||||
placeholder="1001234
|
||||
1001235..."
|
||||
clearable
|
||||
></v-textarea>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn small flat @click="show = false">Cancel</v-btn>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn small color="primary" class="black--text" @click="doAdd()">Add</v-btn>
|
||||
<v-spacer></v-spacer>
|
||||
</v-card-actions>
|
||||
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions } from 'vuex'
|
||||
|
||||
export default {
|
||||
data: () => ({
|
||||
text: null,
|
||||
}),
|
||||
props: {
|
||||
value: Boolean,
|
||||
},
|
||||
computed: {
|
||||
show: {
|
||||
get() {
|
||||
return this.value
|
||||
},
|
||||
set(value) {
|
||||
this.$emit('input', value)
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapActions([
|
||||
'fetchProducts',
|
||||
]),
|
||||
|
||||
doAdd: function() {
|
||||
console.log('adding text', this.text)
|
||||
this.show = false
|
||||
this.fetchProducts(this.text)
|
||||
},
|
||||
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@ -2,8 +2,7 @@
|
||||
<v-container fluid grid-list-lg ma-0 pa-1>
|
||||
|
||||
<v-layout row fill-height>
|
||||
<v-btn @click="step = 1">Add products</v-btn>
|
||||
<v-btn @click="step = 3">Auto arrange</v-btn>
|
||||
<v-btn @click="showAddProductDialog = true">Add products</v-btn>
|
||||
</v-layout>
|
||||
|
||||
<v-layout row fill-height>
|
||||
@ -20,7 +19,7 @@
|
||||
@click="selectSection(item.id)"
|
||||
>
|
||||
<!-- TODO try move sectionparent into v-list-title
|
||||
and so section-drop can cover all interior
|
||||
and so section-drop can cover all interior
|
||||
-->
|
||||
<v-list-tile-content class="section-parent">
|
||||
<v-list-tile-title v-html="item.name"></v-list-tile-title>
|
||||
@ -126,6 +125,8 @@
|
||||
|
||||
</v-layout>
|
||||
|
||||
<AddProductDialog v-model="showAddProductDialog"/>
|
||||
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
@ -136,18 +137,17 @@ import arrayMove from 'array-move'
|
||||
//import RawDisplayer from './RawDisplayer'
|
||||
import { paginateModels } from '@/pagination'
|
||||
import DragListHeading from './DragListHeading'
|
||||
import AddProductDialog from './AddProductDialog'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
DragListHeading,
|
||||
AddProductDialog,
|
||||
//RawDisplayer,
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
// NOTE do we need?
|
||||
'placeholderText': 'placeholder',
|
||||
// NOTE do we need?
|
||||
'selected': null,
|
||||
showAddProductDialog: false,
|
||||
}),
|
||||
computed: {
|
||||
...mapState([
|
||||
@ -186,13 +186,23 @@ export default {
|
||||
this.$store.dispatch('selectModel', id)
|
||||
},
|
||||
|
||||
sectionModelCount(sectionID) {
|
||||
let section = this.section(sectionID)
|
||||
if (section) {
|
||||
let models = this.sectionModels(section) || []
|
||||
return models.length
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
},
|
||||
|
||||
sectionListItemClasses: function(id, hovering) {
|
||||
if (id === this.selectedSectionID) {
|
||||
return 'list-item primary'
|
||||
} else if (hovering) {
|
||||
return 'list-item grey lighten-4'
|
||||
} else {
|
||||
return ''
|
||||
return 'list-item'
|
||||
}
|
||||
},
|
||||
|
||||
@ -395,6 +405,12 @@ function addSectionDrops(myvue) {
|
||||
}
|
||||
|
||||
.list-item {
|
||||
//border-bottom: 1px solid #ddd;
|
||||
background-color: white;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.list-group {
|
||||
background-color: #f0f0ff;
|
||||
min-height: 200px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -2,7 +2,7 @@ import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
import arrayMove from 'array-move'
|
||||
import axios from 'axios'
|
||||
import { paginateModels } from '@/pagination'
|
||||
import { paginateModels, sectionTitle, extendModelFromMaterial } from '@/pagination'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
@ -16,6 +16,7 @@ export const store = new Vuex.Store({
|
||||
selectedMaterial: null,
|
||||
loadingCatalog: false,
|
||||
savingCatalog: false,
|
||||
loadingProducts: false,
|
||||
},
|
||||
getters: {
|
||||
|
||||
@ -41,6 +42,18 @@ export const store = new Vuex.Store({
|
||||
}
|
||||
},
|
||||
|
||||
nextSectionID: state => {
|
||||
if (state.catalog != null) {
|
||||
let id = 0
|
||||
for (let section of state.catalog.sections) {
|
||||
id = Math.max(id, section.id)
|
||||
}
|
||||
return id + 1
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
},
|
||||
|
||||
selectedSection: (state, getters) => {
|
||||
if (state.catalog && state.selectedSectionID) {
|
||||
return getters.section(state.selectedSectionID)
|
||||
@ -69,9 +82,7 @@ export const store = new Vuex.Store({
|
||||
// add extra info from a material
|
||||
let material = getters.material(model.ids[0])
|
||||
if (material) {
|
||||
model['name'] = material.name
|
||||
model['model'] = material.model
|
||||
model['family'] = material.family
|
||||
model = extendModelFromMaterial(material, model)
|
||||
} else {
|
||||
console.log('no material found for id', model.ids[0])
|
||||
}
|
||||
@ -152,6 +163,11 @@ export const store = new Vuex.Store({
|
||||
savingCatalog(state) {
|
||||
return state.savingCatalog
|
||||
},
|
||||
|
||||
loadingProducts(state) {
|
||||
return state.loadingProducts
|
||||
},
|
||||
|
||||
},
|
||||
mutations: {
|
||||
//
|
||||
@ -170,6 +186,10 @@ export const store = new Vuex.Store({
|
||||
// manipulation
|
||||
//
|
||||
|
||||
addSection(state, section) {
|
||||
state.catalog.sections.push(section)
|
||||
},
|
||||
|
||||
reorderSection(state, { from, to }) {
|
||||
if (from === to) return
|
||||
state.catalog.sections = arrayMove(state.catalog.sections, from, to)
|
||||
@ -235,6 +255,10 @@ export const store = new Vuex.Store({
|
||||
state.savingCatalog = value
|
||||
},
|
||||
|
||||
setLoadingProducts(state, value) {
|
||||
state.loadingProducts = value
|
||||
},
|
||||
|
||||
setCatalogProperty(state, { key, value }) {
|
||||
console.log('mutation set prop', key, value)
|
||||
if (state.catalog) {
|
||||
@ -325,6 +349,73 @@ export const store = new Vuex.Store({
|
||||
commit('setSectionPages', { section: newSection, pages: newPages })
|
||||
},
|
||||
|
||||
addMaterialToCatalog({ commit, getters, state }, material) {
|
||||
if (!state.catalog) {
|
||||
console.log('no catalog to add materials to')
|
||||
return
|
||||
}
|
||||
|
||||
// ensure material, not just id
|
||||
if (typeof material === 'string' || typeof material === 'number') {
|
||||
material = getters.material(material)
|
||||
}
|
||||
|
||||
let foundSection = null
|
||||
let foundModels = null
|
||||
|
||||
// look for an existing model in all our sections.
|
||||
// add to first one found.
|
||||
for (let section of state.catalog.sections) {
|
||||
let models = getters.sectionModels(section)
|
||||
let existingModel = models.find(m => m.model === material.model)
|
||||
console.log('section', section.id, 'existing model search', existingModel)
|
||||
if (existingModel) {
|
||||
// prevent duplicates here, but also allow adding the same
|
||||
// id again to a catalog. put in a new section so it can be
|
||||
// placed elsewhere?
|
||||
let existingMaterial = existingModel.ids.find(m => m.id === material.id)
|
||||
console.log('model', existingModel.model, 'existing material', existingMaterial)
|
||||
if (!existingMaterial) {
|
||||
existingModel.ids.push(material.id)
|
||||
foundSection = section
|
||||
foundModels = models
|
||||
} else {
|
||||
console.log('skip duplicate')
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundSection) {
|
||||
// see if we match a section, add a new model at the end
|
||||
let title = sectionTitle(material)
|
||||
for (let section of state.catalog.sections) {
|
||||
if (title === section.name) {
|
||||
let newModel = extendModelFromMaterial(material)
|
||||
let models = getters.sectionModels(section)
|
||||
models.push(newModel)
|
||||
foundSection = section
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// still nothing, add into a new section
|
||||
if (!foundSection) {
|
||||
let title = sectionTitle(material)
|
||||
let newModel = extendModelFromMaterial(material)
|
||||
foundModels = [newModel]
|
||||
foundSection = {
|
||||
'id': getters.nextSectionID,
|
||||
'name': title,
|
||||
}
|
||||
commit('addSection', foundSection)
|
||||
}
|
||||
|
||||
let pages = paginateModels(foundModels)
|
||||
commit('setSectionPages', { section: foundSection, pages: pages })
|
||||
},
|
||||
|
||||
// SET_CAT_SECTIONS: (context, payload) => {
|
||||
// context.commit('SET_CAT_SECTIONS', payload)
|
||||
// },
|
||||
@ -356,6 +447,32 @@ export const store = new Vuex.Store({
|
||||
commit('setCatalog', {})
|
||||
},
|
||||
|
||||
async fetchProducts({ commit, dispatch }, text) {
|
||||
commit('setLoadingProducts', true)
|
||||
axios.post('/api/v1/products/search', text)
|
||||
.then(function(response) {
|
||||
commit('setLoadingProducts', false)
|
||||
|
||||
if (response.data && response.data.missing) {
|
||||
// TODO display these somehow
|
||||
console.log('missing ids:', response.data.missing)
|
||||
}
|
||||
|
||||
if (response.data && response.data.found) {
|
||||
console.log('found prods:', response.data.found)
|
||||
commit('addMaterialsToLibrary', response.data.found)
|
||||
for (let material of response.data.found) {
|
||||
dispatch('addMaterialToCatalog', material)
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(function(error) {
|
||||
commit('setLoadingProducts', false)
|
||||
// TODO set saving error property
|
||||
console.error('error searching for prods: ', error)
|
||||
})
|
||||
},
|
||||
|
||||
async loadCatalog({ commit }, id) {
|
||||
try {
|
||||
commit('setLoadingCatalog', true)
|
||||
|
||||
@ -43,3 +43,36 @@ export function sectionModels(section) {
|
||||
|
||||
return models
|
||||
}
|
||||
|
||||
export function sectionTitle(material) {
|
||||
// "Trailhead (Men)"
|
||||
if (material) {
|
||||
return `${material.category} (${material.gender})`
|
||||
} else {
|
||||
return '(unknown)'
|
||||
}
|
||||
}
|
||||
|
||||
// add properties from the material to the model,
|
||||
// creating it if necessary.
|
||||
export function extendModelFromMaterial(material, model = {}) {
|
||||
if (material) {
|
||||
if (!model['name']) {
|
||||
// don't overwrite possibly overridden value
|
||||
model['name'] = material.name
|
||||
}
|
||||
model['model'] = material.model
|
||||
model['family'] = material.family
|
||||
model['gender'] = material.gender
|
||||
model['category'] = material.category
|
||||
|
||||
// make sure the material id is in the list
|
||||
let ids = model['ids'] || []
|
||||
if (!ids.includes(material.id)) {
|
||||
ids.push(material.id)
|
||||
model['ids'] = ids
|
||||
}
|
||||
}
|
||||
|
||||
return model
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user