diff options
author | Adam T. Carpenter <atc@53hor.net> | 2020-11-11 20:07:12 -0500 |
---|---|---|
committer | Adam T. Carpenter <atc@53hor.net> | 2020-11-11 20:07:12 -0500 |
commit | 7381a7033231e6454a37fd64b1f3de4e8d59355f (patch) | |
tree | 7ae54976c2d036e0fe7cb199a7f6facdd09bbb6d /iridescence/src | |
parent | c5280144de096c274f185fade287ccd63b954ceb (diff) | |
download | theglassyladies-7381a7033231e6454a37fd64b1f3de4e8d59355f.tar.xz theglassyladies-7381a7033231e6454a37fd64b1f3de4e8d59355f.zip |
Kind of flailing with the UI; lots of API bugfixes though.
Diffstat (limited to 'iridescence/src')
-rw-r--r-- | iridescence/src/App.vue | 4 | ||||
-rw-r--r-- | iridescence/src/api/dichroism.js | 18 | ||||
-rw-r--r-- | iridescence/src/components/Navbar.vue | 13 | ||||
-rw-r--r-- | iridescence/src/components/admin/NewProduct.vue | 12 | ||||
-rw-r--r-- | iridescence/src/components/admin/ProductEditCard.vue | 73 | ||||
-rw-r--r-- | iridescence/src/components/admin/ProductEditList.vue | 2 | ||||
-rw-r--r-- | iridescence/src/models/product.js | 62 | ||||
-rw-r--r-- | iridescence/src/models/product_diff.js | 43 | ||||
-rw-r--r-- | iridescence/src/store/index.js | 33 | ||||
-rw-r--r-- | iridescence/src/views/Admin.vue | 11 |
10 files changed, 153 insertions, 118 deletions
diff --git a/iridescence/src/App.vue b/iridescence/src/App.vue index a586f83..debc599 100644 --- a/iridescence/src/App.vue +++ b/iridescence/src/App.vue @@ -29,5 +29,7 @@ export default { </script> <style lang="scss"> -@use "../node_modules/bulma/bulma.sass"; +@charset "utf-8"; +$modal-background-background-color: hsla(0, 0%, 4%, 0.2); +@import "../node_modules/bulma/bulma.sass"; </style> diff --git a/iridescence/src/api/dichroism.js b/iridescence/src/api/dichroism.js index 610941c..c2cc93c 100644 --- a/iridescence/src/api/dichroism.js +++ b/iridescence/src/api/dichroism.js @@ -18,7 +18,7 @@ export default class Dichroism { const photos = await this._sendRequest("photos", options); return photos.map(p => new PhotoSet(p)); } catch (err) { - console.error(err.message); + console.error("Dichroism: " + err.message); return null; } } @@ -28,7 +28,7 @@ export default class Dichroism { const products = await this._sendRequest("products", null); return products.map(p => new Product(p)); } catch (err) { - console.error(err.message); + console.error("Dichroism: " + err.message); return []; } } @@ -36,14 +36,17 @@ export default class Dichroism { async updateProduct(fieldDiff) { const options = { method: "PATCH", - body: fieldDiff + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify(fieldDiff) }; try { const product = await this._sendRequest("products", options); return new Product(product); } catch (err) { - console.error(err.message); + console.error("Dichroism: " + err.message); return null; } } @@ -51,14 +54,17 @@ export default class Dichroism { async createProduct(newProduct) { const options = { method: "POST", - body: newProduct + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify(newProduct) }; try { const product = await this._sendRequest("products", options); return new Product(product); } catch (err) { - console.error(err.message); + console.error("Dichroism: " + err.message); return null; } } diff --git a/iridescence/src/components/Navbar.vue b/iridescence/src/components/Navbar.vue index 0a66fa8..78627e9 100644 --- a/iridescence/src/components/Navbar.vue +++ b/iridescence/src/components/Navbar.vue @@ -36,14 +36,9 @@ > <div class="navbar-end" - v-if="routeName == 'Administration'" - key="newProduct" + v-if="routeName != 'Administration'" + key="cartCheckout" > - <div class="navbar-item"> - <NewProduct></NewProduct> - </div> - </div> - <div class="navbar-end" v-else key="cartCheckout"> <div class="navbar-item has-dropdown is-active" v-for="category in categories.keys()" @@ -74,13 +69,11 @@ <script> import CartCheckout from "@/components/CartCheckout.vue"; -import NewProduct from "@/components/admin/NewProduct.vue"; export default { name: "Navbar", components: { - CartCheckout, - NewProduct + CartCheckout }, data() { return { diff --git a/iridescence/src/components/admin/NewProduct.vue b/iridescence/src/components/admin/NewProduct.vue index 511ae9c..48eb165 100644 --- a/iridescence/src/components/admin/NewProduct.vue +++ b/iridescence/src/components/admin/NewProduct.vue @@ -1,6 +1,6 @@ <template> <div id="addNewProduct"> - <button class="button is-primary" @click="toggleModal"> + <button class="button is-primary is-medium" @click="toggleModal"> + Add New </button> <transition @@ -17,9 +17,7 @@ <button class="delete" @click="toggleModal"></button> </header> <section class="modal-card-body"> - <ProductEditCard - v-bind:current-product="newProduct" - ></ProductEditCard> + <ProductEditCard v-bind:parent-product="template"></ProductEditCard> </section> <footer class="modal-card-foot"></footer> </div> @@ -29,8 +27,8 @@ </template> <script> -import Product from "../../models/product"; -import ProductEditCard from "./ProductEditCard"; +import Product from "@/models/product"; +import ProductEditCard from "@/components/admin/ProductEditCard"; export default { name: "NewProduct", @@ -40,7 +38,7 @@ export default { data: function() { return { modalEnabled: false, - newProduct: new Product(), + template: new Product({}), addAnother: false }; }, diff --git a/iridescence/src/components/admin/ProductEditCard.vue b/iridescence/src/components/admin/ProductEditCard.vue index 350f8df..a8117ce 100644 --- a/iridescence/src/components/admin/ProductEditCard.vue +++ b/iridescence/src/components/admin/ProductEditCard.vue @@ -2,7 +2,7 @@ <div id="productEditCard"> <div class="card"> <div class="card-header"> - <p class="card-header-title" v-if="currentProduct.id > 0"> + <p class="card-header-title" v-if="currentProduct.id"> {{ currentProduct.id }}: {{ currentProduct.name }} </p> </div> @@ -74,7 +74,7 @@ type="file" name="image" accept=".jpg,.jpeg,.JPG,.JPEG" - @change="previewFiles" + @change="changePhotoSet" /> <span class="file-cta"> <span class="file-label has-text-centered"> @@ -82,7 +82,7 @@ </span> </span> <span class="file-name"> - {{ newProduct.photo_set }} + {{ filename }} </span> </label> </div> @@ -107,7 +107,12 @@ enter-active-class="animate__animated animate__fadeIn" leave-active-class="animate__animated animate__fadeOut" > - <div class="card-footer" v-if="isDifferent && isValid"> + <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 @@ -120,7 +125,8 @@ </template> <script> -import Product from "../../models/product"; +import Product from "@/models/product"; +import ProductDiff from "@/models/product_diff"; const dollarRe = /^\$?(\d+)\.(\d{2})/gm; @@ -128,28 +134,18 @@ export default { name: "ProductEditCard", data: function() { return { - newProduct: new Product(this.currentProduct) + currentProduct: new Product(this.parentProduct), + newProduct: new ProductDiff(this.currentProduct), + filename: "" }; }, props: { - currentProduct: { + parentProduct: { type: Product, required: true } }, - watch: { - currentProduct() { - // TODO: necessary? - this.newProduct = new Product(this.currentProduct); - } - }, computed: { - isDifferent() { - return this.newProduct.isDifferent(this.currentProduct); - }, - isValid() { - return this.newProduct.isValid(); - }, newProductQuantity: { get: function() { return this.newProduct.quantity; @@ -165,7 +161,7 @@ export default { return (this.newProduct.cents / 100).toFixed(2); }, set: function(val) { - let groups = dollarRe.exec(val); + const groups = dollarRe.exec(val); if (groups && groups[1] && groups[2]) { this.newProduct.cents = 100 * groups[1] + 1 * groups[2]; } @@ -174,12 +170,24 @@ export default { }, methods: { saveProduct() { - if (this.newProduct.id == 0) { - // new product - this.$store.dispatch("createProduct", this.newProduct); - } else { + if (this.newProduct.id) { // update existing - this.$store.dispatch("updateProduct", this.newProduct); + const updatedProduct = this.$store.dispatch( + "updateProduct", + this.newProduct + ); + if (updatedProduct) { + this.currentProduct = updatedProduct; + } + } else { + // new product + const newProduct = this.$store.dispatch( + "createProduct", + this.newProduct + ); + if (newProduct) { + this.currentProduct = newProduct; + } } }, incrementQuantity(amount) { @@ -187,21 +195,16 @@ export default { this.newProduct.quantity += amount; } }, - async previewFiles(event) { - let file = event.target.files[0]; + changePhotoSet(event) { + const file = event.target.files[0]; if (!file) { return; } - const fd = new FormData(); - fd.append(file.name, file); - - const response = await fetch("http://localhost:8000/photos", { - method: "POST", - body: fd + this.$store.dispatch("createPhotoSet", file).then(r => { + this.filename = file.name; + this.newProduct.photo_set = r[0].id; }); - - console.log(response); } } }; diff --git a/iridescence/src/components/admin/ProductEditList.vue b/iridescence/src/components/admin/ProductEditList.vue index 556f1c3..24a276e 100644 --- a/iridescence/src/components/admin/ProductEditList.vue +++ b/iridescence/src/components/admin/ProductEditList.vue @@ -6,7 +6,7 @@ v-for="product in products" :key="product.id" > - <ProductEditCard v-bind:current-product="product"></ProductEditCard> + <ProductEditCard v-bind:parent-product="product"></ProductEditCard> </div> </div> </div> diff --git a/iridescence/src/models/product.js b/iridescence/src/models/product.js index fb7fd68..c408b79 100644 --- a/iridescence/src/models/product.js +++ b/iridescence/src/models/product.js @@ -1,54 +1,16 @@ export default class Product { - id = 0; - name = ""; - description = ""; - cents = 0; - quantity = 0; - featured = false; - photo_base = ""; - photo_fullsize = ""; - photo_thumbnail = ""; - category = ""; - - constructor(from) { - if (from) { - this.id = from.id; - this.name = from.name; - this.description = from.description; - this.cents = from.cents; - this.quantity = from.quantity; - this.featured = from.featured; - this.photo_base = from.photo_base; - this.photo_fullsize = from.photo_fullsize; - this.photo_thumbnail = from.photo_thumbnail; - this.category = from.category; + constructor(json) { + if (json) { + this.id = json.id ? json.id : null; + this.name = json.name ? json.name : null; + this.description = json.description ? json.description : null; + this.cents = json.cents ? json.cents : null; + this.quantity = json.quantity ? json.quantity : null; + this.featured = json.featured ? json.featured : false; + this.category = json.category ? json.category : null; + this.photo_base = json.photo_base ? json.photo_base : null; + this.photo_thumbnail = json.photo_thumbnail ? json.photo_thumbnail : null; + this.photo_fullsize = json.photo_fullsize ? json.photo_fullsize : null; } } - - isDifferent(product) { - return ( - this.id != product.id || - this.name != product.name || - this.quantity != product.quantity || - this.cents != product.cents || - this.photo_base != product.photo_base || - this.photo_thumbnail != product.photo_thumbnail || - this.photo_fullsize != product.photo_fullsize || - this.description != product.description || - this.featured != product.featured || - this.category != product.category - ); - } - - isValid() { - return ( - this.cents > 0 && - this.name != "" && - this.photo_thumbnail != "" && - this.photo_base != "" && - this.photo_fullsize != "" && - this.category != "" && - this.description != "" - ); - } } diff --git a/iridescence/src/models/product_diff.js b/iridescence/src/models/product_diff.js new file mode 100644 index 0000000..a683102 --- /dev/null +++ b/iridescence/src/models/product_diff.js @@ -0,0 +1,43 @@ +export default class ProductDiff { + constructor(product) { + if (product) { + this.id = product.id ? product.id : 0; + this.name = product.name ? product.name : null; + this.description = product.description ? product.description : null; + this.cents = product.cents ? product.cents : null; + this.quantity = product.quantity ? product.quantity : null; + this.featured = + typeof product.featured === "boolean" ? product.featured : null; + this.category_path = product.category ? product.category : null; + this.photo_set = null; + } + } + + isValidPost() { + return ( + !this.id && + this.name && + this.description && + this.cents && + !this.quantity.isNaN && + this.photo_set && + this.category_path && + this.description && + typeof this.featured === "boolean" + ); + } + + isValidPatch(product) { + return ( + this.id && + (this.photo_set || + (this.name && this.name != product.name) || + (this.cents && this.cents != product.cents) || + (this.category_path && this.category_path != product.category) || + (this.quantity && this.quantity != product.quantity) || + (this.description && this.description != product.description) || + (typeof this.featured === "boolean" && + this.featured != product.featured)) + ); + } +} diff --git a/iridescence/src/store/index.js b/iridescence/src/store/index.js index fc77f79..f98fd87 100644 --- a/iridescence/src/store/index.js +++ b/iridescence/src/store/index.js @@ -29,6 +29,9 @@ export default new Vuex.Store({ } }, mutations: { + toggleBusy(state) { + state.busy = !state.busy; + }, searchTerm(state, term) { if (term) { state.searchTerm = term; @@ -40,9 +43,13 @@ export default new Vuex.Store({ } }, replaceProduct(state, product) { + if (!product || !product.id) { + return; + } + let index = state.products.findIndex(p => p.id == product.id); - if (product && index >= 0) { + if (index) { state.products[index] = product; } }, @@ -53,17 +60,29 @@ export default new Vuex.Store({ } }, actions: { - async refreshProducts(context) { + async refreshProducts({ commit }) { + commit("toggleBusy"); const products = await dichroism.getProducts(); - context.commit("setProducts", products); + commit("setProducts", products); + commit("toggleBusy"); }, - async updateProduct(context, product) { + async updateProduct({ commit }, product) { + commit("toggleBusy"); const updatedProduct = await dichroism.updateProduct(product); - context.dispatch("replaceProduct", updatedProduct); + commit("replaceProduct", updatedProduct); + commit("toggleBusy"); }, - async createProduct(context, product) { + async createProduct({ commit }, product) { + commit("toggleBusy"); const newProduct = await dichroism.createProduct(product); - context.dispatch("addProduct", newProduct); + commit("addProduct", newProduct); + commit("toggleBusy"); + }, + async createPhotoSet({ commit }, file) { + commit("toggleBusy"); + const photoSet = await dichroism.createPhoto(file); + commit("toggleBusy"); + return photoSet; } }, modules: {} diff --git a/iridescence/src/views/Admin.vue b/iridescence/src/views/Admin.vue index ec02e07..5274740 100644 --- a/iridescence/src/views/Admin.vue +++ b/iridescence/src/views/Admin.vue @@ -2,7 +2,14 @@ <div id="admin"> <div class="container"> <section class="section"> - <ProductSearch></ProductSearch> + <div class="columns"> + <div class="column is-narrow"> + <NewProduct></NewProduct> + </div> + <div class="column"> + <ProductSearch></ProductSearch> + </div> + </div> <ProductEditList></ProductEditList> </section> </div> @@ -10,6 +17,7 @@ </template> <script> +import NewProduct from "@/components/admin/NewProduct.vue"; import ProductSearch from "@/components/ProductSearch.vue"; import ProductEditList from "@/components/admin/ProductEditList.vue"; @@ -17,6 +25,7 @@ export default { name: "Admin", components: { ProductEditList, + NewProduct, ProductSearch } }; |