mirror of
https://github.com/penpot/penpot.git
synced 2026-05-07 17:18:35 +00:00
✨ Refactor subscriptions page
This commit is contained in:
parent
6e186143d5
commit
bc13dfcf9e
@ -27,75 +27,114 @@
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc plan-card*
|
||||
{::mf/wrap [mf/memo]}
|
||||
[{:keys [card-title
|
||||
card-title-icon
|
||||
price-value price-period
|
||||
cancel-at
|
||||
benefits-title benefits
|
||||
cta-text
|
||||
cta-link
|
||||
cta-text-trial
|
||||
cta-link-trial
|
||||
cta-text-with-icon
|
||||
cta-link-with-icon
|
||||
cta-text cta-link
|
||||
cta-text-trial cta-link-trial
|
||||
cta-text-with-icon cta-link-with-icon
|
||||
code-action
|
||||
editors
|
||||
recommended
|
||||
show-button-cta]}]
|
||||
|
||||
[:div {:class (stl/css-case :plan-card true
|
||||
:plan-card-highlight recommended)}
|
||||
[:div {:class (stl/css :plan-card-header)}
|
||||
[:div {:class (stl/css :plan-card-title-container)}
|
||||
(when card-title-icon
|
||||
[:> icon* {:icon-id card-title-icon
|
||||
:class (stl/css :plan-title-icon)
|
||||
:size "s"}])
|
||||
[:h4 {:class (stl/css :plan-card-title)} card-title]
|
||||
(when recommended
|
||||
[:& badge-notification {:content (tr "subscription.settings.recommended")
|
||||
:size :small
|
||||
:is-focus true}])
|
||||
(when editors [:span {:class (stl/css :plan-editors)} (tr "subscription.settings.editors" editors)])]
|
||||
(when (and price-value price-period)
|
||||
[:div {:class (stl/css :plan-price)}
|
||||
[:span {:class (stl/css :plan-price-value)} price-value]
|
||||
[:span {:class (stl/css :plan-price-period)} " / " price-period]])
|
||||
(when cancel-at
|
||||
[:div {:class (stl/css :plan-cancel)}
|
||||
[:span {:class (stl/css :plan-cancel-date)} cancel-at]])]
|
||||
(when benefits-title [:h5 {:class (stl/css :benefits-title)} benefits-title])
|
||||
[:ul {:class (stl/css :benefits-list)}
|
||||
(for [benefit benefits]
|
||||
[:li {:key (dm/str benefit) :class (stl/css :benefit)} "- " benefit])]
|
||||
(when (and cta-link cta-text show-button-cta)
|
||||
[:> button* {:variant "primary"
|
||||
:type "button"
|
||||
:class (stl/css-case :bottom-button (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])
|
||||
(when (and cta-link-with-icon cta-text-with-icon)
|
||||
[:button {:class (stl/css :cta-button :more-info)
|
||||
:on-click cta-link-with-icon} cta-text-with-icon
|
||||
[:> icon* {:icon-id "open-link"
|
||||
:size "s"}]])
|
||||
(when (and cta-link cta-text (not show-button-cta))
|
||||
[:button {:class (stl/css-case :cta-button true
|
||||
:bottom-link (not (or (and cta-link-trial cta-text-trial) code-action)))
|
||||
:on-click cta-link} cta-text])
|
||||
(when code-action
|
||||
[:button {:class (stl/css-case :cta-button true
|
||||
:activate-by-code (= code-action :activate)
|
||||
:renew-by-code (= code-action :renovate)
|
||||
:bottom-link (= code-action :renovate))
|
||||
;; TODO add renovation modal
|
||||
:on-click (when (= code-action :activate)
|
||||
#(st/emit! (modal/show {:type :nitrate-code-activation})))}
|
||||
(if (= code-action :activate)
|
||||
(tr "subscription.settings.activate-by-code")
|
||||
(tr "nitrate.subscription.settings.renew-with-code"))])])
|
||||
(let [has-trial? (and cta-link-trial cta-text-trial)
|
||||
has-cta-with-icon? (and cta-link-with-icon cta-text-with-icon)
|
||||
has-cta-button (and cta-link cta-text show-button-cta)
|
||||
has-cta-link (and cta-link cta-text (not show-button-cta))]
|
||||
[:div {:class (stl/css-case :plan-card true
|
||||
:plan-card-highlight recommended)}
|
||||
[:div {:class (stl/css :plan-card-header)}
|
||||
[:div {:class (stl/css :plan-card-title-container)}
|
||||
(when card-title-icon
|
||||
[:> icon* {:icon-id card-title-icon
|
||||
:class (stl/css :plan-title-icon)
|
||||
:size "s"}])
|
||||
[:h4 {:class (stl/css :plan-card-title)} card-title]
|
||||
(when recommended
|
||||
[:& badge-notification {:content (tr "subscription.settings.recommended")
|
||||
:size :small
|
||||
:is-focus true}])
|
||||
(when editors
|
||||
[:span {:class (stl/css :plan-editors)} (tr "subscription.settings.editors" editors)])]
|
||||
(when (and price-value price-period)
|
||||
[:div {:class (stl/css :plan-price)}
|
||||
[:span {:class (stl/css :plan-price-value)} price-value]
|
||||
[:span {:class (stl/css :plan-price-period)} " / " price-period]])
|
||||
(when cancel-at
|
||||
[:div {:class (stl/css :plan-cancel)}
|
||||
[:span {:class (stl/css :plan-cancel-date)} cancel-at]])]
|
||||
(when benefits-title
|
||||
[:h5 {:class (stl/css :benefits-title)} benefits-title])
|
||||
[:ul {:class (stl/css :benefits-list)}
|
||||
(for [benefit benefits]
|
||||
[:li {:key (dm/str benefit) :class (stl/css :benefit)} "- " benefit])]
|
||||
|
||||
(when has-cta-button
|
||||
[:> button* {:variant "primary"
|
||||
:type "button"
|
||||
:class (stl/css-case :bottom-button (not has-trial?))
|
||||
:on-click cta-link} cta-text])
|
||||
(when has-trial?
|
||||
[:button {:class (stl/css :cta-button :bottom-link)
|
||||
:on-click cta-link-trial} cta-text-trial])
|
||||
(when has-cta-with-icon?
|
||||
[:button {:class (stl/css :cta-button :more-info)
|
||||
:on-click cta-link-with-icon} cta-text-with-icon
|
||||
[:> icon* {:icon-id "open-link"
|
||||
:size "s"}]])
|
||||
(when has-cta-link
|
||||
[:button {:class (stl/css-case :cta-button true
|
||||
:bottom-link (not (or has-trial? code-action)))
|
||||
:on-click cta-link} cta-text])
|
||||
(when code-action
|
||||
[:button {:class (stl/css-case :cta-button true
|
||||
:activate-by-code (= code-action :activate)
|
||||
:renew-by-code (= code-action :renovate)
|
||||
:bottom-link (= code-action :renovate))
|
||||
;; TODO add renovation modal
|
||||
:on-click (when (= code-action :activate)
|
||||
#(st/emit! (modal/show {:type :nitrate-code-activation})))}
|
||||
(if (= code-action :activate)
|
||||
(tr "subscription.settings.activate-by-code")
|
||||
(tr "nitrate.subscription.settings.renew-with-code"))])]))
|
||||
|
||||
(defn- get-subscription-name [subscription-type subscribe-to-trial?]
|
||||
(if subscribe-to-trial?
|
||||
(if (= subscription-type "unlimited")
|
||||
(tr "subscription.settings.unlimited-trial")
|
||||
(tr "subscription.settings.enterprise-trial"))
|
||||
(case subscription-type
|
||||
"professional" (tr "subscription.settings.professional")
|
||||
"unlimited" (tr "subscription.settings.unlimited")
|
||||
"enterprise" (tr "subscription.settings.enterprise"))))
|
||||
|
||||
(mf/defc ^:private editors-section*
|
||||
[{:keys [editors]}]
|
||||
(let [show-editors-list* (mf/use-state false)
|
||||
show-editors-list (deref show-editors-list*)
|
||||
handle-click (mf/use-fn
|
||||
(fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(swap! show-editors-list* not)))]
|
||||
[:*
|
||||
[:p {:class (stl/css :editors-text)}
|
||||
(tr "subscription.settings.management.dialog.currently-editors-title" (c (count editors)))]
|
||||
[:button {:class (stl/css :cta-button :show-editors-button) :on-click handle-click}
|
||||
(tr "subscription.settings.management.dialog.editors")
|
||||
[:> icon* {:icon-id (if show-editors-list i/arrow-up i/arrow-down)
|
||||
:class (stl/css :icon-dropdown)
|
||||
:size "s"}]]
|
||||
(when show-editors-list
|
||||
[:*
|
||||
[:p {:class (stl/css :editors-text :editors-list-warning)}
|
||||
(tr "subscription.settings.management.dialog.editors-explanation")]
|
||||
[:ul {:class (stl/css :editors-list)}
|
||||
(for [editor editors]
|
||||
[:li {:key (dm/str (:id editor)) :class (stl/css :team-name)} "- " (:name editor)])]])]))
|
||||
|
||||
(defn- make-management-form-schema [min-editors]
|
||||
[:map {:title "SeatsForm"}
|
||||
@ -114,14 +153,7 @@
|
||||
(deref unlimited-modal-step*)
|
||||
|
||||
subscription-name
|
||||
(if subscribe-to-trial
|
||||
(if (= subscription-type "unlimited")
|
||||
(tr "subscription.settings.unlimited-trial")
|
||||
(tr "subscription.settings.enterprise-trial"))
|
||||
(case subscription-type
|
||||
"professional" (tr "subscription.settings.professional")
|
||||
"unlimited" (tr "subscription.settings.unlimited")
|
||||
"enterprise" (tr "subscription.settings.enterprise")))
|
||||
(get-subscription-name subscription-type subscribe-to-trial)
|
||||
|
||||
min-editors
|
||||
(if (seq editors) (count editors) 1)
|
||||
@ -184,18 +216,6 @@
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "close-subscription-modal"}))
|
||||
(modal/hide!)))
|
||||
|
||||
show-editors-list*
|
||||
(mf/use-state false)
|
||||
|
||||
show-editors-list
|
||||
(deref show-editors-list*)
|
||||
|
||||
handle-click
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(swap! show-editors-list* not)))
|
||||
|
||||
on-submit
|
||||
(mf/use-fn
|
||||
(mf/deps current-subscription unlimited-modal-step*)
|
||||
@ -225,20 +245,7 @@
|
||||
|
||||
[:div {:class (stl/css :modal-content)}
|
||||
(when (and (seq editors) (not= unlimited-modal-step 2))
|
||||
[:* [:p {:class (stl/css :editors-text)}
|
||||
(tr "subscription.settings.management.dialog.currently-editors-title" (c (count editors)))]
|
||||
[:button {:class (stl/css :cta-button :show-editors-button) :on-click handle-click}
|
||||
(tr "subscription.settings.management.dialog.editors")
|
||||
[:> icon* {:icon-id (if show-editors-list i/arrow-up i/arrow-down)
|
||||
:class (stl/css :icon-dropdown)
|
||||
:size "s"}]]
|
||||
(when show-editors-list
|
||||
[:*
|
||||
[:p {:class (stl/css :editors-text :editors-list-warning)}
|
||||
(tr "subscription.settings.management.dialog.editors-explanation")]
|
||||
[:ul {:class (stl/css :editors-list)}
|
||||
(for [editor editors]
|
||||
[:li {:key (dm/str (:id editor)) :class (stl/css :team-name)} "- " (:name editor)])]])])
|
||||
[:> editors-section* {:editors editors}])
|
||||
|
||||
(when (and
|
||||
(or (and (= subscription-type "professional")
|
||||
@ -265,20 +272,20 @@
|
||||
:class (stl/css :input-field)}]]
|
||||
[:div {:class (stl/css :editors-cost)}
|
||||
[:span {:class (stl/css :modal-text-medium)}
|
||||
(when (> (get-in @form [:clean-data :min-members]) 25)
|
||||
(when (> (dm/get-in @form [:clean-data :min-members]) 25)
|
||||
[:> i18n/tr-html*
|
||||
{:class (stl/css :modal-text-cap)
|
||||
:tag-name "span"
|
||||
:content (tr "subscription.settings.management.dialog.price-month" "175")}])
|
||||
[:> i18n/tr-html*
|
||||
{:class (stl/css-case :text-strikethrough (> (get-in @form [:clean-data :min-members]) 25))
|
||||
{:class (stl/css-case :text-strikethrough (> (dm/get-in @form [:clean-data :min-members]) 25))
|
||||
:tag-name "span"
|
||||
:content (tr "subscription.settings.management.dialog.price-month"
|
||||
(* 7 (or (get-in @form [:clean-data :min-members]) 0)))}]]
|
||||
(* 7 (or (dm/get-in @form [:clean-data :min-members]) 0)))}]]
|
||||
[:span {:class (stl/css :modal-text-medium)}
|
||||
(tr "subscription.settings.management.dialog.payment-explanation")]]]
|
||||
|
||||
(when (get-in @form [:errors :min-members])
|
||||
(when (dm/get-in @form [:errors :min-members])
|
||||
[:div {:class (stl/css :error-message)}
|
||||
(tr "subscription.settings.management.dialog.input-error")])
|
||||
|
||||
@ -527,15 +534,15 @@
|
||||
:benefits ["Loren ipsum",
|
||||
"Loren ipsum",
|
||||
"Loren ipsum"]
|
||||
:cta-text-with-icon (when (:licenses connectivity) "Control Center")
|
||||
:cta-link-with-icon (when (:licenses connectivity) dnt/go-to-nitrate-cc)
|
||||
:cta-text (if (:licenses connectivity)
|
||||
:cta-text-with-icon (when (not (:manual nitrate-license)) "Control Center")
|
||||
:cta-link-with-icon (when (not (:manual nitrate-license)) dnt/go-to-nitrate-cc)
|
||||
:cta-text (if (and (:licenses connectivity) (not (:manual nitrate-license)))
|
||||
(tr "subscription.settings.manage-your-subscription")
|
||||
(tr "nitrate.subscription.settings.manual-cancel"))
|
||||
:cta-link (if (:licenses connectivity)
|
||||
:cta-link (if (and (:licenses connectivity) (not (:manual nitrate-license)))
|
||||
dnt/go-to-nitrate-billing
|
||||
open-cancel-contact-sales-modal)
|
||||
:code-action (when (and (not (:licenses connectivity)) (:manual nitrate-license)) :renovate)}]
|
||||
:code-action (when (:manual nitrate-license) :renovate)}]
|
||||
(case subscription-type
|
||||
"professional"
|
||||
[:> plan-card* {:card-title (tr "subscription.settings.professional")
|
||||
@ -615,7 +622,11 @@
|
||||
(tr "subscription.settings.professional.autosave-benefit"),
|
||||
(tr "subscription.settings.professional.teams-editors-benefit")]
|
||||
:cta-text (tr "subscription.settings.subscribe")
|
||||
:cta-link #(open-subscription-modal "professional")
|
||||
:cta-link (if (and (contains? cf/flags :nitrate) nitrate? (= subscription-type "nitrate"))
|
||||
(if (:licenses connectivity)
|
||||
dnt/go-to-nitrate-billing
|
||||
open-cancel-contact-sales-modal)
|
||||
go-to-payments)
|
||||
:cta-text-with-icon (tr "subscription.settings.more-information")
|
||||
:cta-link-with-icon go-to-pricing-page}])
|
||||
|
||||
@ -769,8 +780,7 @@
|
||||
[:> icon* {:icon-id "close"
|
||||
:size "m"}]]
|
||||
[:div {:class (stl/css :modal-title :subscription-title)}
|
||||
(str "Switch to " subscription-type " plan?")]
|
||||
|
||||
(dm/str "Switch to " subscription-type " plan?")]
|
||||
[:div {:class (stl/css :modal-content)}
|
||||
[:div {:class (stl/css :modal-text-medium)}
|
||||
"When you downgrade:"]
|
||||
|
||||
@ -38,10 +38,6 @@
|
||||
margin-block-start: var(--sp-s);
|
||||
}
|
||||
|
||||
.membership.first {
|
||||
margin-block-start: var(--sp-l);
|
||||
}
|
||||
|
||||
.membership-date {
|
||||
@include t.use-typography("body-small");
|
||||
|
||||
@ -109,11 +105,11 @@
|
||||
border: 1.75px solid var(--color-foreground-primary);
|
||||
stroke-width: 2.25px;
|
||||
padding: px2rem(3);
|
||||
}
|
||||
|
||||
svg {
|
||||
block-size: var(--sp-m);
|
||||
inline-size: var(--sp-m);
|
||||
}
|
||||
.plan-title-icon svg {
|
||||
block-size: var(--sp-m);
|
||||
inline-size: var(--sp-m);
|
||||
}
|
||||
|
||||
.plan-card-title,
|
||||
@ -292,16 +288,16 @@
|
||||
justify-content: center;
|
||||
max-inline-size: $sz-224;
|
||||
|
||||
svg {
|
||||
inline-size: 100%;
|
||||
block-size: auto;
|
||||
}
|
||||
|
||||
@media (width <= 992px) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-start svg {
|
||||
inline-size: 100%;
|
||||
block-size: auto;
|
||||
}
|
||||
|
||||
.editors-text {
|
||||
@include t.use-typography("body-medium");
|
||||
|
||||
@ -363,21 +359,21 @@
|
||||
}
|
||||
|
||||
.radio-btns {
|
||||
label {
|
||||
@include t.use-typography("body-large");
|
||||
|
||||
padding: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--color-foreground-secondary);
|
||||
}
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0 0 var(--sp-xl) 0;
|
||||
padding-block-end: var(--sp-xl);
|
||||
gap: var(--sp-s);
|
||||
}
|
||||
|
||||
.radio-btns label {
|
||||
@include t.use-typography("body-large");
|
||||
|
||||
padding: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--color-foreground-secondary);
|
||||
}
|
||||
|
||||
.modal-contact-content {
|
||||
gap: var(--sp-xl);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user