diff --git a/app/javascript/controllers/move_procedures_position_controller.ts b/app/javascript/controllers/move_procedures_position_controller.ts new file mode 100644 index 000000000..90b9476fb --- /dev/null +++ b/app/javascript/controllers/move_procedures_position_controller.ts @@ -0,0 +1,62 @@ +import { ApplicationController } from './application_controller'; + +export class MoveProceduresPositionController extends ApplicationController { + connect() { + this.updateButtonsStates(); + } + + async moveUp(event: Event) { + event.preventDefault(); + const button = event.currentTarget as HTMLButtonElement; + const upCard = button.closest('.fr-card'); + + await this.switchCards(upCard!, upCard!.previousElementSibling!); + + upCard!.parentNode!.insertBefore(upCard!, upCard!.previousElementSibling); + this.updateButtonsStates(); + } + + async moveDown(event: Event) { + event.preventDefault(); + const button = event.currentTarget as HTMLButtonElement; + const downCard = button.closest('.fr-card'); + + await this.switchCards(downCard!.nextElementSibling!, downCard!); + + downCard!.parentNode!.insertBefore(downCard!.nextElementSibling!, downCard); + this.updateButtonsStates(); + } + + private async switchCards(upCard: Element, downCard: Element): Promise { + const upCardRect = upCard.getBoundingClientRect(); + const downCardRect = downCard.getBoundingClientRect(); + + const upAnimation = upCard.animate( + [ + { transform: `translateY(0)` }, + { transform: `translateY(${downCardRect.top - upCardRect.top}px)` } + ], + { duration: 300, easing: 'ease-in-out' } + ); + + const downAnimation = downCard.animate( + [ + { transform: `translateY(0)` }, + { transform: `translateY(${upCardRect.top - downCardRect.top}px)` } + ], + { duration: 300, easing: 'ease-in-out' } + ); + + await Promise.all([upAnimation.finished, downAnimation.finished]); + } + + private updateButtonsStates() { + const buttons = [ + ...this.element.querySelectorAll('button') + ] as HTMLButtonElement[]; + buttons.forEach( + (button, index) => + (button.disabled = index == 0 || index == buttons.length - 1) + ); + } +} diff --git a/app/views/instructeurs/procedures/order_positions.html.haml b/app/views/instructeurs/procedures/order_positions.html.haml index 7d3634aba..f50de80e5 100644 --- a/app/views/instructeurs/procedures/order_positions.html.haml +++ b/app/views/instructeurs/procedures/order_positions.html.haml @@ -4,13 +4,13 @@ Personnaliser l'ordre des #{@procedures.size} démarches « en cours » %p Déplacez les démarches dans la liste pour les classer en fonction de vos préférences : - %fr-container + %fr-container{ data: { controller: 'move-procedures-position' } } = form_tag update_order_positions_instructeur_procedures_path, method: :patch do - @procedures.each do |procedure| .fr-card.fr-mb-1w.fr-py-1w.fr-px-2w .flex.align-center - %button.fr-btn.fr-icon-arrow-up-line.fr-btn--secondary.fr-col-1 - %button.fr-btn.fr-icon-arrow-down-line.fr-btn--secondary.fr-col-1.fr-mx-2w + %button.fr-btn.fr-icon-arrow-up-line.fr-btn--secondary.fr-col-1{ data: { action: "move-procedures-position#moveUp" } } + %button.fr-btn.fr-icon-arrow-down-line.fr-btn--secondary.fr-col-1.fr-mx-2w{ data: { action: "move-procedures-position#moveDown" } } - if procedure.close? %span.fr-badge.fr-mr-2w Close - elsif procedure.depubliee?