♻️ Fix subscriptions inconsistencies

This commit is contained in:
Marina López
2025-08-14 08:52:48 +02:00
committed by Andrey Antukh
parent 2846b80cf7
commit 854f286364
21 changed files with 499 additions and 498 deletions

View File

@@ -1,14 +0,0 @@
[
{
"~:id": "~uf88e52d7-2b77-81fd-8006-23413fafe56c",
"~:name": "The Alpaca team",
"~:total-editors": 3,
"~:total-members": 3
},
{
"~:id": "~u81be1d05-a07b-81d5-8006-3e728bea76fb",
"~:name": "The Quokka team",
"~:total-editors": 1,
"~:total-members": 1
}
]

View File

@@ -0,0 +1,9 @@
{
"~:editors": [
{
"~:id": "~u4f535993-36f9-8135-8006-9b18345c55cd",
"~:name": "Luke Skywalker",
"~:email": "luke@rebels.com"
}
]
}

View File

@@ -0,0 +1,44 @@
{
"~:editors": [
{
"~:id": "~u4f535993-36f9-8135-8006-9b18345c55cd",
"~:name": "Luke Skywalker",
"~:email": "luke@rebels.com"
},
{
"~:id": "~u70a3b232-3722-8008-8006-86646ed3b6af",
"~:name": "Leia Organa",
"~:email": "leia@rebels.com"
},
{
"~:id": "~u81be1d05-a07b-81d5-8006-39095ea4121c",
"~:name": "Han Solo",
"~:email": "han@falcon.com"
},
{
"~:id": "~u96ce2641-e3fd-803a-8006-5e516d034d57",
"~:name": "Darth Vader",
"~:email": "vader@empire.com"
},
{
"~:id": "~uc9aa6cb0-9fb5-80a2-8006-9c3a0783ddc7",
"~:name": "Obi-Wan Kenobi",
"~:email": "obiwan@jedi.com"
},
{
"~:id": "~uf88e52d7-2b77-81fd-8006-234039f9e8db",
"~:name": "Yoda",
"~:email": "yoda@jedi.com"
},
{
"~:id": "~uf88e52d7-2b77-81fd-8006-2341585b061d",
"~:name": "Chewbacca",
"~:email": "chewie@falcon.com"
},
{
"~:id": "~ufa35a73f-fa4f-81f9-8006-a558c4d406b1",
"~:name": "R2-D2",
"~:email": "r2d2@astromech.com"
}
]
}

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1,16 @@
[
{
"~:is-admin": false,
"~:email": "foo@example.com",
"~:team-id": "~udd33ff88-f4e5-8033-8003-8096cc07bdf3",
"~:name": "Princesa Leia",
"~:fullname": "Princesa Leia",
"~:is-owner": false,
"~:modified-at": "~m1713533116365",
"~:can-edit": true,
"~:is-active": true,
"~:id": "~u123456789-0000-0000-0000-abcdefabcdef",
"~:profile-id": "~u123456789-0000-0000-0000-abcdefabcdef",
"~:created-at": "~m1713533116365"
}
]

View File

@@ -39,10 +39,11 @@
"~:is-admin": true, "~:is-admin": true,
"~:can-edit": true "~:can-edit": true
}, },
"~:unique-editors": 1,
"~:subscription": { "~:subscription": {
"~:type": "unlimited", "~:type": "unlimited",
"~:status": "trialing", "~:status": "trialing",
"~:seats": 2 "~:seats": 5
}, },
"~:name": "Second team", "~:name": "Second team",
"~:modified-at": "~m1701164272671", "~:modified-at": "~m1701164272671",

View File

@@ -33,6 +33,7 @@
"fdata/shape-data-type" "fdata/shape-data-type"
] ]
}, },
"~:unique-editors": 1,
"~:permissions": { "~:permissions": {
"~:type": "~:owner", "~:type": "~:owner",
"~:is-owner": true, "~:is-owner": true,
@@ -42,7 +43,7 @@
"~:subscription": { "~:subscription": {
"~:type": "unlimited", "~:type": "unlimited",
"~:status": "trialing", "~:status": "trialing",
"~:seats": 2 "~:seats": 5
}, },
"~:name": "Second team", "~:name": "Second team",
"~:modified-at": "~m1701164272671", "~:modified-at": "~m1701164272671",

View File

@@ -7,8 +7,8 @@ export class SubscriptionProfilePage extends DashboardPage {
await DashboardPage.mockRPC( await DashboardPage.mockRPC(
page, page,
"get-owned-teams", "get-subscription-usage",
"subscription/get-owned-teams.json", "subscription/get-subscription-usage.json",
); );
} }

View File

@@ -19,6 +19,12 @@ test.describe("Subscriptions: dashboard", () => {
"subscription/get-profile-unlimited-subscription.json", "subscription/get-profile-unlimited-subscription.json",
); );
await DashboardPage.mockRPC(
page,
"get-subscription-usage",
"subscription/get-subscription-usage.json",
);
await DashboardPage.mockRPC( await DashboardPage.mockRPC(
page, page,
"get-team-info", "get-team-info",
@@ -55,6 +61,12 @@ test.describe("Subscriptions: dashboard", () => {
"subscription/get-profile-unlimited-subscription.json", "subscription/get-profile-unlimited-subscription.json",
); );
await DashboardPage.mockRPC(
page,
"get-subscription-usage",
"subscription/get-subscription-usage-one-editor.json",
);
await DashboardPage.mockRPC( await DashboardPage.mockRPC(
page, page,
"get-team-info", "get-team-info",
@@ -89,6 +101,12 @@ test.describe("Subscriptions: dashboard", () => {
"subscription/get-profile-unlimited-unpaid-subscription.json", "subscription/get-profile-unlimited-unpaid-subscription.json",
); );
await DashboardPage.mockRPC(
page,
"get-subscription-usage",
"subscription/get-subscription-usage.json",
);
await DashboardPage.mockRPC( await DashboardPage.mockRPC(
page, page,
"get-team-info", "get-team-info",
@@ -123,6 +141,12 @@ test.describe("Subscriptions: dashboard", () => {
"subscription/get-profile-enterprise-canceled-subscription.json", "subscription/get-profile-enterprise-canceled-subscription.json",
); );
await DashboardPage.mockRPC(
page,
"get-subscription-usage",
"subscription/get-subscription-usage.json",
);
await DashboardPage.mockRPC( await DashboardPage.mockRPC(
page, page,
"get-team-info", "get-team-info",
@@ -159,6 +183,12 @@ test.describe("Subscriptions: team members and invitations", () => {
"logged-in-user/get-profile-logged-in.json", "logged-in-user/get-profile-logged-in.json",
); );
await DashboardPage.mockRPC(
page,
"get-subscription-usage",
"subscription/get-subscription-usage.json",
);
await DashboardPage.mockRPC( await DashboardPage.mockRPC(
page, page,
"get-team-info", "get-team-info",
@@ -206,6 +236,12 @@ test.describe("Subscriptions: team members and invitations", () => {
"subscription/get-profile-unlimited-subscription.json", "subscription/get-profile-unlimited-subscription.json",
); );
await DashboardPage.mockRPC(
page,
"get-subscription-usage",
"subscription/get-subscription-usage.json",
);
await DashboardPage.mockRPC( await DashboardPage.mockRPC(
page, page,
"get-team-info", "get-team-info",
@@ -251,7 +287,7 @@ test.describe("Subscriptions: team members and invitations", () => {
).toBeVisible(); ).toBeVisible();
}); });
test("Members tab has warning message when team has more members than subscriptions. Subscribe link is shown for owners.", async ({ test("Members tab has warning message when user has more seats than editors.", async ({
page, page,
}) => { }) => {
await DashboardPage.mockRPC( await DashboardPage.mockRPC(
@@ -260,6 +296,12 @@ test.describe("Subscriptions: team members and invitations", () => {
"subscription/get-profile-unlimited-subscription.json", "subscription/get-profile-unlimited-subscription.json",
); );
await DashboardPage.mockRPC(
page,
"get-subscription-usage",
"subscription/get-subscription-usage-one-editor.json",
);
await DashboardPage.mockRPC( await DashboardPage.mockRPC(
page, page,
"get-team-info", "get-team-info",
@@ -283,97 +325,7 @@ test.describe("Subscriptions: team members and invitations", () => {
await DashboardPage.mockRPC( await DashboardPage.mockRPC(
page, page,
"get-team-members?team-id=*", "get-team-members?team-id=*",
"subscription/get-team-members-subscription-owner.json", "subscription/get-team-members-subscription-one-member.json",
);
await dashboardPage.mockRPC(
"push-audit-events",
"workspace/audit-event-empty.json",
);
await dashboardPage.goToSecondTeamMembersSection();
await expect(page.getByTestId("cta")).toBeVisible();
await expect(page.getByText("Subscribe now.")).toBeVisible();
});
test("Members tab has warning message when team has more members than subscriptions. Contact to owner is shown for members.", async ({
page,
}) => {
await DashboardPage.mockRPC(
page,
"get-profile",
"logged-in-user/get-profile-logged-in.json",
);
await DashboardPage.mockRPC(
page,
"get-team-info",
"subscription/get-team-info-subscriptions.json",
);
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDashboardFull();
await DashboardPage.mockRPC(
page,
"get-teams",
"subscription/get-teams-unlimited-subscription-member.json",
);
await DashboardPage.mockRPC(
page,
"get-projects?team-id=*",
"dashboard/get-projects-second-team.json",
);
await DashboardPage.mockRPC(
page,
"get-team-members?team-id=*",
"subscription/get-team-members-subscription-member.json",
);
await dashboardPage.mockRPC(
"push-audit-events",
"workspace/audit-event-empty.json",
);
await dashboardPage.goToSecondTeamMembersSection();
await expect(page.getByTestId("cta")).toBeVisible();
await expect(page.getByText("Contact with the team owner")).toBeVisible();
});
test("Members tab has warning message when has professional subscription and more than 8 members.", async ({
page,
}) => {
await DashboardPage.mockRPC(
page,
"get-profile",
"logged-in-user/get-profile-logged-in.json",
);
await DashboardPage.mockRPC(
page,
"get-team-info",
"subscription/get-team-info-subscriptions.json",
);
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDashboardFull();
await DashboardPage.mockRPC(
page,
"get-teams",
"subscription/get-teams-professional-subscription-owner.json",
);
await DashboardPage.mockRPC(
page,
"get-projects?team-id=*",
"dashboard/get-projects-second-team.json",
);
await DashboardPage.mockRPC(
page,
"get-team-members?team-id=*",
"subscription/get-team-members-more-than-8.json",
); );
await dashboardPage.mockRPC( await dashboardPage.mockRPC(
@@ -384,13 +336,11 @@ test.describe("Subscriptions: team members and invitations", () => {
await dashboardPage.goToSecondTeamMembersSection(); await dashboardPage.goToSecondTeamMembersSection();
await expect(page.getByTestId("cta")).toBeVisible(); await expect(page.getByTestId("cta")).toBeVisible();
await expect( await expect(
page.getByText( page.getByText("Inviting people while on the unlimited plan"),
"The Professional plan is designed for teams of up to 8 editors (owner, admin, and editor).",
),
).toBeVisible(); ).toBeVisible();
}); });
test("Invitations tab has warning message when team has more members than subscriptions", async ({ test("Invitations tab has warning message when user has more seats than editors.", async ({
page, page,
}) => { }) => {
await DashboardPage.mockRPC( await DashboardPage.mockRPC(
@@ -399,6 +349,12 @@ test.describe("Subscriptions: team members and invitations", () => {
"subscription/get-profile-unlimited-subscription.json", "subscription/get-profile-unlimited-subscription.json",
); );
await DashboardPage.mockRPC(
page,
"get-subscription-usage",
"subscription/get-subscription-usage-one-editor.json",
);
await DashboardPage.mockRPC( await DashboardPage.mockRPC(
page, page,
"get-team-info", "get-team-info",
@@ -422,13 +378,13 @@ test.describe("Subscriptions: team members and invitations", () => {
await DashboardPage.mockRPC( await DashboardPage.mockRPC(
page, page,
"get-team-members?team-id=*", "get-team-members?team-id=*",
"subscription/get-team-members-subscription-owner.json", "subscription/get-team-members-subscription-one-member.json",
); );
await DashboardPage.mockRPC( await DashboardPage.mockRPC(
page, page,
"get-team-invitations?team-id=*", "get-team-invitations?team-id=*",
"dashboard/get-team-invitations-empty.json", "subscription/get-team-invitations.json",
); );
await dashboardPage.mockRPC( await dashboardPage.mockRPC(
@@ -439,64 +395,7 @@ test.describe("Subscriptions: team members and invitations", () => {
await dashboardPage.goToSecondTeamInvitationsSection(); await dashboardPage.goToSecondTeamInvitationsSection();
await expect(page.getByTestId("cta")).toBeVisible(); await expect(page.getByTestId("cta")).toBeVisible();
await expect( await expect(
page.getByText( page.getByText("Inviting people while on the unlimited plan"),
"Looks like your team has grown! Your plan includes 2 seats, but you're now using 3",
),
).toBeVisible();
});
test("Invitations tab has warning message when has professional subscription and more than 8 members.", async ({
page,
}) => {
await DashboardPage.mockRPC(
page,
"get-profile",
"subscription/get-profile-unlimited-subscription.json",
);
await DashboardPage.mockRPC(
page,
"get-team-info",
"subscription/get-team-info-subscriptions.json",
);
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDashboardFull();
await DashboardPage.mockRPC(
page,
"get-teams",
"subscription/get-teams-unlimited-subscription-owner.json",
);
await DashboardPage.mockRPC(
page,
"get-projects?team-id=*",
"dashboard/get-projects-second-team.json",
);
await DashboardPage.mockRPC(
page,
"get-team-members?team-id=*",
"subscription/get-team-members-more-than-8.json",
);
await DashboardPage.mockRPC(
page,
"get-team-invitations?team-id=*",
"dashboard/get-team-invitations-empty.json",
);
await dashboardPage.mockRPC(
"push-audit-events",
"workspace/audit-event-empty.json",
);
await dashboardPage.goToSecondTeamInvitationsSection();
await expect(page.getByTestId("cta")).toBeVisible();
await expect(
page.getByText(
"Looks like your team has grown! Your plan includes 2 seats, but you're now using 9",
),
).toBeVisible(); ).toBeVisible();
}); });
}); });

View File

@@ -22,6 +22,12 @@ test.describe("Subscriptions: workspace", () => {
"subscription/get-profile-unlimited-subscription.json", "subscription/get-profile-unlimited-subscription.json",
); );
await WorkspacePage.mockRPC(
page,
"get-subscription-usage",
"subscription/get-subscription-usage.json",
);
await workspacePage.mockRPC( await workspacePage.mockRPC(
"push-audit-events", "push-audit-events",
"workspace/audit-event-empty.json", "workspace/audit-event-empty.json",
@@ -44,6 +50,12 @@ test.describe("Subscriptions: workspace", () => {
"subscription/get-profile-enterprise-subscription.json", "subscription/get-profile-enterprise-subscription.json",
); );
await WorkspacePage.mockRPC(
page,
"get-subscription-usage",
"subscription/get-subscription-usage.json",
);
await workspacePage.mockRPC( await workspacePage.mockRPC(
"push-audit-events", "push-audit-events",
"workspace/audit-event-empty.json", "workspace/audit-event-empty.json",
@@ -60,6 +72,18 @@ test.describe("Subscriptions: workspace", () => {
const workspacePage = new WorkspacePage(page); const workspacePage = new WorkspacePage(page);
await workspacePage.setupEmptyFile(); await workspacePage.setupEmptyFile();
await WorkspacePage.mockRPC(
page,
"get-profile",
"subscription/get-profile-enterprise-subscription.json",
);
await WorkspacePage.mockRPC(
page,
"get-subscription-usage",
"subscription/get-subscription-usage.json",
);
await workspacePage.mockRPC( await workspacePage.mockRPC(
"push-audit-events", "push-audit-events",
"workspace/audit-event-empty.json", "workspace/audit-event-empty.json",
@@ -90,6 +114,12 @@ test.describe("Subscriptions: workspace", () => {
"subscription/get-profile-unlimited-subscription.json", "subscription/get-profile-unlimited-subscription.json",
); );
await WorkspacePage.mockRPC(
page,
"get-subscription-usage",
"subscription/get-subscription-usage.json",
);
await WorkspacePage.mockRPC( await WorkspacePage.mockRPC(
page, page,
"get-teams", "get-teams",
@@ -126,6 +156,12 @@ test.describe("Subscriptions: workspace", () => {
"subscription/get-profile-enterprise-subscription.json", "subscription/get-profile-enterprise-subscription.json",
); );
await WorkspacePage.mockRPC(
page,
"get-subscription-usage",
"subscription/get-subscription-usage.json",
);
await WorkspacePage.mockRPC( await WorkspacePage.mockRPC(
page, page,
"get-teams", "get-teams",

View File

@@ -91,6 +91,16 @@
ptk/WatchEvent ptk/WatchEvent
(watch [_ _ _] (watch [_ _ _]
(->> (rp/cmd! :get-profile) (->> (rp/cmd! :get-profile)
(rx/mapcat (fn [profile]
(if (and (contains? cf/flags :subscriptions)
(is-authenticated? profile))
(->> (rp/cmd! :get-subscription-usage {})
(rx/map (fn [{:keys [editors]}]
(update-in profile [:props :subscription] assoc :editors editors)))
(rx/catch (fn [cause]
(js/console.error "unexpected error on obtaining subscription usage" cause)
(rx/of profile))))
(rx/of profile))))
(rx/map (partial ptk/data-event ::profile-fetched)) (rx/map (partial ptk/data-event ::profile-fetched))
(rx/catch on-fetch-profile-exception))))) (rx/catch on-fetch-profile-exception)))))

View File

@@ -132,7 +132,7 @@
[:> team-members-page* {:team team :profile profile}] [:> team-members-page* {:team team :profile profile}]
:dashboard-invitations :dashboard-invitations
[:> team-invitations-page* {:team team}] [:> team-invitations-page* {:team team :profile profile}]
:dashboard-webhooks :dashboard-webhooks
[:> webhooks-page* {:team team}] [:> webhooks-page* {:team team}]

View File

@@ -27,7 +27,11 @@
[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 :refer [subscription-sidebar* menu-team-icon* get-subscription-type]] [app.main.ui.dashboard.subscription :refer [subscription-sidebar*
menu-team-icon*
dashboard-cta*
show-subscription-dashboard-banner?
get-subscription-type]]
[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]
@@ -991,7 +995,9 @@
[:* [:*
(when (contains? cf/flags :subscriptions) (when (contains? cf/flags :subscriptions)
[:> subscription-sidebar* {:profile profile}]) (if (show-subscription-dashboard-banner? profile)
[:> dashboard-cta* {:profile profile}]
[:> 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)

View File

@@ -20,7 +20,7 @@
(defn get-subscription-type (defn get-subscription-type
[{:keys [type status] :as subscription}] [{:keys [type status] :as subscription}]
(if (and subscription (not (contains? #{"unpaid" "canceled"} status))) (if (and subscription (:type subscription) (not (contains? #{"unpaid" "canceled"} status)))
type type
"professional")) "professional"))
@@ -61,7 +61,7 @@
[:> cta-power-up* [:> cta-power-up*
{:top-title (tr "subscription.dashboard.power-up.your-subscription") {:top-title (tr "subscription.dashboard.power-up.your-subscription")
:top-description (tr "subscription.dashboard.power-up.professional.top-title") :top-description (tr "subscription.dashboard.power-up.professional.top-title")
:bottom-description (tr "subscription.dashboard.power-up.professional.bottom", subscription-href) :bottom-description (tr "subscription.dashboard.power-up.professional.bottom-text" subscription-href)
:has-dropdown true}] :has-dropdown true}]
"unlimited" "unlimited"
@@ -69,13 +69,13 @@
[:> cta-power-up* [:> cta-power-up*
{:top-title (tr "subscription.dashboard.power-up.your-subscription") {:top-title (tr "subscription.dashboard.power-up.your-subscription")
:top-description (tr "subscription.dashboard.power-up.trial.top-title") :top-description (tr "subscription.dashboard.power-up.trial.top-title")
:bottom-description (tr "subscription.dashboard.power-up.trial.bottom-description", subscription-href) :bottom-description (tr "subscription.dashboard.power-up.trial.bottom-description" subscription-href)
:has-dropdown true}] :has-dropdown true}]
[:> cta-power-up* [:> cta-power-up*
{:top-title (tr "subscription.dashboard.power-up.your-subscription") {:top-title (tr "subscription.dashboard.power-up.your-subscription")
:top-description (tr "subscription.dashboard.power-up.unlimited-plan") :top-description (tr "subscription.dashboard.power-up.unlimited-plan")
:bottom-description (tr "subscription.dashboard.power-up.unlimited.bottom-text", subscription-href) :bottom-description (tr "subscription.dashboard.power-up.unlimited.bottom-text" subscription-href)
:has-dropdown true}]) :has-dropdown true}])
"enterprise" "enterprise"
@@ -147,71 +147,74 @@
[:span {:class (stl/css :item-name)} (tr "subscription.workspace.header.menu.option.power-up")]])) [:span {:class (stl/css :item-name)} (tr "subscription.workspace.header.menu.option.power-up")]]))
(mf/defc members-cta* (mf/defc members-cta*
[{:keys [banner-is-expanded team]}] []
(let [subscription (:subscription team) [:> cta* {:class (stl/css :members-cta)
:title (tr "subscription.dashboard.unlimited-members-extra-editors-cta-title")}
[:> i18n/tr-html*
{:tag-name "span"
:class (stl/css :cta-message)
:content (tr "subscription.dashboard.unlimited-members-extra-editors-cta-text")}]])
(mf/defc dashboard-cta*
[{:keys [profile]}]
(let [subscription (-> profile :props :subscription)
subscription-type (get-subscription-type subscription) subscription-type (get-subscription-type subscription)
is-owner (-> team :permissions :is-owner)
email-owner (:email (some #(when (:is-owner %) %) (: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")) go-to-subscription (dm/str (u/join cf/public-uri "#/settings/subscriptions"))
seats (or (:seats subscription) 0) seats (:quantity subscription)
editors (count (filterv :can-edit (:members team))) editors (count (:editors subscription))
link
(if is-owner
go-to-subscription
mail-to-owner)
cta-title cta-title
(cond (cond
(and (= "professional" subscription-type) (>= editors 8)) (= "professional" subscription-type)
(tr "subscription.dashboard.cta.professional-plan-designed") (tr "subscription.dashboard.professional-dashboard-cta-title" editors)
(and (= "unlimited" subscription-type) (< seats editors)) (= "unlimited" subscription-type)
(tr "subscription.dashboard.cta.unlimited-many-editors" seats editors)) (tr "subscription.dashboard.unlimited-dashboard-cta-title" seats editors))
cta-message cta-message
(cond (cond
(and (= "professional" subscription-type) (>= editors 8) is-owner) (= "professional" subscription-type)
(tr "subscription.dashboard.cta.upgrade-to-unlimited-enterprise-owner" link) (tr "subscription.dashboard.professional-dashboard-cta-upgrade-owner" go-to-subscription)
(and (= "professional" subscription-type) (>= editors 8) (not is-owner)) (= "unlimited" subscription-type)
(tr "subscription.dashboard.cta.upgrade-to-unlimited-enterprise-member" link) (tr "subscription.dashboard.unlimited-dashboard-cta-upgrade-owner" go-to-subscription))]
(and (= "unlimited" subscription-type) (< seats editors) is-owner) [:> cta* {:class (stl/css :dashboard-cta) :title cta-title}
(tr "subscription.dashboard.cta.upgrade-more-seats-owner" link)
(and (= "unlimited" subscription-type) (< seats editors) (not is-owner))
(tr "subscription.dashboard.cta.upgrade-more-seats-member" 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* [:> i18n/tr-html*
{:tag-name "span" {:tag-name "span"
:class (stl/css :cta-message) :class (stl/css :cta-message)
:content cta-message}]])) :content cta-message}]]))
(defn show-subscription-members-main-banner? (defn show-subscription-dashboard-banner?
[team] [profile]
(let [subscription-type (get-subscription-type (:subscription team)) (let [subscription (-> profile :props :subscription)
seats (-> team :subscription :seats) subscription-type (get-subscription-type subscription)
editors (count (filter :can-edit (:members team)))] seats (:quantity subscription)
editors (count (:editors subscription))]
(or (or
(and (= subscription-type "professional") (and (= subscription-type "professional")
(> editors 8)) (> editors 8))
(and (and
(= subscription-type "unlimited") (= subscription-type "unlimited")
(>= editors 8) (or
(< seats editors))))) ;; common: seats < 25 and diff >= 4
(and (< seats 25)
(>= (- editors seats) 4))
;; special: reached 25+ editors, seats < 25 and there is overuse
(and (< seats 25)
(>= editors 25)
(> editors seats)))))))
(defn show-subscription-members-small-banner? (defn show-subscription-members-banner?
[team] [team profile]
(let [subscription-type (get-subscription-type (:subscription team)) (let [subscription (:subscription team)
seats (-> team :subscription :seats) subscription-type (get-subscription-type subscription)
editors (count (filterv :can-edit (:members team)))] seats (:seats subscription)
(or editors (count (-> profile :props :subscription :editors))
(and (= subscription-type "professional") is-owner (-> team :permissions :is-owner)]
(= editors 8)) (and
(and (= subscription-type "unlimited") is-owner
(< editors 8) (= subscription-type "unlimited")
(< seats editors))))) ;; common: seats < 25 and diff >= 4 between editors/seats and there is underuse
(and (< seats 25)
(>= (- seats editors) 4)))))

View File

@@ -143,16 +143,21 @@
.members-cta { .members-cta {
height: fit-content; height: fit-content;
margin-block-start: var(--sp-s); margin-block-start: var(--sp-s);
margin-inline-start: $s-68; margin-inline-start: $s-52;
max-width: $s-200; max-width: $s-220;
.cta-title { .cta-title {
line-height: 1.2; line-height: 1.2;
} }
} }
.members-cta-full-width { .dashboard-cta {
max-width: $s-1000; height: fit-content;
margin: var(--sp-l);
.cta-title {
line-height: 1.2;
}
} }
.cta-message { .cta-message {

View File

@@ -24,8 +24,7 @@
[app.main.ui.dashboard.change-owner] [app.main.ui.dashboard.change-owner]
[app.main.ui.dashboard.subscription :refer [team* [app.main.ui.dashboard.subscription :refer [team*
members-cta* members-cta*
show-subscription-members-main-banner? show-subscription-members-banner?]]
show-subscription-members-small-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]
@@ -541,21 +540,15 @@
[:* [:*
[:& header {:section :dashboard-team-members :team team}] [:& header {:section :dashboard-team-members :team team}]
[:section {:class (stl/css-case [:section {:class (stl/css :dashboard-container :dashboard-team-members)}
:dashboard-container true
:dashboard-team-members true
:dashboard-top-cta (show-subscription-members-main-banner? team))}
(when (and (contains? cfg/flags :subscriptions)
(show-subscription-members-main-banner? team))
[:> members-cta* {:banner-is-expanded true :team team}])
[:> team-members* [:> team-members*
{:profile profile {:profile profile
:team team}] :team team}]
(when (and (when (and (contains? cfg/flags :subscriptions)
(contains? cfg/flags :subscriptions) (show-subscription-members-banner? team profile))
(show-subscription-members-small-banner? team)) [:> members-cta* {:team team}])]])
[:> members-cta* {:banner-is-expanded false :team team}])]])
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; INVITATIONS SECTION ;; INVITATIONS SECTION
@@ -803,7 +796,7 @@
(mf/defc team-invitations-page* (mf/defc team-invitations-page*
{::mf/props :obj} {::mf/props :obj}
[{:keys [team]}] [{:keys [team profile]}]
(mf/with-effect [team] (mf/with-effect [team]
(dom/set-html-title (dom/set-html-title
@@ -818,16 +811,13 @@
[:* [:*
[:& header {:section :dashboard-team-invitations [:& header {:section :dashboard-team-invitations
:team team}] :team team}]
[:section {:class (stl/css-case [:section {:class (stl/css :dashboard-team-invitations)}
:dashboard-team-invitations true
:dashboard-top-cta (show-subscription-members-main-banner? team))}
(when (and (contains? cfg/flags :subscriptions)
(show-subscription-members-main-banner? team))
[:> members-cta* {:banner-is-expanded true :team team}])
[:> invitation-section* {:team team}] [:> invitation-section* {:team team}]
(when (and (contains? cfg/flags :subscriptions) (when (and (contains? cfg/flags :subscriptions)
(show-subscription-members-small-banner? team)) (show-subscription-members-banner? team profile))
[:> members-cta* {:banner-is-expanded false :team team}])]]) [:> members-cta* {:team team}])]])
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; WEBHOOKS SECTION ;; WEBHOOKS SECTION

View File

@@ -293,11 +293,6 @@
scrollbar-gutter: stable; scrollbar-gutter: stable;
} }
.dashboard-team-invitations.dashboard-top-cta {
flex-direction: column;
justify-content: flex-start;
}
.invitations { .invitations {
display: grid; display: grid;
grid-template-rows: auto 1fr; grid-template-rows: auto 1fr;

View File

@@ -7,16 +7,14 @@
[app.main.data.event :as ev] [app.main.data.event :as ev]
[app.main.data.modal :as modal] [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.router :as rt]
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.components.forms :as fm] [app.main.ui.components.forms :as fm]
[app.main.ui.dashboard.subscription :refer [get-subscription-type]] [app.main.ui.dashboard.subscription :refer [get-subscription-type]]
[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 c]]
[app.util.time :as dt] [app.util.time :as dt]
[beicon.v2.core :as rx]
[potok.v2.core :as ptk] [potok.v2.core :as ptk]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
@@ -54,14 +52,15 @@
:on-click cta-link} cta-text]) :on-click cta-link} cta-text])
(when (and cta-link-trial cta-text-trial) [:button {:class (stl/css :cta-button :bottom-link) (when (and cta-link-trial cta-text-trial) [:button {:class (stl/css :cta-button :bottom-link)
:on-click cta-link-trial} cta-text-trial])]) :on-click cta-link-trial} cta-text-trial])])
(def ^:private schema:seats-form (defn schema:seats-form [min-editors]
[:map {:title "SeatsForm"} [:map {:title "SeatsForm"}
[:min-members [::sm/number {:min 1 :max 9999}]]]) [:min-members [::sm/number {:min min-editors
:max 9999}]]])
(mf/defc subscribe-management-dialog (mf/defc subscribe-management-dialog
{::mf/register modal/components {::mf/register modal/components
::mf/register-as :management-dialog} ::mf/register-as :management-dialog}
[{:keys [subscription-type current-subscription teams subscribe-to-trial]}] [{:keys [subscription-type current-subscription editors subscribe-to-trial]}]
(let [subscription-name (if subscribe-to-trial (let [subscription-name (if subscribe-to-trial
(if (= subscription-type "unlimited") (if (= subscription-type "unlimited")
@@ -71,9 +70,10 @@
"professional" (tr "subscription.settings.professional") "professional" (tr "subscription.settings.professional")
"unlimited" (tr "subscription.settings.unlimited") "unlimited" (tr "subscription.settings.unlimited")
"enterprise" (tr "subscription.settings.enterprise"))) "enterprise" (tr "subscription.settings.enterprise")))
initial (mf/with-memo [] min-editors (or (count editors) 1)
{:min-members (or (some->> teams (map :total-editors) (apply max)) 1)}) initial (mf/with-memo [min-editors]
form (fm/use-form :schema schema:seats-form {:min-members min-editors})
form (fm/use-form :schema (schema:seats-form min-editors)
:initial initial) :initial initial)
subscribe-to-unlimited (mf/use-fn subscribe-to-unlimited (mf/use-fn
(fn [form] (fn [form]
@@ -106,7 +106,14 @@
handle-close-dialog (mf/use-fn handle-close-dialog (mf/use-fn
(fn [] (fn []
(st/emit! (ptk/event ::ev/event {::ev/name "close-subscription-modal"})) (st/emit! (ptk/event ::ev/event {::ev/name "close-subscription-modal"}))
(modal/hide!)))] (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)))]
[:div {:class (stl/css :modal-overlay)} [:div {:class (stl/css :modal-overlay)}
[:div {:class (stl/css :modal-dialog)} [:div {:class (stl/css :modal-dialog)}
@@ -115,15 +122,19 @@
(tr "subscription.settings.management.dialog.title" subscription-name)] (tr "subscription.settings.management.dialog.title" subscription-name)]
[:div {:class (stl/css :modal-content)} [:div {:class (stl/css :modal-content)}
(if (seq teams) (when (seq editors)
[:* [:div {:class (stl/css :modal-text)} [:* [:p {:class (stl/css :editors-text)}
(tr "subscription.settings.management.dialog.choose-this-plan")] (tr "subscription.settings.management.dialog.currently-editors-title" (c (count editors)))]
[:ul {:class (stl/css :teams-list)} [:button {:class (stl/css :cta-button :show-editors-button) :on-click handle-click}
(for [team teams] (tr "subscription.settings.management.dialog.editors")
[:li {:key (dm/str (:id team)) :class (stl/css :team-name)} [:span {:class (stl/css :icon-dropdown)} i/arrow]]
(:name team) (tr "subscription.settings.management.dialog.members" (:total-editors team))])]] (when show-editors-list
[:div {:class (stl/css :modal-text)} [:*
(tr "subscription.settings.management.dialog.no-teams")]) [: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)])]])])
(when (and (when (and
(or (and (= subscription-type "professional") (contains? #{"unlimited" "enterprise"} (:type current-subscription))) (or (and (= subscription-type "professional") (contains? #{"unlimited" "enterprise"} (:type current-subscription)))
@@ -138,8 +149,6 @@
[:& fm/form {:on-submit subscribe-to-unlimited [:& fm/form {:on-submit subscribe-to-unlimited
:class (stl/css :seats-form) :class (stl/css :seats-form)
:form form} :form form}
[: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 :editors-wrapper)}
[:div {:class (stl/css :fields-row)} [:div {:class (stl/css :fields-row)}
@@ -149,7 +158,7 @@
:label "" :label ""
:class (stl/css :input-field)}]] :class (stl/css :input-field)}]]
[:div {:class (stl/css :editors-cost)} [:div {:class (stl/css :editors-cost)}
[:span {:class (stl/css :modal-text-small)} [:span {:class (stl/css :modal-text-medium)}
(when (> (get-in @form [:clean-data :min-members]) 25) (when (> (get-in @form [:clean-data :min-members]) 25)
[:> i18n/tr-html* [:> i18n/tr-html*
{:class (stl/css :modal-text-cap) {:class (stl/css :modal-text-cap)
@@ -160,9 +169,16 @@
:tag-name "span" :tag-name "span"
:content (tr "subscription.settings.management.dialog.price-month" :content (tr "subscription.settings.management.dialog.price-month"
(* 7 (or (get-in @form [:clean-data :min-members]) 0)))}]] (* 7 (or (get-in @form [:clean-data :min-members]) 0)))}]]
[:span {:class (stl/css :modal-text-small)} [:span {:class (stl/css :modal-text-medium)}
(tr "subscription.settings.management.dialog.payment-explanation")]]] (tr "subscription.settings.management.dialog.payment-explanation")]]]
(when (get-in @form [:errors :min-members])
[:div {:class (stl/css :error-message)}
(tr "subscription.settings.management.dialog.input-error")])
[:div {:class (stl/css :unlimited-capped-warning)}
(tr "subscription.settings.management.dialog.unlimited-capped-warning")]
[:div {:class (stl/css :modal-footer)} [:div {:class (stl/css :modal-footer)}
[:div {:class (stl/css :action-buttons)} [:div {:class (stl/css :action-buttons)}
[:input [:input
@@ -214,6 +230,8 @@
[:div {:class (stl/css :modal-end)} [:div {:class (stl/css :modal-end)}
[:div {:class (stl/css :modal-title)} (tr "subscription.settings.sucess.dialog.title" subscription-name)] [:div {:class (stl/css :modal-title)} (tr "subscription.settings.sucess.dialog.title" subscription-name)]
(when (not= subscription-name "professional")
[:p {:class (stl/css :modal-text-large)} (tr "subscription.settings.success.dialog.thanks" 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.success.dialog.description")]
[:p {:class (stl/css :modal-text-large)} (tr "subscription.settings.sucess.dialog.footer")] [:p {:class (stl/css :modal-text-large)} (tr "subscription.settings.sucess.dialog.footer")]
@@ -229,9 +247,6 @@
(let [route (mf/deref refs/route) (let [route (mf/deref refs/route)
authenticated? (da/is-authenticated? profile) authenticated? (da/is-authenticated? profile)
teams* (mf/use-state nil)
teams (deref teams*)
locale (mf/deref i18n/locale) locale (mf/deref i18n/locale)
params-subscription params-subscription
@@ -248,6 +263,9 @@
success-modal-is-trial? success-modal-is-trial?
(-> route :params :query :trial) (-> route :params :query :trial)
subscription-editors
(-> profile :props :subscription :editors)
subscription subscription
(-> profile :props :subscription) (-> profile :props :subscription)
@@ -284,7 +302,7 @@
open-subscription-modal open-subscription-modal
(mf/use-fn (mf/use-fn
(mf/deps teams) (mf/deps subscription-editors)
(fn [subscription-type current-subscription] (fn [subscription-type current-subscription]
(st/emit! (ev/event {::ev/name "open-subscription-modal" (st/emit! (ev/event {::ev/name "open-subscription-modal"
::ev/origin "settings:in-app"})) ::ev/origin "settings:in-app"}))
@@ -292,12 +310,7 @@
(modal/show :management-dialog (modal/show :management-dialog
{:subscription-type subscription-type {:subscription-type subscription-type
:current-subscription current-subscription :current-subscription current-subscription
:teams teams :subscribe-to-trial (not subscription)}))))] :editors subscription-editors :subscribe-to-trial (not (:type 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")))
@@ -315,8 +328,8 @@
"unlimited" "unlimited"
"enterprise") "enterprise")
:current-subscription subscription :current-subscription subscription
:teams teams :editors subscription-editors
:subscribe-to-trial (not subscription)}) :subscribe-to-trial (not (:type subscription))})
(rt/nav :settings-subscription {} {::rt/replace true})) (rt/nav :settings-subscription {} {::rt/replace true}))
^boolean show-subscription-success-modal? ^boolean show-subscription-success-modal?
@@ -341,18 +354,18 @@
(case subscription-type (case subscription-type
"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.storage-benefit"),
(tr "subscription.settings.professional.teams-editors"), (tr "subscription.settings.professional.autosave-benefit"),
(tr "subscription.settings.professional.storage-autosave")]}] (tr "subscription.settings.professional.teams-editors-benefit")]}]
"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
:benefits-title (tr "subscription.settings.benefits.all-professional-benefits") :benefits-title (tr "subscription.settings.benefits.all-professional-benefits"),
:benefits [(tr "subscription.settings.unlimited.teams"), :benefits [(tr "subscription.settings.unlimited.storage-benefit")
(tr "subscription.settings.unlimited.bill"), (tr "subscription.settings.unlimited.autosave-benefit"),
(tr "subscription.settings.unlimited.storage-autosave")] (tr "subscription.settings.unlimited.bill")]
: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-text-trial (tr "subscription.settings.add-payment-to-continue")
@@ -362,9 +375,9 @@
[:> 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
:benefits-title (tr "subscription.settings.benefits.all-unlimited-benefits") :benefits-title (tr "subscription.settings.benefits.all-unlimited-benefits")
:benefits [(tr "subscription.settings.unlimited.teams"), :benefits [(tr "subscription.settings.unlimited.storage-benefit"),
(tr "subscription.settings.unlimited.bill"), (tr "subscription.settings.unlimited.autosave-benefit"),
(tr "subscription.settings.unlimited.storage-autosave")] (tr "subscription.settings.unlimited.bill")]
: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
:editors (-> profile :props :subscription :quantity)}]) :editors (-> profile :props :subscription :quantity)}])
@@ -373,18 +386,18 @@
(if subscription-is-trial? (if subscription-is-trial?
[:> plan-card* {:card-title (tr "subscription.settings.enterprise-trial") [:> plan-card* {:card-title (tr "subscription.settings.enterprise-trial")
:card-title-icon i/character-e :card-title-icon i/character-e
:benefits-title (tr "subscription.settings.benefits.all-professional-benefits") :benefits-title (tr "subscription.settings.benefits.all-unlimited-benefits"),
:benefits [(tr "subscription.settings.enterprise.unlimited-storage"), :benefits [(tr "subscription.settings.enterprise.unlimited-storage-benefit"),
(tr "subscription.settings.enterprise.capped-bill"), (tr "subscription.settings.enterprise.autosave"),
(tr "subscription.settings.enterprise.autosave")] (tr "subscription.settings.enterprise.capped-bill")]
: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}]
[:> 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-professional-benefits") :benefits-title (tr "subscription.settings.benefits.all-unlimited-benefits"),
:benefits [(tr "subscription.settings.enterprise.unlimited-storage"), :benefits [(tr "subscription.settings.enterprise.unlimited-storage-benefit"),
(tr "subscription.settings.enterprise.capped-bill"), (tr "subscription.settings.enterprise.autosave"),
(tr "subscription.settings.enterprise.autosave")] (tr "subscription.settings.enterprise.capped-bill")]
: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}]))
@@ -406,9 +419,9 @@
[:> 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.storage-benefit"),
(tr "subscription.settings.professional.teams-editors"), (tr "subscription.settings.professional.autosave-benefit"),
(tr "subscription.settings.professional.storage-autosave")] (tr "subscription.settings.professional.teams-editors-benefit")]
:cta-text (tr "subscription.settings.subscribe") :cta-text (tr "subscription.settings.subscribe")
:cta-link #(open-subscription-modal "professional") :cta-link #(open-subscription-modal "professional")
:cta-text-with-icon (tr "subscription.settings.more-information") :cta-text-with-icon (tr "subscription.settings.more-information")
@@ -420,10 +433,10 @@
: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-professional-benefits") :benefits-title (tr "subscription.settings.benefits.all-professional-benefits")
:benefits [(tr "subscription.settings.unlimited.teams"), :benefits [(tr "subscription.settings.unlimited.storage-benefit"),
(tr "subscription.settings.unlimited.bill"), (tr "subscription.settings.unlimited.autosave-benefit"),
(tr "subscription.settings.unlimited.storage-autosave")] (tr "subscription.settings.unlimited.bill")]
:cta-text (if subscription (tr "subscription.settings.subscribe") (tr "subscription.settings.try-it-free")) :cta-text (if (:type subscription) (tr "subscription.settings.subscribe") (tr "subscription.settings.try-it-free"))
:cta-link #(open-subscription-modal "unlimited" subscription) :cta-link #(open-subscription-modal "unlimited" subscription)
:cta-text-with-icon (tr "subscription.settings.more-information") :cta-text-with-icon (tr "subscription.settings.more-information")
:cta-link-with-icon go-to-pricing-page}]) :cta-link-with-icon go-to-pricing-page}])
@@ -434,10 +447,10 @@
: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-unlimited-benefits") :benefits-title (tr "subscription.settings.benefits.all-unlimited-benefits")
:benefits [(tr "subscription.settings.enterprise.unlimited-storage"), :benefits [(tr "subscription.settings.enterprise.unlimited-storage-benefit"),
(tr "subscription.settings.enterprise.capped-bill"), (tr "subscription.settings.enterprise.autosave"),
(tr "subscription.settings.enterprise.autosave")] (tr "subscription.settings.enterprise.capped-bill")]
:cta-text (if subscription (tr "subscription.settings.subscribe") (tr "subscription.settings.try-it-free")) :cta-text (if (:type subscription) (tr "subscription.settings.subscribe") (tr "subscription.settings.try-it-free"))
:cta-link #(open-subscription-modal "enterprise" subscription) :cta-link #(open-subscription-modal "enterprise" subscription)
:cta-text-with-icon (tr "subscription.settings.more-information") :cta-text-with-icon (tr "subscription.settings.more-information")
:cta-link-with-icon go-to-pricing-page}])]]])) :cta-link-with-icon go-to-pricing-page}])]]]))

View File

@@ -63,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: var(--sp-l); margin-block-end: var(--sp-xxl);
} }
.plan-section-title { .plan-section-title {
@@ -81,7 +81,7 @@
.plan-card-header { .plan-card-header {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
margin-block-end: var(--sp-s); margin-block-end: var(--sp-m);
} }
.plan-card-title-container { .plan-card-title-container {
@@ -135,12 +135,13 @@
} }
.other-subscriptions { .other-subscriptions {
margin-block-start: $s-36; margin-block-start: $s-52;
} }
.cta-button { .cta-button {
@include t.use-typography("body-medium"); @include t.use-typography("body-medium");
@include buttonStyle; @include buttonStyle;
align-items: center;
color: var(--color-accent-tertiary); color: var(--color-accent-tertiary);
display: flex; display: flex;
margin-block-start: var(--sp-m); margin-block-start: var(--sp-m);
@@ -155,6 +156,10 @@
margin-inline-start: var(--sp-xs); margin-inline-start: var(--sp-xs);
} }
.icon-dropdown svg {
transform: rotate(90deg);
}
.bottom-link { .bottom-link {
margin-block-start: var(--sp-xs); margin-block-start: var(--sp-xs);
} }
@@ -168,11 +173,11 @@
display: grid; display: grid;
grid-template-rows: auto 1fr auto; grid-template-rows: auto 1fr auto;
max-height: initial; max-height: initial;
min-width: $s-520; min-width: $s-548;
} }
.modal-dialog.subscription-success { .modal-dialog.subscription-success {
min-width: $s-612; min-width: $s-648;
} }
.close-btn { .close-btn {
@@ -191,12 +196,8 @@
margin-block-end: var(--sp-l); margin-block-end: var(--sp-l);
} }
.modal-text-lage { .modal-text-medium {
@include t.use-typography("body-large"); @include t.use-typography("body-medium");
}
.modal-text-small {
@include t.use-typography("body-small");
} }
.modal-text-cap { .modal-text-cap {
@@ -207,7 +208,7 @@
text-decoration: line-through; text-decoration: line-through;
} }
.modal-text-small strong, .modal-text-medium strong,
.text-strikethrough strong, .text-strikethrough strong,
.modal-text-cap strong { .modal-text-cap strong {
font-weight: $fw700; font-weight: $fw700;
@@ -260,11 +261,21 @@
} }
} }
.teams-list { .editors-text {
list-style-position: inside; @include t.use-typography("body-medium");
list-style-type: disc; margin: 0;
}
.editors-list-warning {
margin-inline-start: var(--sp-xl);
margin-block: var(--sp-s);
}
.editors-list {
@include t.use-typography("body-medium");
list-style-position: inside;
list-style-type: none;
margin-inline-start: var(--sp-xl); margin-inline-start: var(--sp-xl);
margin-block: var(--sp-xxl);
max-height: $s-216; max-height: $s-216;
overflow-y: auto; overflow-y: auto;
} }
@@ -274,11 +285,14 @@
width: $s-80; width: $s-80;
} }
.editors-label { .error-message {
margin-block-start: var(--sp-xxl); @include t.use-typography("body-small");
color: var(--color-foreground-error);
margin-block-start: $s-8;
} }
.editors-wrapper { .editors-wrapper {
align-items: center;
display: flex; display: flex;
gap: var(--sp-xl); gap: var(--sp-xl);
margin-block-start: var(--sp-l); margin-block-start: var(--sp-l);
@@ -288,3 +302,16 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.unlimited-capped-warning {
@include t.use-typography("body-small");
background-color: var(--color-background-tertiary);
border-radius: var(--sp-s);
margin-block-start: $s-40;
padding-block: var(--sp-s);
padding-inline: var(--sp-m);
}
.show-editors-button {
padding-inline: 0;
}

View File

@@ -4275,50 +4275,14 @@ msgstr "Zoom lense increase"
msgid "shortcuts.zoom-selected" msgid "shortcuts.zoom-selected"
msgstr "Zoom to selected" msgstr "Zoom to selected"
#: src/app/main/ui/dashboard/subscription.cljs:154
msgid "subscription.dashboard.cta.professional-plan-designed"
msgstr ""
"The Professional plan is designed for teams of up to 8 editors (owner, "
"admin, and editor)."
#: src/app/main/ui/dashboard/subscription.cljs:160
msgid "subscription.dashboard.cta.unlimited-many-editors"
msgstr ""
"Looks like your team has grown! Your plan includes %s seats, but you're now using %s"
#: src/app/main/ui/dashboard/subscription.cljs:168
#, 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"
#: src/app/main/ui/dashboard/subscription.cljs:165
#, 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.|target:self](%s)"
#: src/app/main/ui/dashboard/subscription.cljs:176
#, markdown
msgid "subscription.dashboard.cta.upgrade-more-seats-owner"
msgstr "Please upgrade to match your usage. [Subscribe now.|target:self](%s)"
#, markdown
msgid "subscription.dashboard.cta.upgrade-more-seats-member"
msgstr "Please upgrade to match your usage. Contact with the team owner: %s"
#: src/app/main/ui/dashboard/subscription.cljs:80 #: src/app/main/ui/dashboard/subscription.cljs:80
msgid "subscription.dashboard.power-up.enterprise-plan" msgid "subscription.dashboard.power-up.enterprise-plan"
msgstr "Enterprise plan" msgstr "Enterprise plan"
#: src/app/main/ui/dashboard/subscription.cljs:60 #: src/app/main/ui/dashboard/subscription.cljs:60
#, markdown #, markdown
msgid "subscription.dashboard.power-up.professional.bottom" msgid "subscription.dashboard.power-up.professional.bottom-text"
msgstr "" msgstr "Get extra storage, file recovery and more for your teams with the Unlimited plan. [Power up!|target:self](%s)"
"Get extra editors and storage, file recovery and more with the Unlimited "
"plan. [Power up|target:self](%s)"
#: src/app/main/ui/dashboard/subscription.cljs:59 #: src/app/main/ui/dashboard/subscription.cljs:59
msgid "subscription.dashboard.power-up.professional.top-title" msgid "subscription.dashboard.power-up.professional.top-title"
@@ -4334,11 +4298,6 @@ msgstr "Subscribe"
msgid "subscription.dashboard.power-up.trial.bottom-description" msgid "subscription.dashboard.power-up.trial.bottom-description"
msgstr "Enjoying your trial? Unlock full access forever.[Subscribe|target:self](%s)" msgstr "Enjoying your trial? Unlock full access forever.[Subscribe|target:self](%s)"
#: src/app/main/ui/dashboard/subscription.cljs:62
#, unused
msgid "subscription.dashboard.power-up.trial.top-description"
msgstr "Extra editors, storage and autosaved version, file backup and more."
#: src/app/main/ui/dashboard/subscription.cljs:67 #: src/app/main/ui/dashboard/subscription.cljs:67
msgid "subscription.dashboard.power-up.trial.top-title" msgid "subscription.dashboard.power-up.trial.top-title"
msgstr "Unlimited plan (trial)" msgstr "Unlimited plan (trial)"
@@ -4353,9 +4312,7 @@ msgstr "Enterprise plan (trial)"
#: src/app/main/ui/dashboard/subscription.cljs:74 #: src/app/main/ui/dashboard/subscription.cljs:74
#, markdown #, markdown
msgid "subscription.dashboard.power-up.unlimited.bottom-text" msgid "subscription.dashboard.power-up.unlimited.bottom-text"
msgstr "" msgstr "Get unlimited storage, extended file recovery and unlimited editors for all your teams at a fixed price. [Take a look at the Enterprise plan.|target:self](%s)"
"Get extra editors, more backup, unlimited storage and more. "
"[Take a look to the Enterprise plan.|target:self](%s)"
#: src/app/main/ui/dashboard/subscription.cljs:70 #: src/app/main/ui/dashboard/subscription.cljs:70
#, unused #, unused
@@ -4379,6 +4336,26 @@ msgstr "Team plan"
msgid "subscription.dashboard.upgrade-plan.power-up" msgid "subscription.dashboard.upgrade-plan.power-up"
msgstr "Power up" msgstr "Power up"
msgid "subscription.dashboard.professional-dashboard-cta-title"
msgstr "You have %s editors across your owned teams, while your professional plan covers up to 8."
#, markdown
msgid "subscription.dashboard.professional-dashboard-cta-upgrade-owner"
msgstr "Please upgrade now to Unlimited or Enterprise to unlock more editors, storage and file recovery. [Subscribe now.|target:self](%s)"
msgid "subscription.dashboard.unlimited-dashboard-cta-title"
msgstr "Your team keeps growing! Your Unlimited plan covers up to %s editors, but you now have %s."
#, markdown
msgid "subscription.dashboard.unlimited-dashboard-cta-upgrade-owner"
msgstr "Please upgrade now to match your current editor count. [Subscribe now.|target:self](%s)"
msgid "subscription.dashboard.unlimited-members-extra-editors-cta-title"
msgstr "Inviting people while on the Unlimited plan"
msgid "subscription.dashboard.unlimited-members-extra-editors-cta-text"
msgstr "Only new editors across your owned teams count towards future billing. A flat $175/month still applies for 25+ editors."
#: src/app/main/ui/settings/sidebar.cljs:116, src/app/main/ui/settings/subscription.cljs:222, src/app/main/ui/settings/subscription.cljs:231 #: src/app/main/ui/settings/sidebar.cljs:116, src/app/main/ui/settings/subscription.cljs:222, src/app/main/ui/settings/subscription.cljs:231
msgid "subscription.labels" msgid "subscription.labels"
msgstr "Subscription" msgstr "Subscription"
@@ -4404,23 +4381,31 @@ msgid "subscription.settings.enterprise-trial"
msgstr "Enterprise (trial)" msgstr "Enterprise (trial)"
#: src/app/main/ui/settings/subscription.cljs:271, src/app/main/ui/settings/subscription.cljs:320 #: src/app/main/ui/settings/subscription.cljs:271, src/app/main/ui/settings/subscription.cljs:320
msgid "subscription.settings.enterprise.unlimited-storage" msgid "subscription.settings.enterprise.unlimited-storage-benefit"
msgstr "Unlimited storage and 90-day autosave versions and file recovery" msgstr "Unlimited storage"
msgid "subscription.settings.enterprise.autosave" msgid "subscription.settings.enterprise.autosave"
msgstr "90-day autosave versions and file recovery" msgstr "90-day autosave versions and file recovery"
#: src/app/main/ui/settings/subscription.cljs:269, src/app/main/ui/settings/subscription.cljs:318 #: src/app/main/ui/settings/subscription.cljs:269, src/app/main/ui/settings/subscription.cljs:318
msgid "subscription.settings.enterprise.capped-bill" msgid "subscription.settings.enterprise.capped-bill"
msgstr "Capped monthly bill" msgstr "Flat monthly bill"
#: src/app/main/ui/dashboard/subscription.cljs:114, src/app/main/ui/settings/subscription.cljs:251, src/app/main/ui/settings/subscription.cljs:262, src/app/main/ui/settings/subscription.cljs:272 #: src/app/main/ui/dashboard/subscription.cljs:114, src/app/main/ui/settings/subscription.cljs:251, src/app/main/ui/settings/subscription.cljs:262, src/app/main/ui/settings/subscription.cljs:272
msgid "subscription.settings.manage-your-subscription" msgid "subscription.settings.manage-your-subscription"
msgstr "Manage your subscription" msgstr "Manage your subscription"
#: src/app/main/ui/settings/subscription.cljs:102 #: src/app/main/ui/settings/subscription.cljs:102
msgid "subscription.settings.management.dialog.choose-this-plan" msgid "subscription.settings.management.dialog.currently-editors-title"
msgstr "You are choosing this plan for:" msgid_plural "subscription.settings.management.dialog.currently-editors-title"
msgstr[0] "Currently, your have %s person across your teams who can edit."
msgstr[1] "Currently, your have %s people across your teams who can edit."
msgid "subscription.settings.management.dialog.editors"
msgstr "Editors"
msgid "subscription.settings.management.dialog.editors-explanation"
msgstr "(Owners, Admin and Editors. Viewers doesn't count as Editors)"
#: src/app/main/ui/settings/subscription.cljs:132 #: src/app/main/ui/settings/subscription.cljs:132
msgid "subscription.settings.management.dialog.downgrade" msgid "subscription.settings.management.dialog.downgrade"
@@ -4428,27 +4413,21 @@ msgstr ""
"Heads up: switching to a lower plan means less storage and shorter backups " "Heads up: switching to a lower plan means less storage and shorter backups "
"and version history." "and version history."
#: src/app/main/ui/settings/subscription.cljs:106
msgid "subscription.settings.management.dialog.members"
msgstr " (%s editors)"
#: src/app/main/ui/settings/subscription.cljs:108
msgid "subscription.settings.management.dialog.no-teams"
msgstr "This plan will apply to all future teams you create or own."
#: src/app/main/ui/settings/subscription.cljs:126 #: src/app/main/ui/settings/subscription.cljs:126
msgid "subscription.settings.management.dialog.payment-explanation" msgid "subscription.settings.management.dialog.payment-explanation"
msgstr "(No payment will be made now)" msgstr "Charged after trial. No credit card required right now."
msgid "subscription.settings.management.dialog.input-error"
msgstr "You can't set fewer editors than you have now. Change the role (editor/admin to viewer) for people who don't actually edit files in the team settings."
msgid "subscription.settings.management.dialog.unlimited-capped-warning"
msgstr "Tip: You can increase your seat count now to stay ahead of invites. At 25+ editors across teams, youll enjoy a flat $175/month."
#: src/app/main/ui/settings/subscription.cljs:124 #: src/app/main/ui/settings/subscription.cljs:124
#, markdown #, markdown
msgid "subscription.settings.management.dialog.price-month" msgid "subscription.settings.management.dialog.price-month"
msgstr "" msgstr ""
"**$%s** per month" "**$%s**/month"
#: src/app/main/ui/settings/subscription.cljs:112
msgid "subscription.settings.management.dialog.select-editors"
msgstr "Select number of editors (seats) you need:"
#: src/app/main/ui/settings/subscription.cljs:97 #: src/app/main/ui/settings/subscription.cljs:97
msgid "subscription.settings.management.dialog.title" msgid "subscription.settings.management.dialog.title"
@@ -4479,16 +4458,16 @@ msgid "subscription.settings.professional"
msgstr "Professional" msgstr "Professional"
#: src/app/main/ui/settings/subscription.cljs:239, src/app/main/ui/settings/subscription.cljs:290 #: src/app/main/ui/settings/subscription.cljs:239, src/app/main/ui/settings/subscription.cljs:290
msgid "subscription.settings.professional.projects-files" msgid "subscription.settings.professional.autosave-benefit"
msgstr "Unlimited projects, files and drafts" msgstr "7-day autosave versions and file recovery"
#: src/app/main/ui/settings/subscription.cljs:241, src/app/main/ui/settings/subscription.cljs:292 #: src/app/main/ui/settings/subscription.cljs:241, src/app/main/ui/settings/subscription.cljs:292
msgid "subscription.settings.professional.storage-autosave" msgid "subscription.settings.professional.storage-benefit"
msgstr "10GB of storage and 7-day autosave versions and file recovery" msgstr "10GB of storage"
#: src/app/main/ui/settings/subscription.cljs:240, src/app/main/ui/settings/subscription.cljs:291 #: src/app/main/ui/settings/subscription.cljs:240, src/app/main/ui/settings/subscription.cljs:291
msgid "subscription.settings.professional.teams-editors" msgid "subscription.settings.professional.teams-editors-benefit"
msgstr "Unlimited teams of up to 8 editors" msgstr "Unlimited teams. Up to 8 editors across your owned teams."
#: src/app/main/ui/settings/subscription.cljs:235 #: src/app/main/ui/settings/subscription.cljs:235
msgid "subscription.settings.section-plan" msgid "subscription.settings.section-plan"
@@ -4505,6 +4484,9 @@ msgstr "Start free trial"
msgid "subscription.settings.subscribe" msgid "subscription.settings.subscribe"
msgstr "Subscribe" msgstr "Subscribe"
msgid "subscription.settings.success.dialog.thanks"
msgstr "Thank your for chosing the Penpot %s plan!"
#: src/app/main/ui/settings/subscription.cljs:167 #: src/app/main/ui/settings/subscription.cljs:167
msgid "subscription.settings.success.dialog.description" msgid "subscription.settings.success.dialog.description"
msgstr "" msgstr ""
@@ -4538,15 +4520,15 @@ msgstr "Unlimited (trial)"
#: src/app/main/ui/settings/subscription.cljs:249, src/app/main/ui/settings/subscription.cljs:260, src/app/main/ui/settings/subscription.cljs:305 #: src/app/main/ui/settings/subscription.cljs:249, src/app/main/ui/settings/subscription.cljs:260, src/app/main/ui/settings/subscription.cljs:305
msgid "subscription.settings.unlimited.bill" msgid "subscription.settings.unlimited.bill"
msgstr "Capped monthly bill" msgstr "Capped monthly bill at $175"
#: src/app/main/ui/settings/subscription.cljs:250, src/app/main/ui/settings/subscription.cljs:261, src/app/main/ui/settings/subscription.cljs:306 #: src/app/main/ui/settings/subscription.cljs:250, src/app/main/ui/settings/subscription.cljs:261, src/app/main/ui/settings/subscription.cljs:306
msgid "subscription.settings.unlimited.storage-autosave" msgid "subscription.settings.unlimited.storage-benefit"
msgstr "25GB of storage and 30-day autosave versions and file recovery" msgstr "25GB of storage"
#: src/app/main/ui/settings/subscription.cljs:248, src/app/main/ui/settings/subscription.cljs:259, src/app/main/ui/settings/subscription.cljs:304 #: src/app/main/ui/settings/subscription.cljs:248, src/app/main/ui/settings/subscription.cljs:259, src/app/main/ui/settings/subscription.cljs:304
msgid "subscription.settings.unlimited.teams" msgid "subscription.settings.unlimited.autosave-benefit"
msgstr "Unlimited teams, no matter your team size" msgstr "30-day autosave versions and file recovery"
#: src/app/main/ui/dashboard/subscription.cljs:133, src/app/main/ui/workspace/main_menu.cljs:928 #: src/app/main/ui/dashboard/subscription.cljs:133, src/app/main/ui/workspace/main_menu.cljs:928
msgid "subscription.workspace.header.menu.option.power-up" msgid "subscription.workspace.header.menu.option.power-up"

View File

@@ -4300,52 +4300,14 @@ msgstr "Incrementar zoom a objetivo"
msgid "shortcuts.zoom-selected" msgid "shortcuts.zoom-selected"
msgstr "Zoom a selección" msgstr "Zoom a selección"
#: src/app/main/ui/dashboard/subscription.cljs:154
msgid "subscription.dashboard.cta.professional-plan-designed"
msgstr ""
"El plan Professional está diseñado para equipos de hasta 8 editores "
"(propietario, administrador y editor)."
#: src/app/main/ui/dashboard/subscription.cljs:160
msgid "subscription.dashboard.cta.unlimited-many-editors"
msgstr ""
"¡Parece que tu equipo ha crecido! Tu plan incluye %s asientos, pero ahora estás usando %s"
#: src/app/main/ui/dashboard/subscription.cljs:168
#, 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"
#: src/app/main/ui/dashboard/subscription.cljs:165
#, 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.|target:self](%s)"
#: src/app/main/ui/dashboard/subscription.cljs:176
#, markdown
msgid "subscription.dashboard.cta.upgrade-more-seats-owner"
msgstr "Por favor, mejóralo para adaptarlo a tu uso. [Suscríbete ahora.|target:self](%s)"
#, markdown
msgid "subscription.dashboard.cta.upgrade-more-seats-member"
msgstr "Por favor, mejóralo para adaptarlo a tu uso. Contacta con el "
"propietario del equipo: %s"
#: src/app/main/ui/dashboard/subscription.cljs:80 #: src/app/main/ui/dashboard/subscription.cljs:80
msgid "subscription.dashboard.power-up.enterprise-plan" msgid "subscription.dashboard.power-up.enterprise-plan"
msgstr "Plan Enterprise" msgstr "Plan Enterprise"
#: src/app/main/ui/dashboard/subscription.cljs:60 #: src/app/main/ui/dashboard/subscription.cljs:60
#, markdown #, markdown
msgid "subscription.dashboard.power-up.professional.bottom" msgid "subscription.dashboard.power-up.professional.bottom-text"
msgstr "" msgstr "Consigue almacenamiento adicional, recuperación de archivos y mucho más para tus equipos con el Plan Unlimited. [Mejóralo!|target:self](%s)"
"Consigue editores y almacenamiento adicionales, recuperación de "
"archivos y mucho más con el Plan Unlimited[Mejóralo|target:self](%s)"
#: src/app/main/ui/dashboard/subscription.cljs:59 #: src/app/main/ui/dashboard/subscription.cljs:59
msgid "subscription.dashboard.power-up.professional.top-title" msgid "subscription.dashboard.power-up.professional.top-title"
@@ -4363,13 +4325,6 @@ msgstr ""
"¿Disfrutas de la prueba? Desbloquea el acceso completo para " "¿Disfrutas de la prueba? Desbloquea el acceso completo para "
"siempre.[Suscríbete|target:self](%s)" "siempre.[Suscríbete|target:self](%s)"
#: src/app/main/ui/dashboard/subscription.cljs:62
#, unused
msgid "subscription.dashboard.power-up.trial.top-description"
msgstr ""
"Editores adicionales, almacenamiento y versión autoguardada, copia de "
"seguridad de archivos y mucho más."
#: src/app/main/ui/dashboard/subscription.cljs:67 #: src/app/main/ui/dashboard/subscription.cljs:67
msgid "subscription.dashboard.power-up.trial.top-title" msgid "subscription.dashboard.power-up.trial.top-title"
msgstr "Plan Unlimited (Prueba)" msgstr "Plan Unlimited (Prueba)"
@@ -4384,9 +4339,7 @@ msgstr "Plan Unlimited"
#: src/app/main/ui/dashboard/subscription.cljs:74 #: src/app/main/ui/dashboard/subscription.cljs:74
#, markdown #, markdown
msgid "subscription.dashboard.power-up.unlimited.bottom-text" msgid "subscription.dashboard.power-up.unlimited.bottom-text"
msgstr "" msgstr "Consigue almacenamiento ilimitado, recuperación extendida de archivos y editores ilimitados para todos tus equipos a un precio fijo. [Echa un ojo al Plan Enterprise|target:self](%s)"
"Consigue editores adicionales, copias de seguridad, almacenamiento ilimitado y mucho más. "
"[Echa un ojo al Plan Enterprise|target:self](%s)"
#: src/app/main/ui/dashboard/subscription.cljs:70 #: src/app/main/ui/dashboard/subscription.cljs:70
#, unused #, unused
@@ -4412,6 +4365,26 @@ msgstr "Plan de equipo"
msgid "subscription.dashboard.upgrade-plan.power-up" msgid "subscription.dashboard.upgrade-plan.power-up"
msgstr "Mejora" msgstr "Mejora"
msgid "subscription.dashboard.professional-dashboard-cta-title"
msgstr "Tienes %s editores en todos tus equipos pero que tu plan profesional cubre hasta 8."
#, markdown
msgid "subscription.dashboard.professional-dashboard-cta-upgrade-owner"
msgstr "Mejora ahora tu plan a Unlimited o Enterprise para desbloquear más editores, almacenamiento y recuperación de archivos. [Suscríbete ahora.|target:self](%s)"
msgid "subscription.dashboard.unlimited-dashboard-cta-title"
msgstr "¡Tu equipo sigue creciendo! Tu plan Unlimited cubre hasta %s editores pero ya tienes %s."
#, markdown
msgid "subscription.dashboard.unlimited-dashboard-cta-upgrade-owner"
msgstr "Por favor, actualiza ahora para ajustar el número actual de editores. [Suscríbete ahora.|target:self](%s)"
msgid "subscription.dashboard.unlimited-members-extra-editors-cta-title"
msgstr "Invita a personas mientras estás en el plan Unlimited"
msgid "subscription.dashboard.unlimited-members-extra-editors-cta-text"
msgstr "Solo los nuevos editores de tus equipos se tendrán en cuenta para la facturación futura. Se seguirá aplicando una tarifa plana de 175$/mes para 25+ editores."
#: src/app/main/ui/settings/sidebar.cljs:116, src/app/main/ui/settings/subscription.cljs:222, src/app/main/ui/settings/subscription.cljs:231 #: src/app/main/ui/settings/sidebar.cljs:116, src/app/main/ui/settings/subscription.cljs:222, src/app/main/ui/settings/subscription.cljs:231
msgid "subscription.labels" msgid "subscription.labels"
msgstr "Suscripción" msgstr "Suscripción"
@@ -4437,23 +4410,31 @@ msgid "subscription.settings.enterprise-trial"
msgstr "Enterprise (prueba)" msgstr "Enterprise (prueba)"
#: src/app/main/ui/settings/subscription.cljs:271, src/app/main/ui/settings/subscription.cljs:320 #: src/app/main/ui/settings/subscription.cljs:271, src/app/main/ui/settings/subscription.cljs:320
msgid "subscription.settings.enterprise.unlimited-storage" msgid "subscription.settings.enterprise.unlimited-storage-benefit"
msgstr "Almacenamiento ilimitado y versiones de autoguardado de 90 días y recuperación de archivos" msgstr "Almacenamiento ilimitado"
msgid "subscription.settings.enterprise.autosave" msgid "subscription.settings.enterprise.autosave"
msgstr "Versiones guardadas automáticamente cada 90 días y recuperación de archivos" msgstr "Versiones guardadas automáticamente cada 90 días y recuperación de archivos"
#: src/app/main/ui/settings/subscription.cljs:269, src/app/main/ui/settings/subscription.cljs:318 #: src/app/main/ui/settings/subscription.cljs:269, src/app/main/ui/settings/subscription.cljs:318
msgid "subscription.settings.enterprise.capped-bill" msgid "subscription.settings.enterprise.capped-bill"
msgstr "Factura mensual limitada" msgstr "Factura mensual fija"
#: src/app/main/ui/dashboard/subscription.cljs:114, src/app/main/ui/settings/subscription.cljs:251, src/app/main/ui/settings/subscription.cljs:262, src/app/main/ui/settings/subscription.cljs:272 #: src/app/main/ui/dashboard/subscription.cljs:114, src/app/main/ui/settings/subscription.cljs:251, src/app/main/ui/settings/subscription.cljs:262, src/app/main/ui/settings/subscription.cljs:272
msgid "subscription.settings.manage-your-subscription" msgid "subscription.settings.manage-your-subscription"
msgstr "Gestionar tu suscripción" msgstr "Gestionar tu suscripción"
#: src/app/main/ui/settings/subscription.cljs:102 #: src/app/main/ui/settings/subscription.cljs:102
msgid "subscription.settings.management.dialog.choose-this-plan" msgid "subscription.settings.management.dialog.currently-editors-title"
msgstr "Estás eligiendo este plan para:" msgid_plural "subscription.settings.management.dialog.currently-editors-title"
msgstr[0] "Actualmente hay %s persona en tus equipos que pueden editar."
msgstr[1] "Actualmente hay %s personas en tus equipos que pueden editar."
msgid "subscription.settings.management.dialog.editors"
msgstr "Editores"
msgid "subscription.settings.management.dialog.editors-explanation"
msgstr "(Propietarios, administradores y editores. Los lectores no cuentan como editores)."
#: src/app/main/ui/settings/subscription.cljs:132 #: src/app/main/ui/settings/subscription.cljs:132
msgid "subscription.settings.management.dialog.downgrade" msgid "subscription.settings.management.dialog.downgrade"
@@ -4461,27 +4442,21 @@ msgstr ""
"Ten en cuenta: cambiar a un plan inferior significa menos almacenamiento y " "Ten en cuenta: cambiar a un plan inferior significa menos almacenamiento y "
"copias de seguridad e historial de versiones más cortos." "copias de seguridad e historial de versiones más cortos."
#: src/app/main/ui/settings/subscription.cljs:106
msgid "subscription.settings.management.dialog.members"
msgstr " (%s editores)"
#: src/app/main/ui/settings/subscription.cljs:108
msgid "subscription.settings.management.dialog.no-teams"
msgstr "Este plan se aplicará a todos los futuros equipos que crees o poseas."
#: src/app/main/ui/settings/subscription.cljs:126 #: src/app/main/ui/settings/subscription.cljs:126
msgid "subscription.settings.management.dialog.payment-explanation" msgid "subscription.settings.management.dialog.payment-explanation"
msgstr "(Ahora no se efectuará ningún pago)" msgstr "Se cobrar después del período de prueba. No se requiere tarjeta de crédito en este momento."
msgid "subscription.settings.management.dialog.input-error"
msgstr "No puedes establecer menos editores de los que tienes ahora. Cambia el rol (de editor/administrador a lector) para las personas que realmente no editan archivos en la configuración del equipo."
msgid "subscription.settings.management.dialog.unlimited-capped-warning"
msgstr "Consejo: Puedes aumentar ahora el número de asientos para adelantarte a las invitaciones. Con más de 25 editores en todos tus equipos, disfrutarás de una tarifa plana de 175 $ al mes."
#: src/app/main/ui/settings/subscription.cljs:124 #: src/app/main/ui/settings/subscription.cljs:124
#, markdown #, markdown
msgid "subscription.settings.management.dialog.price-month" msgid "subscription.settings.management.dialog.price-month"
msgstr "" msgstr ""
"**$%s** por mes" "**$%s**/mes"
#: src/app/main/ui/settings/subscription.cljs:112
msgid "subscription.settings.management.dialog.select-editors"
msgstr "Seleccione el número de editores (puestos) que necesitas:"
#: src/app/main/ui/settings/subscription.cljs:97 #: src/app/main/ui/settings/subscription.cljs:97
msgid "subscription.settings.management.dialog.title" msgid "subscription.settings.management.dialog.title"
@@ -4508,16 +4483,16 @@ msgid "subscription.settings.professional"
msgstr "Professional" msgstr "Professional"
#: src/app/main/ui/settings/subscription.cljs:239, src/app/main/ui/settings/subscription.cljs:290 #: src/app/main/ui/settings/subscription.cljs:239, src/app/main/ui/settings/subscription.cljs:290
msgid "subscription.settings.professional.projects-files" msgid "subscription.settings.professional.autosave-benefit"
msgstr "Proyectos, archivos y borradores ilimitados" msgstr "Versiones con autoguardado de 7 días y recuperación de archivos"
#: src/app/main/ui/settings/subscription.cljs:241, src/app/main/ui/settings/subscription.cljs:292 #: src/app/main/ui/settings/subscription.cljs:241, src/app/main/ui/settings/subscription.cljs:292
msgid "subscription.settings.professional.storage-autosave" msgid "subscription.settings.professional.storage-benefit"
msgstr "10 GB de almacenamiento y versiones de autoguardado de 7 días y recuperación de archivos" msgstr "10 GB de almacenamiento"
#: src/app/main/ui/settings/subscription.cljs:240, src/app/main/ui/settings/subscription.cljs:291 #: src/app/main/ui/settings/subscription.cljs:240, src/app/main/ui/settings/subscription.cljs:291
msgid "subscription.settings.professional.teams-editors" msgid "subscription.settings.professional.teams-editors-benefit"
msgstr "Equipos ilimitados de hasta 8 redactores" msgstr "Equipos ilimitados. Hasta 8 editores en todos tus equipos."
#: src/app/main/ui/settings/subscription.cljs:235 #: src/app/main/ui/settings/subscription.cljs:235
msgid "subscription.settings.section-plan" msgid "subscription.settings.section-plan"
@@ -4534,6 +4509,9 @@ msgstr "Comenzar prueba gratuita"
msgid "subscription.settings.subscribe" msgid "subscription.settings.subscribe"
msgstr "Suscríbete" msgstr "Suscríbete"
msgid "subscription.settings.success.dialog.thanks"
msgstr "¡Gracias por elegir el plan %s de Penpot!"
#: src/app/main/ui/settings/subscription.cljs:167 #: src/app/main/ui/settings/subscription.cljs:167
msgid "subscription.settings.success.dialog.description" msgid "subscription.settings.success.dialog.description"
msgstr "" msgstr ""
@@ -4566,17 +4544,16 @@ msgstr "Unlimited (prueba)"
#: src/app/main/ui/settings/subscription.cljs:249, src/app/main/ui/settings/subscription.cljs:260, src/app/main/ui/settings/subscription.cljs:305 #: src/app/main/ui/settings/subscription.cljs:249, src/app/main/ui/settings/subscription.cljs:260, src/app/main/ui/settings/subscription.cljs:305
msgid "subscription.settings.unlimited.bill" msgid "subscription.settings.unlimited.bill"
msgstr "Factura mensual limitada" msgstr "Factura mensual limitada en $175"
#: src/app/main/ui/settings/subscription.cljs:250, src/app/main/ui/settings/subscription.cljs:261, src/app/main/ui/settings/subscription.cljs:306 #: src/app/main/ui/settings/subscription.cljs:250, src/app/main/ui/settings/subscription.cljs:261, src/app/main/ui/settings/subscription.cljs:306
msgid "subscription.settings.unlimited.storage-autosave" msgid "subscription.settings.unlimited.storage-benefit"
msgstr "" msgstr ""
"25 GB de almacenamiento y 30 días de autoguardado de versiones y recuperación " "25 GB de almacenamiento"
"de archivos"
#: src/app/main/ui/settings/subscription.cljs:248, src/app/main/ui/settings/subscription.cljs:259, src/app/main/ui/settings/subscription.cljs:304 #: src/app/main/ui/settings/subscription.cljs:248, src/app/main/ui/settings/subscription.cljs:259, src/app/main/ui/settings/subscription.cljs:304
msgid "subscription.settings.unlimited.teams" msgid "subscription.settings.unlimited.autosave-benefit"
msgstr "Equipos ilimitados, independientemente de su tamaño" msgstr "Versiones con autoguardado de 30 días y recuperación de archivos"
#: src/app/main/ui/dashboard/subscription.cljs:133, src/app/main/ui/workspace/main_menu.cljs:928 #: src/app/main/ui/dashboard/subscription.cljs:133, src/app/main/ui/workspace/main_menu.cljs:928
msgid "subscription.workspace.header.menu.option.power-up" msgid "subscription.workspace.header.menu.option.power-up"