spree_cm_commissioner 0.0.3 → 1.8.0.pre.beta2

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 (62) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test_and_build_gem.yml +3 -7
  3. data/.tool-versions +1 -0
  4. data/Gemfile.lock +12 -12
  5. data/README.md +19 -6
  6. data/app/assets/images/mailer/bookme-plus_light.svg +1 -0
  7. data/app/controllers/spree/admin/taxons_controller_decorator.rb +10 -0
  8. data/app/controllers/spree/api/v2/organizer/invites_controller.rb +35 -0
  9. data/app/controllers/spree/api/v2/tenant/pin_code_generators_controller.rb +1 -17
  10. data/app/controllers/spree/api/v2/tenant/profile_images_controller.rb +52 -0
  11. data/app/controllers/spree/api/v2/tenant/s3_signed_urls_controller.rb +29 -0
  12. data/app/controllers/spree/api/v2/tenant/taxons_controller.rb +56 -0
  13. data/app/interactors/spree_cm_commissioner/crew_inviter.rb +63 -0
  14. data/app/interactors/spree_cm_commissioner/profile_image_destroyer.rb +16 -0
  15. data/app/mailers/spree_cm_commissioner/crew_invite_mailer.rb +13 -0
  16. data/app/models/concerns/spree_cm_commissioner/{order_requestable.rb → order_state_machine.rb} +44 -14
  17. data/app/models/spree_cm_commissioner/crew_invite.rb +7 -0
  18. data/app/models/spree_cm_commissioner/invite.rb +22 -0
  19. data/app/models/spree_cm_commissioner/invite_user_event.rb +5 -0
  20. data/app/models/spree_cm_commissioner/invite_user_taxon.rb +11 -0
  21. data/app/models/spree_cm_commissioner/order_decorator.rb +8 -44
  22. data/app/models/spree_cm_commissioner/place.rb +2 -0
  23. data/app/models/spree_cm_commissioner/product_decorator.rb +4 -0
  24. data/app/models/spree_cm_commissioner/taxon_decorator.rb +3 -0
  25. data/app/models/spree_cm_commissioner/taxon_video_banner.rb +4 -0
  26. data/app/models/spree_cm_commissioner/user_decorator.rb +4 -0
  27. data/app/models/spree_cm_commissioner/video.rb +15 -0
  28. data/app/overrides/spree/admin/taxons/_form/assets_form.html.erb.deface +19 -0
  29. data/app/overrides/spree/admin/taxons/_form/available_on.html.erb.deface +18 -0
  30. data/app/overrides/spree/admin/taxons/edit/title.html.erb.deface +5 -3
  31. data/app/serializers/spree/v2/organizer/asset_serializer.rb +11 -0
  32. data/app/serializers/spree/v2/organizer/invite_serializer.rb +11 -0
  33. data/app/serializers/spree/v2/organizer/taxon_serializer.rb +10 -0
  34. data/app/serializers/spree/v2/organizer/user_serializer.rb +9 -0
  35. data/app/serializers/spree/v2/storefront/taxon_serializer_decorator.rb +2 -1
  36. data/app/serializers/spree/v2/storefront/vendor_serializer_decorator.rb +1 -1
  37. data/app/serializers/spree/v2/tenant/s3_signed_url_serializer.rb +9 -0
  38. data/app/serializers/spree/v2/tenant/user_profile_serializer.rb +8 -0
  39. data/app/serializers/spree_cm_commissioner/v2/storefront/video_serializer.rb +9 -0
  40. data/app/views/spree/admin/classifications/index.html.erb +1 -1
  41. data/app/views/spree/admin/guest_card_classes/index.html.erb +1 -1
  42. data/app/views/spree/admin/taxon_vendors/index.html.erb +1 -1
  43. data/app/views/spree/admin/user_events/_users.html.erb +1 -1
  44. data/app/views/spree/admin/vendors/_form.html.erb +8 -0
  45. data/app/views/spree_cm_commissioner/crew_invite_mailer/_mailer_stylesheets.html.erb +82 -0
  46. data/app/views/spree_cm_commissioner/crew_invite_mailer/send_crew_invite_email.html.erb +33 -0
  47. data/app/views/spree_cm_commissioner/layouts/crew_invite_mailer.html.erb +15 -0
  48. data/config/initializers/spree_permitted_attributes.rb +1 -0
  49. data/config/locales/en.yml +10 -1
  50. data/config/locales/km.yml +10 -1
  51. data/config/routes.rb +5 -0
  52. data/db/migrate/20250304101907_create_spree_cm_commissioner_invite.rb +12 -0
  53. data/db/migrate/20250304101946_create_spree_cm_commissioner_invite_user_taxon.rb +11 -0
  54. data/db/migrate/20250304155234_add_meta_data_to_spree_vendors.rb +6 -0
  55. data/db/migrate/20250307013422_add_parent_id_to_cm_place.rb +9 -0
  56. data/db/migrate/20250314013434_add_available_on_to_spree_taxons.rb +5 -0
  57. data/lib/spree_cm_commissioner/test_helper/factories/invite_factory.rb +7 -0
  58. data/lib/spree_cm_commissioner/test_helper/factories/invite_user_event_factory.rb +5 -0
  59. data/lib/spree_cm_commissioner/test_helper/factories/user_event_factory.rb +6 -0
  60. data/lib/spree_cm_commissioner/version.rb +1 -1
  61. metadata +39 -6
  62. data/app/models/concerns/spree_cm_commissioner/order_bib_number_concern.rb +0 -17
@@ -2,8 +2,7 @@ module SpreeCmCommissioner
2
2
  module OrderDecorator
3
3
  def self.prepended(base) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
4
4
  base.include SpreeCmCommissioner::PhoneNumberSanitizer
5
- base.include SpreeCmCommissioner::OrderBibNumberConcern
6
- base.include SpreeCmCommissioner::OrderRequestable
5
+ base.include SpreeCmCommissioner::OrderStateMachine
7
6
 
8
7
  base.scope :subscription, -> { where.not(subscription_id: nil) }
9
8
  base.scope :paid, -> { where(payment_state: :paid) }
@@ -23,15 +22,18 @@ module SpreeCmCommissioner
23
22
 
24
23
  base.before_create :link_by_phone_number
25
24
  base.before_create :associate_customer
25
+ base.before_create :set_tenant_id
26
26
 
27
27
  base.validates :promo_total, base::MONEY_VALIDATION
28
28
  base.validate :validate_channel_prefix, if: :channel_changed?
29
-
30
29
  base.validates :phone_number, presence: true, if: :require_phone_number
30
+
31
31
  base.has_one :invoice, dependent: :destroy, class_name: 'SpreeCmCommissioner::Invoice'
32
+ base.has_one :customer, class_name: 'SpreeCmCommissioner::Customer', through: :subscription
32
33
 
34
+ base.belongs_to :tenant, class_name: 'SpreeCmCommissioner::Tenant'
33
35
  base.belongs_to :subscription, class_name: 'SpreeCmCommissioner::Subscription', optional: true
34
- base.has_one :customer, class_name: 'SpreeCmCommissioner::Customer', through: :subscription
36
+
35
37
  base.has_many :taxons, class_name: 'Spree::Taxon', through: :customer
36
38
  base.has_many :vendors, through: :products, class_name: 'Spree::Vendor'
37
39
  base.has_many :taxons, through: :products, class_name: 'Spree::Taxon'
@@ -42,9 +44,6 @@ module SpreeCmCommissioner
42
44
  base.whitelisted_ransackable_associations |= %w[customer taxon payments invoice]
43
45
  base.whitelisted_ransackable_attributes |= %w[intel_phone_number phone_number email number]
44
46
 
45
- base.after_update :precalculate_conversion, if: -> { state_changed_to_complete? }
46
- base.after_update :precalculate_conversion, if: -> { state_changed_to_canceled? }
47
-
48
47
  def base.search_by_qr_data!(data)
49
48
  token = data.match(/^R\d{9,}-([A-Za-z0-9_\-]+)$/)&.captures
50
49
 
@@ -52,9 +51,6 @@ module SpreeCmCommissioner
52
51
 
53
52
  find_by!(token: token)
54
53
  end
55
-
56
- base.belongs_to :tenant, class_name: 'SpreeCmCommissioner::Tenant'
57
- base.before_create :set_tenant_id
58
54
  end
59
55
 
60
56
  def ticket_seller_user?
@@ -63,26 +59,6 @@ module SpreeCmCommissioner
63
59
  user.has_spree_role?('ticket_seller')
64
60
  end
65
61
 
66
- # override
67
- def after_resume
68
- super
69
-
70
- precalculate_conversion
71
- end
72
-
73
- # override
74
- def after_cancel
75
- super
76
-
77
- precalculate_conversion
78
- end
79
-
80
- def precalculate_conversion
81
- line_items.each do |item|
82
- SpreeCmCommissioner::ConversionPreCalculatorJob.perform_later(item.product_id)
83
- end
84
- end
85
-
86
62
  # override
87
63
  def collect_payment_methods(store = nil)
88
64
  return super if user.blank?
@@ -96,24 +72,11 @@ module SpreeCmCommissioner
96
72
  store.payment_methods.available_on_frontend_for_early_adopter.select { |pm| pm.available_for_order?(self) }
97
73
  end
98
74
 
99
- def state_changed_to_complete?
100
- saved_change_to_state? && state == 'complete'
101
- end
102
-
103
- def state_changed_to_canceled?
104
- saved_change_to_state? && state == 'canceled'
105
- end
106
-
75
+ # override
107
76
  def delivery_required?
108
77
  line_items.any?(&:delivery_required?)
109
78
  end
110
79
 
111
- # overrided not to send email yet to user if order needs confirmation
112
- # it will send after vendors accepted.
113
- def confirmation_delivered?
114
- confirmation_delivered || need_confirmation?
115
- end
116
-
117
80
  # overrided
118
81
  def payment_required?
119
82
  return false if need_confirmation?
@@ -240,6 +203,7 @@ module SpreeCmCommissioner
240
203
  require_contact
241
204
  end
242
205
 
206
+ # override
243
207
  def require_email
244
208
  require_contact
245
209
  end
@@ -13,6 +13,8 @@ module SpreeCmCommissioner
13
13
 
14
14
  has_many :product_places, class_name: 'SpreeCmCommissioner::ProductPlace', dependent: :destroy
15
15
  has_many :products, through: :product_places
16
+ has_many :children, class_name: 'SpreeCmCommissioner::Place', foreign_key: :parent_id, dependent: :destroy
17
+ belongs_to :parent, class_name: 'SpreeCmCommissioner::Place', optional: true
16
18
 
17
19
  def self.ransackable_attributes(auth_object = nil)
18
20
  super & %w[name code]
@@ -75,6 +75,10 @@ module SpreeCmCommissioner
75
75
  taxons.event.first&.parent
76
76
  end
77
77
 
78
+ def ticket_url
79
+ "#{Spree::Store.default.formatted_url}/tickets/#{slug}"
80
+ end
81
+
78
82
  private
79
83
 
80
84
  def set_tenant
@@ -28,6 +28,7 @@ module SpreeCmCommissioner
28
28
  base.has_one :web_banner, as: :viewable, dependent: :destroy, class_name: 'SpreeCmCommissioner::TaxonWebBanner'
29
29
  base.has_one :app_banner, as: :viewable, dependent: :destroy, class_name: 'SpreeCmCommissioner::TaxonAppBanner'
30
30
  base.has_one :home_banner, as: :viewable, dependent: :destroy, class_name: 'SpreeCmCommissioner::TaxonHomeBanner'
31
+ base.has_one :video_banner, as: :viewable, dependent: :destroy, class_name: 'SpreeCmCommissioner::TaxonVideoBanner'
31
32
 
32
33
  # Update children association to work with nested set (lft, rgt)
33
34
  base.has_many :children, -> { order(:lft) }, class_name: 'Spree::Taxon', foreign_key: :parent_id, dependent: :destroy
@@ -48,6 +49,8 @@ module SpreeCmCommissioner
48
49
  base.whitelisted_ransackable_attributes |= %w[kind]
49
50
 
50
51
  base.enum purchasable_on: { both: 0, web: 1, app: 2 }
52
+ base.has_many :crew_invites, class_name: 'SpreeCmCommissioner::CrewInvite', dependent: :destroy
53
+ base.has_many :invite_user_events, through: :user_events, class_name: 'SpreeCmCommissioner::InviteUserEvent'
51
54
  end
52
55
  # rubocop:enable Metrics/MethodLength
53
56
 
@@ -0,0 +1,4 @@
1
+ module SpreeCmCommissioner
2
+ class TaxonVideoBanner < Video
3
+ end
4
+ end
@@ -67,6 +67,10 @@ module SpreeCmCommissioner
67
67
  has_spree_role?('organizer')
68
68
  end
69
69
 
70
+ def operator?
71
+ has_spree_role?('operator')
72
+ end
73
+
70
74
  def full_name
71
75
  [first_name, last_name].compact_blank.join(' ')
72
76
  end
@@ -0,0 +1,15 @@
1
+ module SpreeCmCommissioner
2
+ class Video < Spree::Asset
3
+ include ::Rails.application.routes.url_helpers
4
+
5
+ has_one_attached :attachment
6
+
7
+ validates :attachment, attached: true, content_type: %r{\Avideo/.*\z}
8
+
9
+ default_scope { includes(attachment_attachment: :blob) }
10
+
11
+ def original_url
12
+ cdn_image_url(attachment)
13
+ end
14
+ end
15
+ end
@@ -47,5 +47,24 @@
47
47
  form:f,
48
48
  classes: ['col-md-5 ml-3']
49
49
  %>
50
+
51
+ <%= f.field_container :video_banner, direct_upload: true, class: ['col-md-5 ml-3 rounded border p-3'] do %>
52
+ <% if @taxon.video_banner&.attachment.present? %>
53
+ <video class="rounded border mb-4 mw-150" style="max-height: 200px" controls>
54
+ <source src="<%= main_app.rails_blob_url(@taxon.video_banner.attachment) %>" type="<%= @taxon.video_banner.attachment.content_type %>">
55
+ Your browser does not support the video tag.
56
+ </video>
57
+ <% end %>
58
+
59
+ <div data-hook="file" class="mb-3" >
60
+ <%= f.label :video_banner, I18n.t('taxon.video_banner') %>
61
+ <%= f.label :video_banner, I18n.t('taxon.video_banner_require_size') %>
62
+ <%= f.file_field :video_banner, required: false, accept: "video/*" %>
63
+ </div>
64
+
65
+ <% if @taxon.video_banner.present? && defined?(remove_video_banner_admin_taxonomy_taxon_url) %>
66
+ <%= link_to Spree.t(:remove_video), remove_video_banner_admin_taxonomy_taxon_url, method: :delete %>
67
+ <% end %>
68
+ <% end %>
50
69
  </div>
51
70
 
@@ -0,0 +1,18 @@
1
+ <!-- insert_before "erb[loud]:contains('field_container :parent_id')" -->
2
+
3
+ <div class="form-group">
4
+ <%= label_tag nil, Spree.t(:available_on) %>
5
+ <div class="input-group datePickerFrom"
6
+ data-wrap="true"
7
+ data-alt-input="true"
8
+ data-min-date="<%= Time.now.strftime('%Y-%m-%d') %>"
9
+ data-enable-time="true">
10
+ <%= f.text_field :available_on,
11
+ value: @taxon.available_on,
12
+ placeholder: Spree.t(:select_a_date),
13
+ class: 'form-control shadow-none',
14
+ 'data-input':'' %>
15
+
16
+ <%= render partial: 'spree/admin/shared/cal_close' %>
17
+ </div>
18
+ </div>
@@ -1,6 +1,8 @@
1
1
  <!-- replace "erb[silent]:contains('unless @taxon.root?')" closing_selector "erb[silent]:contains('end')" -->
2
2
 
3
- <%if @taxon.depth !=1 %>
4
- / <%= link_to @taxon.parent.name, spree.edit_admin_taxonomy_taxon_url(@taxonomy,@taxon.parent.id) %>
3
+ <%if @taxon.depth !=1 && @taxon.parent.present? %>
4
+ / <%= link_to @taxon.parent.name, spree.edit_admin_taxonomy_taxon_url(@taxonomy,@taxon.parent.id) %>
5
5
  <%end%>
6
- / <%= @taxon.name %>
6
+ <% unless @taxon.root? %>
7
+ / <%= @taxon.name %>
8
+ <% end %>
@@ -0,0 +1,11 @@
1
+ module Spree
2
+ module V2
3
+ module Organizer
4
+ class AssetSerializer < BaseSerializer
5
+ include ::Spree::Api::V2::ImageTransformationConcern
6
+
7
+ attributes :alt, :original_url, :position, :styles
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Spree
2
+ module V2
3
+ module Organizer
4
+ class InviteSerializer < BaseSerializer
5
+ attributes :token, :expires_at
6
+ belongs_to :taxon, serializer: Spree::V2::Organizer::TaxonSerializer
7
+ belongs_to :inviter, serializer: Spree::V2::Organizer::UserSerializer
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ module Spree
2
+ module V2
3
+ module Organizer
4
+ class TaxonSerializer < BaseSerializer
5
+ attributes :name
6
+ has_one :app_banner, serializer: Spree::V2::Organizer::AssetSerializer
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ module Spree
2
+ module V2
3
+ module Organizer
4
+ class UserSerializer < BaseSerializer
5
+ attributes :first_name, :last_name, :email
6
+ end
7
+ end
8
+ end
9
+ end
@@ -10,10 +10,11 @@ module Spree
10
10
  base.has_one :app_banner, serializer: ::SpreeCmCommissioner::V2::Storefront::AssetSerializer
11
11
  base.has_one :web_banner, serializer: ::SpreeCmCommissioner::V2::Storefront::AssetSerializer
12
12
  base.has_one :home_banner, serializer: ::SpreeCmCommissioner::V2::Storefront::AssetSerializer
13
+ base.has_one :video_banner, serializer: ::SpreeCmCommissioner::V2::Storefront::VideoSerializer
13
14
 
14
15
  base.attributes :custom_redirect_url, :kind, :subtitle, :from_date, :to_date,
15
16
  :background_color, :foreground_color, :show_badge_status,
16
- :purchasable_on, :vendor_id
17
+ :purchasable_on, :vendor_id, :available_on
17
18
 
18
19
  base.attribute :purchasable_on_app do |taxon|
19
20
  taxon.purchasable_on == 'app' || taxon.purchasable_on == 'both'
@@ -3,7 +3,7 @@ module Spree
3
3
  module Storefront
4
4
  module VendorSerializerDecorator
5
5
  def self.prepended(base)
6
- base.attributes :min_price, :max_price, :star_rating, :short_description, :full_address, :state
6
+ base.attributes :min_price, :max_price, :star_rating, :short_description, :full_address, :state, :meta_title, :meta_description
7
7
 
8
8
  base.has_many :stock_locations
9
9
  base.has_many :variants, serializer: 'Spree::Variant'
@@ -0,0 +1,9 @@
1
+ module Spree
2
+ module V2
3
+ module Tenant
4
+ class S3SignedUrlSerializer < BaseSerializer
5
+ attribute :host, :fields, :url
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,8 @@
1
+ module Spree
2
+ module V2
3
+ module Tenant
4
+ class UserProfileSerializer < Spree::V2::Tenant::AssetSerializer
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,9 @@
1
+ module SpreeCmCommissioner
2
+ module V2
3
+ module Storefront
4
+ class VideoSerializer < BaseSerializer
5
+ attributes :alt, :original_url
6
+ end
7
+ end
8
+ end
9
+ end
@@ -2,7 +2,7 @@
2
2
  <%= link_to Spree.t(:taxonomies), spree.admin_taxonomies_url %> /
3
3
 
4
4
  <%= link_to @taxonomy.root.name, spree.edit_admin_taxonomy_url(@taxonomy) %>
5
- <%if @taxon.depth !=1 %>
5
+ <%if @taxon.depth !=1 && @taxon.parent.present? %>
6
6
  / <%= link_to @taxon.parent.name, spree.edit_admin_taxonomy_taxon_url(@taxonomy,@taxon.parent.id) %>
7
7
  <%end%>
8
8
  <% unless @taxon.root? %>
@@ -2,7 +2,7 @@
2
2
  <%= link_to Spree.t(:taxonomies), spree.admin_taxonomies_url %> /
3
3
 
4
4
  <%= link_to @taxonomy.root.name, spree.edit_admin_taxonomy_url(@taxonomy) %>
5
- <%if @taxon.depth !=1 %>
5
+ <%if @taxon.depth !=1 && @taxon.parent.present? %>
6
6
  / <%= link_to @taxon.parent.name, spree.edit_admin_taxonomy_taxon_url(@taxonomy,@taxon.parent.id) %>
7
7
  <%end%>
8
8
  <% unless @taxon.root? %>
@@ -2,7 +2,7 @@
2
2
  <%= link_to Spree.t(:taxonomies), spree.admin_taxonomies_url %> /
3
3
 
4
4
  <%= link_to @taxonomy.root.name, spree.edit_admin_taxonomy_url(@taxonomy) %>
5
- <%if @taxon.depth !=1 %>
5
+ <%if @taxon.depth !=1 && @taxon.parent.present? %>
6
6
  / <%= link_to @taxon.parent.name, spree.edit_admin_taxonomy_taxon_url(@taxonomy,@taxon.parent.id) %>
7
7
  <%end%>
8
8
  <% unless @taxon.root? %>
@@ -2,7 +2,7 @@
2
2
  <%= link_to Spree.t(:taxonomies), spree.admin_taxonomies_url %> /
3
3
 
4
4
  <%= link_to @taxonomy.root.name, spree.edit_admin_taxonomy_url(@taxonomy) %>
5
- <%if @taxon.depth !=1 %>
5
+ <%if @taxon.depth !=1 && @taxon.parent.present? %>
6
6
  / <%= link_to @taxon.parent.name, spree.edit_admin_taxonomy_taxon_url(@taxonomy,@taxon.parent.id) %>
7
7
  <%end%>
8
8
  <% unless @taxon.root? %>
@@ -48,6 +48,14 @@
48
48
  <%= f.label :commission_rate %>
49
49
  <%= f.number_field :commission_rate, step: '0.01', class: 'form-control' %>
50
50
  <% end %>
51
+ <%= f.field_container :meta_title do %>
52
+ <%= f.label :meta_title, Spree.t(:meta_title) %>
53
+ <%= f.text_field :meta_title, class: 'form-control', rows: 6 %>
54
+ <% end %>
55
+ <%= f.field_container :meta_description do %>
56
+ <%= f.label :meta_description, Spree.t(:meta_description) %>
57
+ <%= f.text_area :meta_description, class: 'form-control', rows: 6 %>
58
+ <% end %>
51
59
  <%= f.field_container :notification_email do%>
52
60
  <%= f.label :notification_email %>
53
61
  <%= f.email_field :notification_email, class: 'form-control' %>
@@ -0,0 +1,82 @@
1
+ <style>
2
+ body, table, td {
3
+ font-family: 'Poppins', Arial, sans-serif;
4
+ margin: 0;
5
+ padding: 0;
6
+ }
7
+
8
+ .content-wrapper {
9
+ max-width: 500px;
10
+ margin: 0 auto;
11
+ border: 1px solid grey;
12
+ border-top: none;
13
+ }
14
+
15
+ .main-content{
16
+ padding-top: 10px;
17
+ padding-bottom: 25px;
18
+ }
19
+
20
+ .logo {
21
+ display: block;
22
+ width: 150px;
23
+ margin-top: 10px;
24
+ margin-bottom: 20px;
25
+ }
26
+
27
+ .heading-1 {
28
+ font-size: 24px;
29
+ text-align: center;
30
+ line-height: 1.4;
31
+ margin-bottom: 15px;
32
+ }
33
+
34
+ .bar-large {
35
+ height: 10px;
36
+ background-color: #5D54D9;
37
+ margin-bottom: 20px;
38
+
39
+ }
40
+
41
+ .bar-thin {
42
+ height: 3px;
43
+ height: 1px;
44
+ background-color: grey;
45
+ width: 100%;
46
+ margin: 20px auto;
47
+ }
48
+
49
+ .heading-2 {
50
+ font-size: 16px;
51
+ text-align: center;
52
+ line-height: 1.5;
53
+ }
54
+
55
+ .title-bold {
56
+ font-weight: bold;
57
+ color: #000;
58
+ }
59
+
60
+ .action-button {
61
+ display: inline-block;
62
+ background-color: #5D54D9;
63
+ border-radius: 24px;
64
+ font-size: 14px;
65
+ width: 222px;
66
+ height: 50px;
67
+ text-align: center;
68
+ line-height: 50px;
69
+ text-decoration: none;
70
+ cursor: pointer;
71
+ margin: 15px 0;
72
+ color: white !important;
73
+ text-decoration: none;
74
+ }
75
+
76
+ .heading-3 {
77
+ font-size: 12px;
78
+ text-align: center;
79
+ color: #888;
80
+ }
81
+ </style>
82
+
@@ -0,0 +1,33 @@
1
+ <table role="presentation" cellspacing="0" cellpadding="0" border="0" align="center" width="100%">
2
+ <tr>
3
+ <td align="center">
4
+ <div class="content-wrapper">
5
+ <div class="bar-large"></div>
6
+ <div class="main-content">
7
+ <div class="content">
8
+ <div><%= image_tag "mailer/bookme-plus_light.svg", class: "logo" %></div>
9
+ <div class="heading-1">
10
+ Become a part of the <br> event <strong> <%= @invite_user_event.invite.taxon.name %> </strong>
11
+ </div>
12
+ <div class="bar-thin"></div>
13
+ <div class="heading-2">
14
+ <%= @invite_user_event.invite.inviter.full_name.presence || @invite_user_event.inviter.email %> invites you to join the <br>
15
+ <span class="title-bold">Check-in Crew</span> for the event <br>
16
+ <%= @invite_user_event.invite.taxon.name %>
17
+ </div>
18
+ <div style="text-align: center;">
19
+ <a href="<%= @invite_user_event.invite.invite_url %>" class="action-button">
20
+ Get Started
21
+ </a>
22
+ </div>
23
+ <div class="heading-3">
24
+ Please note that this invitation will expire<br>
25
+ in <%= ((@invite_user_event.invite.expires_at - Time.current) / 1.hour).round %> hours.
26
+ </div>
27
+ </div>
28
+ </div>
29
+ </div>
30
+ </td>
31
+ </tr>
32
+ </table>
33
+
@@ -0,0 +1,15 @@
1
+
2
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+ <html>
4
+ <head>
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
6
+ <meta name="x-apple-disable-message-reformatting"/>
7
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
8
+ <link href="https://fonts.googleapis.com/css2?family=Poppins&display=swap" rel="stylesheet">
9
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
10
+ <%= render partial: 'spree_cm_commissioner/crew_invite_mailer/mailer_stylesheets' %>
11
+ </head>
12
+ <body>
13
+ <%= yield %>
14
+ </body>
15
+ </html>
@@ -33,6 +33,7 @@ module Spree
33
33
  preferred_foreground_color
34
34
  show_badge_status
35
35
  purchasable_on
36
+ available_on
36
37
  vendor_id
37
38
  ]
38
39
 
@@ -41,6 +41,8 @@ en:
41
41
  app_banner: App Banner (16x9)
42
42
  web_banner: Web banner (10x2)
43
43
  home_banner: Home Banner (16x9)
44
+ video_banner: Video Banner (9x16)
45
+ video_banner_require_size: Maximum size 10MB
44
46
  note: "<b>Note:</b> Subtitle is used for country code in Nationality Taxon"
45
47
 
46
48
  taxon_vendor:
@@ -564,4 +566,11 @@ en:
564
566
  update_success: Option Type updated successfully.
565
567
  user_roles_assigner:
566
568
  user_not_found: 'User not found'
567
- roles_empty: 'Roles are empty'
569
+ roles_empty: 'Roles are empty'
570
+ invite:
571
+ url_not_found: 'Invite link not found or have been expired'
572
+ accept_fail: 'Failed to accept invite'
573
+ url_expired: 'Invitation link is expired'
574
+ already_invited: 'Failed: User already invited to event'
575
+ update_fail: 'Failed: to Update invite user'
576
+
@@ -46,6 +46,8 @@ km:
46
46
  app_banner: App Banner (16x9)
47
47
  web_banner: Web banner (10x2)
48
48
  home_banner: Home Banner (16x9)
49
+ video_banner: Video Banner (9x16)
50
+ video_banner_require_size: Maximum size 10MB
49
51
 
50
52
  taxon_vendor:
51
53
  empty_info: "មិនមានព័ត៌មានអំពីអ្នកលក់ទេ"
@@ -408,4 +410,11 @@ km:
408
410
  not_found: 'រកមិនឃើញរូបភាព'
409
411
  user_roles_assigner:
410
412
  user_not_found: 'រកមិនឃើញអ្នកប្រើប្រាស់'
411
- roles_empty: 'តួនាទីគឺទទេ'
413
+ roles_empty: 'តួនាទីគឺទទេ'
414
+
415
+ invite:
416
+ url_not_found: 'រកមិនឃើញតំណអញ្ជើញ ឬផុតកំណត់ហើយ'
417
+ accept_fail: 'បរាជ័យក្នុងការទទួលយកការអញ្ជើញ'
418
+ url_expired: 'តំណ​អញ្ជើញ​បាន​ផុត​កំណត់'
419
+ already_invited: 'បរាជ័យ៖ អ្នកប្រើប្រាស់បានអញ្ជើញចូលរួមព្រឹត្តិការណ៍រួចហើយ'
420
+ update_fail: 'បរាជ័យ៖ ធ្វើបច្ចុប្បន្នភាពអ្នកប្រើប្រាស់អញ្ជើញ'
data/config/routes.rb CHANGED
@@ -173,6 +173,7 @@ Spree::Core::Engine.add_routes do
173
173
  delete :remove_app_banner
174
174
  delete :remove_web_banner
175
175
  delete :remove_home_banner
176
+ delete :remove_video_banner
176
177
  end
177
178
  end
178
179
  end
@@ -441,11 +442,13 @@ Spree::Core::Engine.add_routes do
441
442
  end
442
443
  resources :images
443
444
  resource :s3_signed_urls
445
+ resources :invites
444
446
  end
445
447
 
446
448
  namespace :tenant do
447
449
  resources :vendors
448
450
  resources :products
451
+ resources :taxons, only: %i[index show], id: /.+/
449
452
 
450
453
  resources :account_checker
451
454
  resource :pin_code_checkers, only: [:update]
@@ -479,6 +482,8 @@ Spree::Core::Engine.add_routes do
479
482
  end
480
483
 
481
484
  resources :user_account_linkages, only: %i[index create destroy]
485
+ resource :s3_signed_urls
486
+ resource :profile_images, only: %i[update destroy]
482
487
  end
483
488
 
484
489
  namespace :storefront do
@@ -0,0 +1,12 @@
1
+ class CreateSpreeCmCommissionerInvite < ActiveRecord::Migration[7.0]
2
+ def change
3
+ create_table :cm_invites, if_not_exists: true do |t|
4
+ t.string :token, null: false, unique: true
5
+ t.datetime :expires_at
6
+ t.string :type
7
+ t.references :inviter, null: false, foreign_key: { to_table: :spree_users }, index: true
8
+ t.references :taxon, null: false, foreign_key: { to_table: :spree_taxons }, index: true
9
+ t.timestamps
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ class CreateSpreeCmCommissionerInviteUserTaxon < ActiveRecord::Migration[7.0]
2
+ def change
3
+ create_table :cm_invite_user_taxons, if_not_exists: true do |t|
4
+ t.references :invite, foreign_key: { to_table: :cm_invites }, null: true, index: true
5
+ t.references :user_taxon, foreign_key: { to_table: :cm_user_taxons }, null: true, index: true
6
+ t.string :email, index: true
7
+ t.datetime :confirmed_at
8
+ t.timestamps
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,6 @@
1
+ class AddMetaDataToSpreeVendors < ActiveRecord::Migration[7.0]
2
+ def change
3
+ add_column :spree_vendors, :meta_title, :string, if_not_exists: true
4
+ add_column :spree_vendors, :meta_description, :text, if_not_exists: true
5
+ end
6
+ end