From 62880cb58cfdeb76a6c7c260bd99af855d41f9fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20Valderrama?= Date: Fri, 24 Jul 2026 14:08:11 +0200 Subject: [PATCH] :bug: Fix downgrade to Professional bypassing warning modal (#10814) * :bug: Fix downgrade to Professional bypassing warning modal * :paperclip: Code review --- frontend/src/app/main/data/nitrate.cljs | 2 +- .../app/main/ui/settings/subscription.cljs | 49 ++++++++++++------- .../frontend_tests/data/nitrate_test.cljs | 16 ++++++ 3 files changed, 49 insertions(+), 18 deletions(-) diff --git a/frontend/src/app/main/data/nitrate.cljs b/frontend/src/app/main/data/nitrate.cljs index 62f045ea63..cf310693d5 100644 --- a/frontend/src/app/main/data/nitrate.cljs +++ b/frontend/src/app/main/data/nitrate.cljs @@ -93,7 +93,7 @@ :profile-id profile-id :team-permissions team-permissions})) -(def go-to-subscription-url (u/join cf/public-uri "#/settings/subscriptions")) +(def go-to-subscription-url (dm/str (u/join cf/public-uri "#/settings/subscriptions"))) (def go-to-ac-url (build-admin-console-url "")) diff --git a/frontend/src/app/main/ui/settings/subscription.cljs b/frontend/src/app/main/ui/settings/subscription.cljs index 2489b122c0..429301c6af 100644 --- a/frontend/src/app/main/ui/settings/subscription.cljs +++ b/frontend/src/app/main/ui/settings/subscription.cljs @@ -502,10 +502,11 @@ open-contact-sales-modal (mf/use-fn (mf/deps nitrate-license) - (fn [current-subscription subscription-type] + (fn [current-subscription subscription-type & [has-billing-access?]] (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 + :has-billing-access? has-billing-access?}))))) open-cancel-contact-sales-modal (mf/use-fn @@ -701,10 +702,9 @@ (tr "subscription.settings.professional.teams-editors-benefit") (tr "subscription.settings.professional.selfhost.community-support"))] :cta-text (tr "subscription.settings.subscribe") - :cta-link (if (and (contains? cf/flags :nitrate) nitrate? (= subscription-type "nitrate")) - (if (and (:licenses connectivity) (not (:manual nitrate-license))) - dnt/go-to-nitrate-billing - open-cancel-contact-sales-modal) + :cta-link (if (and (contains? cf/flags :nitrate) nitrate?) + #(open-contact-sales-modal subscription-type "Professional" + (and (:licenses connectivity) (not (:manual nitrate-license)))) go-to-payments) :cta-text-with-icon (tr "subscription.settings.more-information") :cta-link-with-icon go-to-pricing-page @@ -827,11 +827,17 @@ (mf/defc nitrate-contact-sales-dialog {::mf/register modal/components ::mf/register-as :nitrate-contact-sales-dialog} - [{:keys [subscription-type]}] + [{:keys [subscription-type has-billing-access?]}] (let [handle-close-dialog (mf/use-fn (fn [] - (modal/hide!)))] + (modal/hide!))) + + handle-continue-click + (mf/use-fn + (fn [] + (modal/hide!) + (dnt/go-to-nitrate-billing)))] [:div {:class (stl/css :modal-overlay)} [:div {:class (stl/css :modal-dialog)} @@ -848,15 +854,24 @@ [:li {:class (stl/css :downgrade-item)} (tr "nitrate.contact-sales.downgrade-teams-available")] [:li {:class (stl/css :downgrade-item)} (tr "nitrate.contact-sales.downgrade-storage-limited")]] - [:div {:class (stl/css :downgrade-warning)} - (tr "nitrate.contact-sales.downgrade-contact-info")] - [:div {:class (stl/css :action-buttons)} - [:> button* {:variant "secondary" - :type "button" - :on-click handle-close-dialog} (tr "ds.confirm-cancel")] - [:> button* {:variant "primary" - :type "button" - :on-click #(dom/open-new-window "mailto:sales@penpot.app?subject=Switch%20to%20the%20Unlimited%20plan")} (tr "nitrate.contact-sales.button")]]]]])) + (if has-billing-access? + [:div {:class (stl/css :action-buttons)} + [:> button* {:variant "secondary" + :type "button" + :on-click handle-close-dialog} (tr "ds.confirm-cancel")] + [:> button* {:variant "primary" + :type "button" + :on-click handle-continue-click} (tr "labels.continue")]] + [:* + [:div {:class (stl/css :downgrade-warning)} + (tr "nitrate.contact-sales.downgrade-contact-info")] + [:div {:class (stl/css :action-buttons)} + [:> button* {:variant "secondary" + :type "button" + :on-click handle-close-dialog} (tr "ds.confirm-cancel")] + [:> button* {:variant "primary" + :type "button" + :on-click #(dom/open-new-window (dm/str "mailto:sales@penpot.app?subject=Switch%20to%20the%20" subscription-type "%20plan"))} (tr "nitrate.contact-sales.button")]]])]]])) (mf/defc nitrate-cancel-contact-sales-dialog {::mf/register modal/components diff --git a/frontend/test/frontend_tests/data/nitrate_test.cljs b/frontend/test/frontend_tests/data/nitrate_test.cljs index 744f8f1b16..ec0a2ba5fe 100644 --- a/frontend/test/frontend_tests/data/nitrate_test.cljs +++ b/frontend/test/frontend_tests/data/nitrate_test.cljs @@ -64,3 +64,19 @@ (u/uri "https://localhost:3449/#/settings/subscriptions"))] (t/is (= "https://localhost:3449/#/settings/subscriptions?subscription=nitrate-checkout-error" (:error-callback callbacks)))))) + +(t/deftest go-to-subscription-url-is-a-string + (t/testing "must be a string so licenses/billing?callback=... survives query encoding" + (t/is (string? dnt/go-to-subscription-url)) + (t/is (not (u/uri? dnt/go-to-subscription-url))))) + +(t/deftest build-admin-console-billing-url-encodes-string-callback + (t/testing "billing callback query param round-trips as a real URL string" + (let [public-uri (u/uri "https://localhost:3449/") + callback "https://localhost:3449/#/settings/subscriptions" + href (dnt/build-admin-console-url + public-uri + "licenses/billing" + {:callback callback}) + parsed (-> href u/uri :query u/query-string->map :callback)] + (t/is (= callback parsed)))))