workarea-product_documents 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +20 -0
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +37 -0
  4. data/.github/ISSUE_TEMPLATE/documentation-request.md +17 -0
  5. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  6. data/.github/workflows/ci.yml +57 -0
  7. data/.gitignore +18 -0
  8. data/.rubocop.yml +3 -0
  9. data/CHANGELOG.md +16 -0
  10. data/CODE_OF_CONDUCT.md +3 -0
  11. data/CONTRIBUTING.md +3 -0
  12. data/Gemfile +10 -0
  13. data/LICENSE.md +3 -0
  14. data/README.md +39 -0
  15. data/Rakefile +116 -0
  16. data/app/assets/javascripts/workarea/admin/modules/sort_documents.js +68 -0
  17. data/app/assets/stylesheets/workarea/storefront/product_documents/components/product_documents.scss +22 -0
  18. data/app/controllers/workarea/.keep +0 -0
  19. data/app/controllers/workarea/admin/catalog_product_documents_controller.rb +59 -0
  20. data/app/models/workarea/catalog/product.decorator +7 -0
  21. data/app/models/workarea/catalog/product_document.rb +29 -0
  22. data/app/view_models/workarea/admin/product_view_model.decorator +7 -0
  23. data/app/view_models/workarea/storefront/product_view_model.decorator +7 -0
  24. data/app/views/workarea/.keep +0 -0
  25. data/app/views/workarea/admin/catalog_product_documents/_product_documents.html.haml +14 -0
  26. data/app/views/workarea/admin/catalog_product_documents/index.html.haml +40 -0
  27. data/app/views/workarea/admin/catalog_product_documents/new.html.haml +44 -0
  28. data/app/views/workarea/admin/catalog_products/_documents_card.haml +22 -0
  29. data/app/views/workarea/storefront/products/_product_documents.html.haml +9 -0
  30. data/bin/rails +20 -0
  31. data/config/initializers/appends.rb +21 -0
  32. data/config/initializers/workarea.rb +0 -0
  33. data/config/locales/en.yml +34 -0
  34. data/config/routes.rb +9 -0
  35. data/lib/workarea/product_documents.rb +11 -0
  36. data/lib/workarea/product_documents/engine.rb +8 -0
  37. data/lib/workarea/product_documents/version.rb +5 -0
  38. data/test/dummy/Rakefile +6 -0
  39. data/test/dummy/app/assets/config/manifest.js +4 -0
  40. data/test/dummy/app/assets/images/.keep +0 -0
  41. data/test/dummy/app/assets/javascripts/application.js +13 -0
  42. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  43. data/test/dummy/app/controllers/application_controller.rb +3 -0
  44. data/test/dummy/app/controllers/concerns/.keep +0 -0
  45. data/test/dummy/app/helpers/application_helper.rb +2 -0
  46. data/test/dummy/app/jobs/application_job.rb +2 -0
  47. data/test/dummy/app/mailers/application_mailer.rb +4 -0
  48. data/test/dummy/app/models/concerns/.keep +0 -0
  49. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  50. data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
  51. data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
  52. data/test/dummy/bin/bundle +3 -0
  53. data/test/dummy/bin/rails +4 -0
  54. data/test/dummy/bin/rake +4 -0
  55. data/test/dummy/bin/setup +34 -0
  56. data/test/dummy/bin/update +29 -0
  57. data/test/dummy/config.ru +5 -0
  58. data/test/dummy/config/application.rb +27 -0
  59. data/test/dummy/config/boot.rb +5 -0
  60. data/test/dummy/config/cable.yml +9 -0
  61. data/test/dummy/config/environment.rb +5 -0
  62. data/test/dummy/config/environments/development.rb +51 -0
  63. data/test/dummy/config/environments/production.rb +83 -0
  64. data/test/dummy/config/environments/test.rb +44 -0
  65. data/test/dummy/config/initializers/application_controller_renderer.rb +6 -0
  66. data/test/dummy/config/initializers/assets.rb +11 -0
  67. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  68. data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
  69. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  70. data/test/dummy/config/initializers/inflections.rb +16 -0
  71. data/test/dummy/config/initializers/mime_types.rb +4 -0
  72. data/test/dummy/config/initializers/new_framework_defaults.rb +18 -0
  73. data/test/dummy/config/initializers/workarea.rb +5 -0
  74. data/test/dummy/config/initializers/wrap_parameters.rb +9 -0
  75. data/test/dummy/config/locales/en.yml +23 -0
  76. data/test/dummy/config/puma.rb +47 -0
  77. data/test/dummy/config/routes.rb +5 -0
  78. data/test/dummy/config/secrets.yml +22 -0
  79. data/test/dummy/config/spring.rb +6 -0
  80. data/test/dummy/db/seeds.rb +2 -0
  81. data/test/dummy/lib/assets/.keep +0 -0
  82. data/test/dummy/log/.keep +0 -0
  83. data/test/integration/workarea/admin/product_documents_integration_test.rb +85 -0
  84. data/test/integration/workarea/storefront/product_documents_integration_test.rb +28 -0
  85. data/test/teaspoon_env.rb +6 -0
  86. data/test/test_helper.rb +15 -0
  87. data/test/view_models/workarea/admin/product_view_model_test.decorator +28 -0
  88. data/workarea-product_documents.gemspec +18 -0
  89. metadata +144 -0
@@ -0,0 +1,22 @@
1
+ /*------------------------------------*\
2
+ #PRODUCT-DOCUMENTS
3
+ \*------------------------------------*/
4
+
5
+ .product-documents {}
6
+
7
+ .product-documents__title {}
8
+
9
+ .product-documents__type {
10
+ margin-bottom: 0;
11
+ }
12
+
13
+ .product-documents__display_name {}
14
+
15
+ .product-documents__list {
16
+ @extend %unstyled-list;
17
+ margin-bottom: $margin-bottom;
18
+ }
19
+
20
+ .product-documents__list-item {}
21
+
22
+ .product-documents__link {}
File without changes
@@ -0,0 +1,59 @@
1
+ module Workarea
2
+ class Admin::CatalogProductDocumentsController < Admin::ApplicationController
3
+ required_permissions :catalog
4
+ before_action :find_product
5
+
6
+ def index; end
7
+
8
+ def create
9
+ @document = @product.product_documents.build(params[:document])
10
+
11
+ if @document.save
12
+ flash[:success] = t("workarea.admin.product_documents.flash_messages.create")
13
+ redirect_to catalog_product_documents_path(@product)
14
+ else
15
+ render :index, status: :unprocessable_entity
16
+ end
17
+ end
18
+
19
+ def update
20
+ document = @product.product_documents.find(params[:id])
21
+
22
+ if document.update_attributes(params[:document])
23
+ flash[:success] = t("workarea.admin.product_documents.flash_messages.update")
24
+ redirect_to catalog_product_documents_path(@product)
25
+ else
26
+ render :index, status: :unprocessable_entity
27
+ end
28
+ end
29
+
30
+ def move
31
+ position_data = params.fetch(:positions, {})
32
+
33
+ position_data.each do |document_id, position|
34
+ document = @product.product_documents.find(document_id)
35
+ document.position = position
36
+ end
37
+
38
+ @product.save!
39
+ flash[:success] = t(
40
+ "workarea.admin.product_documents.flash_messages.sorting_saved"
41
+ )
42
+ head :ok
43
+ end
44
+
45
+ def destroy
46
+ @product.product_documents.find(params[:id]).destroy
47
+ flash[:success] = t("workarea.admin.product_documents.flash_messages.delete")
48
+ redirect_to catalog_product_documents_path(@product)
49
+ end
50
+
51
+ private
52
+
53
+ def find_product
54
+ @product = Workarea::Admin::ProductViewModel.wrap(
55
+ Catalog::Product.where(slug: params[:catalog_product_id]).first
56
+ )
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,7 @@
1
+ module Workarea
2
+ decorate Catalog::Product, with: :product_documents do
3
+ decorated do
4
+ embeds_many :product_documents, class_name: 'Workarea::Catalog::ProductDocument'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,29 @@
1
+ module Workarea
2
+ module Catalog
3
+ class ProductDocument
4
+ include ApplicationDocument
5
+ include Ordering
6
+ extend Dragonfly::Model
7
+
8
+ field :type, type: String
9
+ field :document_name, type: String
10
+ field :document_uid, type: String
11
+ field :display_name, type: String
12
+
13
+ embedded_in :product,
14
+ class_name: "Workarea::Catalog::Product",
15
+ inverse_of: :product_documents,
16
+ touch: true
17
+
18
+ dragonfly_accessor :document, app: :workarea
19
+
20
+ def respond_to?(sym, *args)
21
+ super || document.respond_to?(sym)
22
+ end
23
+
24
+ def method_missing(sym, *args, &block)
25
+ document.send(sym, *args, &block) if document.respond_to?(sym)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,7 @@
1
+ module Workarea
2
+ decorate Admin::ProductViewModel, with: :product_documents do
3
+ def documents_by_type
4
+ product_documents.asc(:position).group_by { |doc| doc.display_name }
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Workarea
2
+ decorate Storefront::ProductViewModel, with: :product_documents do
3
+ def documents_by_name
4
+ product_documents.group_by { |doc| doc.display_name }
5
+ end
6
+ end
7
+ end
File without changes
@@ -0,0 +1,14 @@
1
+ .edit-view-documents
2
+ .edit-product__editable
3
+ %h2.heading.heading--5= pluralize(@product.documents.length, 'Document')
4
+ %p.edit-product__editable-action= link_to 'Edit', catalog_product_documents_path(@product), class: 'button button--small', data: { dialog_button: '' }
5
+
6
+ - if @product.documents_by_type.any?
7
+ %ul.edit-product__data-list
8
+ - @product.documents_by_type.each do |type, documents|
9
+ %li
10
+ %span
11
+ - if type.blank?
12
+ #{documents.count} without Type
13
+ - else
14
+ #{documents.count} for #{type.titleize}
@@ -0,0 +1,40 @@
1
+ - @page_title= t('workarea.admin.product_documents.index.page_title', product: @product.name)
2
+
3
+ .view
4
+ .view__header
5
+ .grid
6
+ .grid__cell.grid__cell--25
7
+ .grid__cell.grid__cell--50
8
+ .view__heading
9
+ = link_to_index_for(@product)
10
+ %h1= link_to @product.name, url_for(@product)
11
+ .grid__cell.grid__cell--25
12
+ = render_aux_navigation_for(@product)
13
+
14
+ .view__container
15
+ = render_cards_for(@product, :documents)
16
+
17
+ .section
18
+ %h2.view__heading= t('workarea.admin.product_documents.index.heading')
19
+
20
+ %table
21
+ %thead
22
+ %tr
23
+ %th
24
+ %th= t('workarea.admin.product_documents.index.display_name')
25
+ %th= t('workarea.admin.product_documents.index.file_name')
26
+ %th
27
+ %tbody{ data: { sort_document: '', product_id: @product.to_param } }
28
+ - @product.product_documents.each do |document|
29
+ %tr{ data: { sort_document_id: document.id } }
30
+ %td= inline_svg('workarea/admin/icons/grip.svg', title: t('workarea.admin.product_documents.index.drag_to_rearrange'), class: 'svg-icon svg-icon--small svg-icon--gray')
31
+ %td= document.display_name
32
+ %td= link_to document.document_name, document.url, :target => '_blank'
33
+ %td
34
+ = form_tag catalog_product_document_path(@product, document), method: 'delete', class: 'text-button text-button--destroy' do
35
+ = button_tag value: 'remove_product_document', class: 'text-button text-button--destroy' do
36
+ = inline_svg('workarea/admin/icons/delete.svg', class: 'text-button__icon', title: t('workarea.admin.actions.delete'))
37
+ .workflow-bar
38
+ .grid.grid--auto.grid--right.grid--middle
39
+ .grid__cell
40
+ = link_to t('workarea.admin.product_documents.index.add_new'), new_catalog_product_document_path(@product), class: 'workflow-bar__button workflow-bar__button--create'
@@ -0,0 +1,44 @@
1
+ - @page_title= t('workarea.admin.product_documents.new.page_title', product: @product.name)
2
+
3
+ .product-images.view
4
+ .view__header
5
+ .grid
6
+ .grid__cell.grid__cell--25
7
+ .grid__cell.grid__cell--50
8
+ .view__heading
9
+ = link_to_index_for(@product)
10
+ %h1= link_to @product.name, url_for(@product)
11
+ .grid__cell.grid__cell--25
12
+ = render_aux_navigation_for(@product)
13
+
14
+ .view__container
15
+ = render_cards_for(@product, :documents)
16
+
17
+ .view__container.view__container--narrow
18
+
19
+ .section
20
+ %h2= t('workarea.admin.product_documents.new.new_document')
21
+
22
+ - if @image.present? && @image.errors.present?
23
+ - @image.errors.full_messages.each do |message|
24
+ = render_message 'error', message
25
+
26
+ = form_tag catalog_product_documents_path(@product), method: 'post', multipart: true do
27
+ .property
28
+ = label_tag 'document_document', class: 'property__name' do
29
+ %span.property__text= t('workarea.admin.product_documents.new.document')
30
+ .value= file_field_tag 'document[document]', required: true
31
+ .property
32
+ = label_tag 'document_display_name', class: 'property__name' do
33
+ %span.property__text= t('workarea.admin.product_documents.new.name')
34
+ .value= text_field_tag 'document[display_name]', nil, class: 'text-box'
35
+
36
+ = append_partials('admin.product_document_fields', product: @product)
37
+ .workflow-bar
38
+ .grid.grid--right.grid--middle
39
+ .grid__cell.grid__cell--20
40
+ = link_to t('workarea.admin.form.cancel'), url_for(@product), class: 'workflow-bar__button workflow-bar__button--delete'
41
+
42
+ .grid__cell.grid__cell--80
43
+ .grid.grid--auto.grid--right.grid--middle
44
+ .grid__cell= button_tag t('workarea.admin.product_documents.new.create_document'), value: t('workarea.admin.product_documents.new.create_document'), class: 'workflow-bar__button workflow-bar__button--create'
@@ -0,0 +1,22 @@
1
+ .grid__cell
2
+ .card{ class: card_classes(:documents, local_assigns[:active]) }
3
+ = link_to catalog_product_documents_path(model), class: 'card__header' do
4
+ %span.card__header-text= t('workarea.admin.product_documents.cards.title')
5
+ = inline_svg 'workarea/admin/icons/pages.svg', class: 'card__icon'
6
+
7
+ - if local_assigns[:active].blank?
8
+ .card__body
9
+ - if model.product_documents.empty?
10
+ %p= t('workarea.admin.product_documents.cards.description')
11
+ = link_to new_catalog_product_document_path(model), class: 'card__button' do
12
+ %span.button.button--small= t('workarea.admin.product_documents.cards.add_documents')
13
+ - else
14
+ %ul.list-reset
15
+ - model.product_documents.take(10).each do |document|
16
+ %li
17
+ %strong= document.display_name
18
+ =document.document_name
19
+ - if model.product_documents.size > 10
20
+ %li= t('workarea.admin.cards.more', amount: model.product_documents.size - 10)
21
+ = link_to catalog_product_documents_path(model), class: 'card__button' do
22
+ %span.button.button--small= t('workarea.admin.product_documents.cards.manage_documents')
@@ -0,0 +1,9 @@
1
+ %div.product-documents
2
+ %h3.product-documents__title= t('workarea.storefront.product_documents.show.documents')
3
+ - product.documents_by_name.each do |display_name, documents|
4
+ %p.product-documents__display_name= display_name
5
+
6
+ %ul.product-documents__list
7
+ - documents.each do |document|
8
+ %li.product-documents__list-item
9
+ = link_to document.document_name, document.url, :target => '_blank', class: "product-documents__link"
data/bin/rails ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails gems
3
+ # installed from the root of your application.
4
+
5
+ ENGINE_ROOT = File.expand_path("../..", __FILE__)
6
+ ENGINE_PATH = File.expand_path("../../lib/workarea/product_documents/engine", __FILE__)
7
+ APP_PATH = File.expand_path("../../test/dummy/config/application", __FILE__)
8
+
9
+ # Set up gems listed in the Gemfile.
10
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
11
+ require "bundler/setup" if File.exist?(ENV["BUNDLE_GEMFILE"])
12
+
13
+ require "action_controller/railtie"
14
+ require "action_view/railtie"
15
+ require "action_mailer/railtie"
16
+ require "rails/test_unit/railtie"
17
+ require "sprockets/railtie"
18
+ require "teaspoon-mocha"
19
+
20
+ require "rails/engine/commands"
@@ -0,0 +1,21 @@
1
+ module Workarea
2
+ Plugin.append_partials(
3
+ "storefront.product_show",
4
+ "workarea/storefront/products/product_documents"
5
+ )
6
+
7
+ Plugin.append_partials(
8
+ "admin.catalog_product_cards",
9
+ "workarea/admin/catalog_products/documents_card"
10
+ )
11
+
12
+ Plugin.append_javascripts(
13
+ "admin.modules",
14
+ "workarea/admin/modules/sort_documents"
15
+ )
16
+
17
+ Plugin.append_stylesheets(
18
+ "store_front.components",
19
+ "workarea/storefront/product_documents/components/product_documents"
20
+ )
21
+ end
File without changes
@@ -0,0 +1,34 @@
1
+ en:
2
+ workarea:
3
+ storefront:
4
+ product_documents:
5
+ show:
6
+ documents: Documents
7
+ admin:
8
+ product_documents:
9
+ new:
10
+ create_document: Create Document
11
+ document: Document
12
+ heading: Documents for %{product}
13
+ name: Display Name
14
+ new_document: New Document
15
+ page_title: Documents for %{product}
16
+ type: Type
17
+ index:
18
+ add_new: Add New Document
19
+ delete: Delete
20
+ display_name: Display Name
21
+ drag_to_rearrange: Drag to rearrange
22
+ file_name: File Name
23
+ heading: Documents
24
+ page_title: Documents for %{product}
25
+ cards:
26
+ title: Documents
27
+ add_documents: Add Documents
28
+ description: Add downloadable documents to show on the product detail page.
29
+ manage_documents: Manage Documents
30
+ flash_messages:
31
+ delete: Your document has been removed.
32
+ create: Your document has been created.
33
+ update: Your document has been updated.
34
+ sorting_saved: The sort has been updated.
data/config/routes.rb ADDED
@@ -0,0 +1,9 @@
1
+ Workarea::Admin::Engine.routes.draw do
2
+ resources :catalog_products, only: [] do
3
+ resources :documents, only: [:index, :create, :update, :destroy, :new ], controller: "catalog_product_documents" do
4
+ collection do
5
+ post :move
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ require "workarea"
2
+ require "workarea/storefront"
3
+ require "workarea/admin"
4
+
5
+ require "workarea/product_documents/engine"
6
+ require "workarea/product_documents/version"
7
+
8
+ module Workarea
9
+ module ProductDocuments
10
+ end
11
+ end
@@ -0,0 +1,8 @@
1
+ module Workarea
2
+ module ProductDocuments
3
+ class Engine < ::Rails::Engine
4
+ include Workarea::Plugin
5
+ isolate_namespace Workarea::ProductDocuments
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ module Workarea
2
+ module ProductDocuments
3
+ VERSION = "1.0.0".freeze
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require_relative 'config/application'
5
+
6
+ Rails.application.load_tasks
@@ -0,0 +1,4 @@
1
+
2
+ //= link_tree ../images
3
+ //= link_directory ../javascripts .js
4
+ //= link_directory ../stylesheets .css
File without changes
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file. JavaScript code in this file should be added after the last require_* statement.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */