Skip to content

Commit

Permalink
subscriptions helpers (#947)
Browse files Browse the repository at this point in the history
  • Loading branch information
michelson committed May 10, 2023
1 parent 4099ae4 commit 2eb1d11
Show file tree
Hide file tree
Showing 16 changed files with 129 additions and 170 deletions.
17 changes: 10 additions & 7 deletions app/graphql/types/app_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def tag_list
field :outgoing_webhooks, [Types::JsonType], null: true

def outgoing_webhooks
# object.plan.allow_feature!('OutgoingWebhooks')
object.plan.allow_feature!("OutgoingWebhooks")
authorize! object, to: :can_read_outgoing_webhooks?, with: AppPolicy
object.outgoing_webhooks
end
Expand Down Expand Up @@ -183,6 +183,8 @@ def register_visits
end

def app_packages
object.plan.allow_feature!("Integrations")

authorize! object, to: :can_manage_app_packages?, with: AppPolicy

integrations = object.app_package_integrations.map(&:app_package_id)
Expand All @@ -207,7 +209,7 @@ def agent_app_packages
field :app_package_integrations, [Types::AppPackageIntegrationType], null: true

def app_package_integrations
# object.plan.allow_feature!('Integrations')
object.plan.allow_feature!("Integrations")
# authorize! object, to: :manage?, with: AppPolicy
authorize! object, to: :can_manage_app_packages?, with: AppPolicy

Expand Down Expand Up @@ -246,7 +248,8 @@ def encryption_key
def conversations(per:, page:, filter:, sort:, agent_id: nil, tag: nil, term: nil, channel_id: nil)
# rubocop:enable Metrics/ParameterLists

# object.plan.allow_feature!("Conversations")
object.blocked?
object.plan.allow_feature!("Conversations")
# authorize! object, to: :show?, with: AppPolicy
authorize! object, to: :can_read_conversations?, with: AppPolicy

Expand Down Expand Up @@ -463,7 +466,7 @@ def quick_reply(id:, lang:)
end

def articles(page:, per:, lang:, mode:, search:)
# object.plan.allow_feature!('Articles')
object.plan.allow_feature!("Articles")
# authorize! object, to: :show?, with: AppPolicy
authorize! object, to: :can_read_help_center?, with: AppPolicy

Expand Down Expand Up @@ -507,7 +510,7 @@ def article_settings
end

def article(id:, lang:)
# object.plan.allow_feature!('Articles')
object.plan.allow_feature!("Articles")
I18n.locale = lang
authorize! object, to: :can_read_help_center?, with: AppPolicy
# authorize! object, to: :show?, with: AppPolicy
Expand Down Expand Up @@ -551,7 +554,7 @@ def agent_search(term:)
end

def collections(lang:)
# object.plan.allow_feature!('Articles')
object.plan.allow_feature!("Articles")
I18n.locale = lang.to_sym
# authorize! object, to: :show?, with: AppPolicy
authorize! object, to: :can_read_help_center?, with: AppPolicy
Expand Down Expand Up @@ -676,7 +679,7 @@ def app_package_dashboard(package:)
# OAUTH
field :oauth_applications, [OauthApplicationType], null: true
def oauth_applications
# object.plan.allow_feature!('OauthApplications')
object.plan.allow_feature!("OauthApplications")
# authorize! object, to: :manage?, with: AppPolicy
authorize! object, to: :can_read_oauth_applications?, with: AppPolicy
object.oauth_applications.ordered_by(:created_at)
Expand Down
4 changes: 2 additions & 2 deletions app/javascript/packages/components/src/components/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ const BaseButton = styled.button<ButtonProps>`
border-transparent
rounded
text-gray-100
bg-black
hover:bg-gray-800
bg-gray-800
hover:bg-gray-700
focus:outline-none
focus:border-gray-700
active:bg-gray-800
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ export function InlineFilterDialog({
</div>

<div className="overflow-scroll h-48">
<ul className="divide-y divide-gray-200">
<ul className="divide-y divide-gray-200 dark:divide-gray-600">
{f.map((o, i) => (
<li key={`select-fields-${i}`}>
<a
Expand Down
4 changes: 2 additions & 2 deletions app/javascript/src/layout/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -507,8 +507,8 @@ function Sidebar({
height={40}
/>
</div>
<div className="ml-3 w-1/3 flex flex-wrap">
<p className="my-1 text-sm leading-5 font-medium text-gray-700 dark:text-gray-50 dark:hover:text-gray-100 group-hover:text-gray-900 dark:group-hover:text-gray-300 truncate">
<div className="ml-3 flex flex-col flex-wrap">
<p className="my-1 w-[147px] text-sm leading-5 font-medium text-gray-700 dark:text-gray-50 dark:hover:text-gray-100 group-hover:text-gray-900 dark:group-hover:text-gray-300 truncate">
<Link to={`/apps/${app.key}/agents/${current_user.id}`}>
{current_user.email}
</Link>
Expand Down
4 changes: 3 additions & 1 deletion app/javascript/src/pages/AppContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,9 @@ function AppContainer({
</button>
</div>

{!isEmpty(upgradePages) && <UpgradePage page={upgradePages} />}
{!isEmpty(upgradePages) && (
<UpgradePage page={upgradePages} app={app} />
)}

{app && isEmpty(upgradePages) && (
<ErrorBoundary variant={'very-wrong'}>
Expand Down
6 changes: 3 additions & 3 deletions app/javascript/src/pages/Billing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ function Billing({ current_user, dispatch, paddleSubscription, app }) {
{app.subscriptionsEnabled && app.preferences.stripe_customer_id && (
<div className="flex items-center justify-end">
<button
className="inline-flex justify-center rounded-lg text-sm font-semibold py-3 px-4 bg-gray-900 text-white hover:bg-gray-700"
className="inline-flex justify-center rounded-lg text-sm font-semibold py-3 px-4 bg-gray-800 text-white hover:bg-gray-700"
onClick={manageSubscription}
disabled={customerPortalLoading}
>
Expand Down Expand Up @@ -928,7 +928,7 @@ function PlanBoard({ appPlan, plans, openCheckout }) {
</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200">
<tbody className="divide-y divide-gray-200 dark:divide-gray-600">
{subscriptionPlanListFeatures().map((k) => (
<tr
key={`mobile-feature-${k}`}
Expand Down Expand Up @@ -998,7 +998,7 @@ function PlanBoard({ appPlan, plans, openCheckout }) {
))}
</tr>
</thead>
<tbody className="border-t border-gray-200 divide-y divide-gray-200">
<tbody className="border-t border-gray-200 divide-y divide-gray-200 dark:divide-gray-600">
<tr>
<th
className="py-8 pl-6 pr-6 align-top text-sm font-medium text-gray-900 dark:text-gray-100 text-left"
Expand Down
2 changes: 1 addition & 1 deletion app/javascript/src/pages/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ function classNames(...classes) {

function Example({ actions }) {
return (
<div className="mt-5 rounded-lg bg-gray-200 dark:bg-gray-900 overflow-hidden shadow divide-y divide-gray-200 sm:divide-y-0 sm:grid sm:grid-cols-2 sm:gap-px">
<div className="mt-5 rounded-lg bg-gray-200 dark:bg-gray-900 overflow-hidden shadow divide-y divide-gray-200 dark:divide-gray-600 sm:divide-y-0 sm:grid sm:grid-cols-2 sm:gap-px">
{actions.map((action, actionIdx) => (
<div
key={action.title}
Expand Down
5 changes: 4 additions & 1 deletion app/javascript/src/pages/Team.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1218,7 +1218,10 @@ function TeamAgentEdit(props) {
</div>

<div className="border-b border-gray-200">
<ul role="list" className="divide-y divide-gray-200">
<ul
role="list"
className="divide-y divide-gray-200 dark:divide-gray-600"
>
{agents.map((agent) => (
<li className="flex py-4" key={`agent-team-id-${agent.id}`}>
<img
Expand Down
37 changes: 20 additions & 17 deletions app/javascript/src/pages/UpgradePage.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,37 @@
import React from 'react';

export default function UpgradePage({ page }) {
export default function UpgradePage({ page, app }) {
return (
<main className="mt-10 mx-auto max-w-screen-xl px-4 sm:mt-12 sm:px-6 md:mt-16 lg:mt-20 lg:px-8 xl:mt-28">
<div className="sm:text-center lg:text-left">
<h2 className="text-4xl tracking-tight leading-10 font-extrabold text-gray-900 sm:text-5xl sm:leading-none md:text-6xl">
<h2 className="text-4xl tracking-tight leading-10 font-extrabold text-gray-900 dark:text-gray-100 sm:text-5xl sm:leading-none md:text-6xl">
Upgrade Plan
<br className="xl:hidden" />
<span className="text-indigo-600">{page.message}</span>
{/*<span className="text-brand-600">{page.message}</span>*/}
</h2>

<p className="mt-3 text-base text-gray-500 sm:mt-5 sm:text-lg sm:max-w-xl sm:mx-auto md:mt-5 md:text-xl lg:mx-0">
Anim aute id magna aliqua ad ad non deserunt sunt. Qui irure qui lorem
cupidatat commodo. Elit sunt amet fugiat veniam occaecat fugiat
aliqua.
We're sorry, but it seems that the feature you're trying to access is
not available on your current subscription plan. But don't worry,
we've got you covered! By upgrading your plan, you'll not only gain
access to this amazing feature, but you'll also unlock a whole new
world of powerful tools and capabilities designed to help you grow
your business and achieve your goals.
</p>

<p className="mt-4 text-gray-500 sm:mt-5 sm:text-xs sm:max-w-xl sm:mx-auto md:mt-5 md:text-sm lg:mx-0">
Ready to upgrade and enjoy all the benefits of a higher tier plan?
Click the button below to explore our pricing options and find the
perfect plan for your needs.
</p>

<div className="mt-5 sm:mt-8 sm:flex sm:justify-center lg:justify-start">
<div className="rounded-md shadow">
<a
href="#"
className="w-full flex items-center justify-center px-8 py-3 border border-transparent text-base leading-6 font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-500 focus:outline-none focus:border-indigo-700 focus:shadow-outline-indigo transition duration-150 ease-in-out md:py-4 md:text-lg md:px-10"
>
Get started
</a>
</div>
<div className="mt-3 sm:mt-0 sm:ml-3">
<a
href="#"
className="w-full flex items-center justify-center px-8 py-3 border border-transparent text-base leading-6 font-medium rounded-md text-indigo-700 bg-indigo-100 hover:text-indigo-600 hover:bg-indigo-50 focus:outline-none focus:shadow-outline-indigo focus:border-indigo-300 transition duration-150 ease-in-out md:py-4 md:text-lg md:px-10"
href={`/apps/${app.key}/billing`}
className="w-full flex items-center justify-center px-8 py-3 border border-transparent text-base leading-6 font-medium rounded-md text-white bg-brand hover:bg-brand focus:outline-none focus:border-brand focus:shadow-outline-brand transition duration-150 ease-in-out md:py-4 md:text-lg md:px-10"
>
Live demo
Go to Billing
</a>
</div>
</div>
Expand Down
4 changes: 2 additions & 2 deletions app/javascript/src/pages/conversations/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ function renderInternal({ object, conversation, app, app_user }) {

function UserBlock({ app_user }) {
return (
<div className="space-y-2 divide-y divide-gray-200">
<div className="space-y-2 divide-y divide-gray-200 dark:divide-gray-600">
<div className="space-y-1 py-2">
<div className="text-sm leading-5 font-medium text-gray-900 dark:text-gray-100">
{I18n.t('conversation.sidebar.browser')}
Expand Down Expand Up @@ -194,7 +194,7 @@ function TagBlocks({ conversation }) {

function ConversationBlock({ conversation }) {
return (
<div className="space-y-2 divide-y divide-gray-200">
<div className="space-y-2 divide-y divide-gray-200 dark:divide-gray-600">
<div className="space-y-2 pt-2">
<dt className="text-sm leading-5 font-medium text-gray-500">
{I18n.t('conversation.sidebar.latest_user_visible_comment_at')}
Expand Down
6 changes: 3 additions & 3 deletions app/javascript/src/pages/settings/QuickReplies.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ function QuickReplies({ app, _update, dispatch }) {

function isSelected(o) {
if (!quickReply) return '';
return o.id === quickReply.id ? 'bg-blue-100' : '';
return o.id === quickReply.id ? 'dark:bg-gray-900 bg-gray-100' : '';
}

function uploadHandler({ serviceUrl, _signedBlobId, imageBlock }) {
Expand All @@ -205,7 +205,7 @@ function QuickReplies({ app, _update, dispatch }) {
<input
ref={inputRef}
defaultValue={quickReply.title}
className="dark:bg-gray-900 outline-none my-2 p-2 border-b form-input block w-full sm:text-sm sm:leading-5"
className="dark:bg-gray-700 outline-none my-2 p-2 border-b form-input block w-full sm:text-sm sm:leading-5"
placeholder="Quick reply title"
onChange={updateStateFromInput}
/>
Expand Down Expand Up @@ -295,7 +295,7 @@ function QuickReplies({ app, _update, dispatch }) {
<div className="min-w-0 flex-1 flex items-center">
<div className="min-w-0 flex-1 px-4 md:grid md:grid-cols-1 md:gap-4">
<div>
<div className="text-sm leading-5 font-medium text-white truncate">
<div className="text-sm leading-5 font-medium dark:text-white text-black truncate">
{o.title}
</div>
</div>
Expand Down
44 changes: 13 additions & 31 deletions app/models/app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class App < ApplicationRecord
include Tokenable
include UserHandler
include Notificable
include Subscribable

store_accessor :preferences, %i[
active_messenger
Expand Down Expand Up @@ -109,15 +110,26 @@ def agent_bots
agents.where("bot =?", true)
end

def default_packages
%w[ContentShowcase ArticleSearch Qualifier InboxSections ContactFields]
end

def attach_default_packages
default_packages = %w[ContentShowcase ArticleSearch Qualifier InboxSections ContactFields]
AppPackage.where(name: default_packages).find_each do |app_package|
app_packages << app_package unless app_package_integrations.exists?(
app_package_id: app_package.id
)
end
end

def packages_integrations_in_use
app_package_integrations.joins(:app_package).where.not("app_packages.name" => default_packages)
end

def disable_packages_in_use!
packages_integrations_in_use.delete_all
end

def encryption_enabled?
encryption_key.present?
end
Expand Down Expand Up @@ -359,36 +371,6 @@ def default_home_apps
end
end

def plan
if stripe_subscription_status == "active" || stripe_subscription_status == "trialing"
@plan ||= Plan.new(
Plan.get_by_id(stripe_subscription_plan_id) || Plan.get("free")
)
elsif paddle_subscription_status == "active" || paddle_subscription_status == "trialing"
@plan ||= Plan.new(
Plan.get_by_id(paddle_subscription_plan_id.to_i) || Plan.get("free")
)
else
@plan = Plan.new(Plan.get("free"))
end
end

def payment_service
if paddle_subscription_plan_id.present?
PaymentServices::Paddle
else
PaymentServices::StripeService
end
end

def payment_attribute(key)
if PaymentServices::StripeService == payment_service
send("stripe_#{key}".to_sym)
elsif PaymentServices::Paddle == payment_service
send("paddle_#{key}".to_sym)
end
end

private

def init_app_segments
Expand Down
58 changes: 58 additions & 0 deletions app/models/concerns/subscribable.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
module Subscribable
extend ActiveSupport::Concern

def plan
if stripe_subscription_status == "active" || stripe_subscription_status == "trialing"
@plan ||= Plan.new(
Plan.get_by_id(stripe_subscription_plan_id) || Plan.get("free")
)
elsif paddle_subscription_status == "active" || paddle_subscription_status == "trialing"
@plan ||= Plan.new(
Plan.get_by_id(paddle_subscription_plan_id.to_i) || Plan.get("free")
)
else
@plan = Plan.new(Plan.get("free"))
end
end

def plan_status
stripe_subscription_status || paddle_subscription_status
end

def payment_service
if paddle_subscription_plan_id.present?
PaymentServices::Paddle
else
PaymentServices::StripeService
end
end

def payment_attribute(key)
if PaymentServices::StripeService == payment_service
send("stripe_#{key}".to_sym)
elsif PaymentServices::Paddle == payment_service
send("paddle_#{key}".to_sym)
end
end

def trialing?
return false if plan_status.present?

plan.name == "free"
end

def canceled?
return false unless subscriptions_enabled?

!trialing? && plan_status == "canceled"
end

def subscriptions_enabled?
Chaskiq::Config.get("SUBSCRIPTIONS_ENABLED") == "true"
end

def blocked?
return unless subscriptions_enabled?
raise Plan::PlanError, { code: "feature", message: "plan not meet on feature" }.to_json if canceled?
end
end

0 comments on commit 2eb1d11

Please sign in to comment.