From 6ad83d24c9d4b794ab39351f91eb8d7703a10c14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marina=20L=C3=B3pez?= Date: Mon, 4 May 2026 15:48:47 +0200 Subject: [PATCH] :sparkles: Add nitrate manual cancel subscription --- backend/src/app/nitrate.clj | 1 + frontend/src/app/main/data/nitrate.cljs | 4 + .../app/main/ui/settings/subscription.cljs | 90 ++++++++++++++++--- .../app/main/ui/settings/subscription.scss | 16 ++++ frontend/translations/en.po | 7 +- frontend/translations/es.po | 6 ++ 6 files changed, 111 insertions(+), 13 deletions(-) diff --git a/backend/src/app/nitrate.clj b/backend/src/app/nitrate.clj index 77935cbad8..ddb5f307a2 100644 --- a/backend/src/app/nitrate.clj +++ b/backend/src/app/nitrate.clj @@ -171,6 +171,7 @@ "day" "week" "year"]] + [:manual :boolean] [:quantity :int] [:description [:maybe ::sm/text]] [:created-at schema:timestamp] diff --git a/frontend/src/app/main/data/nitrate.cljs b/frontend/src/app/main/data/nitrate.cljs index 1748ae516c..cd4328191e 100644 --- a/frontend/src/app/main/data/nitrate.cljs +++ b/frontend/src/app/main/data/nitrate.cljs @@ -83,6 +83,10 @@ href (dm/str "/control-center/licenses/start?" (u/map->query-string params))] (st/emit! (rt/nav-raw :href href))))) +(defn fetch-connectivity + [] + (rp/cmd! ::get-nitrate-connectivity {})) + (defn is-valid-license? [profile] (and (contains? cf/flags :nitrate) diff --git a/frontend/src/app/main/ui/settings/subscription.cljs b/frontend/src/app/main/ui/settings/subscription.cljs index 9e85635f3b..18aaca3e5c 100644 --- a/frontend/src/app/main/ui/settings/subscription.cljs +++ b/frontend/src/app/main/ui/settings/subscription.cljs @@ -22,6 +22,7 @@ [app.main.ui.notifications.badge :refer [badge-notification]] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr c]] + [beicon.v2.core :as rx] [potok.v2.core :as ptk] [rumext.v2 :as mf])) @@ -37,7 +38,7 @@ cta-link-trial cta-text-with-icon cta-link-with-icon - show-activation-by-code + code-action editors recommended show-button-cta]}] @@ -82,12 +83,19 @@ :size "s"}]]) (when (and cta-link cta-text (not show-button-cta)) [:button {:class (stl/css-case :cta-button true - :bottom-link (not (and cta-link-trial cta-text-trial))) + :bottom-link (not (or (and cta-link-trial cta-text-trial) code-action))) :on-click cta-link} cta-text]) - (when show-activation-by-code - [:button {:class (stl/css :cta-button :activate-by-code) - :on-click #(st/emit! (modal/show {:type :nitrate-code-activation}))} - (tr "subscription.settings.activate-by-code")])]) + (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- make-management-form-schema [min-editors] [:map {:title "SeatsForm"} @@ -446,11 +454,27 @@ (fn [current-subscription subscription-type] (if (= current-subscription "unlimited") (st/emit! (dnt/show-nitrate-popup :nitrate-dialog {:nitrate-license nitrate-license :show-contact-sales-option true})) - (st/emit! (modal/show :nitrate-contact-sales-dialog {:subscription-type subscription-type})))))] + (st/emit! (modal/show :nitrate-contact-sales-dialog {:subscription-type subscription-type}))))) + + open-cancel-contact-sales-modal + (mf/use-fn + (fn [] + (st/emit! (modal/show :nitrate-cancel-contact-sales-dialog {:email (:email profile)})))) + + connectivity* + (mf/use-state nil) + + connectivity + (deref connectivity*)] (mf/with-effect [] (dom/set-html-title (tr "subscription.labels"))) + (mf/with-effect [nitrate?] + (when nitrate? + (->> (dnt/fetch-connectivity) + (rx/subs! #(reset! connectivity* %))))) + (mf/with-effect [authenticated? show-subscription-success-modal? show-trial-subscription-modal? @@ -503,10 +527,15 @@ :benefits ["Loren ipsum", "Loren ipsum", "Loren ipsum"] - :cta-text-with-icon "Control Center" - :cta-link-with-icon dnt/go-to-nitrate-cc - :cta-text (tr "subscription.settings.manage-your-subscription") - :cta-link dnt/go-to-nitrate-billing}] + :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) + (tr "subscription.settings.manage-your-subscription") + (tr "nitrate.subscription.settings.manual-cancel")) + :cta-link (if (:licenses connectivity) + dnt/go-to-nitrate-billing + open-cancel-contact-sales-modal) + :code-action (when (and (not (:licenses connectivity)) (:manual nitrate-license)) :renovate)}] (case subscription-type "professional" [:> plan-card* {:card-title (tr "subscription.settings.professional") @@ -635,7 +664,7 @@ :cta-link (if (= subscription-type "unlimited") #(open-contact-sales-modal subscription-type "Nitrate") #(open-subscription-modal "nitrate" subscription)) :cta-text-with-icon (tr "subscription.settings.more-information") :cta-link-with-icon go-to-pricing-page - :show-activation-by-code true + :code-action :activate :show-button-cta (not nitrate-license)}])]]])) @@ -761,3 +790,40 @@ We’ll help you update your subscription and ensure everything is set up correc :type "button" :on-click #(dom/open-new-window "mailto:sales@penpot.app?subject=Switch%20to%20the%20Unlimited%20plan")} "Contact sales"]]]]])) +(mf/defc nitrate-cancel-contact-sales-dialog + {::mf/register modal/components + ::mf/register-as :nitrate-cancel-contact-sales-dialog} + [{:keys [email]}] + (let [encoded-email + (js/encodeURIComponent email) + + mailto-url + (dm/str "mailto:sales@penpot.net" + "?subject=Request%20to%20Cancel%20Nitrate%20Subscription" + "&body=Hello%2C%0A%0A" + "I%20would%20like%20to%20cancel%20my%20Enterprise%20subscription.%0A" + "Account%20email%3A%20" encoded-email ".%0A%0AThank%20you.") + + handle-close-dialog + (mf/use-fn + (fn [] + (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} + [:> icon* {:icon-id "close" + :size "m"}]] + [:div {:class (stl/css :modal-title :subscription-title)} + "Cancel subscription"] + + [:div {:class (stl/css :modal-content)} + [:div {:class (stl/css :modal-text-medium)} + "To cancel your Nitrate subscription, please contact us at:"] + [:a {:class (stl/css :cta-link) :href "mailto:sales@penpot.net"} + "sales@penpot.net"] + [:div {:class (stl/css :action-buttons)} + [:> button* {:class (stl/css :button-full-width) + :variant "primary" + :type "button" + :on-click #(dom/open-new-window mailto-url)} "Contact us"]]]]])) diff --git a/frontend/src/app/main/ui/settings/subscription.scss b/frontend/src/app/main/ui/settings/subscription.scss index 213624d901..18ca4400f2 100644 --- a/frontend/src/app/main/ui/settings/subscription.scss +++ b/frontend/src/app/main/ui/settings/subscription.scss @@ -404,3 +404,19 @@ margin-block-end: var(--sp-l); } + +.cta-link { + @include t.use-typography("body-medium"); + + align-items: center; + color: var(--color-accent-primary); + display: flex; + margin-block-end: var(--sp-xxxl); + text-align: left; + text-decoration: underline; +} + +.button-full-width { + justify-content: center; + inline-size: 100%; +} diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 972e270a13..5fe66d7884 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -9294,7 +9294,6 @@ msgstr "Need a code? Contact us:" msgid "nitrate.code-activation.placeholder" msgstr "Paste your activation code here" - msgid "nitrate.activation-success.title" msgstr "You are Business Nitrate!" @@ -9373,6 +9372,12 @@ msgstr "Contact sales" msgid "nitrate.subscription.active-until" msgstr "Active until %s" +msgid "nitrate.subscription.settings.manual-cancel" +msgstr "Cancel subscription" + +msgid "nitrate.subscription.settings.renew-with-code" +msgstr "Renew with activation code" + msgid "subscription.settings.activate-by-code" msgstr "Enter activation code" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index e33fe69c17..4bbf92126e 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -9078,6 +9078,12 @@ msgstr "Contactar con ventas" msgid "nitrate.subscription.active-until" msgstr "Activo hasta el %s" +msgid "nitrate.subscription.settings.manual-cancel" +msgstr "Cancelar subscripción" + +msgid "nitrate.subscription.settings.renew-with-code" +msgstr "Renovar con código de activación" + msgid "subscription.settings.more-information" msgstr "Más información"