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-container fluid grid-list-lg ma-0 pa-1>
|
||||||
|
|
||||||
<v-layout row fill-height>
|
<v-layout row fill-height>
|
||||||
<v-btn @click="step = 1">Add products</v-btn>
|
<v-btn @click="showAddProductDialog = true">Add products</v-btn>
|
||||||
<v-btn @click="step = 3">Auto arrange</v-btn>
|
|
||||||
</v-layout>
|
</v-layout>
|
||||||
|
|
||||||
<v-layout row fill-height>
|
<v-layout row fill-height>
|
||||||
@ -20,7 +19,7 @@
|
|||||||
@click="selectSection(item.id)"
|
@click="selectSection(item.id)"
|
||||||
>
|
>
|
||||||
<!-- TODO try move sectionparent into v-list-title
|
<!-- 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-content class="section-parent">
|
||||||
<v-list-tile-title v-html="item.name"></v-list-tile-title>
|
<v-list-tile-title v-html="item.name"></v-list-tile-title>
|
||||||
@ -126,6 +125,8 @@
|
|||||||
|
|
||||||
</v-layout>
|
</v-layout>
|
||||||
|
|
||||||
|
<AddProductDialog v-model="showAddProductDialog"/>
|
||||||
|
|
||||||
</v-container>
|
</v-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -136,18 +137,17 @@ import arrayMove from 'array-move'
|
|||||||
//import RawDisplayer from './RawDisplayer'
|
//import RawDisplayer from './RawDisplayer'
|
||||||
import { paginateModels } from '@/pagination'
|
import { paginateModels } from '@/pagination'
|
||||||
import DragListHeading from './DragListHeading'
|
import DragListHeading from './DragListHeading'
|
||||||
|
import AddProductDialog from './AddProductDialog'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
DragListHeading,
|
DragListHeading,
|
||||||
|
AddProductDialog,
|
||||||
//RawDisplayer,
|
//RawDisplayer,
|
||||||
},
|
},
|
||||||
|
|
||||||
data: () => ({
|
data: () => ({
|
||||||
// NOTE do we need?
|
showAddProductDialog: false,
|
||||||
'placeholderText': 'placeholder',
|
|
||||||
// NOTE do we need?
|
|
||||||
'selected': null,
|
|
||||||
}),
|
}),
|
||||||
computed: {
|
computed: {
|
||||||
...mapState([
|
...mapState([
|
||||||
@ -186,13 +186,23 @@ export default {
|
|||||||
this.$store.dispatch('selectModel', id)
|
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) {
|
sectionListItemClasses: function(id, hovering) {
|
||||||
if (id === this.selectedSectionID) {
|
if (id === this.selectedSectionID) {
|
||||||
return 'list-item primary'
|
return 'list-item primary'
|
||||||
} else if (hovering) {
|
} else if (hovering) {
|
||||||
return 'list-item grey lighten-4'
|
return 'list-item grey lighten-4'
|
||||||
} else {
|
} else {
|
||||||
return ''
|
return 'list-item'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -395,6 +405,12 @@ function addSectionDrops(myvue) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.list-item {
|
.list-item {
|
||||||
//border-bottom: 1px solid #ddd;
|
background-color: white;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-group {
|
||||||
|
background-color: #f0f0ff;
|
||||||
|
min-height: 200px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import Vue from 'vue'
|
|||||||
import Vuex from 'vuex'
|
import Vuex from 'vuex'
|
||||||
import arrayMove from 'array-move'
|
import arrayMove from 'array-move'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { paginateModels } from '@/pagination'
|
import { paginateModels, sectionTitle, extendModelFromMaterial } from '@/pagination'
|
||||||
|
|
||||||
Vue.use(Vuex)
|
Vue.use(Vuex)
|
||||||
|
|
||||||
@ -16,6 +16,7 @@ export const store = new Vuex.Store({
|
|||||||
selectedMaterial: null,
|
selectedMaterial: null,
|
||||||
loadingCatalog: false,
|
loadingCatalog: false,
|
||||||
savingCatalog: false,
|
savingCatalog: false,
|
||||||
|
loadingProducts: false,
|
||||||
},
|
},
|
||||||
getters: {
|
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) => {
|
selectedSection: (state, getters) => {
|
||||||
if (state.catalog && state.selectedSectionID) {
|
if (state.catalog && state.selectedSectionID) {
|
||||||
return getters.section(state.selectedSectionID)
|
return getters.section(state.selectedSectionID)
|
||||||
@ -69,9 +82,7 @@ export const store = new Vuex.Store({
|
|||||||
// add extra info from a material
|
// add extra info from a material
|
||||||
let material = getters.material(model.ids[0])
|
let material = getters.material(model.ids[0])
|
||||||
if (material) {
|
if (material) {
|
||||||
model['name'] = material.name
|
model = extendModelFromMaterial(material, model)
|
||||||
model['model'] = material.model
|
|
||||||
model['family'] = material.family
|
|
||||||
} else {
|
} else {
|
||||||
console.log('no material found for id', model.ids[0])
|
console.log('no material found for id', model.ids[0])
|
||||||
}
|
}
|
||||||
@ -152,6 +163,11 @@ export const store = new Vuex.Store({
|
|||||||
savingCatalog(state) {
|
savingCatalog(state) {
|
||||||
return state.savingCatalog
|
return state.savingCatalog
|
||||||
},
|
},
|
||||||
|
|
||||||
|
loadingProducts(state) {
|
||||||
|
return state.loadingProducts
|
||||||
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
//
|
//
|
||||||
@ -170,6 +186,10 @@ export const store = new Vuex.Store({
|
|||||||
// manipulation
|
// manipulation
|
||||||
//
|
//
|
||||||
|
|
||||||
|
addSection(state, section) {
|
||||||
|
state.catalog.sections.push(section)
|
||||||
|
},
|
||||||
|
|
||||||
reorderSection(state, { from, to }) {
|
reorderSection(state, { from, to }) {
|
||||||
if (from === to) return
|
if (from === to) return
|
||||||
state.catalog.sections = arrayMove(state.catalog.sections, from, to)
|
state.catalog.sections = arrayMove(state.catalog.sections, from, to)
|
||||||
@ -235,6 +255,10 @@ export const store = new Vuex.Store({
|
|||||||
state.savingCatalog = value
|
state.savingCatalog = value
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setLoadingProducts(state, value) {
|
||||||
|
state.loadingProducts = value
|
||||||
|
},
|
||||||
|
|
||||||
setCatalogProperty(state, { key, value }) {
|
setCatalogProperty(state, { key, value }) {
|
||||||
console.log('mutation set prop', key, value)
|
console.log('mutation set prop', key, value)
|
||||||
if (state.catalog) {
|
if (state.catalog) {
|
||||||
@ -325,6 +349,73 @@ export const store = new Vuex.Store({
|
|||||||
commit('setSectionPages', { section: newSection, pages: newPages })
|
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) => {
|
// SET_CAT_SECTIONS: (context, payload) => {
|
||||||
// context.commit('SET_CAT_SECTIONS', payload)
|
// context.commit('SET_CAT_SECTIONS', payload)
|
||||||
// },
|
// },
|
||||||
@ -356,6 +447,32 @@ export const store = new Vuex.Store({
|
|||||||
commit('setCatalog', {})
|
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) {
|
async loadCatalog({ commit }, id) {
|
||||||
try {
|
try {
|
||||||
commit('setLoadingCatalog', true)
|
commit('setLoadingCatalog', true)
|
||||||
|
|||||||
@ -43,3 +43,36 @@ export function sectionModels(section) {
|
|||||||
|
|
||||||
return models
|
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