diff options
Diffstat (limited to 'iridescence/src/components')
-rw-r--r-- | iridescence/src/components/ProductSearch.vue | 2 | ||||
-rw-r--r-- | iridescence/src/components/admin/NewProduct.vue | 17 | ||||
-rw-r--r-- | iridescence/src/components/admin/ProductEditCard.vue | 229 | ||||
-rw-r--r-- | iridescence/src/components/admin/ProductEditList.vue | 6 |
4 files changed, 159 insertions, 95 deletions
diff --git a/iridescence/src/components/ProductSearch.vue b/iridescence/src/components/ProductSearch.vue index d452e83..60da209 100644 --- a/iridescence/src/components/ProductSearch.vue +++ b/iridescence/src/components/ProductSearch.vue @@ -40,7 +40,7 @@ export default { }, computed: { noResults() { - return !this.$store.getters.products.length; + return !this.$store.getters.products.length && !this.$store.getters.busy; } }, methods: { diff --git a/iridescence/src/components/admin/NewProduct.vue b/iridescence/src/components/admin/NewProduct.vue index 48eb165..cd8a93e 100644 --- a/iridescence/src/components/admin/NewProduct.vue +++ b/iridescence/src/components/admin/NewProduct.vue @@ -17,7 +17,7 @@ <button class="delete" @click="toggleModal"></button> </header> <section class="modal-card-body"> - <ProductEditCard v-bind:parent-product="template"></ProductEditCard> + <ProductEditCard v-bind:index="-1"></ProductEditCard> </section> <footer class="modal-card-foot"></footer> </div> @@ -27,7 +27,6 @@ </template> <script> -import Product from "@/models/product"; import ProductEditCard from "@/components/admin/ProductEditCard"; export default { @@ -37,11 +36,19 @@ export default { }, data: function() { return { - modalEnabled: false, - template: new Product({}), - addAnother: false + modalEnabled: false }; }, + computed: { + numProducts: function() { + return this.$store.getters.products.length; + } + }, + watch: { + numProducts: function() { + this.modalEnabled = false; + } + }, methods: { toggleModal() { this.modalEnabled = !this.modalEnabled; diff --git a/iridescence/src/components/admin/ProductEditCard.vue b/iridescence/src/components/admin/ProductEditCard.vue index a8117ce..aced39c 100644 --- a/iridescence/src/components/admin/ProductEditCard.vue +++ b/iridescence/src/components/admin/ProductEditCard.vue @@ -2,17 +2,38 @@ <div id="productEditCard"> <div class="card"> <div class="card-header"> - <p class="card-header-title" v-if="currentProduct.id"> - {{ currentProduct.id }}: {{ currentProduct.name }} + <p class="card-header-title" v-if="old.id"> + {{ old.id }}: {{ old.name }} </p> </div> <div class="card-content"> <div class="field"> + <div class="file has-name is-boxed is-fullwidth"> + <label class="file-label"> + <input + class="file-input" + type="file" + name="image" + accept=".jpg,.jpeg,.JPG,.JPEG" + @change="changePhotoSet" + /> + <span class="file-cta"> + <span class="file-label has-text-centered"> + Upload a Photo + </span> + </span> + <span class="file-name"> + {{ filename }} + </span> + </label> + </div> + </div> + <div class="field"> <input class="input" type="text" placeholder="(product name)" - v-model="newProduct.name" + v-model="name" /> </div> <div class="field"> @@ -20,7 +41,7 @@ class="input" type="text" placeholder="(product category)" - v-model="newProduct.category_path" + v-model="category" /> </div> <div class="field has-addons"> @@ -34,7 +55,7 @@ class="input" type="text" placeholder="inventory (quantity)" - v-model="newProductQuantity" + v-model="quantity" /> </p> <div class="control"> @@ -62,148 +83,184 @@ class="input" type="text" placeholder="price" - v-model="newProductPrice" + v-model="price" /> </p> </div> <div class="field"> - <div class="file has-name is-boxed is-fullwidth"> - <label class="file-label"> - <input - class="file-input" - type="file" - name="image" - accept=".jpg,.jpeg,.JPG,.JPEG" - @change="changePhotoSet" - /> - <span class="file-cta"> - <span class="file-label has-text-centered"> - ↑ Choose a picture… - </span> - </span> - <span class="file-name"> - {{ filename }} - </span> - </label> - </div> - </div> - <div class="field"> <textarea class="textarea" type="text" placeholder="(product description)" - v-model="newProduct.description" + v-model="description" > </textarea> </div> <div class="field"> <label class="checkbox"> - <input type="checkbox" v-model="newProduct.featured" /> + <input type="checkbox" v-model="featured" /> Featured? </label> </div> </div> - <transition - enter-active-class="animate__animated animate__fadeIn" - leave-active-class="animate__animated animate__fadeOut" - > - <div - class="card-footer" - v-if=" - newProduct.isValidPost() || newProduct.isValidPatch(currentProduct) - " - > - <div class="card-footer-item"> - <button class="button is-primary is-fullwidth" @click="saveProduct"> - Save - </button> - </div> + <div class="card-footer" v-if="isValidPost || isValidPatch"> + <div class="card-footer-item"> + <button class="button is-primary is-fullwidth" @click="saveProduct"> + Save + </button> </div> - </transition> + </div> </div> </div> </template> <script> -import Product from "@/models/product"; -import ProductDiff from "@/models/product_diff"; - const dollarRe = /^\$?(\d+)\.(\d{2})/gm; export default { name: "ProductEditCard", data: function() { return { - currentProduct: new Product(this.parentProduct), - newProduct: new ProductDiff(this.currentProduct), - filename: "" + filename: "", + diff: {} }; }, props: { - parentProduct: { - type: Product, + index: { + type: Number, required: true } }, + created() { + this.diff = { + id: (this.old && this.old.id) || null, + name: null, + description: null, + cents: null, + quantity: (this.old && this.old.quantity) || 0, + category_path: null, + featured: + this.old && typeof this.old.featured === "boolean" + ? this.old.featured + : false, + photo_set: null + }; + }, computed: { - newProductQuantity: { + old: function() { + return this.$store.getters.products[this.index] || {}; + }, + id: function() { + return this.diff.id || this.old.id; + }, + name: { get: function() { - return this.newProduct.quantity; + return this.diff.name || this.old.name; }, - set: function(val) { - if (!isNaN(val)) { - this.newProduct.quantity = 1 * val; - } + set: function(name) { + this.diff.name = name; } }, - newProductPrice: { + description: { get: function() { - return (this.newProduct.cents / 100).toFixed(2); + return this.diff.description || this.old.description; }, - set: function(val) { - const groups = dollarRe.exec(val); + set: function(description) { + this.diff.description = description; + } + }, + category: { + get: function() { + return this.diff.category_path || this.old.category; + }, + set: function(category) { + this.diff.category_path = category; + } + }, + featured: { + get: function() { + return this.diff.featured; + }, + set: function(featured) { + this.diff.featured = featured; + } + }, + price: { + get: function() { + const cents = this.diff.cents || this.old.cents || 0; + return (cents / 100).toFixed(2); + }, + set: function(price) { + const groups = dollarRe.exec(price); if (groups && groups[1] && groups[2]) { - this.newProduct.cents = 100 * groups[1] + 1 * groups[2]; + this.diff.cents = 100 * groups[1] + 1 * groups[2]; } } + }, + quantity: { + get: function() { + return this.diff.quantity || this.old.quantity || 0; + }, + set: function(quantity) { + if (Number.isFinite(quantity)) { + this.diff.quantity = quantity; + } + } + }, + isValidPost: function() { + return ( + !this.diff.id && + this.diff.name && + this.diff.description && + Number.isFinite(this.diff.cents) && + Number.isFinite(this.diff.quantity) && + this.diff.photo_set && + this.diff.category_path && + typeof this.featured === "boolean" + ); + }, + isValidPatch: function() { + return ( + this.diff.id && + (this.diff.photo_set || + (this.diff.name && this.diff.name != this.old.name) || + (Number.isFinite(this.diff.cents) && + this.diff.cents != this.old.cents) || + (this.diff.category_path && + this.diff.category_path != this.old.category) || + (Number.isFinite(this.diff.quantity) && + this.diff.quantity != this.old.quantity) || + (this.diff.description && + this.diff.description != this.old.description) || + this.diff.featured != this.old.featured) + ); } }, methods: { + incrementQuantity(by) { + if (this.quantity + by >= 0) { + this.diff.quantity += by; + } + }, saveProduct() { - if (this.newProduct.id) { + if (this.id) { // update existing - const updatedProduct = this.$store.dispatch( - "updateProduct", - this.newProduct - ); - if (updatedProduct) { - this.currentProduct = updatedProduct; - } + this.$store.dispatch("updateProduct", this.diff); } else { // new product - const newProduct = this.$store.dispatch( - "createProduct", - this.newProduct - ); - if (newProduct) { - this.currentProduct = newProduct; - } - } - }, - incrementQuantity(amount) { - if (this.newProduct.quantity + amount >= 0) { - this.newProduct.quantity += amount; + this.$store.dispatch("createProduct", this.diff); } + + this.diff.photo_set = null; }, changePhotoSet(event) { const file = event.target.files[0]; if (!file) { return; } - this.$store.dispatch("createPhotoSet", file).then(r => { this.filename = file.name; - this.newProduct.photo_set = r[0].id; + this.diff.photo_set = r[0].id; }); } } diff --git a/iridescence/src/components/admin/ProductEditList.vue b/iridescence/src/components/admin/ProductEditList.vue index 24a276e..0880d7c 100644 --- a/iridescence/src/components/admin/ProductEditList.vue +++ b/iridescence/src/components/admin/ProductEditList.vue @@ -3,10 +3,10 @@ <div class="columns is-multiline is-variable is-desktop"> <div class="column is-one-third-desktop" - v-for="product in products" - :key="product.id" + v-for="(product, index) in products" + :key="index" > - <ProductEditCard v-bind:parent-product="product"></ProductEditCard> + <ProductEditCard v-bind:index="index"></ProductEditCard> </div> </div> </div> |