diff options
-rw-r--r-- | dichroism/src/dtos/product_post.rs | 1 | ||||
-rw-r--r-- | iridescence/src/api/dichroism.js | 40 | ||||
-rw-r--r-- | iridescence/src/components/BusyBar.vue | 10 | ||||
-rw-r--r-- | iridescence/src/components/ProductList.vue | 10 | ||||
-rw-r--r-- | iridescence/src/components/admin/NewProduct.vue | 20 | ||||
-rw-r--r-- | iridescence/src/components/admin/ProductEditCard.vue | 73 | ||||
-rw-r--r-- | iridescence/src/components/admin/ProductEditList.vue | 4 | ||||
-rw-r--r-- | iridescence/src/models/product.js | 42 | ||||
-rw-r--r-- | iridescence/src/store/index.js | 41 |
9 files changed, 147 insertions, 94 deletions
diff --git a/dichroism/src/dtos/product_post.rs b/dichroism/src/dtos/product_post.rs index ee3ba03..c04b211 100644 --- a/dichroism/src/dtos/product_post.rs +++ b/dichroism/src/dtos/product_post.rs @@ -1,5 +1,6 @@ #[derive(Debug, Deserialize)] pub struct ProductPost { + pub id: Option<i32>, pub name: String, pub quantity: i32, pub cents: i32, diff --git a/iridescence/src/api/dichroism.js b/iridescence/src/api/dichroism.js index e3b08a8..610941c 100644 --- a/iridescence/src/api/dichroism.js +++ b/iridescence/src/api/dichroism.js @@ -14,13 +14,23 @@ export default class Dichroism { body: fd }; - const photos = await self._sendRequest("photos", options); - return photos.map(p => new PhotoSet(p)); + try { + const photos = await this._sendRequest("photos", options); + return photos.map(p => new PhotoSet(p)); + } catch (err) { + console.error(err.message); + return null; + } } async getProducts() { - const products = await self._sendRequest("products", null); - return products.map(p => new Product(p)); + try { + const products = await this._sendRequest("products", null); + return products.map(p => new Product(p)); + } catch (err) { + console.error(err.message); + return []; + } } async updateProduct(fieldDiff) { @@ -29,8 +39,13 @@ export default class Dichroism { body: fieldDiff }; - const product = await self._sendRequest("products", options); - return new Product(product); + try { + const product = await this._sendRequest("products", options); + return new Product(product); + } catch (err) { + console.error(err.message); + return null; + } } async createProduct(newProduct) { @@ -39,17 +54,22 @@ export default class Dichroism { body: newProduct }; - const product = await self._sendRequest("products", options); - return new Product(product); + try { + const product = await this._sendRequest("products", options); + return new Product(product); + } catch (err) { + console.error(err.message); + return null; + } } async _sendRequest(endpoint, options) { - const response = await fetch(self.base_addr + endpoint, options); + const response = await fetch(this._base_addr + endpoint, options); if (response.ok) { return await response.json(); } else { - return new ApiError(await response.text()); + throw new ApiError(await response.text()); } } } diff --git a/iridescence/src/components/BusyBar.vue b/iridescence/src/components/BusyBar.vue index fff2c4c..721a5fd 100644 --- a/iridescence/src/components/BusyBar.vue +++ b/iridescence/src/components/BusyBar.vue @@ -5,6 +5,13 @@ max="100" v-if="isBusy" ></progress> + <progress + class="progress is-small is-primary" + v-bind:value="progress" + max="100" + v-if="progress < 100" + >{{ progress }}%</progress + > </div> </template> @@ -14,6 +21,9 @@ export default { computed: { isBusy() { return this.$store.getters.busy; + }, + progress() { + return this.$store.getters.progress; } } }; diff --git a/iridescence/src/components/ProductList.vue b/iridescence/src/components/ProductList.vue index 537e802..bed37b3 100644 --- a/iridescence/src/components/ProductList.vue +++ b/iridescence/src/components/ProductList.vue @@ -3,10 +3,10 @@ <div class="columns is-multiline is-variable is-7-desktop"> <div class="column is-one-quarter" - v-for="item in products" - :key="item.id" + v-for="product in products" + :key="product.id" > - <ProductCard v-bind="item"></ProductCard> + <ProductCard v-bind="product"></ProductCard> </div> </div> </div> @@ -20,15 +20,11 @@ export default { components: { ProductCard }, - data() { - return {}; - }, computed: { products() { return this.$store.getters.products; } }, - methods: {}, created() { this.$store.dispatch("refreshProducts"); } diff --git a/iridescence/src/components/admin/NewProduct.vue b/iridescence/src/components/admin/NewProduct.vue index 8c45f0b..511ae9c 100644 --- a/iridescence/src/components/admin/NewProduct.vue +++ b/iridescence/src/components/admin/NewProduct.vue @@ -17,7 +17,9 @@ <button class="delete" @click="toggleModal"></button> </header> <section class="modal-card-body"> - <ProductEditCard v-bind:current-product="product"></ProductEditCard> + <ProductEditCard + v-bind:current-product="newProduct" + ></ProductEditCard> </section> <footer class="modal-card-foot"></footer> </div> @@ -27,26 +29,18 @@ </template> <script> -import ProductEditCard from "./ProductEditCard.vue"; +import Product from "../../models/product"; +import ProductEditCard from "./ProductEditCard"; export default { - name: "AddNewProduct", + name: "NewProduct", components: { ProductEditCard }, data: function() { return { modalEnabled: false, - product: { - id: 0, - name: "", - quantity: 0, - cents: 0, - imgPath: "", - description: "", - featured: false, - categories: [] - }, + newProduct: new Product(), addAnother: false }; }, diff --git a/iridescence/src/components/admin/ProductEditCard.vue b/iridescence/src/components/admin/ProductEditCard.vue index 2784fc9..350f8df 100644 --- a/iridescence/src/components/admin/ProductEditCard.vue +++ b/iridescence/src/components/admin/ProductEditCard.vue @@ -15,6 +15,14 @@ v-model="newProduct.name" /> </div> + <div class="field"> + <input + class="input" + type="text" + placeholder="(product category)" + v-model="newProduct.category_path" + /> + </div> <div class="field has-addons"> <p class="control"> <a class="button is-static"> @@ -74,18 +82,12 @@ </span> </span> <span class="file-name"> - {{ newProduct.imgPath }} + {{ newProduct.photo_set }} </span> </label> </div> </div> <div class="field"> - <label class="checkbox"> - <input type="checkbox" v-model="newProduct.featured" /> - Featured? - </label> - </div> - <div class="field"> <textarea class="textarea" type="text" @@ -94,13 +96,12 @@ > </textarea> </div> - <progress - class="progress is-primary" - v-bind:value="fileProgress" - max="100" - v-if="fileProgress < 100" - >{{ fileProgress }}%</progress - > + <div class="field"> + <label class="checkbox"> + <input type="checkbox" v-model="newProduct.featured" /> + Featured? + </label> + </div> </div> <transition enter-active-class="animate__animated animate__fadeIn" @@ -119,63 +120,35 @@ </template> <script> +import Product from "../../models/product"; + const dollarRe = /^\$?(\d+)\.(\d{2})/gm; export default { name: "ProductEditCard", data: function() { return { - newProduct: { - id: this.currentProduct.id, - name: this.currentProduct.name, - quantity: this.currentProduct.quantity, - cents: this.currentProduct.cents, - imgPath: this.currentProduct.imgPath, - description: this.currentProduct.description, - featured: this.currentProduct.featured, - categories: this.currentProduct.categories.slice(0) - }, - fileProgress: 100 + newProduct: new Product(this.currentProduct) }; }, props: { currentProduct: { - type: Object, + type: Product, required: true } }, watch: { currentProduct() { - this.newProduct.id = this.currentProduct.id; - this.newProduct.name = this.currentProduct.name; - this.newProduct.quantity = this.currentProduct.quantity; - this.newProduct.cents = this.currentProduct.cents; - this.newProduct.imgPath = this.currentProduct.imgPath; - this.newProduct.description = this.currentProduct.description; - this.newProduct.featured = this.currentProduct.featured; - this.newProduct.categories = this.currentProduct.categories.slice(0); + // TODO: necessary? + this.newProduct = new Product(this.currentProduct); } }, computed: { isDifferent() { - // TODO: check categories! - return ( - this.newProduct.id != this.currentProduct.id || - this.newProduct.name != this.currentProduct.name || - this.newProduct.quantity != this.currentProduct.quantity || - this.newProduct.cents != this.currentProduct.cents || - this.newProduct.imgPath != this.currentProduct.imgPath || - this.newProduct.description != this.currentProduct.description || - this.newProduct.featured != this.currentProduct.featured - ); + return this.newProduct.isDifferent(this.currentProduct); }, isValid() { - return ( - this.newProductPrice > 0 && - this.newProduct.name != "" && - this.newProduct.imgPath != "" && - this.newProduct.description != "" - ); + return this.newProduct.isValid(); }, newProductQuantity: { get: function() { diff --git a/iridescence/src/components/admin/ProductEditList.vue b/iridescence/src/components/admin/ProductEditList.vue index ae57406..556f1c3 100644 --- a/iridescence/src/components/admin/ProductEditList.vue +++ b/iridescence/src/components/admin/ProductEditList.vue @@ -20,15 +20,11 @@ export default { components: { ProductEditCard }, - data() { - return {}; - }, computed: { products() { return this.$store.getters.products; } }, - methods: {}, created() { this.$store.dispatch("refreshProducts"); } diff --git a/iridescence/src/models/product.js b/iridescence/src/models/product.js index c826073..fb7fd68 100644 --- a/iridescence/src/models/product.js +++ b/iridescence/src/models/product.js @@ -10,7 +10,45 @@ export default class Product { photo_thumbnail = ""; category = ""; - constructor(json) { - Object.assign(this, json); + 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; + } + } + + 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/store/index.js b/iridescence/src/store/index.js index 2b24816..fc77f79 100644 --- a/iridescence/src/store/index.js +++ b/iridescence/src/store/index.js @@ -10,12 +10,16 @@ export default new Vuex.Store({ state: { searchTerm: "", products: [], - busy: false + busy: false, + progress: 100 }, getters: { busy(state) { return state.busy; }, + progress(state) { + return state.progress; + }, products(state) { return state.products.filter(item => { return JSON.stringify(item) @@ -26,19 +30,40 @@ export default new Vuex.Store({ }, mutations: { searchTerm(state, term) { - state.searchTerm = term; + if (term) { + state.searchTerm = term; + } }, setProducts(state, products) { - state.products = products; + if (products) { + state.products = products; + } + }, + replaceProduct(state, product) { + let index = state.products.findIndex(p => p.id == product.id); + + if (product && index >= 0) { + state.products[index] = product; + } + }, + addProduct(state, product) { + if (product) { + state.products.push(product); + } } }, actions: { - refreshProducts(context) { - context.commit("setProducts", dichroism.getProducts()); + async refreshProducts(context) { + const products = await dichroism.getProducts(); + context.commit("setProducts", products); + }, + async updateProduct(context, product) { + const updatedProduct = await dichroism.updateProduct(product); + context.dispatch("replaceProduct", updatedProduct); }, - updateProduct(context, product) { - dichroism.updateProduct(product); - context.dispatch("refreshProducts"); + async createProduct(context, product) { + const newProduct = await dichroism.createProduct(product); + context.dispatch("addProduct", newProduct); } }, modules: {} |