Skip to content

Commit

Permalink
Fix for Classification Reposition using Update Action (#23)
Browse files Browse the repository at this point in the history
* Change PUT to PATCH on classifications.

* Fix using update.

* Use fetch utility for ajax indicators on fetch requests.

* Set up drag-and-drop Caprybara.

* Fix spelling.
  • Loading branch information
MatthewKennedy authored Nov 10, 2021
1 parent 65b6978 commit 8a2a0f0
Show file tree
Hide file tree
Showing 8 changed files with 189 additions and 17 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ module.exports = {
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 13,
"ecmaVersion": 2021,
"sourceType": "module"
},
"rules": {
Expand Down
2 changes: 2 additions & 0 deletions app/assets/javascripts/spree/backend/global/_index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//= require spree/backend/global/alerts
//= require spree/backend/global/animate_css
//= require spree/backend/global/bootstrap
//= require spree/backend/global/fetch_request_utility
//= require spree/backend/global/flatpickr
//= require spree/backend/global/ransack
//= require spree/backend/global/info_alert
Expand Down
19 changes: 19 additions & 0 deletions app/assets/javascripts/spree/backend/global/animate_css.es6
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/* eslint-disable no-unused-vars */

//
// Handle clearing out of animation styles from complete animation.
const animateCSS = (element, animation, speed, prefix = 'animate__') =>
new Promise((resolve) => {
const animationName = `${prefix}${animation}`
const node = document.querySelector(element)

node.classList.add(`${prefix}animated`, animationName, prefix + speed)

function handleAnimationEnd(event) {
event.stopPropagation()
node.classList.remove(`${prefix}animated`, animationName)
resolve('Animation ended')
}

node.addEventListener('animationend', handleAnimationEnd, { once: true })
})
120 changes: 120 additions & 0 deletions app/assets/javascripts/spree/backend/global/fetch_request_utility.es6
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/* eslint-disable no-undef */
/* eslint-disable no-unused-vars */

//
// Shows the progress bar on fech requests
const showProgressIndicator = () => {
const progressBar = document.querySelector('#progress')
progressBar.classList.add('d-block')
animateCSS('#progress', 'fadeIn', 'faster')
}

//
// Hides the progress bar on fech requests
const hideProgressIndicator = () => {
const progressBar = document.querySelector('#progress')

animateCSS('#progress', 'fadeOut', 'fast')

progressBar.addEventListener('animationend', () => {
progressBar.classList.remove('d-block')
})
}

//
// Handles the fetch request response.
// If the response has content it is returned, else if the response is a 204 no-content,
// the resolved text is returned.
const spreeHandleFetchRequestResponse = function(response) {
hideProgressIndicator()

if (response.status === 204) {
return response.text()
} else {
return response.json()
}
}

//
// Handles fech request errors by triggering the appropriate flash alert type and displaying
// the response message.
const spreeHandleFetchRequestError = function(data) {
if (data.error != null) {
show_flash('error', data.error)
} else if (data.message != null) {
show_flash('success', data.message)
} else if (data.exception != null) {
show_flash('info', data.exception)
} else if (data.detail != null) {
show_flash('info', data.detail)
}
}

//
// Reloads the window.
const spreeWindowReload = function() {
window.location.reload()
}

//
// SPREE FECTCH REQUEST
// Pass a json object containing your fetch request details and settings, you can also send a second optional
// argument, this second argument is your success response handler, and lastly a third argument that carries
// through a target element to the response method if needed, the second and third arguments are optional.
// When using spreeFetchRequest() the loading... progress bar, flash notice and errors are all handled for you.
//
// EXAMPLE SENDING A POST REQUEST TO CREATE A NEW SHIPMENT:
// const data = {
// order_id: 'H8213728798',
// variant_id: 2,
// quantity: 4,
// stock_location_id: 1
// }
//
// const requestData = {
// // request details
// uri: Spree.routes.shipments_api_v2,
// method: 'POST',
// dataBody: data,
//
// // Optional Settings
// // disableProgressIndicator: true, Allows you to disable the progress loader bar if needed.
// // formatDataBody: false If you have pre-formatted data, pass this option to stop the function performing the default stringify.
// }
// spreeFetchRequest(requestData, someCallbackFunction, this)
//
const spreeFetchRequest = function(requstData, success = null, target = null) {
if (!requstData.disableProgressIndicator === true) showProgressIndicator()

let requestDataBody

const requestUri = requstData.uri || null
const requestMethod = requstData.method || 'GET'
const requestContentType = requstData.ContentType || 'application/json'

if (requstData.formatDataBody === false) {
requestDataBody = requstData.dataBody
} else {
requestDataBody = JSON.stringify(requstData.dataBody) || null
}

if (requestUri == null) return

fetch(requestUri, {
method: requestMethod,
headers: {
'Authorization': 'Bearer ' + OAUTH_TOKEN,
'Content-Type': requestContentType
},
body: requestDataBody
})
.then((response) => spreeHandleFetchRequestResponse(response)
.then((data) => {
if (response.ok) {
if (success != null) success(data, target)
} else {
spreeHandleFetchRequestError(data)
}
}))
.catch(err => console.log(err))
}
29 changes: 16 additions & 13 deletions app/assets/javascripts/spree/backend/taxons.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,26 @@ $(function () {
swapThreshold: 0.9,
forceFallback: true,
onEnd: function (evt) {
var classificationId = evt.item.getAttribute('data-classification-id')
var newIndex = evt.newIndex
return $.ajax({
url: Spree.routes.classifications_api_v2 + '/' + classificationId.toString() + '/reposition',
headers: Spree.apiV2Authentication(),
method: 'PUT',
dataType: 'json',
data: {
classification: {
position: newIndex
}
}
})
handleClassificationReposition(evt)
}
})
}

function handleClassificationReposition(evt) {
var classificationId = evt.item.getAttribute('data-classification-id')
var data = {
classification: {
position: parseInt(evt.newIndex, 10) + 1
}
}
var requestData = {
uri: Spree.routes.classifications_api_v2 + '/' + classificationId,
method: 'PATCH',
dataBody: data,
}
spreeFetchRequest(requestData)
}

if (taxonId.length > 0) {
taxonId.select2({
placeholder: Spree.translations.find_a_taxon,
Expand Down
2 changes: 1 addition & 1 deletion app/views/spree/admin/taxons/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<% end %>

<div class="taxon-products-view">
<div class="form-group">
<div id="taxonSearch" class="form-group">
<%= select_tag :taxon_id, nil, class: 'd-block w-100' %>
</div>

Expand Down
6 changes: 4 additions & 2 deletions app/views/spree/layouts/admin.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,10 @@
<%#-------------------------------------------------%>
<div id="progress">
<div class="alert alert-info alert-progress">
<div class="spinner"><%= Spree.t(:loading) %>...</div>
<div class="progress-message"><%= Spree.t(:loading) %>...</div>
<div class="progress-message">
<span class="spinner-border spinner-border-sm mr-2" style="width: 1.2em;height: 1.2em;" role="status" aria-hidden="true"></span>
<span style="font-size: 1.2em;"><%= Spree.t(:loading) %>...</span>
</div>
</div>
</div>
</body>
Expand Down
26 changes: 26 additions & 0 deletions spec/features/admin/taxons_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,32 @@
expect(page).to have_css('#taxon_icon_field img')
end

# it 'admin should be able to drag and save' do
# taxon_2 = create(:taxon, name: 'Drag Test')

# product_drag_a = create(:product, stores: Spree::Store.all)
# product_drag_b = create(:product, stores: Spree::Store.all)
# product_drag_c = create(:product, stores: Spree::Store.all)
# product_drag_d = create(:product, stores: Spree::Store.all)
# product_drag_e = create(:product, stores: Spree::Store.all)

# product_drag_a.taxons << taxon_2
# product_drag_b.taxons << taxon_2
# product_drag_c.taxons << taxon_2
# product_drag_d.taxons << taxon_2
# product_drag_e.taxons << taxon_2

# visit spree.admin_taxons_path

# select2(taxon_2.pretty_name, css: '#taxonSearch', search: 'Drag')

# first_item = page.find("li#product_#{product_drag_a.id} > div > nav > a")
# last_item = page.find("li#product_#{product_drag_e.id} > div > nav > a")

# last_item.drag_to(first_item)
# expect(page).to have_content('Fail')
# end

it 'admin should be able to remove taxon icon' do
add_icon_to_root_taxon

Expand Down

0 comments on commit 8a2a0f0

Please sign in to comment.