summaryrefslogtreecommitdiff
path: root/iridescence/src
diff options
context:
space:
mode:
authorAdam T. Carpenter <atc@53hor.net>2020-11-11 20:07:12 -0500
committerAdam T. Carpenter <atc@53hor.net>2020-11-11 20:07:12 -0500
commit7381a7033231e6454a37fd64b1f3de4e8d59355f (patch)
tree7ae54976c2d036e0fe7cb199a7f6facdd09bbb6d /iridescence/src
parentc5280144de096c274f185fade287ccd63b954ceb (diff)
downloadtheglassyladies-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.vue4
-rw-r--r--iridescence/src/api/dichroism.js18
-rw-r--r--iridescence/src/components/Navbar.vue13
-rw-r--r--iridescence/src/components/admin/NewProduct.vue12
-rw-r--r--iridescence/src/components/admin/ProductEditCard.vue73
-rw-r--r--iridescence/src/components/admin/ProductEditList.vue2
-rw-r--r--iridescence/src/models/product.js62
-rw-r--r--iridescence/src/models/product_diff.js43
-rw-r--r--iridescence/src/store/index.js33
-rw-r--r--iridescence/src/views/Admin.vue11
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
}
};