diff --git a/app/controllers/data_controller.rb b/app/controllers/data_controller.rb index 0dc53a83..69143202 100644 --- a/app/controllers/data_controller.rb +++ b/app/controllers/data_controller.rb @@ -33,6 +33,14 @@ class DataController < ApplicationController @threads_posted_to = Thredded::Topic.where(id: @posts.pluck(:postable_id) - @topics.pluck(:id)) end + def collaboration + universe_ids = current_user.universes.pluck(:id) + @collaborators = Contributor.where(universe_id: universe_ids).includes(:user, :universe)#.uniq { |c| c.user_id } + @shared_universes = current_user.universes.where(id: @collaborators.pluck(:universe_id)) + collaborating_ids = Contributor.where(user_id: current_user.id).pluck(:universe_id) + @collaborating_universes = Universe.where(id: collaborating_ids) + end + private def set_sidenav_expansion diff --git a/app/models/billing/page_unlock_promo_code.rb b/app/models/billing/page_unlock_promo_code.rb index 8ac6c7ab..5924b30f 100644 --- a/app/models/billing/page_unlock_promo_code.rb +++ b/app/models/billing/page_unlock_promo_code.rb @@ -1,5 +1,5 @@ class PageUnlockPromoCode < ApplicationRecord - has_many :promotions + has_many :promotions, dependent: :destroy has_many :users, -> { distinct }, through: :promotions serialize :page_types, Array diff --git a/app/models/paypal_invoice.rb b/app/models/paypal_invoice.rb index 6bfca215..4a664cca 100644 --- a/app/models/paypal_invoice.rb +++ b/app/models/paypal_invoice.rb @@ -31,6 +31,27 @@ class PaypalInvoice < ApplicationRecord description: "Prepaid Premium subscription" ) self.save! + + if PromoService.active?(:promo_bogo) && (self.months == 3 || self.months == 6) + # During this promo, we create a separate Invoice + PromoCode also + self.user.paypal_invoices.create( + paypal_id: "None -- Created from promo_bogo promo", + status: self.status, + user_id: self.user_id, + months: self.months, + amount_cents: 0, + page_unlock_promo_code: PageUnlockPromoCode.create( + code: 'BOGO-' + (0...8).map { (65 + rand(26)).chr }.join + '-' + (0...8).map { (65 + rand(26)).chr }.join, + page_types: Rails.application.config.content_types[:premium].map(&:name), + uses_remaining: 1, + days_active: 30 * self.months.to_i, + internal_description: "promo_bogo duplicate code", + description: "Your free buy-one-get-one-free Premium Code", + ), + approval_url: nil, + payer_id: self.payer_id + ) + end end def activateable? diff --git a/app/services/paypal_service.rb b/app/services/paypal_service.rb index 571da732..1feeefbb 100644 --- a/app/services/paypal_service.rb +++ b/app/services/paypal_service.rb @@ -7,12 +7,12 @@ class PaypalService < Service request.request_body({ intent: "CAPTURE", application_context: { - return_url: 'https://www.notebook.ai/my/billing/prepay/paid', - cancel_url: 'https://www.notebook.ai/my/billing/prepay', - brand_name: 'Notebook.ai by Indent Labs', - landing_page: 'BILLING', + return_url: 'https://www.notebook.ai/my/billing/prepay/paid', + cancel_url: 'https://www.notebook.ai/my/billing/prepay', + brand_name: 'Notebook.ai by Indent Labs', + landing_page: 'BILLING', shipping_preference: 'NO_SHIPPING', - user_action: 'PAY_NOW' + user_action: 'PAY_NOW' }, purchase_units: [{ amount: { @@ -143,7 +143,7 @@ class PaypalService < Service client_id = Rails.application.config.paypal[:client_id] client_secret = Rails.application.config.paypal[:client_secret] - environment = if Rails.env.production? + environment = if Rails.env.production? PayPal::LiveEnvironment.new(client_id, client_secret) else PayPal::SandboxEnvironment.new(client_id, client_secret) diff --git a/app/services/promo_service.rb b/app/services/promo_service.rb new file mode 100644 index 00000000..ae43f290 --- /dev/null +++ b/app/services/promo_service.rb @@ -0,0 +1,13 @@ +class PromoService < Service + def self.active?(promo_key) + [ + Date.current >= Rails.application.config.promos.fetch(promo_key, {}).fetch(:start_date), + Date.current <= Rails.application.config.promos.fetch(promo_key, {}).fetch(:end_date) + ].all? + rescue false + end + + def self.end_date(promo_key) + Rails.application.config.promos.fetch(promo_key, {}).fetch(:end_date) + end +end \ No newline at end of file diff --git a/app/views/content/display/_contributors.html.erb b/app/views/content/display/_contributors.html.erb index 3f74be6e..419b2113 100644 --- a/app/views/content/display/_contributors.html.erb +++ b/app/views/content/display/_contributors.html.erb @@ -10,7 +10,7 @@ <% raw_model.contributors.each do |contributor| %> <% next if contributor.user.nil? && (current_user != content.user) %>
  • - person + <%= User.icon %> <%= contributor.user ? link_to(contributor.user.name, contributor.user) : "#{contributor.email} (invited)" %> diff --git a/app/views/customization/content_types.html.erb b/app/views/customization/content_types.html.erb index 641ea4e7..332dfe8b 100644 --- a/app/views/customization/content_types.html.erb +++ b/app/views/customization/content_types.html.erb @@ -70,20 +70,6 @@ -<% if current_user.notice_dismissals.where(notice_id: 5).none? %> - -<% end %> -
    <% @all_content_types.sort_by(&:name).each.with_index do |content_type, i| %>
    diff --git a/app/views/data/collaboration.html.erb b/app/views/data/collaboration.html.erb new file mode 100644 index 00000000..de1646b1 --- /dev/null +++ b/app/views/data/collaboration.html.erb @@ -0,0 +1,82 @@ +

    + <%= link_to data_vault_path, class: 'grey-text tooltipped', style: 'position: relative; top: 4px;', data: { + position: 'bottom', + enterDelay: '500', + tooltip: "Back to your Data Vault" + } do %> + arrow_back + <% end %> + Collaboration on Notebook.ai +

    + +
    Your shared universes
    +<% if @shared_universes.any? %> +
      + <% @shared_universes.reverse.each do |universe| %> +
    • +
      + <%= Universe.icon %> + <%= universe.name %> + (<%= pluralize universe.contributors.count, 'collaborator' %>) +
      +
      + <%= render partial: 'content/display/contributors', locals: { content: universe } %> +
      +
    • + <% end %> +
    +<% else %> +

    None yet!

    +<% end %> + +
    Universes shared with you
    +<% if @collaborating_universes.any? %> +
      + <% @collaborating_universes.each do |universe| %> +
    • +
      + <%= Universe.icon %> + <%= universe.name %> +
      +
      + <%= render partial: 'content/display/contributors', locals: { content: universe } %> +
      +
    • + <% end %> +
    +<% else %> +

    None yet!

    +<% end %> + +<% if @collaborators.any? %> +
    Your collaborators
    +
      + <% @collaborators.group_by { |c| c.user }.each do |collaborator, collab_list| %> +
    • +
      + <%= User.icon %> + <%= collaborator.name %> <%= "(@#{collaborator.username})" if collaborator.username? %> +
      +
      + Contributing on: +
        + <% Universe.where(id: collab_list.pluck(:universe_id)).each do |universe| %> +
      • + <%= link_to universe, class: "#{Universe.color}-text" do %> + <%= Universe.icon %> + <%= universe.name %> + <% end %> +
      • + <% end %> +
      +
      +
    • + <% end %> +
    +<% else %> +

    None yet!

    +<% end %> + +<%= content_for :javascript do %> + $('.panel').show(); +<% end %> \ No newline at end of file diff --git a/app/views/data/index.html.erb b/app/views/data/index.html.erb index ef186ec0..cd37717a 100644 --- a/app/views/data/index.html.erb +++ b/app/views/data/index.html.erb @@ -69,6 +69,20 @@ <% end %>
    +
    + <%= link_to discussions_path, class: 'black-text' do %> +
    +
    + forum +
    Discussion activity
    +

    + See your activity on the discussion boards. +

    +
    +
    + <% end %> +
    +
    <%= link_to uploads_path, class: 'black-text' do %>
    @@ -83,19 +97,21 @@ <% end %>
    +
    <%= link_to privacy_policy_path, class: 'black-text' do %> diff --git a/app/views/main/dashboard.html.erb b/app/views/main/dashboard.html.erb index 3600fdac..27a11a4a 100644 --- a/app/views/main/dashboard.html.erb +++ b/app/views/main/dashboard.html.erb @@ -1,6 +1,21 @@
    <%= render partial: 'main/dashboard_header_links' %> + <% if PromoService.active?(:promo_bogo) %> + <% if current_user.notice_dismissals.where(notice_id: 6).none? %> +
    +
    + <%= link_to 'Dismiss this notice.', notice_dismissal_dismiss_path(notice_id: 6), class: 'blue-text right', style: 'padding: 0 10px;' %> + <%= link_to prepay_path, class: 'black-text' do %> + card_giftcard + Limited-time Discount: Stay safe and stay home while worldbuilding with friends! Shareable 3-month and 6-month Premium Codes are buy-one-get-one-free until + <%= PromoService.end_date(:promo_bogo).strftime("%B %-d") %>. Happy worldbuilding! + <% end %> +
    +
    + <% end %> + <% end %> + <% if @content %>
    <%= render partial: 'cards/serendipitous/content_question', locals: { @@ -11,18 +26,6 @@
    <% end %> - <% if current_user.created_at > 3.months.ago && current_user.notice_dismissals.where(notice_id: 4).none? %> -
    -
    - <%= link_to 'Dismiss this notice.', notice_dismissal_dismiss_path(notice_id: 4), class: 'blue-text right' %> - <%= link_to prepay_path, class: 'black-text' do %> - - New in Notebook.ai: You can now purchase Premium for yourself — or your friends — with PayPal. - <% end %> -
    -
    - <% end %> - <% s_width = 12 m_width = 6 diff --git a/app/views/subscriptions/new.html.erb b/app/views/subscriptions/new.html.erb index 6dc10c6e..0a1bcec8 100644 --- a/app/views/subscriptions/new.html.erb +++ b/app/views/subscriptions/new.html.erb @@ -14,6 +14,21 @@

    <% end %> +<% if PromoService.active?(:promo_bogo) %> + <% if current_user.notice_dismissals.where(notice_id: 6).none? %> +
    +
    + <%= link_to 'Dismiss this notice.', notice_dismissal_dismiss_path(notice_id: 6), class: 'blue-text right', style: 'padding: 0 10px;' %> + <%= link_to prepay_path, class: 'black-text' do %> + card_giftcard + Limited-time Discount: Stay safe and stay home while worldbuilding with friends! Shareable 3-month and 6-month Premium Codes are buy-one-get-one-free until + <%= PromoService.end_date(:promo_bogo).strftime("%B %-d") %>. Click this banner to get started. + <% end %> +
    +
    + <% end %> +<% end %> +

    Subscription Plan

    diff --git a/app/views/subscriptions/prepay.html.erb b/app/views/subscriptions/prepay.html.erb index dbef291d..da4fc063 100644 --- a/app/views/subscriptions/prepay.html.erb +++ b/app/views/subscriptions/prepay.html.erb @@ -1,14 +1,40 @@

    -
    +
    -
    You can now purchase sharable Premium Codes for yourself or others
    -

    - Making a purchase below will generate a single-use code that can be redeemed at any time for a Premium subscription on Notebook.ai. - You can purchase these codes for yourself if you'd like to prepay for a certain amount of months without a recurring monthly subscription, - or for others if you'd like to gift a Notebook.ai Premium membership to someone else! You can purchase as many codes as you'd like - and redeem them whenever you'd like. -

    +
    Prepaid Premium Codes
    +
    +
    +

    + Making a purchase below will generate a single-use code that can be redeemed at any time for a Premium subscription on Notebook.ai. + You can purchase these codes for yourself if you'd like to prepay for a certain amount of months without a recurring monthly subscription, + or for others if you'd like to gift a Notebook.ai Premium membership to someone else! +

    +
    +

    + You can purchase as many codes as you'd like and redeem them whenever you'd like. +

    +
    +

    + While your Premium is active, you'll have access to <%= Rails.application.config.content_types[:premium].count %> additional worldbuilding + pages: you'll be able to create unlimited + <%= + Rails.application.config.content_types[:premium].map { |page| + " #{page.icon} #{page.name.pluralize}" + }.to_sentence.html_safe + %>! +

    +
    +
    + <%= image_tag 'tristan/small.png', + class: 'tooltipped tristan', + data: { + position: 'left', + enterDelay: '500', + tooltip: "Hey, I'm Tristan! I'm here to help you around the site!" + } %> +
    +
    @@ -18,7 +44,7 @@
    <%= link_to prepay_paypal_gateway_path(months: 1), class: 'black-text' do %> -
    +
    star @@ -34,41 +60,53 @@
    <%= link_to prepay_paypal_gateway_path(months: 3), class: 'black-text' do %> -
    +
    star 3 months of Premium + includes limited-time offer

    All Premium features - for $24.00
    + for $24.00 (save $3.00 compared to monthly)

    +
    +

    + Limited-time offer: Purchasing this Premium Code before <%= PromoService.end_date(:promo_bogo).strftime("%B %-d") %> + will generate two Premium Codes for the price of one! +

    <% end %>
    <%= link_to prepay_paypal_gateway_path(months: 6), class: 'black-text' do %> -
    +
    star 6 months of Premium + includes limited-time offer

    All Premium features - for $48.00
    + for $48.00 (save $6.00 compared to monthly)

    +
    +

    + Limited-time offer: Purchasing this Premium Code before <%= PromoService.end_date(:promo_bogo).strftime("%B %-d") %> + will generate two Premium Codes for the price of one! +

    <% end %>
    <%= link_to prepay_paypal_gateway_path(months: 12), class: 'black-text' do %> -
    +
    star @@ -76,7 +114,7 @@

    All Premium features - for $84.00
    + for $84.00 (save $24.00 compared to monthly)

    @@ -118,8 +156,13 @@

    <% if invoice.page_unlock_promo_code.present? %> +

    + Description: <%= invoice.page_unlock_promo_code.description %> +

    <% if invoice.activateable? %> - Promo code: <%= invoice.page_unlock_promo_code.code %> +

    + Promo code: <%= invoice.page_unlock_promo_code.code %> +

    <% end %> <% else %> <% if invoice.status == 'APPROVED' %> @@ -172,7 +215,7 @@
    <% else %>
    - <% if invoice.page_unlock_promo_code && invoice.page_unlock_promo_code.uses_remaining.zero? %> + <% if invoice.page_unlock_promo_code && invoice.page_unlock_promo_code.uses_remaining.zero? && invoice.page_unlock_promo_code.promotions.any? %> Activated <%= time_ago_in_words invoice.page_unlock_promo_code.promotions.last.created_at %> ago <% else %> <% if invoice.status == 'CREATED' %> diff --git a/config/initializers/promos.rb b/config/initializers/promos.rb new file mode 100644 index 00000000..f7edf7dc --- /dev/null +++ b/config/initializers/promos.rb @@ -0,0 +1,5 @@ +Rails.application.config.promos = {} + +Rails.application.config.promos[:promo_bogo] = {} +Rails.application.config.promos[:promo_bogo][:start_date] = 'March 20, 2020'.to_date +Rails.application.config.promos[:promo_bogo][:end_date] = Rails.application.config.promos[:promo_bogo][:start_date] + 2.weeks diff --git a/config/routes.rb b/config/routes.rb index ba117dc8..6473fcb0 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -74,12 +74,13 @@ Rails.application.routes.draw do # TODO delete deprecated/unused referrals controller/views scope '/data' do - get '/', to: 'data#index', as: :data_vault - get '/usage', to: 'data#usage' - get '/recyclebin', to: 'data#recyclebin' - get '/archive', to: 'data#archive' - get '/uploads', to: 'data#uploads' - get '/discussions', to: 'data#discussions' + get '/', to: 'data#index', as: :data_vault + get '/usage', to: 'data#usage' + get '/recyclebin', to: 'data#recyclebin' + get '/archive', to: 'data#archive' + get '/uploads', to: 'data#uploads' + get '/discussions', to: 'data#discussions' + get '/collaboration', to: 'data#collaboration' scope 'export' do get '/', to: 'export#index', as: :notebook_export