diff --git a/backend/src/app/nitrate.clj b/backend/src/app/nitrate.clj index d0bb729fa5..03eb5a4131 100644 --- a/backend/src/app/nitrate.clj +++ b/backend/src/app/nitrate.clj @@ -391,6 +391,24 @@ profile-id) schema:subscription params))) +(def ^:private schema:subscription-warning + [:maybe + [:map {:title "SubscriptionWarning"} + [:type {:optional true} ::sm/text] + [:days-from-expiry {:optional true} ::sm/int] + [:days-until-expiry {:optional true} ::sm/int] + [:expiration-date {:optional true} schema:timestamp]]]) + +(defn- get-subscription-warning-api + [cfg {:keys [penpot-id profile-id] :as params}] + (let [baseuri (cf/get :nitrate-backend-uri) + penpot-id (or penpot-id profile-id)] + (request-to-nitrate cfg :get + (str baseuri + "/api/subscription-warning/" + penpot-id) + schema:subscription-warning params))) + (defn- get-connectivity-api [cfg params] (let [baseuri (cf/get :nitrate-backend-uri)] @@ -459,6 +477,7 @@ :delete-team (partial delete-team-api cfg) :remove-team-from-org (partial remove-team-from-org-api cfg) :get-subscription (partial get-subscription-api cfg) + :get-subscription-warning (partial get-subscription-warning-api cfg) :connectivity (partial get-connectivity-api cfg) :redeem-activation-code (partial redeem-activation-code-api cfg)})) @@ -527,6 +546,3 @@ :context {:team-id (:id team) :organization-id (:organization-id params)})) team)) - - - diff --git a/backend/src/app/rpc/commands/nitrate.clj b/backend/src/app/rpc/commands/nitrate.clj index 6161a4eac7..ba831c41d9 100644 --- a/backend/src/app/rpc/commands/nitrate.clj +++ b/backend/src/app/rpc/commands/nitrate.clj @@ -59,6 +59,22 @@ [cfg _params] (nitrate/call cfg :connectivity {})) +(def ^:private schema:subscription-warning + [:maybe + [:map {:title "SubscriptionWarning"} + [:type {:optional true} ::sm/text] + [:days-from-expiry {:optional true} ::sm/int] + [:days-until-expiry {:optional true} ::sm/int] + [:expiration-date {:optional true} ct/schema:inst]]]) + +(sv/defmethod ::get-subscription-warning + {::rpc/auth true + ::doc/added "2.14" + ::sm/params [:map] + ::sm/result schema:subscription-warning} + [cfg {:keys [::rpc/profile-id]}] + (nitrate/call cfg :get-subscription-warning {:profile-id profile-id})) + (def ^:private schema:redeem-activation-code-params [:map {:title "RedeemActivationCodeParams"} [:activation-code ::sm/text]]) diff --git a/frontend/src/app/main/data/nitrate.cljs b/frontend/src/app/main/data/nitrate.cljs index 45bd1da882..033d3525d0 100644 --- a/frontend/src/app/main/data/nitrate.cljs +++ b/frontend/src/app/main/data/nitrate.cljs @@ -133,6 +133,10 @@ [] (rp/cmd! ::get-nitrate-connectivity {})) +(defn fetch-subscription-warning + [] + (rp/cmd! ::get-subscription-warning {})) + (defn is-valid-license? [profile] (and (contains? cf/flags :nitrate) diff --git a/frontend/src/app/main/ui/dashboard/subscription.cljs b/frontend/src/app/main/ui/dashboard/subscription.cljs index 72594eb677..f207d735b2 100644 --- a/frontend/src/app/main/ui/dashboard/subscription.cljs +++ b/frontend/src/app/main/ui/dashboard/subscription.cljs @@ -4,6 +4,7 @@ (:require-macros [app.main.style :as stl]) (:require [app.common.data.macros :as dm] + [app.common.time :as ct] [app.config :as cf] [app.main.data.event :as ev] [app.main.data.nitrate :as dnt] @@ -16,6 +17,7 @@ [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [app.util.keyboard :as kbd] + [beicon.v2.core :as rx] [lambdaisland.uri :as u] [rumext.v2 :as mf])) @@ -119,6 +121,20 @@ [{:keys [profile teams]}] (let [nitrate? (dnt/is-valid-license? profile) nitrate-license (:subscription profile) + manual-license? (:manual nitrate-license) + subscription-warning* (mf/use-state nil) + subscription-warning (deref subscription-warning*) + days-until-expiry (or (:days-until-expiry subscription-warning) + (:daysUntilExpiry subscription-warning) + (:days-from-expiry subscription-warning) + (:daysFromExpiry subscription-warning)) + expiration-date (or (:expiration-date subscription-warning) + (:expirationDate subscription-warning)) + expiration-date-text (when expiration-date + (ct/format-inst expiration-date "MMMM d")) + show-subscription-warning? (and manual-license? + (some? days-until-expiry) + (some? expiration-date-text)) subscription-type (if nitrate? (:type nitrate-license) (get-subscription-type (-> profile :props :subscription))) no-orgs-created? (mf/with-memo [teams] (->> teams @@ -134,34 +150,64 @@ (st/emit! (dnt/show-nitrate-popup :nitrate-form))))) handle-go-to-cc - (mf/use-fn dnt/go-to-nitrate-ac-create-org)] + (mf/use-fn dnt/go-to-nitrate-ac-create-org) - ;; TODO add translations for this texts when we have the definitive ones - (if (and nitrate? no-orgs-created?) - ;; Banner for users with active nitrate license but no organizations created - [:div {:class (stl/css :nitrate-banner :highlighted)} - [:div {:class (stl/css :nitrate-content)} - [:span {:class (stl/css :nitrate-title)} (tr "subscription.banner.see-enterprise")]] - [:div {:class (stl/css :nitrate-content)} - [:span {:class (stl/css :nitrate-info)} (tr "subscription.banner.create-org-info")] - [:> button* {:variant "primary" - :type "button" - :class (stl/css :nitrate-bottom-button) - :on-click handle-go-to-cc} (tr "nitrate.activation-success.create-org")]]] + handle-go-to-subscription + (mf/use-fn #(st/emit! (rt/nav :settings-subscription)))] - ;; Banner for users without nitrate license - (when (not nitrate?) - [:div {:class (stl/css :nitrate-banner :highlighted)} - [:div {:class (stl/css :nitrate-content)} - [:span {:class (stl/css :nitrate-title)} (tr "subscription.dashboard.banner.unlock-features")]] - [:div {:class (stl/css :nitrate-content)} - [:span {:class (stl/css :nitrate-info)} (tr "subscription.dashboard.banner.unlock-features-description")] - [:> button* {:variant "primary" - :type "button" - :class (stl/css :nitrate-bottom-button) - :on-click handle-click} (if (:subscription profile) - (tr "subscription.dashboard.banner.upgrade-nitrate") - (tr "nitrate.form.try-free"))]]])))) + (mf/with-effect [manual-license?] + (if manual-license? + (->> (dnt/fetch-subscription-warning) + (rx/subs! #(reset! subscription-warning* %))) + (reset! subscription-warning* nil))) + + [:* + ;; TODO add translations for this texts when we have the definitive ones + (if (and nitrate? no-orgs-created? (not show-subscription-warning?)) + ;; Banner for users with active nitrate license but no organizations created + [:div {:class (stl/css :nitrate-banner :highlighted)} + [:div {:class (stl/css :nitrate-content)} + [:span {:class (stl/css :nitrate-title)} (tr "subscription.banner.see-enterprise")]] + [:div {:class (stl/css :nitrate-content)} + [:span {:class (stl/css :nitrate-info)} (tr "subscription.banner.create-org-info")] + [:> button* {:variant "primary" + :type "button" + :class (stl/css :nitrate-bottom-button) + :on-click handle-go-to-cc} (tr "nitrate.activation-success.create-org")]]] + + ;; Banner for users without nitrate license + (when (not nitrate?) + [:div {:class (stl/css :nitrate-banner :highlighted)} + [:div {:class (stl/css :nitrate-content)} + [:span {:class (stl/css :nitrate-title)} (tr "subscription.dashboard.banner.unlock-features")]] + [:div {:class (stl/css :nitrate-content)} + [:span {:class (stl/css :nitrate-info)} (tr "subscription.dashboard.banner.unlock-features-description")] + [:> button* {:variant "primary" + :type "button" + :class (stl/css :nitrate-bottom-button) + :on-click handle-click} (if (:subscription profile) + (tr "subscription.dashboard.banner.upgrade-nitrate") + (tr "nitrate.form.try-free"))]]])) + + ;; Banner for users with nitrate license almost expired or expired + (when show-subscription-warning? + [:div {:class (stl/css :nitrate-banner :highlighted)} + [:div {:class (stl/css :nitrate-content)} + [:span {:class (stl/css :nitrate-title)} + (tr "subscription.dashboard.banner.renew-subscription")]] + [:div {:class (stl/css :nitrate-content)} + [:span {:class (stl/css :nitrate-info)} + (if (neg? days-until-expiry) + (tr "subscription.dashboard.banner.subscription-expired" + expiration-date-text) + (tr "subscription.dashboard.banner.subscription-expire-days" + days-until-expiry + expiration-date-text))] + [:> button* {:variant "primary" + :type "button" + :class (stl/css :nitrate-bottom-button) + :on-click handle-go-to-subscription} + (tr "subscription.dashboard.banner.renew")]]])])) (mf/defc nitrate-current-plan* [{:keys [profile]}] diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 0fd2322113..7a70622ece 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -5812,7 +5812,27 @@ msgstr "Inviting people while on the Unlimited plan" msgid "subscription.dashboard.upgrade-plan.power-up" msgstr "Power up" -#: src/app/main/ui/settings/subscription.cljs:409 +msgid "subscription.dashboard.banner.unlock-features" +msgstr "Unlock Enterprise features" + +msgid "subscription.dashboard.banner.unlock-features-description" +msgstr "Set fine-grained permissions and keep your design operations secure, without compromising the open-source freedom your team already loves." + +msgid "subscription.dashboard.banner.renew-subscription" +msgstr "Renew your subscription" + +msgid "subscription.dashboard.banner.subscription-expire-days" +msgstr "Your Enterprise subscription expires in %s days (%s)" + +msgid "subscription.dashboard.banner.subscription-expired" +msgstr "Your Enterprise subscription has expired. (%s)" + +msgid "subscription.dashboard.banner.renew" +msgstr "Renew" + +msgid "subscription.dashboard.banner.upgrade-nitrate" +msgstr "Get started with Enterprise" + msgid "subscription.error.nitrate.checkout-cancelled" msgstr "Payment was not completed. Try again whenever you're ready." diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 064638ff77..3a4de46821 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -5674,7 +5674,27 @@ msgstr "Invita a personas mientras estás en el plan Unlimited" msgid "subscription.dashboard.upgrade-plan.power-up" msgstr "Mejora" -#: src/app/main/ui/settings/subscription.cljs:409 +msgid "subscription.dashboard.banner.unlock-features" +msgstr "Desbloquea las funciones Enterprise" + +msgid "subscription.dashboard.banner.unlock-features-description" +msgstr "Establece permisos detallados y garantiza la seguridad de tus operaciones de diseño, sin renunciar a la libertad del código abierto que tanto valora tu equipo." + +msgid "subscription.dashboard.banner.renew-subscription" +msgstr "Renueva tu suscripción" + +msgid "subscription.dashboard.banner.subscription-expire-days" +msgstr "Tu suscripción Enterprise caduca en %s días (%s)" + +msgid "subscription.dashboard.banner.subscription-expired" +msgstr "Tu suscripción Enterprise ha caducado. (%s)" + +msgid "subscription.dashboard.banner.renew" +msgstr "Renovar" + +msgid "subscription.dashboard.banner.upgrade-nitrate" +msgstr "Empieza a utilizar Enterprise" + msgid "subscription.error.nitrate.checkout-cancelled" msgstr "El pago no se completó. Inténtalo de nuevo cuando quieras."