diff --git a/app/assets/stylesheets/application.tailwind.css b/app/assets/stylesheets/application.tailwind.css index e8b37c80..93ebbb55 100644 --- a/app/assets/stylesheets/application.tailwind.css +++ b/app/assets/stylesheets/application.tailwind.css @@ -20,7 +20,7 @@ } th { - @apply whitespace-nowrap px-2 py-3.5 text-left text-sm font-semibold text-gray-900; + @apply whitespace-nowrap px-2 text-left text-sm font-semibold text-gray-900 py-3.5; } tbody { @@ -28,22 +28,22 @@ } td { - @apply px-2 py-2 text-sm text-gray-500 whitespace-nowrap; + @apply whitespace-nowrap px-2 py-2 text-sm text-gray-500; } } .form-field { - @apply relative border border-alpha-black-100 bg-white rounded-md shadow-xs; - @apply focus-within:shadow-none focus-within:border-gray-900 focus-within:ring-4 focus-within:ring-gray-100; + @apply relative rounded-md border bg-white border-alpha-black-100 shadow-xs; + @apply focus-within:border-gray-900 focus-within:shadow-none focus-within:ring-4 focus-within:ring-gray-100; } .form-field__label { - @apply px-3 pt-2 pb-0 block text-xs text-gray-500; + @apply block px-3 pt-2 pb-0 text-xs text-gray-500; } .form-field__input { - @apply px-3 pb-2 pt-1 text-sm w-full bg-transparent border-none opacity-100; - @apply focus:outline-none focus:ring-0 focus:opacity-100; + @apply w-full border-none bg-transparent px-3 pt-1 pb-2 text-sm opacity-100; + @apply focus:opacity-100 focus:outline-none focus:ring-0; @apply placeholder-shown:opacity-50; @apply disabled:opacity-50; } @@ -53,7 +53,7 @@ } .form-field__submit { - @apply w-full p-3 text-center text-white bg-black rounded-lg cursor-pointer hover:bg-gray-700; + @apply w-full cursor-pointer rounded-lg bg-black p-3 text-center text-white hover:bg-gray-700; } input:checked + label + .toggle-switch-dot { @@ -65,7 +65,7 @@ } [type='checkbox'].maybe-checkbox--light { - @apply border-alpha-black-200 checked:bg-gray-900 checked:hover:bg-gray-500 checked:ring-gray-900 focus-visible:ring-gray-900 focus:ring-gray-900; + @apply border-alpha-black-200 checked:bg-gray-900 checked:ring-gray-900 focus:ring-gray-900 focus-visible:ring-gray-900 checked:hover:bg-gray-500; } [type='checkbox'].maybe-checkbox--dark { @@ -75,6 +75,12 @@ [type='checkbox'].maybe-checkbox--dark:checked { background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='111827' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e"); } + + .maybe-switch { + @apply block bg-gray-100 w-9 h-5 rounded-full cursor-pointer; + @apply after:content-[''] after:block after:absolute after:top-0.5 after:left-0.5 after:bg-white after:w-4 after:h-4 after:rounded-full after:transition-transform after:duration-300 after:ease-in-out; + @apply peer-checked:bg-green-600 peer-checked:after:translate-x-4; + } } /* Small, single purpose classes that should take precedence over other styles */ diff --git a/app/controllers/transactions_controller.rb b/app/controllers/transactions_controller.rb index bc12c677..b00212dc 100644 --- a/app/controllers/transactions_controller.rb +++ b/app/controllers/transactions_controller.rb @@ -52,6 +52,21 @@ class TransactionsController < ApplicationController redirect_to transactions_url, notice: t(".success") end + def bulk_delete + destroyed = Current.family.transactions.destroy_by(id: bulk_delete_params[:transaction_ids]) + redirect_to transactions_url, notice: t(".success", count: destroyed.count) + end + + def bulk_update + transactions = Current.family.transactions.where(id: bulk_update_params[:transaction_ids]) + updates = bulk_update_params.except(:transaction_ids) + if transactions.update_all(bulk_update_params.except(:transaction_ids).to_h) + redirect_to transactions_url, notice: t(".success", count: transactions.count) + else + render :index, status: :unprocessable_entity, notice: t(".failure") + end + end + private def set_transaction @@ -70,11 +85,19 @@ class TransactionsController < ApplicationController params[:transaction][:nature].to_s.inquiry end + def bulk_delete_params + params.require(:bulk_delete).permit(transaction_ids: []) + end + + def bulk_update_params + params.require(:bulk_update).permit(:category_id, :excluded, :currency, tag_ids: [], transaction_ids: []) + end + def search_params params.fetch(:q, {}).permit(:start_date, :end_date, :search, accounts: [], account_ids: [], categories: [], merchants: []) end def transaction_params - params.require(:transaction).permit(:name, :date, :amount, :currency, :notes, :excluded, :category_id, :merchant_id, tag_ids: [], taggings_attributes: [ :id, :tag_id, :_destroy ]) + params.require(:transaction).permit(:name, :date, :amount, :currency, :notes, :excluded, :category_id, :merchant_id, tag_ids: []) end end diff --git a/app/javascript/controllers/bulk_select_controller.js b/app/javascript/controllers/bulk_select_controller.js index c5ff2c1c..124ddf9c 100644 --- a/app/javascript/controllers/bulk_select_controller.js +++ b/app/javascript/controllers/bulk_select_controller.js @@ -18,6 +18,12 @@ export default class extends Controller { document.removeEventListener("turbo:load", this.#updateView) } + submitBulkDeletionRequest(e) { + const form = e.target.closest("form"); + this.#addHiddenFormInputsForSelectedIds(form, "bulk_delete[transaction_ids][]", this.selectedIdsValue) + form.requestSubmit() + } + togglePageSelection(e) { if (e.target.checked) { this.#selectAll() @@ -54,6 +60,16 @@ export default class extends Controller { this.#updateView() } + #addHiddenFormInputsForSelectedIds(form, paramName, transactionIds) { + transactionIds.forEach(id => { + const input = document.createElement("input"); + input.type = 'hidden' + input.name = paramName + input.value = id + form.appendChild(input) + }) + } + #rowsForGroup(group) { return this.rowTargets.filter(row => group.contains(row)) } diff --git a/app/views/transactions/_selection_bar.html.erb b/app/views/transactions/_selection_bar.html.erb index d3264ec8..4e42d7dc 100644 --- a/app/views/transactions/_selection_bar.html.erb +++ b/app/views/transactions/_selection_bar.html.erb @@ -10,8 +10,10 @@ <%= lucide_icon "pencil-line", class: "w-5 group-hover:text-white" %> <% end %> - <%= button_to "#", disabled: true, class: "cursor-not-allowed p-1.5 group hover:bg-gray-700 flex items-center justify-center rounded-md", title: "Delete" do %> - <%= lucide_icon "trash-2", class: "w-5 group-hover:text-white" %> + <%= form_with url: bulk_delete_transactions_path, builder: ActionView::Helpers::FormBuilder, data: { turbo_confirm: true } do %> + <% end %> diff --git a/app/views/transactions/show.html.erb b/app/views/transactions/show.html.erb index a4649eb4..1436ce46 100644 --- a/app/views/transactions/show.html.erb +++ b/app/views/transactions/show.html.erb @@ -1,81 +1,105 @@ <%= drawer do %> -