Moved form to API endpoint + fixed opts
							parent
							
								
									2f2b050c47
								
							
						
					
					
						commit
						f149b87c3a
					
				|  | @ -112,6 +112,38 @@ $(document).ready(function (){ | ||||||
|         }); |         }); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|  |     $('#productEditForm').validator().on('submit', function(e){ | ||||||
|  |         if(!e.isDefaultPrevented()){ | ||||||
|  |             e.preventDefault(); | ||||||
|  |             if($('#productPermalink').val() === '' && $('#productTitle').val() !== ''){ | ||||||
|  |                 $('#productPermalink').val(slugify($('#productTitle').val())); | ||||||
|  |             } | ||||||
|  |             $.ajax({ | ||||||
|  |                 method: 'POST', | ||||||
|  |                 url: '/admin/product/update', | ||||||
|  |                 data: { | ||||||
|  |                     productId: $('#productId').val(), | ||||||
|  |                     productTitle: $('#productTitle').val(), | ||||||
|  |                     productPrice: $('#productPrice').val(), | ||||||
|  |                     productPublished: $('#productPublished').val(), | ||||||
|  |                     productStock: $('#productStock').val(), | ||||||
|  |                     productDescription: $('#productDescription').val(), | ||||||
|  |                     productPermalink: $('#productPermalink').val(), | ||||||
|  |                     productOptions: $('#productOptions').val(), | ||||||
|  |                     productSubscription: $('#productSubscription').val(), | ||||||
|  |                     productComment: $('#productComment').is(':checked'), | ||||||
|  |                     productTags: $('#productTags').val() | ||||||
|  |                 } | ||||||
|  |             }) | ||||||
|  |             .done(function(msg){ | ||||||
|  |                 showNotification(msg.message, 'success', true); | ||||||
|  |             }) | ||||||
|  |             .fail(function(msg){ | ||||||
|  |                 showNotification(msg.responseJSON.message, 'danger'); | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|     $('.set-as-main-image').on('click', function(){ |     $('.set-as-main-image').on('click', function(){ | ||||||
|         $.ajax({ |         $.ajax({ | ||||||
|             method: 'POST', |             method: 'POST', | ||||||
|  | @ -219,13 +251,6 @@ $(document).ready(function (){ | ||||||
|         window.location = '/admin/orders/bystatus/' + $('#orderStatusFilter').val(); |         window.location = '/admin/orders/bystatus/' + $('#orderStatusFilter').val(); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     // create a permalink from the product title if no permalink has already been set
 |  | ||||||
|     $(document).on('click', '#frm_edit_product_save', function(e){ |  | ||||||
|         if($('#productPermalink').val() === '' && $('#productTitle').val() !== ''){ |  | ||||||
|             $('#productPermalink').val(slugify($('#productTitle').val())); |  | ||||||
|         } |  | ||||||
|     }); |  | ||||||
| 
 |  | ||||||
|     // Call to API for a change to the published state of a product
 |     // Call to API for a change to the published state of a product
 | ||||||
|     $('input[class="published_state"]').change(function(){ |     $('input[class="published_state"]').change(function(){ | ||||||
|         $.ajax({ |         $.ajax({ | ||||||
|  |  | ||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							|  | @ -226,6 +226,9 @@ router.get('/admin/product/edit/:id', restrict, checkAccess, async (req, res) => | ||||||
|     let options = {}; |     let options = {}; | ||||||
|     if(product.productOptions){ |     if(product.productOptions){ | ||||||
|         options = product.productOptions; |         options = product.productOptions; | ||||||
|  |         if(typeof product.productOptions !== 'object'){ | ||||||
|  |             options = JSON.parse(product.productOptions); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // If API request, return json
 |     // If API request, return json
 | ||||||
|  | @ -258,8 +261,8 @@ router.post('/admin/product/removeoption', restrict, checkAccess, async (req, re | ||||||
|         delete opts[req.body.optName]; |         delete opts[req.body.optName]; | ||||||
| 
 | 
 | ||||||
|         try{ |         try{ | ||||||
|             const updateOption = await db.products.updateOne({ _id: common.getId(req.body.productId) }, { $set: { productOptions: opts } }); |             const updateOption = await db.products.findOneAndUpdate({ _id: common.getId(req.body.productId) }, { $set: { productOptions: opts } }); | ||||||
|             if(updateOption.result.nModified === 1){ |             if(updateOption.ok === 1){ | ||||||
|                 res.status(200).json({ message: 'Option successfully removed' }); |                 res.status(200).json({ message: 'Option successfully removed' }); | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|  | @ -280,42 +283,12 @@ router.post('/admin/product/update', restrict, checkAccess, async (req, res) => | ||||||
|     const product = await db.products.findOne({ _id: common.getId(req.body.productId) }); |     const product = await db.products.findOne({ _id: common.getId(req.body.productId) }); | ||||||
| 
 | 
 | ||||||
|     if(!product){ |     if(!product){ | ||||||
|         req.session.message = 'Failed updating product.'; |         res.status(400).json({ message: 'Failed to update product' }); | ||||||
|         req.session.messageType = 'danger'; |  | ||||||
| 
 |  | ||||||
|         // If API request, return json
 |  | ||||||
|         if(req.apiAuthenticated){ |  | ||||||
|             res.status(400).json({ message: 'Failed to update product' }); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         res.redirect('/admin/product/edit/' + req.body.productId); |  | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     const count = await db.products.countDocuments({ productPermalink: req.body.productPermalink, _id: { $ne: common.getId(product._id) } }); |     const count = await db.products.countDocuments({ productPermalink: req.body.productPermalink, _id: { $ne: common.getId(product._id) } }); | ||||||
|     if(count > 0 && req.body.productPermalink !== ''){ |     if(count > 0 && req.body.productPermalink !== ''){ | ||||||
|         // If API request, return json
 |         res.status(400).json({ message: 'Permalink already exists. Pick a new one.' }); | ||||||
|         if(req.apiAuthenticated){ |  | ||||||
|             res.status(400).json({ message: 'Permalink already exists. Pick a new one.' }); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // permalink exits
 |  | ||||||
|         req.session.message = 'Permalink already exists. Pick a new one.'; |  | ||||||
|         req.session.messageType = 'danger'; |  | ||||||
| 
 |  | ||||||
|         // keep the current stuff
 |  | ||||||
|         req.session.productTitle = req.body.productTitle; |  | ||||||
|         req.session.productDescription = req.body.productDescription; |  | ||||||
|         req.session.productPrice = req.body.productPrice; |  | ||||||
|         req.session.productPermalink = req.body.productPermalink; |  | ||||||
|         req.session.productTags = req.body.productTags; |  | ||||||
|         req.session.productOptions = req.body.productOptions; |  | ||||||
|         req.session.productComment = common.checkboxBool(req.body.productComment); |  | ||||||
|         req.session.productStock = req.body.productStock ? req.body.productStock : null; |  | ||||||
| 
 |  | ||||||
|         // redirect to insert
 |  | ||||||
|         res.redirect('/admin/product/edit/' + req.body.productId); |  | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     const images = await common.getImages(req.body.productId, req, res); |     const images = await common.getImages(req.body.productId, req, res); | ||||||
|  | @ -345,27 +318,10 @@ router.post('/admin/product/update', restrict, checkAccess, async (req, res) => | ||||||
|     // Validate the body again schema
 |     // Validate the body again schema
 | ||||||
|     const schemaValidate = validateJson('editProduct', productDoc); |     const schemaValidate = validateJson('editProduct', productDoc); | ||||||
|     if(!schemaValidate.result){ |     if(!schemaValidate.result){ | ||||||
|         // If API request, return json
 |         res.status(400).json({ | ||||||
|         if(req.apiAuthenticated){ |             message: 'Form invalid. Please check values and try again.', | ||||||
|             res.status(400).json(schemaValidate.errors); |             error: schemaValidate.errors | ||||||
|             return; |         }); | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         req.session.message = 'Form invalid. Please check values and try again.'; |  | ||||||
|         req.session.messageType = 'danger'; |  | ||||||
| 
 |  | ||||||
|         // keep the current stuff
 |  | ||||||
|         req.session.productTitle = req.body.productTitle; |  | ||||||
|         req.session.productDescription = req.body.productDescription; |  | ||||||
|         req.session.productPrice = req.body.productPrice; |  | ||||||
|         req.session.productPermalink = req.body.productPermalink; |  | ||||||
|         req.session.productOptions = productOptions; |  | ||||||
|         req.session.productComment = common.checkboxBool(req.body.productComment); |  | ||||||
|         req.session.productTags = req.body.productTags; |  | ||||||
|         req.session.productStock = req.body.productStock ? parseInt(req.body.productStock) : null; |  | ||||||
| 
 |  | ||||||
|         // redirect to insert
 |  | ||||||
|         res.redirect('/admin/product/edit/' + req.body.productId); |  | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -388,27 +344,10 @@ router.post('/admin/product/update', restrict, checkAccess, async (req, res) => | ||||||
|         // Update the index
 |         // Update the index
 | ||||||
|         indexProducts(req.app) |         indexProducts(req.app) | ||||||
|         .then(() => { |         .then(() => { | ||||||
|             // If API request, return json
 |             res.status(200).json({ message: 'Successfully saved', product: productDoc }); | ||||||
|             if(req.apiAuthenticated){ |  | ||||||
|                 res.status(200).json({ message: 'Successfully saved', product: productDoc }); |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             req.session.message = 'Successfully saved'; |  | ||||||
|             req.session.messageType = 'success'; |  | ||||||
|             res.redirect('/admin/product/edit/' + req.body.productId); |  | ||||||
|         }); |         }); | ||||||
|     }catch(ex){ |     }catch(ex){ | ||||||
|         // If API request, return json
 |         res.status(400).json({ message: 'Failed to save. Please try again' }); | ||||||
|         if(req.apiAuthenticated){ |  | ||||||
|             res.status(400).json({ message: 'Failed to save. Please try again' }); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         console.error(colors.red('Failed to save product: ' + ex)); |  | ||||||
|         req.session.message = 'Failed to save. Please try again'; |  | ||||||
|         req.session.messageType = 'danger'; |  | ||||||
|         res.redirect('/admin/product/edit/' + req.body.productId); |  | ||||||
|     } |     } | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,18 +1,18 @@ | ||||||
| {{> partials/menu}} | {{> partials/menu}} | ||||||
| <div class="col-lg-9"> | <div class="col-lg-9"> | ||||||
|     <form method="post" class="form-horizontal" id="insert_form" action="/admin/product/update" data-toggle="validator"> |     <form class="form-horizontal" id="productEditForm" data-toggle="validator"> | ||||||
|         <div class="col-lg-12"> |         <div class="col-lg-12"> | ||||||
|             <div class="page-header"> |             <div class="page-header"> | ||||||
|                 <div class="pull-right"> |                 <div class="pull-right"> | ||||||
|                     <button type="button" class="btn btn-info" data-toggle="modal" data-target="#myModal">{{ @root.__ "Upload image" }}</button> |                     <button type="button" class="btn btn-info" data-toggle="modal" data-target="#myModal">{{ @root.__ "Upload image" }}</button> | ||||||
|                     <button id="frm_edit_product_save" class="btn btn-success">{{ @root.__ "Save product" }} <i class="fa fa-floppy-o"></i></button> |                     <button id="productUpdate" class="btn btn-success">{{ @root.__ "Save product" }} <i class="fa fa-floppy-o"></i></button> | ||||||
|                 </div> |                 </div> | ||||||
|                 <h2>{{ @root.__ "Edit product" }}</h2> |                 <h2>{{ @root.__ "Edit product" }}</h2> | ||||||
|             </div> |             </div> | ||||||
|             <div class="form-group"> |             <div class="form-group"> | ||||||
|                 <label for="productTitle" class="col-sm-2 control-label">{{ @root.__ "Product title" }} *</label> |                 <label for="productTitle" class="col-sm-2 control-label">{{ @root.__ "Product title" }} *</label> | ||||||
|                 <div class="col-sm-10"> |                 <div class="col-sm-10"> | ||||||
|                     <input type="text" name="productTitle" class="form-control" minlength="5" maxlength="200" value="{{result.productTitle}}" required/> |                     <input type="text" id="productTitle" class="form-control" minlength="5" maxlength="200" value="{{result.productTitle}}" required/> | ||||||
|                 </div> |                 </div> | ||||||
|             </div> |             </div> | ||||||
|             <div class="form-group"> |             <div class="form-group"> | ||||||
|  | @ -20,14 +20,14 @@ | ||||||
|                 <div class="col-sm-6"> |                 <div class="col-sm-6"> | ||||||
|                     <div class="input-group"> |                     <div class="input-group"> | ||||||
|                         <span class="input-group-addon">{{currencySymbol config.currencySymbol}}</span> |                         <span class="input-group-addon">{{currencySymbol config.currencySymbol}}</span> | ||||||
|                         <input type="number" name="productPrice" class="form-control" value="{{result.productPrice}}" step="any" required/> |                         <input type="number" id="productPrice" class="form-control" value="{{result.productPrice}}" step="any" required/> | ||||||
|                     </div> |                     </div> | ||||||
|                 </div> |                 </div> | ||||||
|             </div> |             </div> | ||||||
|             <div class="form-group"> |             <div class="form-group"> | ||||||
|                 <label for="productPublished" class="col-sm-2 control-label">{{ @root.__ "Status" }}</label> |                 <label for="productPublished" class="col-sm-2 control-label">{{ @root.__ "Status" }}</label> | ||||||
|                 <div class="col-sm-6"> |                 <div class="col-sm-6"> | ||||||
|                     <select class="form-control" id="productPublished" name="productPublished"> |                     <select class="form-control" id="productPublished"> | ||||||
|                         <option value="true"  {{selectState result.productPublished "true"}}>{{ @root.__ "Published" }}</option> |                         <option value="true"  {{selectState result.productPublished "true"}}>{{ @root.__ "Published" }}</option> | ||||||
|                         <option value="false" {{selectState result.productPublished "false"}}>{{ @root.__ "Draft" }}</option> |                         <option value="false" {{selectState result.productPublished "false"}}>{{ @root.__ "Draft" }}</option> | ||||||
|                     </select> |                     </select> | ||||||
|  | @ -37,21 +37,21 @@ | ||||||
|             <div class="form-group"> |             <div class="form-group"> | ||||||
|                 <label for="productStock" class="col-sm-2 control-label">{{ @root.__ "Stock level" }}</label> |                 <label for="productStock" class="col-sm-2 control-label">{{ @root.__ "Stock level" }}</label> | ||||||
|                 <div class="col-sm-6"> |                 <div class="col-sm-6"> | ||||||
|                     <input type="number" name="productStock" class="form-control" value="{{result.productStock}}" step="any" /> |                     <input type="number" id="productStock" class="form-control" value="{{result.productStock}}" step="any" /> | ||||||
|                 </div> |                 </div> | ||||||
|             </div> |             </div> | ||||||
|             {{/if}} |             {{/if}} | ||||||
|             <div class="form-group"> |             <div class="form-group"> | ||||||
|                 <label for="editor" class="col-sm-2 control-label">{{ @root.__ "Product description" }} *</label> |                 <label for="productDescription" class="col-sm-2 control-label">{{ @root.__ "Product description" }} *</label> | ||||||
|                 <div class="col-sm-10"> |                 <div class="col-sm-10"> | ||||||
|                     <textarea id="editor" minlength="5" rows="10" id="productDescription" name="productDescription" class="form-control" required>{{result.productDescription}}</textarea> |                     <textarea minlength="5" rows="10" id="productDescription" class="form-control" required>{{result.productDescription}}</textarea> | ||||||
|                 </div> |                 </div> | ||||||
|             </div> |             </div> | ||||||
|             <div class="form-group"> |             <div class="form-group"> | ||||||
|                 <label class="col-sm-2 control-label">Permalink</label> |                 <label class="col-sm-2 control-label">Permalink</label> | ||||||
|                 <div class="col-sm-10"> |                 <div class="col-sm-10"> | ||||||
|                     <div class="input-group"> |                     <div class="input-group"> | ||||||
|                         <input type="text" class="form-control" name="productPermalink" id="productPermalink" placeholder="Permalink for the article" value={{result.productPermalink}}> |                         <input type="text" class="form-control" id="productPermalink" placeholder="Permalink for the article" value={{result.productPermalink}}> | ||||||
|                         <span class="input-group-btn"> |                         <span class="input-group-btn"> | ||||||
|                             <button class="btn btn-success" id="validate_permalink" type="button">{{ @root.__ "Validate" }}</button> |                             <button class="btn btn-success" id="validate_permalink" type="button">{{ @root.__ "Validate" }}</button> | ||||||
|                         </span> |                         </span> | ||||||
|  | @ -60,8 +60,8 @@ | ||||||
|                 </div> |                 </div> | ||||||
|             </div> |             </div> | ||||||
|             <div class="form-group"> |             <div class="form-group"> | ||||||
|                 <input type="hidden" id="productOptions" name="productOptions" value="{{stringify result.productOptions}}" /> |                 <input type="hidden" id="productOptions" value="{{stringify result.productOptions}}" /> | ||||||
|                 <label for="editor" class="col-sm-2 control-label">{{ @root.__ "Product options" }}</label> |                 <label class="col-sm-2 control-label">{{ @root.__ "Product options" }}</label> | ||||||
|                 <div class="col-lg-10"> |                 <div class="col-lg-10"> | ||||||
|                     <ul class="list-group" id="product_opt_wrapper"> |                     <ul class="list-group" id="product_opt_wrapper"> | ||||||
|                         <li class="list-group-item"> |                         <li class="list-group-item"> | ||||||
|  | @ -111,7 +111,7 @@ | ||||||
|             <div class="form-group"> |             <div class="form-group"> | ||||||
|                 <label class="col-sm-2 control-label">Subscription plan</label> |                 <label class="col-sm-2 control-label">Subscription plan</label> | ||||||
|                 <div class="col-sm-10"> |                 <div class="col-sm-10"> | ||||||
|                     <input type="text" class="form-control" name="productSubscription" id="productSubscription" placeholder="plan_XXXXXXXXXXXXXX" value={{@root.result.productSubscription}}> |                     <input type="text" class="form-control" id="productSubscription" placeholder="plan_XXXXXXXXXXXXXX" value={{@root.result.productSubscription}}> | ||||||
|                     <p class="help-block">First setup the plan in <strong>Stripe</strong> dashboard and enter the Plan ID. Format: plan_XXXXXXXXXXXXXX</p> |                     <p class="help-block">First setup the plan in <strong>Stripe</strong> dashboard and enter the Plan ID. Format: plan_XXXXXXXXXXXXXX</p> | ||||||
|                 </div> |                 </div> | ||||||
|             </div> |             </div> | ||||||
|  | @ -121,8 +121,7 @@ | ||||||
|                 <div class="col-sm-10"> |                 <div class="col-sm-10"> | ||||||
|                     <div class="checkbox"> |                     <div class="checkbox"> | ||||||
|                         <label> |                         <label> | ||||||
|                             <input class="productComment" type="checkbox" {{checkedState result.productComment}} id="productComment" |                             <input class="productComment" type="checkbox" {{checkedState result.productComment}} id="productComment"> | ||||||
|                                 name="productComment"> |  | ||||||
|                         </label> |                         </label> | ||||||
|                     </div> |                     </div> | ||||||
|                     <p class="help-block">{{ @root.__ "Allow free form comments when adding products to cart" }}</p> |                     <p class="help-block">{{ @root.__ "Allow free form comments when adding products to cart" }}</p> | ||||||
|  | @ -131,7 +130,7 @@ | ||||||
|             <div class="form-group"> |             <div class="form-group"> | ||||||
|                 <label for="productTags" class="col-sm-2 control-label">{{ @root.__ "Product tag words" }}</label> |                 <label for="productTags" class="col-sm-2 control-label">{{ @root.__ "Product tag words" }}</label> | ||||||
|                 <div class="col-sm-10"> |                 <div class="col-sm-10"> | ||||||
|                     <input type="text" class="form-control" id="productTags" name="productTags" value="{{result.productTags}}"> |                     <input type="text" class="form-control" id="productTags" value="{{result.productTags}}"> | ||||||
|                     <p class="help-block">{{ @root.__ "Tag words used to indexed products, making them easier to find and filter." }}</p> |                     <p class="help-block">{{ @root.__ "Tag words used to indexed products, making them easier to find and filter." }}</p> | ||||||
|                 </div> |                 </div> | ||||||
|             </div> |             </div> | ||||||
|  | @ -160,7 +159,7 @@ | ||||||
|                 {{/if}} |                 {{/if}} | ||||||
|             </div> |             </div> | ||||||
|         </div> |         </div> | ||||||
|         <input type="hidden" name="productId" id="productId" value="{{result._id}}" /> |         <input type="hidden" id="productId" value="{{result._id}}" /> | ||||||
|     </form> |     </form> | ||||||
| </div> | </div> | ||||||
| 
 | 
 | ||||||
|  | @ -190,7 +189,7 @@ | ||||||
| <link href="https://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.2/summernote.css" rel="stylesheet"> | <link href="https://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.2/summernote.css" rel="stylesheet"> | ||||||
| <script> | <script> | ||||||
|     $(document).ready(function() { |     $(document).ready(function() { | ||||||
|         $('#editor').summernote({ |         $('#productDescription').summernote({ | ||||||
|             height: 300, |             height: 300, | ||||||
|             minHeight: null |             minHeight: null | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue