summaryrefslogtreecommitdiff
path: root/iridescence/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'iridescence/src/components')
-rw-r--r--iridescence/src/components/ProductSearch.vue2
-rw-r--r--iridescence/src/components/admin/NewProduct.vue17
-rw-r--r--iridescence/src/components/admin/ProductEditCard.vue229
-rw-r--r--iridescence/src/components/admin/ProductEditList.vue6
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>