summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dichroism/src/dtos/product_post.rs1
-rw-r--r--iridescence/src/api/dichroism.js40
-rw-r--r--iridescence/src/components/BusyBar.vue10
-rw-r--r--iridescence/src/components/ProductList.vue10
-rw-r--r--iridescence/src/components/admin/NewProduct.vue20
-rw-r--r--iridescence/src/components/admin/ProductEditCard.vue73
-rw-r--r--iridescence/src/components/admin/ProductEditList.vue4
-rw-r--r--iridescence/src/models/product.js42
-rw-r--r--iridescence/src/store/index.js41
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: {}