From 465dc994efb0541f996f01097ff630c716092819 Mon Sep 17 00:00:00 2001 From: Ellen Wittingen <101463776+Ellen-Wittingen@users.noreply.github.com> Date: Wed, 7 Feb 2024 20:44:49 +0100 Subject: [PATCH] Made price-lists table scrollable and made lists archivable (#911) * Made price-lists table scrollable and made lists archivable * Fixed trailing whitespace * Fixed scss linting issues --- app/assets/stylesheets/price_lists.scss | 105 ++++++++++++------ app/controllers/price_lists_controller.rb | 36 +++++- app/javascript/packs/price_lists.js | 29 ++++- app/policies/price_list_policy.rb | 8 ++ app/views/price_lists/index.html.erb | 52 +++++---- config/routes.rb | 7 +- ...202124405_add_archived_at_to_price_list.rb | 5 + db/schema.rb | 8 +- 8 files changed, 188 insertions(+), 62 deletions(-) create mode 100644 db/migrate/20240202124405_add_archived_at_to_price_list.rb diff --git a/app/assets/stylesheets/price_lists.scss b/app/assets/stylesheets/price_lists.scss index c8cd21f2f..b1ba68630 100644 --- a/app/assets/stylesheets/price_lists.scss +++ b/app/assets/stylesheets/price_lists.scss @@ -1,21 +1,59 @@ @import 'theme_sofia'; -.center-text { - margin: 0 auto; - text-align: center; -} +.price-lists-table { + width: fit-content; + max-height: calc(100vh - 18rem); + + .center-text { + margin: 0 auto; + text-align: center; + } -th { - &.products-id { + .products-id, + .products-cancel-edit { + left: 0; width: 1.75rem; } - &.products-actions { - width: 4rem; + .products-name { + left: 2.1rem; + width: 6rem; + } + + .products-actions, + .products-new-edit-button, + .products-save-new { + right: 0; + } + + .products-id, + .products-cancel-edit, + .products-name, + .products-new-edit-button, + .products-save-new { + position: sticky; + z-index: 1; + background-color: $body-bg; + } + + .products-actions { + position: sticky; + z-index: 1; + } + + thead { + position: sticky; + top: 0; + z-index: 2; + background-color: $body-bg; + } + + th { + &.products-actions { + width: 4rem; + } } -} -.price_lists_table { tr { &:last-child { td { @@ -23,38 +61,39 @@ th { } } } -} -td { - &.products-new-edit-button { - padding: .5rem 1rem; - } - &.products-new { - input { - &.form-control { - width: 6rem; - } + td { + &.products-new-edit-button { + padding: .5rem 1rem; } - select { - &.form-control { - width: 4rem; + &.products-new { + input { + &.form-control { + width: 6rem; + } + } + + select { + &.form-control { + width: 4rem; + } } } - } - &.products-new-price { - input { - &.form-control { - width: 2rem; + &.products-new-price { + input { + &.form-control { + width: 4rem; + } } } - } - &.products-cancel-new, - &.products-cancel-edit, - &.products-save-new { - vertical-align: middle; + &.products-cancel-new, + &.products-cancel-edit, + &.products-save-new { + vertical-align: middle; + } } } diff --git a/app/controllers/price_lists_controller.rb b/app/controllers/price_lists_controller.rb index 62c22909d..6a1a02ec3 100644 --- a/app/controllers/price_lists_controller.rb +++ b/app/controllers/price_lists_controller.rb @@ -4,14 +4,14 @@ class PriceListsController < ApplicationController after_action :verify_authorized def index - recent_price_lists = PriceList.order(created_at: :desc).limit(6) + price_lists = PriceList.order(created_at: :desc) products = Product.all.order(:id).includes(:product_prices) - authorize recent_price_lists + authorize price_lists @price_list = PriceList.new - @recent_price_lists_json = recent_price_lists.to_json(except: %i[created_at updated_at deleted_at]) + @price_lists_json = price_lists.to_json(except: %i[created_at updated_at deleted_at]) @products_json = products.to_json( include: { product_prices: { except: %i[created_at updated_at deleted_at] } }, methods: :t_category, @@ -43,6 +43,36 @@ def update redirect_to @price_list end + def archive + @price_list = PriceList.find(params[:id]) + authorize @price_list + + @price_list.archived_at = Time.zone.now + + respond_to do |format| + if @price_list.save + format.json { render json: @price_list.archived_at } + else + format.json { render json: @price_list.errors, status: :unprocessable_entity } + end + end + end + + def unarchive + @price_list = PriceList.find(params[:id]) + authorize @price_list + + @price_list.archived_at = nil + + respond_to do |format| + if @price_list.save + format.json { render json: @price_list.archived_at } + else + format.json { render json: @price_list.errors, status: :unprocessable_entity } + end + end + end + private def permitted_attributes diff --git a/app/javascript/packs/price_lists.js b/app/javascript/packs/price_lists.js index 82fd06a2a..7585ec79d 100644 --- a/app/javascript/packs/price_lists.js +++ b/app/javascript/packs/price_lists.js @@ -8,7 +8,7 @@ Vue.use(VueResource); document.addEventListener('turbolinks:load', () => { Vue.http.headers.common['X-CSRF-TOKEN'] = document.querySelector('meta[name="csrf-token"]').getAttribute('content'); - var element = document.getElementById('price_lists_table'); + var element = document.getElementById('pricelists-container'); if (element != null) { var priceLists = JSON.parse(element.dataset.priceLists); var products = JSON.parse(element.dataset.products); @@ -19,7 +19,16 @@ document.addEventListener('turbolinks:load', () => { new Vue({ el: element, data: () => { - return { priceLists: priceLists, products: products }; + return { priceLists: priceLists, products: products, showArchived: false }; + }, + computed: { + filteredPriceLists: function() { + if (this.showArchived) { + return priceLists; + } else { + return priceLists.filter(priceList => !priceList.archived_at); + } + } }, methods: { findPrice: function(product, priceList) { @@ -124,6 +133,22 @@ document.addEventListener('turbolinks:load', () => { return products; }, + archivePriceList: function(priceList) { + this.$http.post(`/price_lists/${priceList.id}/archive`, {}).then((response) => { + priceList.archived_at = response.data; + }, (response) => { + this.errors = response.data.errors; + }); + }, + + unarchivePriceList: function(priceList) { + this.$http.post(`/price_lists/${priceList.id}/unarchive`, {}).then((response) => { + priceList.archived_at = response.data; + }, (response) => { + this.errors = response.data.errors; + }); + }, + productPriceToCurrency: function(productPrice) { return (productPrice && productPrice.price) ? `€ ${parseFloat(productPrice.price).toFixed(2)}` : ''; }, diff --git a/app/policies/price_list_policy.rb b/app/policies/price_list_policy.rb index 4d6d653ec..a28c98dec 100644 --- a/app/policies/price_list_policy.rb +++ b/app/policies/price_list_policy.rb @@ -15,6 +15,14 @@ def update? create? end + def archive? + create? + end + + def unarchive? + create? + end + def search? index? end diff --git a/app/views/price_lists/index.html.erb b/app/views/price_lists/index.html.erb index f67bd48e9..ca0f0c25e 100644 --- a/app/views/price_lists/index.html.erb +++ b/app/views/price_lists/index.html.erb @@ -3,7 +3,8 @@ <%= render 'modal' %> <% end %> - +<% end %> diff --git a/config/routes.rb b/config/routes.rb index 18807cd79..94c0d9774 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -12,7 +12,12 @@ end resources :orders, only: %i[index create update destroy] - resources :price_lists, only: %i[index create update] + resources :price_lists, only: %i[index create update] do + member do + post :archive + post :unarchive + end + end resources :users, only: %i[index show create update] do collection do diff --git a/db/migrate/20240202124405_add_archived_at_to_price_list.rb b/db/migrate/20240202124405_add_archived_at_to_price_list.rb new file mode 100644 index 000000000..99e50757b --- /dev/null +++ b/db/migrate/20240202124405_add_archived_at_to_price_list.rb @@ -0,0 +1,5 @@ +class AddArchivedAtToPriceList < ActiveRecord::Migration[7.0] + def change + add_column :price_lists, :archived_at, :datetime + end +end diff --git a/db/schema.rb b/db/schema.rb index 5497d9d59..26fcbda0c 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,8 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2022_10_12_161008) do - +ActiveRecord::Schema[7.0].define(version: 2024_02_02_124405) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -50,8 +49,8 @@ t.integer "amount", null: false t.decimal "price", precision: 8, scale: 2, null: false t.datetime "deleted_at" - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.index ["invoice_id"], name: "index_invoice_rows_on_invoice_id" end @@ -115,6 +114,7 @@ t.datetime "deleted_at" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.datetime "archived_at" end create_table "product_prices", force: :cascade do |t|