workarea-save_for_later 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) 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/.gitignore +25 -0
  7. data/CHANGELOG.md +17 -0
  8. data/CODE_OF_CONDUCT.md +3 -0
  9. data/CONTRIBUTING.md +3 -0
  10. data/Gemfile +17 -0
  11. data/LICENSE +52 -0
  12. data/README.md +51 -0
  13. data/Rakefile +60 -0
  14. data/app/assets/stylesheets/workarea/storefront/save_for_later/components/_product_prices.scss +5 -0
  15. data/app/controllers/workarea/storefront/cart_items_controller.decorator +12 -0
  16. data/app/controllers/workarea/storefront/current_saved_list.rb +54 -0
  17. data/app/controllers/workarea/storefront/saved_list_items_controller.rb +55 -0
  18. data/app/helpers/.keep +0 -0
  19. data/app/helpers/workarea/storefront/saved_lists_helper.rb +13 -0
  20. data/app/models/workarea/saved_list.rb +27 -0
  21. data/app/models/workarea/saved_list/item.rb +14 -0
  22. data/app/view_models/workarea/storefront/saved_list_item_view_model.rb +45 -0
  23. data/app/view_models/workarea/storefront/saved_list_view_model.rb +19 -0
  24. data/app/views/workarea/storefront/carts/_save_for_later_button.html.haml +8 -0
  25. data/app/views/workarea/storefront/carts/_saved_for_later.html.haml +52 -0
  26. data/bin/rails +20 -0
  27. data/config/initializers/appends.rb +14 -0
  28. data/config/initializers/config.rb +3 -0
  29. data/config/locales/en.yml +14 -0
  30. data/config/routes.rb +5 -0
  31. data/lib/workarea/save_for_later.rb +11 -0
  32. data/lib/workarea/save_for_later/engine.rb +13 -0
  33. data/lib/workarea/save_for_later/version.rb +5 -0
  34. data/test/dummy/.ruby-version +1 -0
  35. data/test/dummy/Rakefile +6 -0
  36. data/test/dummy/app/assets/config/manifest.js +3 -0
  37. data/test/dummy/app/assets/images/.keep +0 -0
  38. data/test/dummy/app/assets/javascripts/application.js +14 -0
  39. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  40. data/test/dummy/app/controllers/application_controller.rb +2 -0
  41. data/test/dummy/app/controllers/concerns/.keep +0 -0
  42. data/test/dummy/app/helpers/application_helper.rb +2 -0
  43. data/test/dummy/app/jobs/application_job.rb +2 -0
  44. data/test/dummy/app/mailers/application_mailer.rb +4 -0
  45. data/test/dummy/app/models/concerns/.keep +0 -0
  46. data/test/dummy/app/views/layouts/application.html.erb +15 -0
  47. data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
  48. data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
  49. data/test/dummy/bin/bundle +3 -0
  50. data/test/dummy/bin/rails +4 -0
  51. data/test/dummy/bin/rake +4 -0
  52. data/test/dummy/bin/setup +36 -0
  53. data/test/dummy/bin/update +31 -0
  54. data/test/dummy/bin/yarn +11 -0
  55. data/test/dummy/config.ru +5 -0
  56. data/test/dummy/config/application.rb +29 -0
  57. data/test/dummy/config/boot.rb +5 -0
  58. data/test/dummy/config/cable.yml +10 -0
  59. data/test/dummy/config/environment.rb +5 -0
  60. data/test/dummy/config/environments/development.rb +61 -0
  61. data/test/dummy/config/environments/production.rb +94 -0
  62. data/test/dummy/config/environments/test.rb +45 -0
  63. data/test/dummy/config/initializers/application_controller_renderer.rb +8 -0
  64. data/test/dummy/config/initializers/assets.rb +14 -0
  65. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  66. data/test/dummy/config/initializers/content_security_policy.rb +25 -0
  67. data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
  68. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  69. data/test/dummy/config/initializers/inflections.rb +16 -0
  70. data/test/dummy/config/initializers/mime_types.rb +4 -0
  71. data/test/dummy/config/initializers/workarea.rb +5 -0
  72. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  73. data/test/dummy/config/locales/en.yml +33 -0
  74. data/test/dummy/config/puma.rb +34 -0
  75. data/test/dummy/config/routes.rb +5 -0
  76. data/test/dummy/config/secrets.yml +32 -0
  77. data/test/dummy/config/spring.rb +6 -0
  78. data/test/dummy/config/storage.yml +34 -0
  79. data/test/dummy/db/seeds.rb +2 -0
  80. data/test/dummy/lib/assets/.keep +0 -0
  81. data/test/dummy/log/.keep +0 -0
  82. data/test/factories/workarea/saved_list.rb +13 -0
  83. data/test/integration/workarea/storefront/cart_items_save_for_later_integration_test.rb +46 -0
  84. data/test/integration/workarea/storefront/current_saved_list_integration_test.rb +62 -0
  85. data/test/integration/workarea/storefront/saved_list_items_integration_test.rb +107 -0
  86. data/test/models/workarea/saved_list_test.rb +40 -0
  87. data/test/system/workarea/storefront/save_for_later_system_test.rb +59 -0
  88. data/test/teaspoon_env.rb +6 -0
  89. data/test/test_helper.rb +10 -0
  90. data/workarea-save_for_later.gemspec +23 -0
  91. metadata +146 -0
@@ -0,0 +1,34 @@
1
+ # Puma can serve each request in a thread from an internal thread pool.
2
+ # The `threads` method setting takes two numbers: a minimum and maximum.
3
+ # Any libraries that use thread pools should be configured to match
4
+ # the maximum value specified for Puma. Default is set to 5 threads for minimum
5
+ # and maximum; this matches the default thread size of Active Record.
6
+ #
7
+ threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
8
+ threads threads_count, threads_count
9
+
10
+ # Specifies the `port` that Puma will listen on to receive requests; default is 3000.
11
+ #
12
+ port ENV.fetch("PORT") { 3000 }
13
+
14
+ # Specifies the `environment` that Puma will run in.
15
+ #
16
+ environment ENV.fetch("RAILS_ENV") { "development" }
17
+
18
+ # Specifies the number of `workers` to boot in clustered mode.
19
+ # Workers are forked webserver processes. If using threads and workers together
20
+ # the concurrency of the application would be max `threads` * `workers`.
21
+ # Workers do not work on JRuby or Windows (both of which do not support
22
+ # processes).
23
+ #
24
+ # workers ENV.fetch("WEB_CONCURRENCY") { 2 }
25
+
26
+ # Use the `preload_app!` method when specifying a `workers` number.
27
+ # This directive tells Puma to first boot the application and load code
28
+ # before forking the application. This takes advantage of Copy On Write
29
+ # process behavior so workers use less memory.
30
+ #
31
+ # preload_app!
32
+
33
+ # Allow puma to be restarted by `rails restart` command.
34
+ plugin :tmp_restart
@@ -0,0 +1,5 @@
1
+ Rails.application.routes.draw do
2
+ mount Workarea::Core::Engine => '/'
3
+ mount Workarea::Admin::Engine => '/admin', as: 'admin'
4
+ mount Workarea::Storefront::Engine => '/', as: 'storefront'
5
+ end
@@ -0,0 +1,32 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Your secret key is used for verifying the integrity of signed cookies.
4
+ # If you change this key, all old signed cookies will become invalid!
5
+
6
+ # Make sure the secret is at least 30 characters and all random,
7
+ # no regular words or you'll be exposed to dictionary attacks.
8
+ # You can use `rails secret` to generate a secure secret key.
9
+
10
+ # Make sure the secrets in this file are kept private
11
+ # if you're sharing your code publicly.
12
+
13
+ # Shared secrets are available across all environments.
14
+
15
+ # shared:
16
+ # api_key: a1B2c3D4e5F6
17
+
18
+ # Environmental secrets are only available for that specific environment.
19
+
20
+ development:
21
+ secret_key_base: d3364c9c3fe096e40cc6a7760d7a8a6ce5c77d14740aa93cd5a22fb0ba93399e2ac37f3389beafa9972baea954a11e212d9e758403118da6b81cf63586010975
22
+
23
+ test:
24
+ secret_key_base: 0269072d24b9571bb0ec5da912551468faebdea32ed5acccec913c16d6ff09f5420f229db0740a40d095f85014d56e357f629d07b43e95d011cac5b67e657a37
25
+
26
+ # Do not keep production secrets in the unencrypted secrets file.
27
+ # Instead, either read values from the environment.
28
+ # Or, use `bin/rails secrets:setup` to configure encrypted secrets
29
+ # and move the `production:` environment over there.
30
+
31
+ production:
32
+ secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
@@ -0,0 +1,6 @@
1
+ %w[
2
+ .ruby-version
3
+ .rbenv-vars
4
+ tmp/restart.txt
5
+ tmp/caching-dev.txt
6
+ ].each { |path| Spring.watch(path) }
@@ -0,0 +1,34 @@
1
+ test:
2
+ service: Disk
3
+ root: <%= Rails.root.join("tmp/storage") %>
4
+
5
+ local:
6
+ service: Disk
7
+ root: <%= Rails.root.join("storage") %>
8
+
9
+ # Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
10
+ # amazon:
11
+ # service: S3
12
+ # access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
13
+ # secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
14
+ # region: us-east-1
15
+ # bucket: your_own_bucket
16
+
17
+ # Remember not to checkin your GCS keyfile to a repository
18
+ # google:
19
+ # service: GCS
20
+ # project: your_project
21
+ # credentials: <%= Rails.root.join("path/to/gcs.keyfile") %>
22
+ # bucket: your_own_bucket
23
+
24
+ # Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key)
25
+ # microsoft:
26
+ # service: AzureStorage
27
+ # storage_account_name: your_account_name
28
+ # storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %>
29
+ # container: your_container_name
30
+
31
+ # mirror:
32
+ # service: Mirror
33
+ # primary: local
34
+ # mirrors: [ amazon, google, microsoft ]
@@ -0,0 +1,2 @@
1
+ require 'workarea/seeds'
2
+ Workarea::Seeds.run
File without changes
File without changes
@@ -0,0 +1,13 @@
1
+ require 'workarea/testing/factories'
2
+
3
+ module Workarea
4
+ module Factories
5
+ module SavedList
6
+ Factories.add(SavedList)
7
+
8
+ def create_saved_list(attributes = {})
9
+ Workarea::SavedList.create!(attributes)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,46 @@
1
+ require 'test_helper'
2
+
3
+ module Workarea
4
+ module Storefront
5
+ class CartItemsSaveForLaterIntegrationTest < Workarea::IntegrationTest
6
+ setup :set_product
7
+
8
+ def set_product
9
+ @product = create_product(
10
+ name: 'Integration Product',
11
+ variants: [
12
+ { sku: 'SKU1', regular: 5.to_m },
13
+ { sku: 'SKU2', regular: 6.to_m }
14
+ ]
15
+ )
16
+ end
17
+
18
+ def test_can_add_an_item
19
+ list = create_saved_list(
20
+ items: [{ product_id: @product.id, sku: @product.skus.first }]
21
+ )
22
+ item = list.items.first
23
+ cookies[:saved_list_id] = list.id.to_s
24
+
25
+ post storefront.cart_items_path,
26
+ params: {
27
+ product_id: item.product_id,
28
+ sku: item.sku,
29
+ quantity: item.quantity,
30
+ saved_list_item_id: item.id
31
+ }
32
+
33
+ order = Order.first
34
+ assert_equal(@product.id, order.items.first.product_id)
35
+ assert_equal(@product.skus.first, order.items.first.sku)
36
+ assert_equal(1, order.items.first.quantity)
37
+ assert_equal(5.to_m, order.items.first.total_price)
38
+
39
+ list.reload
40
+ assert_equal(0, list.items.count)
41
+
42
+ assert_redirected_to(storefront.cart_path)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,62 @@
1
+ require 'test_helper'
2
+
3
+ module Workarea
4
+ module Storefront
5
+ class CurrentSavedListIntegrationTest < Workarea::IntegrationTest
6
+ setup :product, :user
7
+
8
+ def product
9
+ @product ||= create_product
10
+ end
11
+
12
+ def user
13
+ @user ||= create_user(
14
+ email: 'test@workarea.com',
15
+ password: 'W3bl1nc!'
16
+ )
17
+ end
18
+
19
+ def test_current_saved_list
20
+ post storefront.cart_items_path,
21
+ params: {
22
+ product_id: product.id,
23
+ sku: product.skus.first,
24
+ quantity: 3,
25
+ }
26
+
27
+ get storefront.cart_path
28
+
29
+ refute(cookies[:saved_list_id].present?)
30
+
31
+ order = Order.first
32
+ item = order.items.first
33
+
34
+ post storefront.saved_list_items_path,
35
+ params: {
36
+ product_id: item.product_id,
37
+ sku: item.sku,
38
+ quantity: item.quantity,
39
+ cart_item_id: item.id
40
+ }
41
+
42
+ assert(cookies[:saved_list_id].present?)
43
+
44
+ list = SavedList.find(cookies[:saved_list_id])
45
+ assert_equal(1, list.items.count)
46
+
47
+ post storefront.login_path,
48
+ params: {
49
+ email: 'test@workarea.com',
50
+ password: 'W3bl1nc!'
51
+ }
52
+
53
+ refute(cookies[:saved_list_id].present?)
54
+
55
+ assert_raises(Mongoid::Errors::DocumentNotFound) { list.reload }
56
+
57
+ list = SavedList.find(user.id.to_s)
58
+ assert_equal(1, list.items.count)
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,107 @@
1
+ require 'test_helper'
2
+
3
+ module Workarea
4
+ module Storefront
5
+ class SavedListItemsIntegrationTest < Workarea::IntegrationTest
6
+ include CatalogCustomizationTestClass
7
+
8
+ setup :product, :saved_list
9
+
10
+ def product
11
+ @product ||= create_product(customizations: 'foo_cust')
12
+ end
13
+
14
+ def saved_list
15
+ @saved_list ||= create_saved_list.tap do |list|
16
+ cookies[:saved_list_id] = list.id.to_s
17
+ end
18
+ end
19
+
20
+ def test_create
21
+ post storefront.saved_list_items_path,
22
+ params: {
23
+ product_id: product.id,
24
+ sku: product.skus.first,
25
+ quantity: 2,
26
+ customizations: { foo: 'test', bar: 'baz' }.to_json
27
+ }
28
+
29
+ assert_redirected_to(storefront.cart_path)
30
+
31
+ saved_list.reload
32
+ item = saved_list.items.first
33
+ assert_equal(product.id, item.product_id)
34
+ assert_equal(product.skus.first, item.sku)
35
+ assert_equal(2, item.quantity)
36
+ assert_equal({ 'foo' => 'test', 'bar' => 'baz' }, item.customizations)
37
+ end
38
+
39
+ def test_create_from_order_item
40
+ post storefront.cart_items_path,
41
+ params: {
42
+ product_id: product.id,
43
+ sku: product.skus.first,
44
+ quantity: 3,
45
+ customizations: { foo: 'test', bar: 'baz' }
46
+ }
47
+
48
+ order = Order.first
49
+ item = order.items.first
50
+
51
+ post storefront.saved_list_items_path,
52
+ params: {
53
+ product_id: item.product_id,
54
+ sku: item.sku,
55
+ quantity: item.quantity,
56
+ customizations: { foo: 'test', bar: 'baz' }.to_json,
57
+ cart_item_id: item.id
58
+ }
59
+
60
+ assert_redirected_to(storefront.cart_path)
61
+
62
+ saved_list.reload
63
+ item = saved_list.items.first
64
+ assert_equal(product.id, item.product_id)
65
+ assert_equal(product.skus.first, item.sku)
66
+ assert_equal(3, item.quantity)
67
+ assert_equal({ 'foo' => 'test', 'bar' => 'baz' }, item.customizations)
68
+
69
+ order.reload
70
+ assert_equal(0, order.items.count)
71
+ end
72
+
73
+ def test_create_with_invalid_customizations
74
+ post storefront.saved_list_items_path,
75
+ params: {
76
+ product_id: product.id,
77
+ sku: product.skus.first,
78
+ quantity: 2,
79
+ customizations: { foo: 'test' }.to_json
80
+ }
81
+
82
+ assert_redirected_to(storefront.cart_path)
83
+ assert_equal(
84
+ t('workarea.storefront.saved_lists.flash_messages.error'),
85
+ flash[:error]
86
+ )
87
+
88
+ saved_list.reload
89
+ assert_equal(0, saved_list.items.count)
90
+ end
91
+
92
+ def test_destroy
93
+ saved_list.items.create!(
94
+ product_id: product.id,
95
+ sku: product.skus.first,
96
+ )
97
+
98
+ delete storefront.saved_list_item_path(saved_list.items.first.id)
99
+
100
+ assert_redirected_to(storefront.cart_path)
101
+
102
+ saved_list.reload
103
+ assert_equal(0, saved_list.items.count)
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,40 @@
1
+ require 'test_helper'
2
+
3
+ module Workarea
4
+ class SavedListTest < TestCase
5
+ def test_add_item
6
+ product = create_product
7
+
8
+ list = SavedList.new
9
+
10
+ list.add_item(product_id: 'PROD1', sku: 'SKU1')
11
+ assert_equal(1, list.items.count)
12
+
13
+ item = list.items.first
14
+ assert_equal('PROD1', item.product_id)
15
+ assert_equal('SKU1', item.sku)
16
+ assert_equal(1, item.quantity)
17
+
18
+ list.add_item(
19
+ product_id: 'PROD1',
20
+ sku: 'SKU2',
21
+ quantity: 3,
22
+ customizations: { 'foo' => 'bar' }
23
+ )
24
+ assert_equal(2, list.items.count)
25
+
26
+ item = list.items.where(sku: 'SKU2').first
27
+ assert_equal('PROD1', item.product_id)
28
+ assert_equal('SKU2', item.sku)
29
+ assert_equal(3, item.quantity)
30
+ assert_equal({ 'foo' => 'bar' }, item.customizations)
31
+
32
+ list.add_item(product_id: 'PROD1', sku: 'SKU1', quantity: 4)
33
+
34
+ item = list.items.where(sku: 'SKU1').first
35
+ assert_equal('PROD1', item.product_id)
36
+ assert_equal('SKU1', item.sku)
37
+ assert_equal(5, item.quantity)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,59 @@
1
+ require 'test_helper'
2
+
3
+ module Workarea
4
+ module Storefront
5
+ class SaveForLaterSystemTest < Workarea::SystemTest
6
+ def test_managing_saved_list
7
+ product = create_product
8
+ inventory = create_inventory(
9
+ id: product.skus.first,
10
+ policy: :standard,
11
+ available: 10
12
+ )
13
+
14
+ visit storefront.product_path(product)
15
+ click_button t('workarea.storefront.products.add_to_cart')
16
+
17
+ visit storefront.cart_path
18
+
19
+ assert(page.has_no_content?(t('workarea.storefront.carts.empty')))
20
+ assert(page.has_no_content?(t('workarea.storefront.saved_lists.title')))
21
+ assert(page.has_content?(product.name))
22
+ assert(page.has_content?(product.skus.first))
23
+
24
+ click_button t('workarea.storefront.carts.save_for_later')
25
+
26
+ assert(page.has_content?('Success'))
27
+
28
+ assert(page.has_content?(t('workarea.storefront.carts.empty')))
29
+ assert(page.has_content?(t('workarea.storefront.saved_lists.title')))
30
+ assert(page.has_content?(product.name))
31
+ assert(page.has_content?(product.skus.first))
32
+ assert(page.has_content?(t('workarea.storefront.products.in_stock')))
33
+
34
+ click_button t('workarea.storefront.saved_lists.move_to_cart')
35
+
36
+ assert(page.has_no_content?(t('workarea.storefront.carts.empty')))
37
+ assert(page.has_no_content?(t('workarea.storefront.saved_lists.title')))
38
+ assert(page.has_content?(product.name))
39
+ assert(page.has_content?(product.skus.first))
40
+
41
+ inventory.update(available: 0)
42
+
43
+ click_button t('workarea.storefront.carts.save_for_later')
44
+
45
+ assert(page.has_content?('Success'))
46
+ assert(page.has_content?(t('workarea.storefront.products.out_of_stock')))
47
+ assert(page.has_no_content?(t('workarea.storefront.saved_lists.move_to_cart')))
48
+ assert(page.has_content?(t('workarea.storefront.products.unavailable')))
49
+
50
+ click_link t('workarea.storefront.saved_lists.remove')
51
+
52
+ assert(page.has_content?('Success'))
53
+
54
+ assert(page.has_content?(t('workarea.storefront.carts.empty')))
55
+ assert(page.has_no_content?(t('workarea.storefront.saved_lists.title')))
56
+ end
57
+ end
58
+ end
59
+ end