mirror of
https://github.com/penpot/penpot.git
synced 2025-06-13 20:51:38 +02:00
✨ Visual indicators subscription for teams and project settings (#6546)
* ✨ Visual indicators subscription for teams and project settings * 📎 Fixes PR feedback --------- Co-authored-by: Andrey Antukh <niwi@niwi.nz>
This commit is contained in:
parent
5e8929e504
commit
e5bc369e56
19 changed files with 1116 additions and 155 deletions
|
@ -31,8 +31,8 @@ export PENPOT_FLAGS="\
|
||||||
enable-tiered-file-data-storage \
|
enable-tiered-file-data-storage \
|
||||||
enable-file-validation \
|
enable-file-validation \
|
||||||
enable-file-schema-validation \
|
enable-file-schema-validation \
|
||||||
enable-subscriptons \
|
enable-subscriptions \
|
||||||
enable-subscriptons-old";
|
enable-subscriptions-old";
|
||||||
|
|
||||||
# Default deletion delay for devenv
|
# Default deletion delay for devenv
|
||||||
export PENPOT_DELETION_DELAY="24h"
|
export PENPOT_DELETION_DELAY="24h"
|
||||||
|
|
|
@ -24,8 +24,8 @@ export PENPOT_FLAGS="\
|
||||||
enable-tiered-file-data-storage \
|
enable-tiered-file-data-storage \
|
||||||
enable-file-validation \
|
enable-file-validation \
|
||||||
enable-file-schema-validation \
|
enable-file-schema-validation \
|
||||||
enable-subscriptons \
|
enable-subscriptions \
|
||||||
enable-subscriptons-old ";
|
enable-subscriptions-old ";
|
||||||
|
|
||||||
# Default deletion delay for devenv
|
# Default deletion delay for devenv
|
||||||
export PENPOT_DELETION_DELAY="24h"
|
export PENPOT_DELETION_DELAY="24h"
|
||||||
|
|
1
frontend/resources/images/assets/logo-subscription.svg
Normal file
1
frontend/resources/images/assets/logo-subscription.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 78 KiB |
1
frontend/resources/images/icons/logo-subscription.svg
Normal file
1
frontend/resources/images/icons/logo-subscription.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 78 KiB |
|
@ -46,6 +46,10 @@
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(assoc state :router (create routes)))))
|
(assoc state :router (create routes)))))
|
||||||
|
|
||||||
|
(defn encode-url
|
||||||
|
[url]
|
||||||
|
(js/encodeURIComponent url))
|
||||||
|
|
||||||
(defn match
|
(defn match
|
||||||
"Given routing tree and current path, return match with possibly
|
"Given routing tree and current path, return match with possibly
|
||||||
coerced parameters. Return nil if no match found."
|
coerced parameters. Return nil if no match found."
|
||||||
|
|
|
@ -21,12 +21,13 @@
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.router :as rt]
|
[app.main.router :as rt]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.components.dropdown-menu :refer [dropdown-menu dropdown-menu-item*]]
|
[app.main.ui.components.dropdown-menu :refer [dropdown-menu
|
||||||
|
dropdown-menu-item*]]
|
||||||
[app.main.ui.components.link :refer [link]]
|
[app.main.ui.components.link :refer [link]]
|
||||||
[app.main.ui.dashboard.comments :refer [comments-icon* comments-section]]
|
[app.main.ui.dashboard.comments :refer [comments-icon* comments-section]]
|
||||||
[app.main.ui.dashboard.inline-edition :refer [inline-edition]]
|
[app.main.ui.dashboard.inline-edition :refer [inline-edition]]
|
||||||
[app.main.ui.dashboard.project-menu :refer [project-menu*]]
|
[app.main.ui.dashboard.project-menu :refer [project-menu*]]
|
||||||
[app.main.ui.dashboard.subscription :as subscription]
|
[app.main.ui.dashboard.subscription :refer [subscription-sidebar* menu-team-icon*]]
|
||||||
[app.main.ui.dashboard.team-form]
|
[app.main.ui.dashboard.team-form]
|
||||||
[app.main.ui.icons :as i :refer [icon-xref]]
|
[app.main.ui.icons :as i :refer [icon-xref]]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
|
@ -330,8 +331,14 @@
|
||||||
[:img {:src (cf/resolve-team-photo-url team-item)
|
[:img {:src (cf/resolve-team-photo-url team-item)
|
||||||
:class (stl/css :team-picture)
|
:class (stl/css :team-picture)
|
||||||
:alt (:name team-item)}]
|
:alt (:name team-item)}]
|
||||||
|
|
||||||
|
(if (and (contains? cf/flags :subscriptions)
|
||||||
|
(or (= "unlimited" (:type (:subscription team-item))) (= "enterprise" (:type (:subscription team-item)))))
|
||||||
|
[:div {:class (stl/css :team-text-with-icon)}
|
||||||
|
[:span {:class (stl/css :team-text) :title (:name team-item)} (:name team-item)]
|
||||||
|
[:> menu-team-icon* {:subscription-name (:type (:subscription team-item))}]]
|
||||||
[:span {:class (stl/css :team-text)
|
[:span {:class (stl/css :team-text)
|
||||||
:title (:name team-item)} (:name team-item)]
|
:title (:name team-item)} (:name team-item)])
|
||||||
(when (= (:id team-item) (:id team))
|
(when (= (:id team-item) (:id team))
|
||||||
tick-icon)])
|
tick-icon)])
|
||||||
|
|
||||||
|
@ -645,19 +652,35 @@
|
||||||
|
|
||||||
handle-close-team
|
handle-close-team
|
||||||
(fn []
|
(fn []
|
||||||
(reset! show-teams-ddwn? false))]
|
(reset! show-teams-ddwn? false))
|
||||||
|
subscription (:subscription team)
|
||||||
|
subscription-name (:type subscription)]
|
||||||
|
|
||||||
[:div {:class (stl/css :sidebar-team-switch)}
|
[:div {:class (stl/css :sidebar-team-switch)}
|
||||||
[:div {:class (stl/css :switch-content)}
|
[:div {:class (stl/css :switch-content)}
|
||||||
[:button {:class (stl/css :current-team)
|
[:button {:class (stl/css :current-team)
|
||||||
:on-click handle-show-team-click
|
:on-click handle-show-team-click
|
||||||
:on-key-down handle-show-team-keydown}
|
:on-key-down handle-show-team-keydown}
|
||||||
|
(cond
|
||||||
(if (:is-default team)
|
(:is-default team)
|
||||||
[:div {:class (stl/css :team-name)}
|
[:div {:class (stl/css :team-name)}
|
||||||
[:span {:class (stl/css :penpot-icon)} i/logo-icon]
|
[:span {:class (stl/css :penpot-icon)} i/logo-icon]
|
||||||
[:span {:class (stl/css :team-text)} (tr "dashboard.default-team-name")]]
|
[:span {:class (stl/css :team-text)} (tr "dashboard.default-team-name")]]
|
||||||
|
|
||||||
|
(and (contains? cf/flags :subscriptions)
|
||||||
|
(not (:is-default team))
|
||||||
|
(or (= "unlimited" subscription-name) (= "enterprise" subscription-name)))
|
||||||
|
[:div {:class (stl/css :team-name)}
|
||||||
|
[:img {:src (cf/resolve-team-photo-url team)
|
||||||
|
:class (stl/css :team-picture)
|
||||||
|
:alt (:name team)}]
|
||||||
|
[:div {:class (stl/css :team-text-with-icon)}
|
||||||
|
[:span {:class (stl/css :team-text) :title (:name team)} (:name team)]
|
||||||
|
[:> menu-team-icon* {:subscription-name subscription-name}]]]
|
||||||
|
|
||||||
|
|
||||||
|
(and (not (:is-default team))
|
||||||
|
(not (contains? cf/flags :subscriptions)))
|
||||||
[:div {:class (stl/css :team-name)}
|
[:div {:class (stl/css :team-name)}
|
||||||
[:img {:src (cf/resolve-team-photo-url team)
|
[:img {:src (cf/resolve-team-photo-url team)
|
||||||
:class (stl/css :team-picture)
|
:class (stl/css :team-picture)
|
||||||
|
@ -964,7 +987,7 @@
|
||||||
|
|
||||||
[:*
|
[:*
|
||||||
(when (contains? cf/flags :subscriptions)
|
(when (contains? cf/flags :subscriptions)
|
||||||
[:> subscription/sidebar*])
|
[:> subscription-sidebar* {:profile profile}])
|
||||||
|
|
||||||
;; TODO remove this block when subscriptions is full implemented
|
;; TODO remove this block when subscriptions is full implemented
|
||||||
(when (contains? cf/flags :subscriptions-old)
|
(when (contains? cf/flags :subscriptions-old)
|
||||||
|
@ -974,7 +997,7 @@
|
||||||
[:span (tr "dashboard.upgrade-plan.penpot-free")]
|
[:span (tr "dashboard.upgrade-plan.penpot-free")]
|
||||||
[:span {:class (stl/css :no-limits)} (tr "dashboard.upgrade-plan.no-limits")]]
|
[:span {:class (stl/css :no-limits)} (tr "dashboard.upgrade-plan.no-limits")]]
|
||||||
[:div {:class (stl/css :power-up)}
|
[:div {:class (stl/css :power-up)}
|
||||||
(tr "dashboard.upgrade-plan.power-up")]])
|
(tr "subscription.dashboard.upgrade-plan.power-up")]])
|
||||||
|
|
||||||
(when (and team profile)
|
(when (and team profile)
|
||||||
[:& comments-section
|
[:& comments-section
|
||||||
|
|
|
@ -84,11 +84,18 @@
|
||||||
.team-text {
|
.team-text {
|
||||||
@include textEllipsis;
|
@include textEllipsis;
|
||||||
@include smallTitleTipography;
|
@include smallTitleTipography;
|
||||||
width: $s-144;
|
width: auto;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
color: var(--menu-foreground-color-hover);
|
color: var(--menu-foreground-color-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.team-text-with-icon {
|
||||||
|
display: flex;
|
||||||
|
gap: $s-8;
|
||||||
|
max-width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
// This icon still use the old svg
|
// This icon still use the old svg
|
||||||
.penpot-icon {
|
.penpot-icon {
|
||||||
@include flexCenter;
|
@include flexCenter;
|
||||||
|
|
|
@ -3,15 +3,21 @@
|
||||||
(ns app.main.ui.dashboard.subscription
|
(ns app.main.ui.dashboard.subscription
|
||||||
(:require-macros [app.main.style :as stl])
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.data.macros :as dm]
|
||||||
|
[app.config :as cf]
|
||||||
[app.main.router :as rt]
|
[app.main.router :as rt]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
|
[app.main.ui.components.dropdown-menu :refer [dropdown-menu-item*]]
|
||||||
|
[app.main.ui.ds.product.cta :refer [cta*]]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
|
[app.util.keyboard :as kbd]
|
||||||
|
[lambdaisland.uri :as u]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
(mf/defc cta-power-up*
|
(mf/defc cta-power-up*
|
||||||
[{:keys [top-title top-description bottom-description cta-text cta-link has-dropdown]}]
|
[{:keys [top-title top-description bottom-description has-dropdown]}]
|
||||||
(let [show-data* (mf/use-state false)
|
(let [show-data* (mf/use-state false)
|
||||||
show-data (deref show-data*)
|
show-data (deref show-data*)
|
||||||
handle-click
|
handle-click
|
||||||
|
@ -24,55 +30,166 @@
|
||||||
:on-click handle-click}
|
:on-click handle-click}
|
||||||
[:button {:class (stl/css :cta-top-section)}
|
[:button {:class (stl/css :cta-top-section)}
|
||||||
[:div {:class (stl/css :content)}
|
[:div {:class (stl/css :content)}
|
||||||
[:span {:class (stl/css :cta-title)} top-title]
|
[:span {:class (stl/css :cta-title :cta-text)} top-title]
|
||||||
[:span {:class (stl/css :cta-text)} top-description]]
|
[:span {:class (stl/css :cta-text-m)} top-description]]
|
||||||
(when has-dropdown [:span {:class (stl/css :icon-dropdown)} i/arrow])]
|
(when has-dropdown [:span {:class (stl/css :icon-dropdown)} i/arrow])]
|
||||||
|
|
||||||
(when (and has-dropdown show-data)
|
(when (and has-dropdown show-data)
|
||||||
[:div {:class (stl/css :cta-bottom-section)}
|
[:div {:class (stl/css :cta-bottom-section)}
|
||||||
[:> i18n/tr-html* {:content bottom-description
|
[:> i18n/tr-html* {:content bottom-description
|
||||||
:class (stl/css :content)
|
:class (stl/css :content)
|
||||||
:tag-name "button"}]
|
:tag-name "span"}]])]))
|
||||||
[:button {:class (stl/css :cta-highlight :cta-link) :on-click cta-link}
|
|
||||||
cta-text]])]))
|
|
||||||
|
|
||||||
(mf/defc sidebar*
|
(mf/defc subscription-sidebar*
|
||||||
[]
|
[{:keys [profile]}]
|
||||||
(let [;; TODO subscription cases professional/unlimited/enterprise
|
(let [subscription (:subscription (:props profile))
|
||||||
subscription-name :unlimited
|
subscription-name (if subscription
|
||||||
subscription-is-trial false
|
(:type subscription)
|
||||||
|
"professional")
|
||||||
go-to-subscription
|
subscription-is-trial (= (:status subscription) "trialing")
|
||||||
(mf/use-fn #(st/emit! (rt/nav :settings-subscription)))]
|
subscription-href (dm/str (u/join cf/public-uri "#/settings/subscriptions"))]
|
||||||
|
|
||||||
(case subscription-name
|
(case subscription-name
|
||||||
:professional
|
"professional"
|
||||||
[:> cta-power-up*
|
[:> cta-power-up*
|
||||||
{:top-title (tr "subscription.dashboard.power-up.professional.top-title")
|
{:top-title (tr "subscription.dashboard.power-up.your-subscription")
|
||||||
:top-description (tr "dashboard.upgrade-plan.no-limits")
|
:top-description (tr "subscription.dashboard.power-up.professional.top-title")
|
||||||
:bottom-description (tr "subscription.dashboard.power-up.professional.bottom-description")
|
:bottom-description (tr "subscription.dashboard.power-up.professional.bottom-description", subscription-href)
|
||||||
:cta-text (tr "dashboard.upgrade-plan.power-up")
|
|
||||||
:cta-link go-to-subscription
|
|
||||||
:has-dropdown true}]
|
:has-dropdown true}]
|
||||||
|
|
||||||
:unlimited
|
"unlimited"
|
||||||
(if subscription-is-trial
|
(if subscription-is-trial
|
||||||
[:> cta-power-up*
|
[:> cta-power-up*
|
||||||
{:top-title (tr "subscription.dashboard.power-up.trial.top-title")
|
{:top-title (tr "subscription.dashboard.power-up.your-subscription")
|
||||||
:top-description (tr "subscription.dashboard.power-up.trial.top-description")
|
:top-description (tr "subscription.dashboard.power-up.trial.top-title")
|
||||||
:bottom-description (tr "subscription.dashboard.power-up.trial.bottom-description")
|
:bottom-description (tr "subscription.dashboard.power-up.trial.bottom-description", subscription-href)
|
||||||
:cta-text (tr "subscription.dashboard.power-up.subscribe")}]
|
:has-dropdown true}]
|
||||||
|
|
||||||
[:> cta-power-up*
|
[:> cta-power-up*
|
||||||
{:top-title (tr "subscription.dashboard.power-up.unlimited-plan")
|
{:top-title (tr "subscription.dashboard.power-up.your-subscription")
|
||||||
:top-description (tr "subscription.dashboard.power-up.unlimited.top-description")
|
:top-description (tr "subscription.dashboard.power-up.unlimited-plan")
|
||||||
:bottom-description (tr "subscription.dashboard.power-up.unlimited.bottom-description")
|
:bottom-description (tr "subscription.dashboard.power-up.unlimited.bottom-description", subscription-href)
|
||||||
:cta-text (tr "subscription.dashboard.power-up.unlimited.cta")
|
|
||||||
:cta-link go-to-subscription
|
|
||||||
:has-dropdown true}])
|
:has-dropdown true}])
|
||||||
|
|
||||||
:enterprise
|
"enterprise"
|
||||||
[:> cta-power-up*
|
[:> cta-power-up*
|
||||||
{:top-title (tr "subscription.dashboard.power-up.enterprise-plan")
|
{:top-title (tr "subscription.dashboard.power-up.your-subscription")
|
||||||
:top-description (tr "subscription.dashboard.power-up.enterprise.description")
|
:top-description (tr "subscription.dashboard.power-up.enterprise-plan")
|
||||||
:has-dropdown false}])))
|
:has-dropdown false}])))
|
||||||
|
|
||||||
|
(mf/defc team*
|
||||||
|
[{:keys [is-owner team]}]
|
||||||
|
(let [subscription (:subscription team)
|
||||||
|
subscription-name (:type subscription)
|
||||||
|
subscription-is-trial (= "trialing" (:status subscription))
|
||||||
|
|
||||||
|
go-to-manage-subscription
|
||||||
|
(mf/use-fn
|
||||||
|
(fn []
|
||||||
|
;; TODO add event tracking
|
||||||
|
(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-name
|
||||||
|
"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-name "professional"))
|
||||||
|
[:button {:class (stl/css :manage-subscription-link)
|
||||||
|
:on-click go-to-manage-subscription}
|
||||||
|
(tr "subscription.settings.manage-your-subscription")])]))
|
||||||
|
|
||||||
|
(mf/defc menu-team-icon*
|
||||||
|
[{:keys [subscription-name]}]
|
||||||
|
[:span {:class (stl/css :subscription-icon)}
|
||||||
|
(case subscription-name
|
||||||
|
"unlimited" i/character-u
|
||||||
|
"enterprise" i/character-e)])
|
||||||
|
|
||||||
|
(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*
|
||||||
|
[{:keys [banner-is-expanded team profile]}]
|
||||||
|
(let [subscription (:subscription team)
|
||||||
|
subscription-name (:type subscription)
|
||||||
|
subscription-is-trial (= "trialing" (:status subscription))
|
||||||
|
is-owner (:is-owner (:permissions team))
|
||||||
|
|
||||||
|
email-owner (:email (some #(when (:is-admin %) %) (:members team)))
|
||||||
|
mail-to-owner (str "<a href=\"" "mailto:" email-owner "\">" email-owner "</a>")
|
||||||
|
go-to-subscription (dm/str (u/join cf/public-uri "#/settings/subscriptions"))
|
||||||
|
|
||||||
|
link
|
||||||
|
(if is-owner
|
||||||
|
go-to-subscription
|
||||||
|
mail-to-owner)
|
||||||
|
|
||||||
|
cta-title
|
||||||
|
(cond
|
||||||
|
(= "professional" subscription-name)
|
||||||
|
(tr "subscription.dashboard.cta.professional-plan-designed")
|
||||||
|
|
||||||
|
subscription-is-trial
|
||||||
|
(tr "subscription.dashboard.cta.trial-plan-designed")
|
||||||
|
|
||||||
|
(= "unlimited" subscription-name)
|
||||||
|
(tr "subscription.dashboard.cta.unlimited-many-editors" (:quantity (:subscription (:props profile)))))
|
||||||
|
|
||||||
|
cta-message
|
||||||
|
(cond
|
||||||
|
(and (= "professional" subscription-name) is-owner)
|
||||||
|
(tr "subscription.dashboard.cta.upgrade-to-unlimited-enterprise-owner" link)
|
||||||
|
|
||||||
|
(and (= "professional" subscription-name) (not is-owner))
|
||||||
|
(tr "subscription.dashboard.cta.upgrade-to-unlimited-enterprise-member" link)
|
||||||
|
|
||||||
|
(and subscription-is-trial is-owner)
|
||||||
|
(tr "subscription.dashboard.cta.upgrade-to-full-access-owner" link)
|
||||||
|
|
||||||
|
(and subscription-is-trial (not is-owner))
|
||||||
|
(tr "subscription.dashboard.cta.upgrade-to-full-access-member" link)
|
||||||
|
(and (= "unlimited" subscription-name) (not subscription-is-trial))
|
||||||
|
(tr "subscription.dashboard.cta.upgrade-to-unlimited-enterprise-owner-more-seats" link))]
|
||||||
|
|
||||||
|
[:> cta* {:class (stl/css-case ::members-cta-full-width banner-is-expanded :members-cta (not banner-is-expanded)) :title cta-title}
|
||||||
|
[:> i18n/tr-html*
|
||||||
|
{:tag-name "span"
|
||||||
|
:class (stl/css :cta-message)
|
||||||
|
:content cta-message}]]))
|
||||||
|
|
||||||
|
(defn show-subscription-members-main-banner?
|
||||||
|
[team profile]
|
||||||
|
(or
|
||||||
|
(and (= (:type (:subscription team)) "professional") (>= (count (:members team)) 8))
|
||||||
|
(and
|
||||||
|
(= (:type (:subscription team)) "unlimited")
|
||||||
|
(not (= (:status (:subscription team)) "trialing"))
|
||||||
|
(>= (count (:members team)) (:quantity (:subscription (:props profile))))
|
||||||
|
(:is-owner (:permissions team)))
|
||||||
|
(= (:status (:subscription team)) "paused")))
|
||||||
|
|
||||||
|
(defn show-subscription-invitations-main-banner?
|
||||||
|
[team]
|
||||||
|
(or
|
||||||
|
(and (= (:type (:subscription team)) "professional")
|
||||||
|
(>= (count (:members team)) 8))
|
||||||
|
(= (:status (:subscription team)) "paused")))
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
@use "common/refactor/common-dashboard";
|
@use "common/refactor/common-dashboard";
|
||||||
@use "../ds/typography.scss" as t;
|
@use "../ds/typography.scss" as t;
|
||||||
@use "../ds/_borders.scss" as *;
|
@use "../ds/_borders.scss" as *;
|
||||||
|
@use "../ds/spacing.scss" as *;
|
||||||
|
|
||||||
.cta-power-up {
|
.cta-power-up {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -27,7 +28,7 @@
|
||||||
.icon-dropdown {
|
.icon-dropdown {
|
||||||
@include flexCenter;
|
@include flexCenter;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: $s-16;
|
width: var(--sp-l);
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-dropdown svg {
|
.icon-dropdown svg {
|
||||||
|
@ -37,42 +38,114 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.cta-bottom-section {
|
.cta-bottom-section {
|
||||||
border-block-start: $s-1 solid var(--color-background-quaternary);
|
border-block-start: $b-1 solid var(--color-background-quaternary);
|
||||||
display: grid;
|
|
||||||
color: var(--color-foreground-secondary);
|
color: var(--color-foreground-secondary);
|
||||||
grid-template-columns: 1fr auto;
|
margin-block-start: var(--sp-m);
|
||||||
margin-block-start: $s-12;
|
padding-block-start: var(--sp-m);
|
||||||
padding-block-start: $s-12;
|
|
||||||
}
|
}
|
||||||
.cta-bottom-section .content {
|
.cta-bottom-section .content {
|
||||||
@include t.use-typography("body-small");
|
@include t.use-typography("body-small");
|
||||||
@include buttonStyle;
|
@include buttonStyle;
|
||||||
color: var(--color-foreground-secondary);
|
color: var(--color-foreground-secondary);
|
||||||
display: inline;
|
display: inline-block;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cta-text,
|
.cta-text,
|
||||||
|
.cta-text-m,
|
||||||
.cta-title {
|
.cta-title {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cta-title {
|
||||||
|
margin-block-end: var(--sp-xs);
|
||||||
|
}
|
||||||
|
|
||||||
.cta-text {
|
.cta-text {
|
||||||
@include t.use-typography("body-small");
|
@include t.use-typography("body-small");
|
||||||
}
|
}
|
||||||
|
|
||||||
.cta-title {
|
.cta-text-m {
|
||||||
@include t.use-typography("body-medium");
|
@include t.use-typography("body-medium");
|
||||||
}
|
}
|
||||||
|
|
||||||
.cta-bottom-section .content strong,
|
.cta-bottom-section .content a {
|
||||||
.cta-highlight {
|
|
||||||
@include t.use-typography("body-small");
|
@include t.use-typography("body-small");
|
||||||
color: var(--color-accent-tertiary);
|
color: var(--color-accent-tertiary);
|
||||||
|
margin-inline-start: var(--sp-xs);
|
||||||
}
|
}
|
||||||
|
|
||||||
.cta-link {
|
.cta-link {
|
||||||
@include buttonStyle;
|
@include buttonStyle;
|
||||||
align-self: end;
|
align-self: end;
|
||||||
margin-inline-start: $s-4;
|
margin-inline-start: var(--sp-xs);
|
||||||
|
}
|
||||||
|
|
||||||
|
.team {
|
||||||
|
display: grid;
|
||||||
|
grid-auto-rows: min-content;
|
||||||
|
gap: var(--sp-s);
|
||||||
|
max-width: $s-1000;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-label {
|
||||||
|
@include t.use-typography("headline-small");
|
||||||
|
color: var(--title-foreground-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-text {
|
||||||
|
@include t.use-typography("body-large");
|
||||||
|
color: var(--color-foreground-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.manage-subscription-link {
|
||||||
|
@include buttonStyle;
|
||||||
|
@include t.use-typography("body-small");
|
||||||
|
color: var(--color-accent-tertiary);
|
||||||
|
display: flex;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscription-icon {
|
||||||
|
@extend .button-icon;
|
||||||
|
background: var(--color-background-primary);
|
||||||
|
stroke: var(--color-foreground-secondary);
|
||||||
|
border-radius: var(--sp-xs);
|
||||||
|
border: $b-1 solid var(--color-foreground-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-item {
|
||||||
|
@extend .menu-item-base;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--menu-foreground-color-hover);
|
||||||
|
|
||||||
|
.open-arrow {
|
||||||
|
svg {
|
||||||
|
stroke: var(--menu-foreground-color-hover);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.members-cta {
|
||||||
|
height: fit-content;
|
||||||
|
margin-block-start: var(--sp-s);
|
||||||
|
margin-inline-start: $s-68;
|
||||||
|
max-width: $s-200;
|
||||||
|
}
|
||||||
|
|
||||||
|
.members-cta-full-width {
|
||||||
|
max-width: $s-1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta-message {
|
||||||
|
@include t.use-typography("body-small");
|
||||||
|
color: var(--color-foreground-secondary);
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--color-accent-primary);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,10 @@
|
||||||
[app.main.ui.components.file-uploader :refer [file-uploader]]
|
[app.main.ui.components.file-uploader :refer [file-uploader]]
|
||||||
[app.main.ui.components.forms :as fm]
|
[app.main.ui.components.forms :as fm]
|
||||||
[app.main.ui.dashboard.change-owner]
|
[app.main.ui.dashboard.change-owner]
|
||||||
|
[app.main.ui.dashboard.subscription :refer [team*
|
||||||
|
members-cta*
|
||||||
|
show-subscription-members-main-banner?
|
||||||
|
show-subscription-invitations-main-banner?]]
|
||||||
[app.main.ui.dashboard.team-form]
|
[app.main.ui.dashboard.team-form]
|
||||||
[app.main.ui.ds.foundations.assets.icon :refer [icon*]]
|
[app.main.ui.ds.foundations.assets.icon :refer [icon*]]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
|
@ -537,10 +541,22 @@
|
||||||
|
|
||||||
[:*
|
[:*
|
||||||
[:& header {:section :dashboard-team-members :team team}]
|
[:& header {:section :dashboard-team-members :team team}]
|
||||||
[:section {:class (stl/css :dashboard-container :dashboard-team-members)}
|
[:section {:class (stl/css-case
|
||||||
|
:dashboard-container true
|
||||||
|
:dashboard-team-members true
|
||||||
|
:dashboard-top-cta (show-subscription-members-main-banner? team profile))}
|
||||||
|
(when (and (contains? cfg/flags :subscriptions)
|
||||||
|
(show-subscription-members-main-banner? team profile))
|
||||||
|
[:> members-cta* {:banner-is-expanded true :team team :profile profile}])
|
||||||
[:> team-members*
|
[:> team-members*
|
||||||
{:profile profile
|
{:profile profile
|
||||||
:team team}]]])
|
:team team}]
|
||||||
|
(when (and
|
||||||
|
(contains? cfg/flags :subscriptions)
|
||||||
|
(or
|
||||||
|
(and (= (:type (:subscription team)) "professional") (< (count (:members team)) 8))
|
||||||
|
(= (:status (:subscription team)) "trialing")))
|
||||||
|
[:> members-cta* {:banner-is-expanded false :team team}])]])
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; INVITATIONS SECTION
|
;; INVITATIONS SECTION
|
||||||
|
@ -803,8 +819,18 @@
|
||||||
[:*
|
[:*
|
||||||
[:& header {:section :dashboard-team-invitations
|
[:& header {:section :dashboard-team-invitations
|
||||||
:team team}]
|
:team team}]
|
||||||
[:section {:class (stl/css :dashboard-team-invitations)}
|
[:section {:class (stl/css-case
|
||||||
[:> invitation-section* {:team team}]]])
|
:dashboard-team-invitations true
|
||||||
|
:dashboard-top-cta (show-subscription-invitations-main-banner? team))}
|
||||||
|
(when (and (contains? cfg/flags :subscriptions)
|
||||||
|
(show-subscription-invitations-main-banner? team))
|
||||||
|
[:> members-cta* {:banner-is-expanded true :team team}])
|
||||||
|
[:> invitation-section* {:team team}]
|
||||||
|
(when (and (contains? cfg/flags :subscriptions)
|
||||||
|
(or
|
||||||
|
(and (= (:type (:subscription team)) "professional") (< (count (:members team)) 8))
|
||||||
|
(= (:status (:subscription team)) "trialing")))
|
||||||
|
[:> members-cta* {:banner-is-expanded false :team team}])]])
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; WEBHOOKS SECTION
|
;; WEBHOOKS SECTION
|
||||||
|
@ -1159,5 +1185,8 @@
|
||||||
[:div {:class (stl/css :block-content)}
|
[:div {:class (stl/css :block-content)}
|
||||||
document-icon
|
document-icon
|
||||||
[:span {:class (stl/css :block-text)}
|
[:span {:class (stl/css :block-text)}
|
||||||
(tr "labels.num-of-files" (i18n/c (:files stats)))]]]]]))
|
(tr "labels.num-of-files" (i18n/c (:files stats)))]]]
|
||||||
|
|
||||||
|
(when (contains? cfg/flags :subscriptions)
|
||||||
|
[:> team* {:is-owner (:is-owner permissions) :team team}])]]))
|
||||||
|
|
||||||
|
|
|
@ -9,13 +9,14 @@
|
||||||
|
|
||||||
// Dashboard team settings
|
// Dashboard team settings
|
||||||
.dashboard-team-settings {
|
.dashboard-team-settings {
|
||||||
display: grid;
|
display: flex;
|
||||||
grid-template-rows: auto auto 1fr;
|
flex-direction: column;
|
||||||
justify-items: center;
|
align-items: center;
|
||||||
gap: $s-24;
|
gap: $s-24;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-top: $s-1 solid var(--panel-border-color);
|
border-top: $s-1 solid var(--panel-border-color);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
padding-inline: $s-24;
|
||||||
}
|
}
|
||||||
|
|
||||||
.block {
|
.block {
|
||||||
|
@ -23,7 +24,7 @@
|
||||||
grid-auto-rows: min-content;
|
grid-auto-rows: min-content;
|
||||||
gap: $s-8;
|
gap: $s-8;
|
||||||
max-width: $s-1000;
|
max-width: $s-1000;
|
||||||
width: $s-1000;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.info-block {
|
.info-block {
|
||||||
|
@ -105,22 +106,28 @@
|
||||||
|
|
||||||
// TEAM MEMBERS PAGE
|
// TEAM MEMBERS PAGE
|
||||||
.dashboard-team-members {
|
.dashboard-team-members {
|
||||||
display: grid;
|
display: flex;
|
||||||
justify-items: center;
|
justify-content: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding-top: $s-20;
|
padding-inline-start: $s-20;
|
||||||
|
padding-block-start: $s-20;
|
||||||
border-top: $s-1 solid var(--panel-border-color);
|
border-top: $s-1 solid var(--panel-border-color);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
scrollbar-gutter: stable;
|
scrollbar-gutter: stable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dashboard-team-members.dashboard-top-cta {
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
.team-members {
|
.team-members {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: auto 1fr;
|
grid-template-rows: auto 1fr;
|
||||||
height: fit-content;
|
height: fit-content;
|
||||||
max-width: $s-1000;
|
max-width: $s-1000;
|
||||||
width: $s-1000;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-header {
|
.table-header {
|
||||||
|
@ -275,22 +282,28 @@
|
||||||
|
|
||||||
// TEAM INVITATION PAGE
|
// TEAM INVITATION PAGE
|
||||||
.dashboard-team-invitations {
|
.dashboard-team-invitations {
|
||||||
display: grid;
|
display: flex;
|
||||||
justify-items: center;
|
justify-content: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding-top: $s-20;
|
padding-inline-start: $s-20;
|
||||||
|
padding-block-start: $s-20;
|
||||||
border-top: $s-1 solid var(--panel-border-color);
|
border-top: $s-1 solid var(--panel-border-color);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
scrollbar-gutter: stable;
|
scrollbar-gutter: stable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dashboard-team-invitations .dashboard-top-cta {
|
||||||
|
flex-direction: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
.invitations {
|
.invitations {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: auto 1fr;
|
grid-template-rows: auto 1fr;
|
||||||
height: fit-content;
|
height: fit-content;
|
||||||
max-width: $s-1000;
|
max-width: $s-1000;
|
||||||
width: $s-1000;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-row-invitations {
|
.table-row-invitations {
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
(def ^:svg-id loader "loader")
|
(def ^:svg-id loader "loader")
|
||||||
(def ^:svg-id logo-error-screen "logo-error-screen")
|
(def ^:svg-id logo-error-screen "logo-error-screen")
|
||||||
(def ^:svg-id login-illustration "login-illustration")
|
(def ^:svg-id login-illustration "login-illustration")
|
||||||
|
(def ^:svg-id logo-subscription "logo-subscription")
|
||||||
(def ^:svg-id marketing-arrows "marketing-arrows")
|
(def ^:svg-id marketing-arrows "marketing-arrows")
|
||||||
(def ^:svg-id marketing-exchange "marketing-exchange")
|
(def ^:svg-id marketing-exchange "marketing-exchange")
|
||||||
(def ^:svg-id marketing-file "marketing-file")
|
(def ^:svg-id marketing-file "marketing-file")
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
(def ^:icon logo-icon (icon-xref :penpot-logo-icon))
|
(def ^:icon logo-icon (icon-xref :penpot-logo-icon))
|
||||||
(def ^:icon logo-error-screen (icon-xref :logo-error-screen))
|
(def ^:icon logo-error-screen (icon-xref :logo-error-screen))
|
||||||
(def ^:icon login-illustration (icon-xref :login-illustration))
|
(def ^:icon login-illustration (icon-xref :login-illustration))
|
||||||
|
(def ^:icon logo-subscription (icon-xref :logo-subscription))
|
||||||
|
|
||||||
(def ^:icon brand-openid (icon-xref :brand-openid))
|
(def ^:icon brand-openid (icon-xref :brand-openid))
|
||||||
(def ^:icon brand-github (icon-xref :brand-github))
|
(def ^:icon brand-github (icon-xref :brand-github))
|
||||||
|
|
|
@ -69,7 +69,7 @@
|
||||||
[:& options-page]
|
[:& options-page]
|
||||||
|
|
||||||
:settings-subscription
|
:settings-subscription
|
||||||
[:> subscription-page*]
|
[:> subscription-page* {:profile profile}]
|
||||||
|
|
||||||
:settings-access-tokens
|
:settings-access-tokens
|
||||||
[:& access-tokens-page]
|
[:& access-tokens-page]
|
||||||
|
|
|
@ -1,16 +1,24 @@
|
||||||
(ns app.main.ui.settings.subscription
|
(ns app.main.ui.settings.subscription
|
||||||
(:require-macros [app.main.style :as stl])
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.data.macros :as dm]
|
||||||
|
[app.main.data.event :as ev]
|
||||||
|
[app.main.data.modal :as modal]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
|
[app.main.repo :as rp]
|
||||||
|
[app.main.router :as rt]
|
||||||
|
[app.main.store :as st]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
[app.util.time :as dt]
|
[app.util.time :as dt]
|
||||||
|
[beicon.v2.core :as rx]
|
||||||
|
[potok.v2.core :as ptk]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
(mf/defc plan-card*
|
(mf/defc plan-card*
|
||||||
{::mf/props :obj}
|
{::mf/props :obj}
|
||||||
[{:keys [card-title card-title-icon price-value price-period benefits-title benefits cta-text cta-link]}]
|
[{:keys [card-title card-title-icon price-value price-period benefits-title benefits cta-text cta-link cta-text-trial cta-link-trial cta-text-with-icon cta-link-with-icon]}]
|
||||||
[:div {:class (stl/css :plan-card)}
|
[:div {:class (stl/css :plan-card)}
|
||||||
[:div {:class (stl/css :plan-card-header)}
|
[:div {:class (stl/css :plan-card-header)}
|
||||||
[:div {:class (stl/css :plan-card-title-container)}
|
[:div {:class (stl/css :plan-card-title-container)}
|
||||||
|
@ -23,25 +31,195 @@
|
||||||
(when benefits-title [:h5 {:class (stl/css :benefits-title)} benefits-title])
|
(when benefits-title [:h5 {:class (stl/css :benefits-title)} benefits-title])
|
||||||
[:ul {:class (stl/css :benefits-list)}
|
[:ul {:class (stl/css :benefits-list)}
|
||||||
(for [benefit benefits]
|
(for [benefit benefits]
|
||||||
[:li {:key (str benefit) :class (stl/css :benefit)} "- " benefit])]
|
[:li {:key (dm/str benefit) :class (stl/css :benefit)} "- " benefit])]
|
||||||
(when (and cta-link cta-text) [:a {:class (stl/css :cta-button)
|
(when (and cta-link-with-icon cta-text-with-icon) [:button {:class (stl/css :cta-button :more-info)
|
||||||
:href cta-link} cta-text])])
|
:on-click cta-link-with-icon} cta-text-with-icon i/open-link])
|
||||||
|
(when (and cta-link cta-text) [:button {:class (stl/css-case :cta-button true
|
||||||
|
:bottom-link (not (and cta-link-trial cta-text-trial)))
|
||||||
|
:on-click cta-link} cta-text])
|
||||||
|
(when (and cta-link-trial cta-text-trial) [:button {:class (stl/css :cta-button :bottom-link)
|
||||||
|
:on-click cta-link-trial} cta-text-trial])])
|
||||||
|
|
||||||
|
(mf/defc subscribe-management-dialog
|
||||||
|
{::mf/register modal/components
|
||||||
|
::mf/register-as :management-dialog}
|
||||||
|
[{:keys [subscription-name teams subscribe-to-trial]}]
|
||||||
|
|
||||||
|
(let [min-members* (mf/use-state (or (some->> teams (map :total-members) (apply max)) 1))
|
||||||
|
min-members (deref min-members*)
|
||||||
|
formatted-subscription-name (if subscribe-to-trial
|
||||||
|
(if (= subscription-name "unlimited")
|
||||||
|
(tr "subscription.settings.unlimited-trial")
|
||||||
|
(tr "subscription.settings.enterprise-trial"))
|
||||||
|
(case subscription-name
|
||||||
|
"professional" (tr "subscription.settings.professional")
|
||||||
|
"unlimited" (tr "subscription.settings.unlimited")
|
||||||
|
"enterprise" (tr "subscription.settings.enterprise")))
|
||||||
|
handle-subscription-trial (if "unlimited"
|
||||||
|
(mf/use-fn
|
||||||
|
(mf/deps min-members)
|
||||||
|
(fn []
|
||||||
|
;; TODO add event tracking subscribe trial unlimited
|
||||||
|
(let [current-href (rt/get-current-href)
|
||||||
|
returnUrl (js/encodeURIComponent current-href)
|
||||||
|
href (dm/str "payments/subscriptions/create?type=unlimited&quantity=" min-members "&returnUrl=" returnUrl)]
|
||||||
|
(st/emit! (rt/nav-raw :href href)))))
|
||||||
|
|
||||||
|
(mf/use-fn
|
||||||
|
(fn []
|
||||||
|
;; TODO add event tracking subscribe trial enterprise
|
||||||
|
(let [current-href (rt/get-current-href)
|
||||||
|
returnUrl (js/encodeURIComponent current-href)
|
||||||
|
href (dm/str "payments/subscriptions/create?type=enterprise&returnUrl=" returnUrl)]
|
||||||
|
(st/emit! (rt/nav-raw :href href))))))
|
||||||
|
handle-accept-dialog (mf/use-callback
|
||||||
|
(fn []
|
||||||
|
;; TODO add event subscribe to another subscription
|
||||||
|
(let [current-href (rt/get-current-href)
|
||||||
|
returnUrl (js/encodeURIComponent current-href)
|
||||||
|
href (dm/str "payments/subscriptions/show?returnUrl=" returnUrl)]
|
||||||
|
(st/emit! (rt/nav-raw :href href)))
|
||||||
|
(modal/hide!)))
|
||||||
|
handle-close-dialog (mf/use-callback
|
||||||
|
(fn []
|
||||||
|
;; TODO add event tracking close modal/cancel subscription
|
||||||
|
(modal/hide!)))]
|
||||||
|
|
||||||
|
[:div {:class (stl/css :modal-overlay)}
|
||||||
|
[:div {:class (stl/css :modal-dialog)}
|
||||||
|
[:button {:class (stl/css :close-btn) :on-click handle-close-dialog} i/close]
|
||||||
|
[:div {:class (stl/css :modal-title :subscription-title)}
|
||||||
|
(tr "subscription.settings.management.dialog.title" formatted-subscription-name)]
|
||||||
|
|
||||||
|
[:div {:class (stl/css :modal-content)}
|
||||||
|
(if (seq teams)
|
||||||
|
[* [:div {:class (stl/css :modal-text)}
|
||||||
|
(tr "subscription.settings.management.dialog.choose-this-plan")]
|
||||||
|
[:ul {:class (stl/css :teams-list)}
|
||||||
|
(for [team (js->clj teams :keywordize-keys true)]
|
||||||
|
[:li {:key (dm/str (:id team)) :class (stl/css :team-name)}
|
||||||
|
(:name team) (tr "subscription.settings.management.dialog.members" (:total-members team))])]]
|
||||||
|
[:div {:class (stl/css :modal-text)}
|
||||||
|
(tr "subscription.settings.management.dialog.no-teams")])
|
||||||
|
|
||||||
|
(when (and (= subscription-name "unlimited") subscribe-to-trial)
|
||||||
|
[[:label {:for "editors-subscription" :class (stl/css :modal-text :editors-label)}
|
||||||
|
(tr "subscription.settings.management.dialog.select-editors")]
|
||||||
|
[:div {:class (stl/css :editors-wrapper)}
|
||||||
|
[:div {:class (stl/css :input-wrapper)}
|
||||||
|
[:input {:id "editors-subscription"
|
||||||
|
:class (stl/css :input-field)
|
||||||
|
:type "number"
|
||||||
|
:value min-members
|
||||||
|
:min 1
|
||||||
|
:on-change #(let [new-value (js/parseInt (.. % -target -value))]
|
||||||
|
(reset! min-members* (if (or (js/isNaN new-value) (zero? new-value)) 1 (max 1 new-value))))}]]
|
||||||
|
[:div {:class (stl/css :editors-cost)}
|
||||||
|
[:span {:class (stl/css :modal-text-small)}
|
||||||
|
(tr "subscription.settings.management.dialog.price-month" min-members)]
|
||||||
|
[:span {:class (stl/css :modal-text-small)}
|
||||||
|
(tr "subscription.settings.management.dialog.payment-explanation")]]]])
|
||||||
|
|
||||||
|
(when (and
|
||||||
|
(or (= subscription-name "professional") (= subscription-name "unlimited"))
|
||||||
|
(not subscribe-to-trial))
|
||||||
|
[:div {:class (stl/css :modal-text)}
|
||||||
|
(tr "subscription.settings.management.dialog.downgrade")])
|
||||||
|
|
||||||
|
[:div {:class (stl/css :modal-footer)}
|
||||||
|
[:div {:class (stl/css :action-buttons)}
|
||||||
|
[:input
|
||||||
|
{:class (stl/css :cancel-button)
|
||||||
|
:type "button"
|
||||||
|
:value (tr "ds.confirm-cancel")
|
||||||
|
:on-click handle-close-dialog}]
|
||||||
|
|
||||||
|
[:input
|
||||||
|
{:class (stl/css :primary-button)
|
||||||
|
:type "button"
|
||||||
|
:value (if subscribe-to-trial (tr "subscription.settings.start-trial") (tr "labels.continue"))
|
||||||
|
:on-click (if subscribe-to-trial handle-subscription-trial handle-accept-dialog)}]]]]]]))
|
||||||
|
|
||||||
|
(mf/defc subscription-success-dialog
|
||||||
|
{::mf/register modal/components
|
||||||
|
::mf/register-as :subscription-success}
|
||||||
|
[{:keys [subscription-name]}]
|
||||||
|
|
||||||
|
(let [handle-close-dialog (mf/use-callback
|
||||||
|
(fn []
|
||||||
|
;; TODO add event tracking close modal
|
||||||
|
(modal/hide!)))]
|
||||||
|
|
||||||
|
[:div {:class (stl/css :modal-overlay)}
|
||||||
|
[:div {:class (stl/css :modal-dialog :subscription-success)}
|
||||||
|
[:button {:class (stl/css :close-btn) :on-click handle-close-dialog} i/close]
|
||||||
|
[:div {:class (stl/css :modal-success-content)}
|
||||||
|
[:div {:class (stl/css :modal-start)}
|
||||||
|
i/logo-subscription]
|
||||||
|
|
||||||
|
[:div {:class (stl/css :modal-end)}
|
||||||
|
[:div {:class (stl/css :modal-title)} (tr "subscription.settings.sucess.dialog.title" subscription-name)]
|
||||||
|
[:p {:class (stl/css :modal-text-large)} (tr "subscription.settings.success.dialog.description")]
|
||||||
|
[:p {:class (stl/css :modal-text-large)} (tr "subscription.settings.sucess.dialog.footer")]
|
||||||
|
|
||||||
|
[:div {:class (stl/css :success-action-buttons)}
|
||||||
|
[:input
|
||||||
|
{:class (stl/css :primary-button)
|
||||||
|
:type "button"
|
||||||
|
:value (tr "labels.close")
|
||||||
|
:on-click handle-close-dialog}]]]]]]))
|
||||||
|
|
||||||
(mf/defc subscription-page*
|
(mf/defc subscription-page*
|
||||||
[]
|
[{:keys [profile]}]
|
||||||
(let [;; TODO subscription cases professional/unlimited/enterprise
|
(let [route (mf/deref refs/route)
|
||||||
subscription-name :unlimited
|
params (:params route)
|
||||||
subscription-is-trial false
|
show-subscription-success-modal (and (:query params)
|
||||||
|
(or (= (:subscription (:query params)) "subscribed-to-penpot-unlimited")
|
||||||
|
(= (:subscription (:query params)) "subscribed-to-penpot-enterprise")))
|
||||||
|
subscription (:subscription (:props profile))
|
||||||
|
subscription-name (if subscription
|
||||||
|
(:type subscription)
|
||||||
|
"professional")
|
||||||
|
subscription-is-trial (= (:status subscription) "trialing")
|
||||||
|
teams* (mf/use-state nil)
|
||||||
|
teams (deref teams*)
|
||||||
locale (mf/deref i18n/locale)
|
locale (mf/deref i18n/locale)
|
||||||
profile (mf/deref refs/profile)
|
|
||||||
penpot-member (dt/format-date-locale-short (:created-at profile) {:locale locale})
|
penpot-member (dt/format-date-locale-short (:created-at profile) {:locale locale})
|
||||||
;; TODO get subscription member date
|
subscription-member (dt/format-date-locale-short (:start-date subscription) {:locale locale})
|
||||||
subscription-member "January 17, 2024"
|
go-to-pricing-page (mf/use-fn
|
||||||
;; TODO update url to penpot payments
|
(fn []
|
||||||
go-to-payments "https://penpot.app/pricing"]
|
(st/emit! (ptk/event ::ev/event {::ev/name "explore-pricing-click" ::ev/origin "settings" :section "subscription"}))
|
||||||
|
(dom/open-new-window "https://penpot.app/pricing")))
|
||||||
|
go-to-payments (mf/use-fn
|
||||||
|
(fn []
|
||||||
|
;; TODO add event tracking manage subscription in stripe
|
||||||
|
(let [current-href (rt/get-current-href)
|
||||||
|
returnUrl (js/encodeURIComponent current-href)
|
||||||
|
href (dm/str "payments/subscriptions/show?returnUrl=" returnUrl)]
|
||||||
|
(st/emit! (rt/nav-raw :href href)))))
|
||||||
|
open-subscription-modal (mf/use-fn
|
||||||
|
(mf/deps teams)
|
||||||
|
(fn [subscription-name]
|
||||||
|
;; TODO add event tracking open modal to try trial
|
||||||
|
(st/emit!
|
||||||
|
(modal/show :management-dialog
|
||||||
|
{:subscription-name subscription-name
|
||||||
|
:teams teams :subscribe-to-trial (not subscription)}))))]
|
||||||
|
|
||||||
|
(mf/with-effect []
|
||||||
|
(->> (rp/cmd! :get-owned-teams)
|
||||||
|
(rx/subs! (fn [teams]
|
||||||
|
(reset! teams* teams)))))
|
||||||
|
|
||||||
(mf/with-effect []
|
(mf/with-effect []
|
||||||
(dom/set-html-title (tr "subscription.labels")))
|
(dom/set-html-title (tr "subscription.labels")))
|
||||||
|
|
||||||
|
(when show-subscription-success-modal
|
||||||
|
;; add name subscription from params
|
||||||
|
(st/emit! (modal/show :subscription-success
|
||||||
|
{:subscription-name (if (= (:subscription (:query params)) "subscribed-to-penpot-unlimited")
|
||||||
|
(tr "subscription.settings.unlimited-trial-modal")
|
||||||
|
(tr "subscription.settings.enterprise-trial-modal"))})))
|
||||||
[:section {:class (stl/css :dashboard-section)}
|
[:section {:class (stl/css :dashboard-section)}
|
||||||
[:div {:class (stl/css :dashboard-content)}
|
[:div {:class (stl/css :dashboard-content)}
|
||||||
[:h2 {:class (stl/css :title-section)} (tr "subscription.labels")]
|
[:h2 {:class (stl/css :title-section)} (tr "subscription.labels")]
|
||||||
|
@ -50,13 +228,13 @@
|
||||||
[:div {:class (stl/css :your-subscription)}
|
[:div {:class (stl/css :your-subscription)}
|
||||||
[:h3 {:class (stl/css :plan-section-title)} (tr "subscription.settings.section-plan")]
|
[:h3 {:class (stl/css :plan-section-title)} (tr "subscription.settings.section-plan")]
|
||||||
(case subscription-name
|
(case subscription-name
|
||||||
:professional
|
"professional"
|
||||||
[:> plan-card* {:card-title (tr "subscription.settings.professional")
|
[:> plan-card* {:card-title (tr "subscription.settings.professional")
|
||||||
:benefits [(tr "subscription.settings.professional.projects-files"),
|
:benefits [(tr "subscription.settings.professional.projects-files"),
|
||||||
(tr "subscription.settings.professional.teams-editors"),
|
(tr "subscription.settings.professional.teams-editors"),
|
||||||
(tr "subscription.settings.professional.storage")]}]
|
(tr "subscription.settings.professional.storage")]}]
|
||||||
|
|
||||||
:unlimited
|
"unlimited"
|
||||||
(if subscription-is-trial
|
(if subscription-is-trial
|
||||||
[:> plan-card* {:card-title (tr "subscription.settings.unlimited-trial")
|
[:> plan-card* {:card-title (tr "subscription.settings.unlimited-trial")
|
||||||
:card-title-icon i/character-u
|
:card-title-icon i/character-u
|
||||||
|
@ -65,7 +243,9 @@
|
||||||
(tr "subscription.settings.unlimited.bill"),
|
(tr "subscription.settings.unlimited.bill"),
|
||||||
(tr "subscription.settings.unlimited.storage")]
|
(tr "subscription.settings.unlimited.storage")]
|
||||||
:cta-text (tr "subscription.settings.manage-your-subscription")
|
:cta-text (tr "subscription.settings.manage-your-subscription")
|
||||||
:cta-link go-to-payments}]
|
:cta-link go-to-payments
|
||||||
|
:cta-text-trial (tr "subscription.settings.add-payment-to-continue")
|
||||||
|
:cta-link-trial go-to-payments}]
|
||||||
|
|
||||||
[:> plan-card* {:card-title (tr "subscription.settings.unlimited")
|
[:> plan-card* {:card-title (tr "subscription.settings.unlimited")
|
||||||
:card-title-icon i/character-u
|
:card-title-icon i/character-u
|
||||||
|
@ -76,10 +256,10 @@
|
||||||
:cta-text (tr "subscription.settings.manage-your-subscription")
|
:cta-text (tr "subscription.settings.manage-your-subscription")
|
||||||
:cta-link go-to-payments}])
|
:cta-link go-to-payments}])
|
||||||
|
|
||||||
:enterprise
|
"enterprise"
|
||||||
[:> plan-card* {:card-title (tr "subscription.settings.enterprise")
|
[:> plan-card* {:card-title (tr "subscription.settings.enterprise")
|
||||||
:card-title-icon i/character-e
|
:card-title-icon i/character-e
|
||||||
:benefits-title (tr "subscription.settings.benefits.all-professiona-benefits")
|
:benefits-title (tr "subscription.settings.benefits.all-professional-benefits")
|
||||||
:benefits [(tr "subscription.settings.enterprise.support"),
|
:benefits [(tr "subscription.settings.enterprise.support"),
|
||||||
(tr "subscription.settings.enterprise.security"),
|
(tr "subscription.settings.enterprise.security"),
|
||||||
(tr "subscription.settings.enterprise.logs")]
|
(tr "subscription.settings.enterprise.logs")]
|
||||||
|
@ -97,36 +277,42 @@
|
||||||
|
|
||||||
[:div {:class (stl/css :other-subscriptions)}
|
[:div {:class (stl/css :other-subscriptions)}
|
||||||
[:h3 {:class (stl/css :plan-section-title)} (tr "subscription.settings.other-plans")]
|
[:h3 {:class (stl/css :plan-section-title)} (tr "subscription.settings.other-plans")]
|
||||||
(when (not= subscription-name :professional)
|
(when (not= subscription-name "professional")
|
||||||
[:> plan-card* {:card-title (tr "subscription.settings.professional")
|
[:> plan-card* {:card-title (tr "subscription.settings.professional")
|
||||||
:price-value "$0"
|
:price-value "$0"
|
||||||
:price-period (tr "subscription.settings.price-editor-month")
|
:price-period (tr "subscription.settings.price-editor-month")
|
||||||
:benefits [(tr "subscription.settings.professional.projects-files"),
|
:benefits [(tr "subscription.settings.professional.projects-files"),
|
||||||
(tr "subscription.settings.professional.teams-editors"),
|
(tr "subscription.settings.professional.teams-editors"),
|
||||||
(tr "subscription.settings.professional.storage")]
|
(tr "subscription.settings.professional.storage")]
|
||||||
:cta-text (tr "subscription.dashboard.power-up.subscribe")
|
:cta-text (tr "subscription.settings.subscribe")
|
||||||
:cta-link go-to-payments}])
|
:cta-link #(open-subscription-modal "professional")
|
||||||
|
:cta-text-with-icon (tr "subscription.settings.more-information")
|
||||||
|
:cta-link-with-icon go-to-pricing-page}])
|
||||||
|
|
||||||
(when (not= subscription-name :unlimited)
|
(when (not= subscription-name "unlimited")
|
||||||
[:> plan-card* {:card-title (tr "subscription.settings.unlimited")
|
[:> plan-card* {:card-title (tr "subscription.settings.unlimited")
|
||||||
:card-title-icon i/character-u
|
:card-title-icon i/character-u
|
||||||
:price-value "$7"
|
:price-value "$7"
|
||||||
:price-period (tr "subscription.settings.price-editor-month")
|
:price-period (tr "subscription.settings.price-editor-month")
|
||||||
:benefits-title (tr "subscription.settings.benefits.all-professiona-benefits")
|
:benefits-title (tr "subscription.settings.benefits.all-professional-benefits")
|
||||||
:benefits [(tr "subscription.settings.unlimited.teams"),
|
:benefits [(tr "subscription.settings.unlimited.teams"),
|
||||||
(tr "subscription.settings.unlimited.bill"),
|
(tr "subscription.settings.unlimited.bill"),
|
||||||
(tr "subscription.settings.unlimited.storage")]
|
(tr "subscription.settings.unlimited.storage")]
|
||||||
:cta-text (tr "subscription.settings.ulimited.try-it-free")
|
:cta-text (if subscription (tr "subscription.settings.subscribe") (tr "subscription.settings.try-it-free"))
|
||||||
:cta-link go-to-payments}])
|
:cta-link #(open-subscription-modal "unlimited")
|
||||||
|
:cta-text-with-icon (tr "subscription.settings.more-information")
|
||||||
|
:cta-link-with-icon go-to-pricing-page}])
|
||||||
|
|
||||||
(when (not= subscription-name :enterprise)
|
(when (not= subscription-name "enterprise")
|
||||||
[:> plan-card* {:card-title (tr "subscription.settings.enterprise")
|
[:> plan-card* {:card-title (tr "subscription.settings.enterprise")
|
||||||
:card-title-icon i/character-e
|
:card-title-icon i/character-e
|
||||||
:price-value "$950"
|
:price-value "$950"
|
||||||
:price-period (tr "subscription.settings.price-organization-month")
|
:price-period (tr "subscription.settings.price-organization-month")
|
||||||
:benefits-title (tr "subscription.settings.benefits.all-professiona-benefits")
|
:benefits-title (tr "subscription.settings.benefits.all-professional-benefits")
|
||||||
:benefits [(tr "subscription.settings.enterprise.support"),
|
:benefits [(tr "subscription.settings.enterprise.support"),
|
||||||
(tr "subscription.settings.enterprise.security"),
|
(tr "subscription.settings.enterprise.security"),
|
||||||
(tr "subscription.settings.enterprise.logs")]
|
(tr "subscription.settings.enterprise.logs")]
|
||||||
:cta-text (tr "subscription.dashboard.power-up.subscribe")
|
:cta-text (if subscription (tr "subscription.settings.subscribe") (tr "subscription.settings.try-it-free"))
|
||||||
:cta-link go-to-payments}])]]]))
|
:cta-link #(open-subscription-modal "enterprise")
|
||||||
|
:cta-text-with-icon (tr "subscription.settings.more-information")
|
||||||
|
:cta-link-with-icon go-to-pricing-page}])]]]))
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
|
|
||||||
@use "common/refactor/common-refactor.scss" as *;
|
@use "common/refactor/common-refactor.scss" as *;
|
||||||
@use "../ds/typography.scss" as t;
|
@use "../ds/typography.scss" as t;
|
||||||
|
@use "../ds/_borders.scss" as *;
|
||||||
|
@use "../ds/spacing.scss" as *;
|
||||||
|
|
||||||
.dashboard-section {
|
.dashboard-section {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -19,30 +21,30 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
max-width: $s-500;
|
max-width: $s-500;
|
||||||
margin-bottom: $s-32;
|
margin-block-end: var(--sp-xxxl);
|
||||||
width: $s-580;
|
width: $s-580;
|
||||||
margin: $s-92 auto $s-120 auto;
|
margin: $s-92 auto $s-120 auto;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.membership-container {
|
.membership-container {
|
||||||
margin-block-start: $s-16;
|
margin-block-start: var(--sp-l);
|
||||||
}
|
}
|
||||||
|
|
||||||
.membership {
|
.membership {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-block-start: $s-8;
|
margin-block-start: var(--sp-s);
|
||||||
}
|
}
|
||||||
|
|
||||||
.membership.first {
|
.membership.first {
|
||||||
margin-block-start: $s-16;
|
margin-block-start: var(--sp-l);
|
||||||
}
|
}
|
||||||
|
|
||||||
.membership-date {
|
.membership-date {
|
||||||
@include t.use-typography("body-small");
|
@include t.use-typography("body-small");
|
||||||
color: var(--color-foreground-secondary);
|
color: var(--color-foreground-secondary);
|
||||||
margin-inline-start: $s-8;
|
margin-inline-start: var(--sp-s);
|
||||||
}
|
}
|
||||||
|
|
||||||
.subscription-member,
|
.subscription-member,
|
||||||
|
@ -61,7 +63,7 @@
|
||||||
.title-section {
|
.title-section {
|
||||||
@include t.use-typography("title-large");
|
@include t.use-typography("title-large");
|
||||||
color: var(--color-foreground-primary);
|
color: var(--color-foreground-primary);
|
||||||
margin-block-end: $s-16;
|
margin-block-end: var(--sp-l);
|
||||||
}
|
}
|
||||||
|
|
||||||
.plan-section-title {
|
.plan-section-title {
|
||||||
|
@ -70,29 +72,32 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.plan-card {
|
.plan-card {
|
||||||
border: $s-1 solid var(--color-foreground-secondary);
|
border: $b-1 solid var(--color-foreground-secondary);
|
||||||
border-radius: $s-8;
|
border-radius: var(--sp-s);
|
||||||
margin-block-start: $s-16;
|
margin-block-start: var(--sp-l);
|
||||||
padding: $s-16;
|
padding: var(--sp-l);
|
||||||
}
|
}
|
||||||
|
|
||||||
.plan-card-header {
|
.plan-card-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin-block-end: $s-8;
|
margin-block-end: var(--sp-s);
|
||||||
}
|
}
|
||||||
|
|
||||||
.plan-card-title-container {
|
.plan-card-title-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: $s-8;
|
gap: var(--sp-s);
|
||||||
}
|
}
|
||||||
|
|
||||||
.plan-title-icon {
|
.plan-title-icon {
|
||||||
@extend .button-icon;
|
@extend .button-icon;
|
||||||
stroke: var(--color-foreground-primary);
|
stroke: var(--color-foreground-primary);
|
||||||
border-radius: $s-4;
|
height: var(--sp-xl);
|
||||||
border: $s-1 solid var(--color-foreground-primary);
|
width: var(--sp-xl);
|
||||||
|
border-radius: var(--sp-xs);
|
||||||
|
border: $b-1 solid var(--color-foreground-primary);
|
||||||
|
padding: $s-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.plan-card-title,
|
.plan-card-title,
|
||||||
|
@ -122,5 +127,134 @@
|
||||||
|
|
||||||
.cta-button {
|
.cta-button {
|
||||||
@include t.use-typography("body-small");
|
@include t.use-typography("body-small");
|
||||||
|
@include buttonStyle;
|
||||||
color: var(--color-accent-tertiary);
|
color: var(--color-accent-tertiary);
|
||||||
|
display: flex;
|
||||||
|
margin-block-start: var(--sp-m);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta-button svg {
|
||||||
|
@extend .button-icon;
|
||||||
|
height: var(--sp-l);
|
||||||
|
width: var(--sp-l);
|
||||||
|
stroke: var(--color-accent-tertiary);
|
||||||
|
margin-inline-start: var(--sp-xs);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-link {
|
||||||
|
margin-block-start: var(--sp-xs);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-overlay {
|
||||||
|
@extend .modal-overlay-base;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-dialog {
|
||||||
|
@extend .modal-container-base;
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: auto 1fr auto;
|
||||||
|
max-height: initial;
|
||||||
|
min-width: $s-520;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-dialog.subscription-success {
|
||||||
|
min-width: $s-612;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-btn {
|
||||||
|
@extend .modal-close-btn-base;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-title {
|
||||||
|
@include t.use-typography("title-large");
|
||||||
|
margin-block-end: var(--sp-xxxl);
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
display: flex;
|
||||||
|
gap: var(--sp-m);
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscription-title {
|
||||||
|
margin-block-end: var(--sp-l);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-text-lage {
|
||||||
|
@include t.use-typography("body-large");
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-text-small {
|
||||||
|
@include t.use-typography("body-small");
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content,
|
||||||
|
.modal-end {
|
||||||
|
color: var(--color-foreground-secondary);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-success-content {
|
||||||
|
display: flex;
|
||||||
|
gap: $s-40;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer {
|
||||||
|
margin-block-start: $s-40;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-buttons {
|
||||||
|
@extend .modal-action-btns;
|
||||||
|
}
|
||||||
|
|
||||||
|
.success-action-buttons {
|
||||||
|
margin-block-start: var(--sp-l);
|
||||||
|
}
|
||||||
|
|
||||||
|
.primary-button {
|
||||||
|
@extend .modal-accept-btn;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-button {
|
||||||
|
@extend .modal-cancel-btn;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-start {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
max-width: $s-220;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 992px) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.teams-list {
|
||||||
|
list-style-position: inside;
|
||||||
|
list-style-type: disc;
|
||||||
|
margin-inline-start: var(--sp-xl);
|
||||||
|
margin-block: var(--sp-xxl);
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-wrapper {
|
||||||
|
@extend .input-element;
|
||||||
|
width: $s-80;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editors-label {
|
||||||
|
margin-block-start: var(--sp-xxl);
|
||||||
|
}
|
||||||
|
|
||||||
|
.editors-wrapper {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--sp-xl);
|
||||||
|
margin-block-start: var(--sp-l);
|
||||||
|
}
|
||||||
|
|
||||||
|
.editors-cost {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.components.dropdown-menu :refer [dropdown-menu dropdown-menu-item*]]
|
[app.main.ui.components.dropdown-menu :refer [dropdown-menu dropdown-menu-item*]]
|
||||||
[app.main.ui.context :as ctx]
|
[app.main.ui.context :as ctx]
|
||||||
|
[app.main.ui.dashboard.subscription :refer [main-menu-power-up*]]
|
||||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||||
[app.main.ui.hooks.resize :as r]
|
[app.main.ui.hooks.resize :as r]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
|
@ -819,7 +820,12 @@
|
||||||
(reset! sub-menu* nil)
|
(reset! sub-menu* nil)
|
||||||
(st/emit!
|
(st/emit!
|
||||||
(ptk/event ::ev/event {::ev/name "open-plugins-manager" ::ev/origin "workspace:menu"})
|
(ptk/event ::ev/event {::ev/name "open-plugins-manager" ::ev/origin "workspace:menu"})
|
||||||
(modal/show :plugin-management {}))))]
|
(modal/show :plugin-management {}))))
|
||||||
|
|
||||||
|
subscription (:subscription (:props profile))
|
||||||
|
subscription-name (if subscription
|
||||||
|
(:type subscription)
|
||||||
|
"professional")]
|
||||||
|
|
||||||
(mf/with-effect []
|
(mf/with-effect []
|
||||||
(let [disposable (->> st/stream
|
(let [disposable (->> st/stream
|
||||||
|
@ -904,6 +910,10 @@
|
||||||
:id "file-menu-help-info"}
|
:id "file-menu-help-info"}
|
||||||
[:span {:class (stl/css :item-name)} (tr "workspace.header.menu.option.help-info")]
|
[:span {:class (stl/css :item-name)} (tr "workspace.header.menu.option.help-info")]
|
||||||
[:span {:class (stl/css :open-arrow)} i/arrow]]
|
[:span {:class (stl/css :open-arrow)} i/arrow]]
|
||||||
|
|
||||||
|
(when (and (contains? cf/flags :subscriptions) (not= "enterprise" subscription-name))
|
||||||
|
[:> main-menu-power-up* {:close-sub-menu close-sub-menu}])
|
||||||
|
|
||||||
;; TODO remove this block when subscriptions is full implemented
|
;; TODO remove this block when subscriptions is full implemented
|
||||||
(when (contains? cf/flags :subscriptions-old)
|
(when (contains? cf/flags :subscriptions-old)
|
||||||
[:> dropdown-menu-item* {:class (stl/css-case :menu-item true)
|
[:> dropdown-menu-item* {:class (stl/css-case :menu-item true)
|
||||||
|
@ -913,7 +923,7 @@
|
||||||
(on-power-up-click)))
|
(on-power-up-click)))
|
||||||
:on-pointer-enter close-sub-menu
|
:on-pointer-enter close-sub-menu
|
||||||
:id "file-menu-power-up"}
|
:id "file-menu-power-up"}
|
||||||
[:span {:class (stl/css :item-name)} (tr "workspace.header.menu.option.power-up")]])]
|
[:span {:class (stl/css :item-name)} (tr "subscription.workspace.header.menu.option.power-up")]])]
|
||||||
|
|
||||||
(case sub-menu
|
(case sub-menu
|
||||||
:file
|
:file
|
||||||
|
|
|
@ -1067,11 +1067,72 @@ msgstr "No limits on creativity"
|
||||||
msgid "dashboard.upgrade-plan.penpot-free"
|
msgid "dashboard.upgrade-plan.penpot-free"
|
||||||
msgstr "Penpot Free"
|
msgstr "Penpot Free"
|
||||||
|
|
||||||
#: src/app/main/ui/dashboard/sidebar.cljs:977, src/app/main/ui/dashboard/subscription.cljs:54
|
#: src/app/main/ui/dashboard/sidebar.cljs:972
|
||||||
msgid "dashboard.upgrade-plan.power-up"
|
msgid "subscription.dashboard.upgrade-plan.power-up"
|
||||||
msgstr "Power up"
|
msgstr "Power up"
|
||||||
|
|
||||||
#: src/app/main/ui/dashboard/team.cljs:924
|
#: src/app/main/ui/workspace/main_menu.cljs:910
|
||||||
|
msgid "subscription.workspace.header.menu.option.power-up"
|
||||||
|
msgstr "Power up your plan"
|
||||||
|
|
||||||
|
msgid "subscription.dashboard.team-plan"
|
||||||
|
msgstr "Team plan"
|
||||||
|
|
||||||
|
msgid "subscription.dashboard.power-up.your-subscription"
|
||||||
|
msgstr "Your subscription:"
|
||||||
|
|
||||||
|
msgid "subscription.dashboard.power-up.professional.top-title"
|
||||||
|
msgstr "Professional plan"
|
||||||
|
|
||||||
|
msgid "subscription.dashboard.power-up.unlimited-plan"
|
||||||
|
msgstr "Unlimited plan"
|
||||||
|
|
||||||
|
msgid "subscription.dashboard.power-up.enterprise-plan"
|
||||||
|
msgstr "Enterprise plan"
|
||||||
|
|
||||||
|
msgid "subscription.dashboard.power-up.trial.top-title"
|
||||||
|
msgstr "Unlimited plan (trial)"
|
||||||
|
|
||||||
|
msgid "subscription.dashboard.cta.professional-plan-designed"
|
||||||
|
msgstr "The Professional plan is designed for teams of up to 8 editors (owner, admin, and editor)."
|
||||||
|
|
||||||
|
msgid "subscription.dashboard.cta.unlimited-many-editors"
|
||||||
|
msgstr "Looks like your team has grown! Your plan includes %s seats, but you're now using more than that."
|
||||||
|
|
||||||
|
msgid "subscription.dashboard.cta.trial-plan-designed"
|
||||||
|
msgstr "The Unlimited (trial) plan is designed for teams of more than 8 editors (owner, admin, and editor)."
|
||||||
|
|
||||||
|
#, markdown
|
||||||
|
msgid "subscription.dashboard.cta.upgrade-to-unlimited-enterprise-owner"
|
||||||
|
msgstr ""
|
||||||
|
"Get more editors, more storage, and more autosaved versions with the Unlimited or Enterprise plan. "
|
||||||
|
"[Subscribe now.](%s)"
|
||||||
|
|
||||||
|
#, markdown
|
||||||
|
msgid "subscription.dashboard.cta.upgrade-to-unlimited-enterprise-owner-more-seats"
|
||||||
|
msgstr ""
|
||||||
|
"Please upgrade to match your usage. "
|
||||||
|
"[Subscribe now.](%s)"
|
||||||
|
|
||||||
|
#, markdown
|
||||||
|
msgid "subscription.dashboard.cta.upgrade-to-unlimited-enterprise-member"
|
||||||
|
msgstr ""
|
||||||
|
"Get more editors, more storage, and more autosaved versions with the Unlimited or Enterprise plan. Contact with the team owner: "
|
||||||
|
"%s"
|
||||||
|
|
||||||
|
#, markdown
|
||||||
|
msgid "subscription.dashboard.cta.upgrade-to-full-access-owner"
|
||||||
|
msgstr ""
|
||||||
|
"Unlock full access forever. "
|
||||||
|
"[Subscribe now.](%s)"
|
||||||
|
|
||||||
|
#, markdown
|
||||||
|
msgid "subscription.dashboard.cta.upgrade-to-full-access-member"
|
||||||
|
msgstr ""
|
||||||
|
"Unlock full access forever. Contact with the team owner: "
|
||||||
|
"%s"
|
||||||
|
|
||||||
|
#: src/app/main/ui/dashboard/team.cljs:909
|
||||||
msgid "dashboard.webhooks.active"
|
msgid "dashboard.webhooks.active"
|
||||||
msgstr "Is active"
|
msgstr "Is active"
|
||||||
|
|
||||||
|
@ -4267,13 +4328,6 @@ msgstr "Enterprise plan"
|
||||||
msgid "subscription.dashboard.power-up.enterprise.description"
|
msgid "subscription.dashboard.power-up.enterprise.description"
|
||||||
msgstr "Advanced security, activity logs, dedicated support and more."
|
msgstr "Advanced security, activity logs, dedicated support and more."
|
||||||
|
|
||||||
#: src/app/main/ui/dashboard/subscription.cljs:53
|
|
||||||
#, markdown
|
|
||||||
msgid "subscription.dashboard.power-up.professional.bottom-description"
|
|
||||||
msgstr ""
|
|
||||||
"Get extra editors and storage, file backup and more with the **Unlimited "
|
|
||||||
"plan**"
|
|
||||||
|
|
||||||
#: src/app/main/ui/dashboard/subscription.cljs:51
|
#: src/app/main/ui/dashboard/subscription.cljs:51
|
||||||
msgid "subscription.dashboard.power-up.professional.top-title"
|
msgid "subscription.dashboard.power-up.professional.top-title"
|
||||||
msgstr "Professional plan"
|
msgstr "Professional plan"
|
||||||
|
@ -4282,10 +4336,6 @@ msgstr "Professional plan"
|
||||||
msgid "subscription.dashboard.power-up.subscribe"
|
msgid "subscription.dashboard.power-up.subscribe"
|
||||||
msgstr "Subscribe"
|
msgstr "Subscribe"
|
||||||
|
|
||||||
#: src/app/main/ui/dashboard/subscription.cljs:63
|
|
||||||
msgid "subscription.dashboard.power-up.trial.bottom-description"
|
|
||||||
msgstr "Enjoying your trial? Unlock full access forever."
|
|
||||||
|
|
||||||
#: src/app/main/ui/dashboard/subscription.cljs:62
|
#: src/app/main/ui/dashboard/subscription.cljs:62
|
||||||
msgid "subscription.dashboard.power-up.trial.top-description"
|
msgid "subscription.dashboard.power-up.trial.top-description"
|
||||||
msgstr "Extra editors, storage and autosaved version, file backup and more."
|
msgstr "Extra editors, storage and autosaved version, file backup and more."
|
||||||
|
@ -4298,12 +4348,25 @@ msgstr "Unlimited plan (trial)"
|
||||||
msgid "subscription.dashboard.power-up.unlimited-plan"
|
msgid "subscription.dashboard.power-up.unlimited-plan"
|
||||||
msgstr "Unlimited plan"
|
msgstr "Unlimited plan"
|
||||||
|
|
||||||
|
#: src/app/main/ui/dashboard/subscription.cljs:53
|
||||||
|
#, markdown
|
||||||
|
msgid "subscription.dashboard.power-up.professional.bottom-description"
|
||||||
|
msgstr ""
|
||||||
|
"Get extra editors and storage, file backup and more with the Unlimited plan"
|
||||||
|
"[Power up](%s)"
|
||||||
|
|
||||||
#: src/app/main/ui/dashboard/subscription.cljs:69
|
#: src/app/main/ui/dashboard/subscription.cljs:69
|
||||||
#, markdown
|
#, markdown
|
||||||
msgid "subscription.dashboard.power-up.unlimited.bottom-description"
|
msgid "subscription.dashboard.power-up.unlimited.bottom-description"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Get advanced security, activity logs, dedicated support and more with "
|
"Get advanced security, activity logs, dedicated support and more. Take a look to the"
|
||||||
"**Enterprise plan**"
|
"[Enterprise plan.](%s)"
|
||||||
|
|
||||||
|
#, markdown
|
||||||
|
msgid "subscription.dashboard.power-up.trial.bottom-description"
|
||||||
|
msgstr ""
|
||||||
|
"Enjoying your trial? Unlock full access forever."
|
||||||
|
"[Subscribe](%s)"
|
||||||
|
|
||||||
#: src/app/main/ui/dashboard/subscription.cljs:70
|
#: src/app/main/ui/dashboard/subscription.cljs:70
|
||||||
msgid "subscription.dashboard.power-up.unlimited.cta"
|
msgid "subscription.dashboard.power-up.unlimited.cta"
|
||||||
|
@ -4466,7 +4529,127 @@ msgstr "Password - Penpot"
|
||||||
msgid "title.settings.profile"
|
msgid "title.settings.profile"
|
||||||
msgstr "Profile - Penpot"
|
msgstr "Profile - Penpot"
|
||||||
|
|
||||||
#: src/app/main/ui/dashboard/team.cljs:795
|
msgid "subscription.settings.section-plan"
|
||||||
|
msgstr "Your subscription"
|
||||||
|
|
||||||
|
msgid "subscription.settings.other-plans"
|
||||||
|
msgstr "Other penpot plans"
|
||||||
|
|
||||||
|
msgid "subscription.settings.unlimited"
|
||||||
|
msgstr "Unlimited"
|
||||||
|
|
||||||
|
msgid "subscription.settings.unlimited-trial"
|
||||||
|
msgstr "Unlimited (trial)"
|
||||||
|
|
||||||
|
msgid "subscription.settings.unlimited-trial-modal"
|
||||||
|
msgstr "Unlimited trial"
|
||||||
|
|
||||||
|
msgid "subscription.settings.enterprise"
|
||||||
|
msgstr "Enterprise"
|
||||||
|
|
||||||
|
msgid "subscription.settings.enterprise-trial"
|
||||||
|
msgstr "Enterprise (trial)"
|
||||||
|
|
||||||
|
msgid "subscription.settings.enterprise-trial-modal"
|
||||||
|
msgstr "Enterprise trial"
|
||||||
|
|
||||||
|
msgid "subscription.settings.support-us-since"
|
||||||
|
msgstr "You've been supporting us with this plan since %s"
|
||||||
|
|
||||||
|
msgid "subscription.settings.member-since"
|
||||||
|
msgstr "Penpot member since %s"
|
||||||
|
|
||||||
|
msgid "subscription.settings.price-editor-month"
|
||||||
|
msgstr "editor per month"
|
||||||
|
|
||||||
|
msgid "subscription.settings.price-organization-month"
|
||||||
|
msgstr "organization per month"
|
||||||
|
|
||||||
|
msgid "subscription.settings.more-information"
|
||||||
|
msgstr "More information"
|
||||||
|
|
||||||
|
msgid "subscription.settings.try-it-free"
|
||||||
|
msgstr "Try it free for 14 days"
|
||||||
|
|
||||||
|
msgid "subscription.settings.subscribe"
|
||||||
|
msgstr "Subscribe"
|
||||||
|
|
||||||
|
msgid "subscription.settings.start-trial"
|
||||||
|
msgstr "Start free trial"
|
||||||
|
|
||||||
|
msgid "subscription.settings.professional.projects-files"
|
||||||
|
msgstr "Unlimited projects, files and drafts"
|
||||||
|
|
||||||
|
msgid "subscription.settings.professional.teams-editors"
|
||||||
|
msgstr "Unlimited teams of up to 8 editors"
|
||||||
|
|
||||||
|
msgid "subscription.settings.professional.storage"
|
||||||
|
msgstr "10GB of storage and 7-day autosave versions"
|
||||||
|
|
||||||
|
msgid "subscription.settings.benefits.all-professional-benefits"
|
||||||
|
msgstr "All Professional plan benefits and:"
|
||||||
|
|
||||||
|
msgid "subscription.settings.benefits.all-unlimited-benefits"
|
||||||
|
msgstr "All Unlimited plan benefits and:"
|
||||||
|
|
||||||
|
msgid "subscription.settings.unlimited.teams"
|
||||||
|
msgstr "Unlimited teams, no matter your team size"
|
||||||
|
|
||||||
|
msgid "subscription.settings.unlimited.bill"
|
||||||
|
msgstr "Capped monthly bill"
|
||||||
|
|
||||||
|
msgid "subscription.settings.unlimited.storage"
|
||||||
|
msgstr "25GB of storage and 30-day autosave versions and file backup"
|
||||||
|
|
||||||
|
msgid "subscription.settings.manage-your-subscription"
|
||||||
|
msgstr "Manage your subscription"
|
||||||
|
|
||||||
|
msgid "subscription.settings.add-payment-to-continue"
|
||||||
|
msgstr "Add a payment method to continue after your trial"
|
||||||
|
|
||||||
|
msgid "subscription.settings.enterprise.support"
|
||||||
|
msgstr "Dedicated support"
|
||||||
|
|
||||||
|
msgid "subscription.settings.enterprise.security"
|
||||||
|
msgstr "Advanced security"
|
||||||
|
|
||||||
|
msgid "subscription.settings.enterprise.logs"
|
||||||
|
msgstr "Activity logs"
|
||||||
|
|
||||||
|
msgid "subscription.settings.sucess.dialog.title"
|
||||||
|
msgstr "You are %s!"
|
||||||
|
|
||||||
|
msgid "subscription.settings.success.dialog.description"
|
||||||
|
msgstr "You can edit your subscription at any time from the 'Subscription' page in your account details."
|
||||||
|
|
||||||
|
msgid "subscription.settings.sucess.dialog.footer"
|
||||||
|
msgstr "Enjoy your plan!"
|
||||||
|
|
||||||
|
msgid "subscription.settings.management.dialog.title"
|
||||||
|
msgstr "Apply %s to your teams"
|
||||||
|
|
||||||
|
msgid "subscription.settings.management.dialog.choose-this-plan"
|
||||||
|
msgstr "You are choosing this plan for:"
|
||||||
|
|
||||||
|
msgid "subscription.settings.management.dialog.members"
|
||||||
|
msgstr " (%s editors)"
|
||||||
|
|
||||||
|
msgid "subscription.settings.management.dialog.no-teams"
|
||||||
|
msgstr "This plan will apply to all future teams you create or own."
|
||||||
|
|
||||||
|
msgid "subscription.settings.management.dialog.select-editors"
|
||||||
|
msgstr "Select number of editors (seats) you need:"
|
||||||
|
|
||||||
|
msgid "subscription.settings.management.dialog.price-month"
|
||||||
|
msgstr "$7 per editor/month x %s"
|
||||||
|
|
||||||
|
msgid "subscription.settings.management.dialog.payment-explanation"
|
||||||
|
msgstr "(No payment will be made now)"
|
||||||
|
|
||||||
|
msgid "subscription.settings.management.dialog.downgrade"
|
||||||
|
msgstr "Heads up: switching to a lower plan means less storage and shorter backups and version history."
|
||||||
|
|
||||||
|
#: src/app/main/ui/dashboard/team.cljs:779
|
||||||
msgid "title.team-invitations"
|
msgid "title.team-invitations"
|
||||||
msgstr "Invitations - %s - Penpot"
|
msgstr "Invitations - %s - Penpot"
|
||||||
|
|
||||||
|
@ -4474,7 +4657,6 @@ msgstr "Invitations - %s - Penpot"
|
||||||
msgid "title.team-members"
|
msgid "title.team-members"
|
||||||
msgstr "Members - %s - Penpot"
|
msgstr "Members - %s - Penpot"
|
||||||
|
|
||||||
#: src/app/main/ui/dashboard/team.cljs:1105
|
|
||||||
msgid "title.team-settings"
|
msgid "title.team-settings"
|
||||||
msgstr "Settings - %s - Penpot"
|
msgstr "Settings - %s - Penpot"
|
||||||
|
|
||||||
|
@ -4932,12 +5114,6 @@ msgstr "Help & info"
|
||||||
#: src/app/main/ui/workspace/main_menu.cljs:916
|
#: src/app/main/ui/workspace/main_menu.cljs:916
|
||||||
msgid "workspace.header.menu.option.power-up"
|
msgid "workspace.header.menu.option.power-up"
|
||||||
msgstr "Power up your plan"
|
msgstr "Power up your plan"
|
||||||
|
|
||||||
#: src/app/main/ui/workspace/main_menu.cljs:881
|
|
||||||
msgid "workspace.header.menu.option.preferences"
|
|
||||||
msgstr "Preferences"
|
|
||||||
|
|
||||||
#: src/app/main/ui/workspace/main_menu.cljs:870
|
|
||||||
msgid "workspace.header.menu.option.view"
|
msgid "workspace.header.menu.option.view"
|
||||||
msgstr "View"
|
msgstr "View"
|
||||||
|
|
||||||
|
|
|
@ -1079,11 +1079,86 @@ msgstr "Sin límites a la creatividad"
|
||||||
msgid "dashboard.upgrade-plan.penpot-free"
|
msgid "dashboard.upgrade-plan.penpot-free"
|
||||||
msgstr "Penpot Gratis"
|
msgstr "Penpot Gratis"
|
||||||
|
|
||||||
#: src/app/main/ui/dashboard/sidebar.cljs:977, src/app/main/ui/dashboard/subscription.cljs:54
|
#: src/app/main/ui/dashboard/sidebar.cljs:972
|
||||||
msgid "dashboard.upgrade-plan.power-up"
|
msgid "subscription.dashboard.upgrade-plan.power-up"
|
||||||
msgstr "Mejora"
|
msgstr "Mejora"
|
||||||
|
|
||||||
#: src/app/main/ui/dashboard/team.cljs:924
|
#: src/app/main/ui/workspace/main_menu.cljs:910
|
||||||
|
msgid "subscription.workspace.header.menu.option.power-up"
|
||||||
|
msgstr "Mejora tu plan"
|
||||||
|
|
||||||
|
msgid "subscription.dashboard.team-plan"
|
||||||
|
msgstr "Plan de equipo"
|
||||||
|
|
||||||
|
msgid "subscription.dashboard.power-up.professional.top-title"
|
||||||
|
msgstr "Plan Professional"
|
||||||
|
|
||||||
|
#, markdown
|
||||||
|
msgid "subscription.dashboard.power-up.professional.bottom-description"
|
||||||
|
msgstr "Consigue editores y almacenamiento adicionales, copias de seguridad de archivos y mucho más con el Plan Unlimited"
|
||||||
|
"[Mejóralo](%s)"
|
||||||
|
|
||||||
|
msgid "subscription.dashboard.power-up.unlimited-plan"
|
||||||
|
msgstr "Plan ilimitado"
|
||||||
|
|
||||||
|
#, markdown
|
||||||
|
msgid "subscription.dashboard.power-up.unlimited.bottom-description"
|
||||||
|
msgstr ""
|
||||||
|
"Obtenga seguridad avanzada, registros de actividad, asistencia dedicada y mucho más. Echa un ojo al"
|
||||||
|
"[Plan Enterprise](%s)"
|
||||||
|
|
||||||
|
msgid "subscription.dashboard.power-up.enterprise-plan"
|
||||||
|
msgstr "Plan Enterprise"
|
||||||
|
|
||||||
|
msgid "subscription.dashboard.power-up.trial.top-title"
|
||||||
|
msgstr "Plan Unlimited (Prueba)"
|
||||||
|
|
||||||
|
#, markdown
|
||||||
|
msgid "subscription.dashboard.power-up.trial.bottom-description"
|
||||||
|
msgstr ""
|
||||||
|
"¿Disfrutas de la prueba? Desbloquea el acceso completo para siempre."
|
||||||
|
"[Suscríbete](%s)"
|
||||||
|
|
||||||
|
msgid "subscription.dashboard.cta.unlimited-many-editors"
|
||||||
|
msgstr "¡Parece que tu equipo ha crecido! Tu plan incluye %s asientos, pero ahora estás usando más que eso."
|
||||||
|
|
||||||
|
msgid "subscription.dashboard.cta.professional-plan-designed"
|
||||||
|
msgstr "El plan Professional está diseñado para equipos de hasta 8 editores (propietario, administrador y editor)."
|
||||||
|
|
||||||
|
msgid "subscription.dashboard.cta.trial-plan-designed"
|
||||||
|
msgstr "El plan Unlimited (de prueba) está diseñado para equipos de más de 8 editores (propietario, administrador y editor)."
|
||||||
|
|
||||||
|
#, markdown
|
||||||
|
msgid "subscription.dashboard.cta.upgrade-to-unlimited-enterprise-owner"
|
||||||
|
msgstr ""
|
||||||
|
"Consigue más editores, más almacenamiento y más versiones guardadas automáticamente con el plan Unlimited o Enterprise. "
|
||||||
|
"[Suscríbete ahora.](%s)"
|
||||||
|
|
||||||
|
#, markdown
|
||||||
|
msgid "subscription.dashboard.cta.upgrade-to-unlimited-enterprise-owner-more-seats"
|
||||||
|
msgstr ""
|
||||||
|
"Por favor, mejóralo para adaptarlo a tu uso. "
|
||||||
|
"[Suscríbete ahora.](%s)"
|
||||||
|
|
||||||
|
#, markdown
|
||||||
|
msgid "subscription.dashboard.cta.upgrade-to-unlimited-enterprise-member"
|
||||||
|
msgstr ""
|
||||||
|
"Consigue más editores, más almacenamiento y más versiones guardadas automáticamente con el plan Unlimited o Enterprise. Contacta con el propietario del equipo: "
|
||||||
|
"%s"
|
||||||
|
|
||||||
|
#, markdown
|
||||||
|
msgid "subscription.dashboard.cta.upgrade-to-full-access-owner"
|
||||||
|
msgstr ""
|
||||||
|
"Desbloquea el acceso completo para siempre. "
|
||||||
|
"[Suscríbete ahora.](%s)"
|
||||||
|
|
||||||
|
#, markdown
|
||||||
|
msgid "subscription.dashboard.cta.upgrade-to-full-access-member"
|
||||||
|
msgstr ""
|
||||||
|
"Desbloquea el acceso completo para siempre. Contacta con el propietario del equipo: "
|
||||||
|
"%s"
|
||||||
|
|
||||||
|
#: src/app/main/ui/dashboard/team.cljs:909
|
||||||
msgid "dashboard.webhooks.active"
|
msgid "dashboard.webhooks.active"
|
||||||
msgstr "Activo"
|
msgstr "Activo"
|
||||||
|
|
||||||
|
@ -4489,7 +4564,121 @@ msgstr "Contraseña - Penpot"
|
||||||
msgid "title.settings.profile"
|
msgid "title.settings.profile"
|
||||||
msgstr "Perfil - Penpot"
|
msgstr "Perfil - Penpot"
|
||||||
|
|
||||||
#: src/app/main/ui/dashboard/team.cljs:795
|
msgid "subscription.settings.section-plan"
|
||||||
|
msgstr "Tu suscripción"
|
||||||
|
|
||||||
|
msgid "subscription.settings.other-plans"
|
||||||
|
msgstr "Otros planes de penpot"
|
||||||
|
|
||||||
|
msgid "subscription.settings.professional"
|
||||||
|
msgstr "Professional"
|
||||||
|
|
||||||
|
msgid "subscription.settings.unlimited"
|
||||||
|
msgstr "Unlimited"
|
||||||
|
|
||||||
|
msgid "subscription.settings.unlimited-trial"
|
||||||
|
msgstr "Unlimited (prueba)"
|
||||||
|
|
||||||
|
msgid "subscription.settings.unlimited-trial-modal"
|
||||||
|
msgstr "Unlimited de prueba"
|
||||||
|
|
||||||
|
msgid "subscription.settings.enterprise"
|
||||||
|
msgstr "Enterprise"
|
||||||
|
|
||||||
|
msgid "subscription.settings.enterprise-trial"
|
||||||
|
msgstr "Enterprise (prueba)"
|
||||||
|
|
||||||
|
msgid "subscription.settings.enterprise-trial-modal"
|
||||||
|
msgstr "Enterprise de prueba"
|
||||||
|
|
||||||
|
msgid "subscription.settings.support-us-since"
|
||||||
|
msgstr "Nos has estado apoyando con este plan desde %s"
|
||||||
|
|
||||||
|
msgid "subscription.settings.member-since"
|
||||||
|
msgstr "Miembro de penpot desde %s"
|
||||||
|
|
||||||
|
msgid "subscription.settings.price-editor-month"
|
||||||
|
msgstr "editor por mes"
|
||||||
|
|
||||||
|
msgid "subscription.settings.price-organization-month"
|
||||||
|
msgstr "organización por mes"
|
||||||
|
|
||||||
|
msgid "subscription.settings.try-it-free"
|
||||||
|
msgstr "Pruébalo gratis durante 14 días"
|
||||||
|
|
||||||
|
msgid "subscription.settings.professional.projects-files"
|
||||||
|
msgstr "Proyectos, archivos y borradores ilimitados"
|
||||||
|
|
||||||
|
msgid "subscription.settings.professional.teams-editors"
|
||||||
|
msgstr "Equipos ilimitados de hasta 8 redactores"
|
||||||
|
|
||||||
|
msgid "subscription.settings.professional.storage"
|
||||||
|
msgstr "10 GB de almacenamiento y versiones de autoguardado de 7 días"
|
||||||
|
|
||||||
|
msgid "subscription.settings.benefits.all-professional-benefits"
|
||||||
|
msgstr "Todas las prestaciones del plan Professional y:"
|
||||||
|
|
||||||
|
msgid "subscription.settings.benefits.all-unlimited-benefits"
|
||||||
|
msgstr "Todas las prestaciones del plan Unlimited y:"
|
||||||
|
|
||||||
|
msgid "subscription.settings.unlimited.teams"
|
||||||
|
msgstr "Equipos ilimitados, independientemente de su tamaño"
|
||||||
|
|
||||||
|
msgid "subscription.settings.unlimited.bill"
|
||||||
|
msgstr "Factura mensual limitada"
|
||||||
|
|
||||||
|
msgid "subscription.settings.unlimited.storage"
|
||||||
|
msgstr "25 GB de almacenamiento y 30 días de autoguardado de versiones y copias de seguridad de archivos"
|
||||||
|
|
||||||
|
msgid "subscription.settings.manage-your-subscription"
|
||||||
|
msgstr "Gestionar tu suscripción"
|
||||||
|
|
||||||
|
msgid "subscription.settings.add-payment-to-continue"
|
||||||
|
msgstr "Añade un método de pago para continuar después del periodo de prueba"
|
||||||
|
|
||||||
|
msgid "subscription.settings.enterprise.support"
|
||||||
|
msgstr "Apoyo específico"
|
||||||
|
|
||||||
|
msgid "subscription.settings.enterprise.security"
|
||||||
|
msgstr "Seguridad avanzada"
|
||||||
|
|
||||||
|
msgid "subscription.settings.enterprise.logs"
|
||||||
|
msgstr "Registros de actividad"
|
||||||
|
|
||||||
|
msgid "subscription.settings.sucess.dialog.title"
|
||||||
|
msgstr "Eres %s!"
|
||||||
|
|
||||||
|
msgid "subscription.settings.success.dialog.description"
|
||||||
|
msgstr "Puedes modificar tu suscripción en cualquier momento desde la página 'Suscripción' en los datos de tu cuenta."
|
||||||
|
|
||||||
|
msgid "subscription.settings.sucess.dialog.footer"
|
||||||
|
msgstr "¡Disfruta de tu plan!"
|
||||||
|
|
||||||
|
msgid "subscription.settings.management.dialog.title"
|
||||||
|
msgstr "Aplica %s a tus equipos"
|
||||||
|
|
||||||
|
msgid "subscription.settings.management.dialog.choose-this-plan"
|
||||||
|
msgstr "Estás eligiendo este plan para:"
|
||||||
|
|
||||||
|
msgid "subscription.settings.management.dialog.members"
|
||||||
|
msgstr " (%s editores)"
|
||||||
|
|
||||||
|
msgid "subscription.settings.management.dialog.no-teams"
|
||||||
|
msgstr "Este plan se aplicará a todos los futuros equipos que crees o poseas."
|
||||||
|
|
||||||
|
msgid "subscription.settings.management.dialog.select-editors"
|
||||||
|
msgstr "Seleccione el número de editores (puestos) que necesitas:"
|
||||||
|
|
||||||
|
msgid "subscription.settings.management.dialog.price-month"
|
||||||
|
msgstr "$7 por editor/mes x %s"
|
||||||
|
|
||||||
|
msgid "subscription.settings.management.dialog.payment-explanation"
|
||||||
|
msgstr "(Ahora no se efectuará ningún pago)"
|
||||||
|
|
||||||
|
msgid "subscription.settings.management.dialog.downgrade"
|
||||||
|
msgstr "Ten en cuenta: cambiar a un plan inferior significa menos almacenamiento y copias de seguridad e historial de versiones más cortos."
|
||||||
|
|
||||||
|
#: src/app/main/ui/dashboard/team.cljs:779
|
||||||
msgid "title.team-invitations"
|
msgid "title.team-invitations"
|
||||||
msgstr "Invitaciones - %s - Penpot"
|
msgstr "Invitaciones - %s - Penpot"
|
||||||
|
|
||||||
|
@ -4954,10 +5143,6 @@ msgstr "Archivo"
|
||||||
msgid "workspace.header.menu.option.help-info"
|
msgid "workspace.header.menu.option.help-info"
|
||||||
msgstr "Ayuda e información"
|
msgstr "Ayuda e información"
|
||||||
|
|
||||||
#: src/app/main/ui/workspace/main_menu.cljs:916
|
|
||||||
msgid "workspace.header.menu.option.power-up"
|
|
||||||
msgstr "Mejora tu plan"
|
|
||||||
|
|
||||||
#: src/app/main/ui/workspace/main_menu.cljs:881
|
#: src/app/main/ui/workspace/main_menu.cljs:881
|
||||||
msgid "workspace.header.menu.option.preferences"
|
msgid "workspace.header.menu.option.preferences"
|
||||||
msgstr "Preferencias"
|
msgstr "Preferencias"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue