mirror of
				https://github.com/KevinMidboe/planetposen.git
				synced 2025-10-29 17:50:32 +00:00 
			
		
		
		
	Fully supports editing product and its variations.
Edit page now handles customizing most properties of a product. This uses new color and size picker.
This commit is contained in:
		| @@ -7,42 +7,117 @@ | |||||||
|         <h2>Edit mode</h2> |         <h2>Edit mode</h2> | ||||||
|         <div class="edit-product" v-if="product"> |         <div class="edit-product" v-if="product"> | ||||||
|           <h4>Product</h4> |           <h4>Product</h4> | ||||||
|           <input v-model="product.color" placeholder="color" /> |           <div class="row"> | ||||||
|  |             <div class="row-item"> | ||||||
|  |               Name: | ||||||
|               <input v-model="product.name" placeholder="name" /> |               <input v-model="product.name" placeholder="name" /> | ||||||
|           <input v-model="product.description" placeholder="description" /> |             </div> | ||||||
|           <input v-model="product.image" placeholder="image" /> |             <div class="row-item"> | ||||||
|           <input v-model="product.slug" placeholder="slug (default: empty)" /> |               Color: | ||||||
|  |               <color-picker @selectedColor="colorSelected" :color="product.color" /> | ||||||
|  |             </div> | ||||||
|           </div> |           </div> | ||||||
|  |  | ||||||
|         <div v-if="variation"> |           <div class="row"> | ||||||
|  |             <div class="row-item"> | ||||||
|  |               Description: | ||||||
|  |               <input v-model="product.description" placeholder="description" /> | ||||||
|  |             </div> | ||||||
|  |             <div class="row-item"> | ||||||
|  |               Image: | ||||||
|  |               <input v-model="product.image" placeholder="image" /> | ||||||
|  |             </div> | ||||||
|  |             <div class="row-item"> | ||||||
|  |               Slug (default empty): | ||||||
|  |               <input v-model="product.urlSlug" placeholder="slug" /> | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |  | ||||||
|  |         <div v-if="product && product.variations"> | ||||||
|           <h4>Variations</h4> |           <h4>Variations</h4> | ||||||
|           <input v-for="key in Object.keys(variation)" v-model="variation[key]" :placeholder="key" /> |  | ||||||
|  |           <div v-for="(variation, index) in product.variations" class="variation"> | ||||||
|  |             <div class="variation-controls"> | ||||||
|  |               <i class="icon icon--arrow-dropup" @click="moveVariation(variation, -1)" | ||||||
|  |                  v-if="index != 0"></i> | ||||||
|  |               <i v-else class="icon"></i> | ||||||
|  |  | ||||||
|  |               <i class="icon icon--close-circle-outline" @click="removeVariation(variation)"></i> | ||||||
|  |  | ||||||
|  |               <i class="icon icon--arrow-dropdown" @click="moveVariation(variation, 1)" | ||||||
|  |                  v-if="index + 1 < product.variations.length"></i> | ||||||
|  |               <i v-else class="icon"></i> | ||||||
|  |             </div> | ||||||
|  |             <div> | ||||||
|  |               <div class="row"> | ||||||
|  |                 <div class="row-item"> | ||||||
|  |                   Stock: | ||||||
|  |                   <input v-model="variation.stock" type="number" placeholder="0" min="0" /> | ||||||
|  |                 </div> | ||||||
|  |  | ||||||
|  |                 <div class="row-item"> | ||||||
|  |                   Price (NOK): | ||||||
|  |                   <input v-model="variation.price" type="number" placeholder="0.00" min="0" /> | ||||||
|  |                 </div> | ||||||
|  |               </div> | ||||||
|  |  | ||||||
|  |               <div class="row"> | ||||||
|  |                 <div class="row-item"> | ||||||
|  |                   Discounted price (empty if none): | ||||||
|  |                   <input v-model="variation.discount" type="number" placeholder="0.00" min="0" /> | ||||||
|  |                 </div> | ||||||
|  |               </div> | ||||||
|  |  | ||||||
|  |               <div class="row"> | ||||||
|  |                 <div class="row-item"> | ||||||
|  |                   Available sizes: | ||||||
|  |                   <size-picker :sizeVariable.sync="variation.size" /> | ||||||
|  |                 </div> | ||||||
|  |               </div> | ||||||
|  |  | ||||||
|  |               <hr /> | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|  |  | ||||||
|  |          <Button :small="true" color="yellow" @click="addVariation"> | ||||||
|  |             Add variation | ||||||
|  |             <i class="add-variation icon icon--add-circle"></i> | ||||||
|  |           </Button> | ||||||
|          </div> |          </div> | ||||||
|  |  | ||||||
|         <Button :small="true" @click="hide = !hide">Preview</Button> |         <Button :small="true" @click="hide = !hide">Preview</Button> | ||||||
|         <Button :small="true" color="green">Submit new bag</Button> |         <Button :small="true" color="green">Update</Button> | ||||||
|       </div> |       </div> | ||||||
|  |  | ||||||
|       <product :product="product" /> |       <product v-if="product" :product="product" /> | ||||||
|     </main> |     </main> | ||||||
|     <main v-else> |     <main v-else> | ||||||
|       <Button @click="hide = !hide" class="pos-abs" :small="true">Close preview</Button> |       <Button @click="hide = !hide" class="pos-abs" :small="true">Close preview</Button> | ||||||
|       <product :product="product" /> |       <product :product="product" v-if="product" /> | ||||||
|     </main> |     </main> | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script> | <script> | ||||||
|  | import ColorPicker from '@/components/ui/colorPicker'; | ||||||
|  | import SizePicker from '@/components/ui/sizePicker'; | ||||||
| import Product from '@/components/ui/product'; | import Product from '@/components/ui/product'; | ||||||
| import Button from '@/components/ui/Button'; | import Button from '@/components/ui/Button'; | ||||||
|  |  | ||||||
| export default { | export default { | ||||||
|   components: { Product, Button }, |   components: { | ||||||
|  |     ColorPicker, | ||||||
|  |     SizePicker, | ||||||
|  |     Product, | ||||||
|  |     Button | ||||||
|  |   }, | ||||||
|   data() { |   data() { | ||||||
|     return { |     return { | ||||||
|       hide: false, |       hide: false, | ||||||
|       product: undefined, |       product: undefined, | ||||||
|       variation: undefined |       productTemplate: undefined, | ||||||
|  |       variationTemplate: undefined | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   created() { |   created() { | ||||||
| @@ -53,10 +128,28 @@ export default { | |||||||
|       this.getAndSetProductBySlug(this.$route.params.slug); |       this.getAndSetProductBySlug(this.$route.params.slug); | ||||||
|     } else { |     } else { | ||||||
|       this.getProductSchema() |       this.getProductSchema() | ||||||
|       this.getVariationSchema() |  | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   methods: { |   methods: { | ||||||
|  |     colorSelected(color) { | ||||||
|  |       this.product.color = color; | ||||||
|  |     }, | ||||||
|  |     moveVariation(variation, direction) { | ||||||
|  |       let variations = [ ...this.product.variations ]; | ||||||
|  |       const variationIndex = variations.findIndex(el => el == variation); | ||||||
|  |  | ||||||
|  |       variations = variations.filter(el => el != variation); | ||||||
|  |       variations.splice(variationIndex + direction, 0, variation); | ||||||
|  |       this.product.variations = variations; | ||||||
|  |     }, | ||||||
|  |     removeVariation(variation) { | ||||||
|  |       this.product.variations = this.product.variations.filter(el => el != variation); | ||||||
|  |     }, | ||||||
|  |     async addVariation() { | ||||||
|  |       if (this.variationTemplate == undefined) | ||||||
|  |         await this.getVariationSchema(); | ||||||
|  |       this.product.variations.push({ ...this.variationTemplate }) | ||||||
|  |     }, | ||||||
|     getProductSchema() { |     getProductSchema() { | ||||||
|       let url = '/api/product/schema'; |       let url = '/api/product/schema'; | ||||||
|       if (window.location.href.includes('localhost')) |       if (window.location.href.includes('localhost')) | ||||||
| @@ -64,7 +157,8 @@ export default { | |||||||
|  |  | ||||||
|       fetch(url) |       fetch(url) | ||||||
|         .then(resp => resp.json()) |         .then(resp => resp.json()) | ||||||
|         .then(product => this.product = product); |         .then(product => this.product = product) | ||||||
|  |         .then(this.getVariationSchema) | ||||||
|     }, |     }, | ||||||
|     getVariationSchema() { |     getVariationSchema() { | ||||||
|       let url = '/api/variation/schema'; |       let url = '/api/variation/schema'; | ||||||
| @@ -73,7 +167,11 @@ export default { | |||||||
|  |  | ||||||
|       fetch(url) |       fetch(url) | ||||||
|         .then(resp => resp.json()) |         .then(resp => resp.json()) | ||||||
|         .then(variation => this.variation = variation); |         .then(variation => { | ||||||
|  |           this.variationTemplate = variation; | ||||||
|  |           if (this.product.variations.length == 0) | ||||||
|  |             this.product.variations = [{ ...variation }]; | ||||||
|  |         }) | ||||||
|     }, |     }, | ||||||
|     getAndSetProductBySlug(slug) { |     getAndSetProductBySlug(slug) { | ||||||
|       let url = `/api/product/${ slug }`; |       let url = `/api/product/${ slug }`; | ||||||
| @@ -105,16 +203,58 @@ h2 { | |||||||
|   margin-top: 0.75rem; |   margin-top: 0.75rem; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | .row:not(:first-of-type) { | ||||||
|  |   margin-top: 0.5rem; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .row-item { | ||||||
|  |   display: flex; | ||||||
|  |   flex-direction: column; | ||||||
|  |   display: inline-flex; | ||||||
|  |  | ||||||
|  |   &:not(:first-of-type) { | ||||||
|  |     margin-left: 0.5rem; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | .heading { | ||||||
|  | //  display: block; | ||||||
|  | } | ||||||
|  |  | ||||||
| input { | input { | ||||||
|   border-color: black; |   border-color: black; | ||||||
|   padding: 0.5rem; |   padding: 0.5rem; | ||||||
|   font-size: 1rem; |   font-size: 1rem; | ||||||
|  |  | ||||||
|  |   &[type=number] { | ||||||
|  |     width: 5rem; | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| button { | button { | ||||||
|   margin-top: 0.5rem; |   margin-top: 0.5rem; | ||||||
| }  | }  | ||||||
|  |  | ||||||
|  | .variation { | ||||||
|  |   display: flex; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .variation-controls { | ||||||
|  |   display: flex; | ||||||
|  |   flex-direction: column; | ||||||
|  |   justify-content: space-around; | ||||||
|  |   margin-right: 1rem; | ||||||
|  |  | ||||||
|  |   .icon { | ||||||
|  |     font-size: 2em; | ||||||
|  |     cursor: pointer; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .add-variation { | ||||||
|  | //  font-size: 1.5em; | ||||||
|  | } | ||||||
|  |  | ||||||
| .edit { | .edit { | ||||||
|   color: var(--color-background); |   color: var(--color-background); | ||||||
|   margin: 2rem auto; |   margin: 2rem auto; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user