penpot/frontend/src/app/main/ui/dashboard/subscription.cljs
Marina López 49bbdfb257
🐛 Fix U and E icon displayed in project list (#7875)
* 🐛 Fix U and E icon displayed in project lis

* 🐛 Fix U and E icon displayed in project list
2025-12-03 12:50:51 +01:00

249 lines
10 KiB
Clojure

;; Copyright (c) KALEIDOS INC
(ns app.main.ui.dashboard.subscription
(:require-macros [app.main.style :as stl])
(:require
[app.common.data.macros :as dm]
[app.config :as cf]
[app.main.data.event :as ev]
[app.main.router :as rt]
[app.main.store :as st]
[app.main.ui.components.dropdown-menu :refer [dropdown-menu-item*]]
[app.main.ui.ds.buttons.button :refer [button*]]
[app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i]
[app.main.ui.ds.product.cta :refer [cta*]]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]]
[app.util.keyboard :as kbd]
[lambdaisland.uri :as u]
[potok.v2.core :as ptk]
[rumext.v2 :as mf]))
(defn get-subscription-type
[{:keys [type status] :as subscription}]
(if (and subscription (:type subscription) (not (contains? #{"unpaid" "canceled"} status)))
type
"professional"))
(mf/defc cta-power-up*
[{:keys [top-title top-description bottom-description bottom-button bottom-button-href has-dropdown is-highlighted]}]
(let [show-data* (mf/use-state false)
show-data (deref show-data*)
handle-click
(mf/use-fn
(fn [event]
(dom/stop-propagation event)
(swap! show-data* not)))
handle-navigation
(mf/use-fn
(fn [event]
(dom/stop-propagation event)
(st/emit! (rt/nav-raw :href bottom-button-href))))]
[:div {:class (stl/css-case :cta-power-up true
:highlighted is-highlighted)
:on-click handle-click}
[:button {:class (stl/css-case :cta-top-section true
:cta-without-dropdown (not has-dropdown))}
[:div {:class (stl/css :content)}
[:span {:class (stl/css :cta-title)} top-title]
[:span {:class (stl/css :cta-text) :data-testid "subscription-name"} top-description]]
(when has-dropdown
[:> icon* {:icon-id (if (and has-dropdown show-data) i/arrow-up i/arrow-down)
:class (stl/css :icon-dropdown)
:size "s"}])]
(when (and has-dropdown show-data)
[:div {:class (stl/css :cta-bottom-section)}
[:> i18n/tr-html* {:content bottom-description
:class (stl/css :content)
:tag-name "span"}]])
(when (and bottom-description bottom-button)
[:div {:class (stl/css :cta-bottom-section)}
[:span {:class (stl/css :content)}
bottom-description]
[:> button* {:variant "primary"
:type "button"
:class (stl/css :cta-bottom-button)
:on-click handle-navigation} bottom-button]])]))
(mf/defc subscription-sidebar*
[{:keys [profile]}]
(let [subscription (:subscription (:props profile))
subscription-type (get-subscription-type subscription)
subscription-is-trial (= (:status subscription) "trialing")
subscription-href (dm/str (u/join cf/public-uri "#/settings/subscriptions"))]
(case subscription-type
"professional"
[:> cta-power-up*
{:top-title (tr "subscription.dashboard.power-up.your-subscription")
:top-description (tr "subscription.dashboard.power-up.professional.top-title")
:bottom-description (tr "subscription.dashboard.power-up.professional.bottom-description")
:bottom-button (tr "subscription.dashboard.power-up.professional.bottom-button")
:bottom-button-href subscription-href
:has-dropdown false
:is-highlighted true}]
"unlimited"
(if subscription-is-trial
[:> cta-power-up*
{:top-title (tr "subscription.dashboard.power-up.your-subscription")
:top-description (tr "subscription.dashboard.power-up.trial.top-title")
:bottom-description (tr "subscription.dashboard.power-up.trial.bottom-description" subscription-href)
:has-dropdown true
:is-highlighted false}]
[:> cta-power-up*
{:top-title (tr "subscription.dashboard.power-up.your-subscription")
:top-description (tr "subscription.dashboard.power-up.unlimited-plan")
:bottom-description (tr "subscription.dashboard.power-up.unlimited.bottom-text" subscription-href)
:has-dropdown true
:is-highlighted false}])
"enterprise"
(if subscription-is-trial
[:> cta-power-up*
{:top-title (tr "subscription.dashboard.power-up.your-subscription")
:top-description (tr "subscription.dashboard.power-up.enterprise-trial.top-title")
:has-dropdown false
:is-highlighted false}]
[:> cta-power-up*
{:top-title (tr "subscription.dashboard.power-up.your-subscription")
:top-description (tr "subscription.dashboard.power-up.enterprise-plan")
:has-dropdown false
:is-highlighted false}]))))
(mf/defc team*
[{:keys [is-owner team]}]
(let [subscription (:subscription team)
subscription-type (get-subscription-type subscription)
subscription-is-trial (= "trialing" (:status subscription))
go-to-manage-subscription
(mf/use-fn
(fn []
(st/emit! (ptk/event ::ev/event {::ev/name "open-subscription-management"
::ev/origin "dashboard"
:section "team-settings"}))
(let [href (-> (rt/get-current-href)
(rt/encode-url))
href (str "payments/subscriptions/show?returnUrl=" href)]
(st/emit! (rt/nav-raw :href href)))))]
[:div {:class (stl/css :team)}
[:div {:class (stl/css :team-label)}
(tr "subscription.dashboard.team-plan")]
[:span {:class (stl/css :team-text)}
(case subscription-type
"professional" (tr "subscription.settings.professional")
"unlimited" (if subscription-is-trial
(tr "subscription.settings.unlimited-trial")
(tr "subscription.settings.unlimited"))
"enterprise" (tr "subscription.settings.enterprise"))]
(when (and is-owner (not= subscription-type "professional"))
[:button {:class (stl/css :manage-subscription-link)
:on-click go-to-manage-subscription
:data-testid "manage-subscription-link"}
(tr "subscription.settings.manage-your-subscription")])]))
(mf/defc menu-team-icon*
[{:keys [subscription-type]}]
[:span {:class (stl/css :subscription-icon-wrapper)}
[:> icon* {:icon-id (case subscription-type
"unlimited" i/character-u
"enterprise" i/character-e)
:class (stl/css :subscription-icon)
:size "s"
:title (if (= subscription-type "unlimited")
(tr "subscription.dashboard.power-up.unlimited-plan")
(tr "subscription.dashboard.power-up.enterprise-plan"))
:data-testid "subscription-icon"}]])
(mf/defc main-menu-power-up*
[{:keys [close-sub-menu]}]
(let [go-to-subscription (mf/use-fn #(st/emit! (rt/nav :settings-subscription)))]
[:> dropdown-menu-item* {:class (stl/css-case :menu-item true)
:on-click go-to-subscription
:on-key-down (fn [event]
(when (kbd/enter? event)
(go-to-subscription)))
:on-pointer-enter close-sub-menu
:id "file-menu-power-up"}
[:span {:class (stl/css :item-name)} (tr "subscription.workspace.header.menu.option.power-up")]]))
(mf/defc members-cta*
[]
[:> cta* {:class (stl/css :members-cta)
:title (tr "subscription.dashboard.unlimited-members-extra-editors-cta-title")}
[:> i18n/tr-html*
{:tag-name "span"
:class (stl/css :cta-message)
:content (tr "subscription.dashboard.unlimited-members-extra-editors-cta-text")}]])
(mf/defc dashboard-cta*
[{:keys [profile]}]
(let [subscription (-> profile :props :subscription)
subscription-type (get-subscription-type subscription)
go-to-subscription (dm/str (u/join cf/public-uri "#/settings/subscriptions"))
seats (:quantity subscription)
editors (count (:editors subscription))
cta-title
(cond
(= "professional" subscription-type)
(tr "subscription.dashboard.professional-dashboard-cta-title" editors)
(= "unlimited" subscription-type)
(tr "subscription.dashboard.unlimited-dashboard-cta-title" seats editors))
cta-message
(cond
(= "professional" subscription-type)
(tr "subscription.dashboard.professional-dashboard-cta-upgrade-owner" go-to-subscription)
(= "unlimited" subscription-type)
(tr "subscription.dashboard.unlimited-dashboard-cta-upgrade-owner" go-to-subscription))]
[:> cta* {:class (stl/css :dashboard-cta) :title cta-title}
[:> i18n/tr-html*
{:tag-name "span"
:class (stl/css :cta-message)
:content cta-message}]]))
(defn show-subscription-dashboard-banner?
[profile]
(let [subscription (-> profile :props :subscription)
subscription-type (get-subscription-type subscription)
seats (:quantity subscription)
editors (count (:editors subscription))]
(or
(and (= subscription-type "professional")
(> editors 8))
(and
(= subscription-type "unlimited")
(or
;; common: seats < 25 and diff >= 4
(and (< seats 25)
(>= (- editors seats) 4))
;; special: reached 25+ editors, seats < 25 and there is overuse
(and (< seats 25)
(>= editors 25)
(> editors seats)))))))
(defn show-subscription-members-banner?
[team profile]
(let [subscription (:subscription team)
subscription-type (get-subscription-type subscription)
seats (:seats subscription)
editors (count (-> profile :props :subscription :editors))
is-owner (-> team :permissions :is-owner)]
(and
is-owner
(= subscription-type "unlimited")
;; common: seats < 25 and diff >= 4 between editors/seats and there is overuse
(and (< seats 25)
(>= (- editors seats) 4)))))