poetry-jumpstart_pro 0.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +14 -0
- data/LICENSE.txt +21 -0
- data/README.md +119 -0
- data/lib/generators/poetry_jumpstart_pro/install/files/poetry_jumpstart_pro_helper.rb +41 -0
- data/lib/generators/poetry_jumpstart_pro/install/install_generator.rb +196 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/accounts/account/passwords/edit.html.erb +46 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/accounts/account_invitations/show.html.erb +29 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/accounts/account_users/_form.html.erb +20 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/accounts/account_users/edit.html.erb +34 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/accounts/accounts/_form.html.erb +26 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/accounts/accounts/account_invitations/edit.html.erb +49 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/accounts/accounts/account_invitations/new.html.erb +37 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/accounts/accounts/edit.html.erb +51 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/accounts/accounts/index.html.erb +56 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/accounts/accounts/new.html.erb +18 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/accounts/accounts/show.html.erb +102 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/accounts/accounts/transfers/_form.html.erb +30 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/accounts/application/_account_navbar.html.erb +40 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/announcements/announcements/_announcement.html.erb +28 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/announcements/announcements/index.html.erb +50 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/announcements/announcements/show.html.erb +32 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/api_tokens/api_tokens/_form.html.erb +39 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/api_tokens/api_tokens/edit.html.erb +16 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/api_tokens/api_tokens/index.html.erb +48 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/api_tokens/api_tokens/new.html.erb +15 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/api_tokens/api_tokens/show.html.erb +69 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/auth/application/_error_messages.html.erb +17 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/auth/users/passwords/edit.html.erb +23 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/auth/users/passwords/new.html.erb +26 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/auth/users/registrations/edit.html.erb +103 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/auth/users/registrations/new.html.erb +55 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/auth/users/sessions/new.html.erb +39 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/auth/users/sessions/otps/new.html.erb +24 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/auth/users/shared/_oauth.html.erb +22 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/auth/users/sudo/new.html.erb +31 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/auth/users/two_factor/verify.html.erb +53 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/billing/billing/_charges.html.erb +45 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/billing/billing/_email.html.erb +15 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/billing/billing/_info.html.erb +30 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/billing/billing/show.html.erb +26 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/billing/billing/subscriptions/_plan.html.erb +33 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/billing/billing/subscriptions/_subscription.html.erb +74 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/billing/billing/subscriptions/_summary.html.erb +21 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/billing/billing/subscriptions/cancels/show.html.erb +46 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/billing/billing/subscriptions/edit.html.erb +65 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/billing/billing/subscriptions/paddle_billing/edit.html.erb +17 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/billing/billing/subscriptions/payment_methods/forms/_fake_processor.html.erb +6 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/billing/billing/subscriptions/payment_methods/new.html.erb +26 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/billing/billing/subscriptions/resumes/show.html.erb +29 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/billing/billing/subscriptions/upcomings/show.html.erb +67 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/billing/pricing/show.html.erb +61 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/checkouts/checkouts/_testimonial.html.erb +15 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/checkouts/checkouts/show.html.erb +125 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/dashboard/dashboard/show.html.erb +60 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/errors/errors/404.html.erb +12 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/errors/errors/500.html.erb +12 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/errors/errors/show.html.erb +16 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/madmin/madmin/dashboard/show.html.erb +40 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/madmin/madmin/fields/array_field/_form.html.erb +29 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/madmin/madmin/fields/array_field/_index.html.erb +13 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/madmin/madmin/fields/array_field/_show.html.erb +13 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/notifications/notifications/_notification.html.erb +12 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/notifications/notifications/index.html.erb +31 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/notifications/notifications/nav.html.erb +17 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/public/public/about.html.erb +32 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/public/public/index.html.erb +71 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/public/public/privacy.html.erb +37 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/public/public/terms.html.erb +37 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/shell/application/_account_menu.html.erb +41 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/shell/application/_dev_menu.html.erb +13 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/shell/application/_flash.html.erb +37 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/shell/application/_footer.html.erb +18 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/shell/application/_left_nav.html.erb +11 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/shell/application/_navbar.html+native.erb +36 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/shell/application/_navbar.html.erb +32 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/shell/application/_notifications.html.erb +26 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/shell/application/_right_nav.html.erb +6 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/shell/application/_user_menu.html.erb +34 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/users/users/_user.html.erb +9 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/users/users/agreements/show.html.erb +33 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/users/users/connected_accounts/_connected_account.html.erb +25 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/users/users/connected_accounts/index.html.erb +34 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/users/users/referrals/index.html.erb +49 -0
- data/lib/generators/poetry_jumpstart_pro/install/templates/users/users/two_factor/backup_codes.html.erb +32 -0
- data/lib/poetry/jumpstart_pro/css_scanner.rb +121 -0
- data/lib/poetry/jumpstart_pro/engine.rb +15 -0
- data/lib/poetry/jumpstart_pro/stylesheets.rb +155 -0
- data/lib/poetry/jumpstart_pro/test_edits.rb +51 -0
- data/lib/poetry/jumpstart_pro/version.rb +8 -0
- data/lib/poetry/jumpstart_pro.rb +43 -0
- metadata +194 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<%# Poetry recreation of Jumpstart's billing/subscriptions/cancels/show: the
|
|
2
|
+
destructive-panel pattern. The DELETE form keeps the engine's route; the
|
|
3
|
+
confirmation is an AlertDialog whose destructive action submits that form
|
|
4
|
+
(form= attribute) in place of the engine's data-turbo-confirm. %>
|
|
5
|
+
<% content_for :title, t(".title") %>
|
|
6
|
+
|
|
7
|
+
<% support_href = "mailto:#{Jumpstart.config.support_email}?subject=#{ERB::Util.url_encode(t(".subject", product: Jumpstart.config.application_name))}" %>
|
|
8
|
+
|
|
9
|
+
<div class="flex max-w-xl flex-col gap-8">
|
|
10
|
+
<header class="flex flex-col gap-1">
|
|
11
|
+
<h1 class="text-2xl font-semibold tracking-tight"><%= t(".title") %></h1>
|
|
12
|
+
<p class="text-sm text-muted-foreground"><%= t(".description", product: Jumpstart.config.application_name) %></p>
|
|
13
|
+
</header>
|
|
14
|
+
|
|
15
|
+
<%= poetry_card do |card| %>
|
|
16
|
+
<%= render partial: "billing/subscriptions/summary", locals: { subscription: @subscription, heading_tag: :h2 } %>
|
|
17
|
+
<% end %>
|
|
18
|
+
|
|
19
|
+
<section class="flex flex-col gap-4 rounded-lg border border-destructive/50 p-6" aria-labelledby="cancel-plan-title">
|
|
20
|
+
<h2 id="cancel-plan-title" class="sr-only"><%= t(".button") %></h2>
|
|
21
|
+
|
|
22
|
+
<%= poetry_alert(variant: :destructive) do |alert| %>
|
|
23
|
+
<% alert.with_icon(name: :"triangle-alert") %>
|
|
24
|
+
<% alert.with_title { @subscription.metered? ? t(".cancel_immediately") : t(".active_until") } %>
|
|
25
|
+
<% end %>
|
|
26
|
+
|
|
27
|
+
<div class="flex flex-col gap-2 text-sm text-muted-foreground">
|
|
28
|
+
<p><%= t(".resume") %></p>
|
|
29
|
+
<p><%= t(".help_html", link: poetry_link(href: support_href) { t(".contact_us") }) %></p>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<%= form_with url: billing_subscription_cancel_path(@subscription), method: :delete, id: "cancel-subscription-form" do |f| %><% end %>
|
|
33
|
+
|
|
34
|
+
<div class="flex flex-wrap items-center justify-between gap-3">
|
|
35
|
+
<%= poetry_button(variant: :outline, href: billing_path) { t(".back") } %>
|
|
36
|
+
|
|
37
|
+
<%= poetry_alert_dialog do |dialog| %>
|
|
38
|
+
<% dialog.with_trigger(variant: :destructive) { t(".button") } %>
|
|
39
|
+
<% dialog.with_title { t("are_you_sure") } %>
|
|
40
|
+
<% dialog.with_description { @subscription.metered? ? t(".cancel_immediately") : t(".active_until") } %>
|
|
41
|
+
<% dialog.with_cancel { t(".keep_plan", default: "Keep my plan") } %>
|
|
42
|
+
<% dialog.with_action(variant: :destructive, type: :submit, form: "cancel-subscription-form", data: { turbo_submits_with: t(".processing") }) { t(".button") } %>
|
|
43
|
+
<% end %>
|
|
44
|
+
</div>
|
|
45
|
+
</section>
|
|
46
|
+
</div>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<%# Poetry recreation of Jumpstart's billing/subscriptions/edit (change plan).
|
|
2
|
+
The pricing Stimulus controller with its targets, actions and class
|
|
3
|
+
values, the data-turbo-prefetch guard and the per-plan PATCH form (hidden
|
|
4
|
+
plan param, data-turbo-confirm) are the switcher contract - kept. The
|
|
5
|
+
plan cards come from billing/subscriptions/_plan. %>
|
|
6
|
+
<% content_for :title, t(".title") %>
|
|
7
|
+
|
|
8
|
+
<div class="mx-auto w-full max-w-5xl px-4 py-10 lg:px-6">
|
|
9
|
+
<% if @subscription.on_trial? %>
|
|
10
|
+
<%= poetry_alert(class: "mb-8") do |alert| %>
|
|
11
|
+
<% alert.with_icon(name: :clock) %>
|
|
12
|
+
<% alert.with_title { t(".trial_ends", days: time_ago_in_words(@subscription.trial_ends_at)) } %>
|
|
13
|
+
<% end %>
|
|
14
|
+
<% end %>
|
|
15
|
+
|
|
16
|
+
<header class="flex flex-col items-center gap-2 text-center">
|
|
17
|
+
<h1 class="text-3xl font-semibold tracking-tight"><%= t(".title") %></h1>
|
|
18
|
+
<p class="text-lg text-muted-foreground"><%= t(".description") %></p>
|
|
19
|
+
</header>
|
|
20
|
+
|
|
21
|
+
<div data-controller="pricing"
|
|
22
|
+
data-pricing-frequency-value="<%= @subscription.plan&.yearly? ? "yearly" : "monthly" %>"
|
|
23
|
+
data-pricing-active-frequency-class="bg-background text-foreground shadow-xs"
|
|
24
|
+
data-pricing-inactive-frequency-class="text-muted-foreground"
|
|
25
|
+
data-pricing-inactive-plans-class="hidden"
|
|
26
|
+
data-pricing-hidden-toggle-class="hidden"
|
|
27
|
+
class="mt-10 flex flex-col items-center gap-8">
|
|
28
|
+
<div data-pricing-target="toggle" role="group" aria-label="<%= t(".billing_interval", default: "Billing interval") %>" class="hidden flex items-center gap-1 rounded-full border bg-muted p-1">
|
|
29
|
+
<%= poetry_button(variant: :ghost, size: :sm, class: "rounded-full", data: { action: "pricing#switch", pricing_target: "frequency", frequency: "monthly" }) { t(".monthly") } %>
|
|
30
|
+
<%= poetry_button(variant: :ghost, size: :sm, class: "rounded-full", data: { action: "pricing#switch", pricing_target: "frequency", frequency: "yearly" }) { t(".yearly") } %>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<div data-turbo-prefetch="false" class="w-full">
|
|
34
|
+
<div data-pricing-target="plans" data-frequency="monthly" class="<%= class_names("grid gap-6 sm:grid-cols-2 lg:grid-cols-none lg:grid-flow-col lg:auto-cols-fr", "mx-auto max-w-sm sm:grid-cols-1": @monthly_plans.one?) %>">
|
|
35
|
+
<% @monthly_plans.each do |plan| %>
|
|
36
|
+
<%= render layout: "billing/subscriptions/plan", locals: { plan: plan } do %>
|
|
37
|
+
<% if @subscription.plan == plan %>
|
|
38
|
+
<%= poetry_button(variant: :outline, disabled: true, class: "w-full") { t(".current_plan") } %>
|
|
39
|
+
<% else %>
|
|
40
|
+
<%= form_with url: billing_subscription_url(@subscription), method: :patch do |f| %>
|
|
41
|
+
<%= f.hidden_field :plan, value: plan.to_param %>
|
|
42
|
+
<%= poetry_button(type: :submit, variant: :outline, class: "w-full", data: { turbo_submits_with: t(".processing"), turbo_confirm: t("are_you_sure") }) { t(".change_plan") } %>
|
|
43
|
+
<% end %>
|
|
44
|
+
<% end %>
|
|
45
|
+
<% end %>
|
|
46
|
+
<% end %>
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<div data-pricing-target="plans" data-frequency="yearly" class="<%= class_names("hidden grid gap-6 sm:grid-cols-2 lg:grid-cols-none lg:grid-flow-col lg:auto-cols-fr", "mx-auto max-w-sm sm:grid-cols-1": @yearly_plans.one?) %>">
|
|
50
|
+
<% @yearly_plans.each do |plan| %>
|
|
51
|
+
<%= render layout: "billing/subscriptions/plan", locals: { plan: plan } do %>
|
|
52
|
+
<% if @subscription.plan == plan %>
|
|
53
|
+
<%= poetry_button(variant: :outline, disabled: true, class: "w-full") { t(".current_plan") } %>
|
|
54
|
+
<% else %>
|
|
55
|
+
<%= form_with url: billing_subscription_url(@subscription), method: :patch do |f| %>
|
|
56
|
+
<%= f.hidden_field :plan, value: plan.to_param %>
|
|
57
|
+
<%= poetry_button(type: :submit, variant: :outline, class: "w-full", data: { turbo_submits_with: t(".processing"), turbo_confirm: t("are_you_sure") }) { t(".change_plan") } %>
|
|
58
|
+
<% end %>
|
|
59
|
+
<% end %>
|
|
60
|
+
<% end %>
|
|
61
|
+
<% end %>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<%# Poetry recreation of Jumpstart's billing/subscriptions/paddle_billing/edit:
|
|
2
|
+
the page Paddle Billing renders its update/cancel flow into. The
|
|
3
|
+
paddle--billing controller element is processor wiring - kept verbatim;
|
|
4
|
+
only the surrounding surface and the back button are restyled. %>
|
|
5
|
+
<div class="mx-auto w-full max-w-2xl px-4 py-10 lg:px-6">
|
|
6
|
+
<%= poetry_card(content_class: "flex flex-col items-center gap-6 text-center") do |card| %>
|
|
7
|
+
<%= tag.div data: {
|
|
8
|
+
controller: "paddle--billing",
|
|
9
|
+
paddle__billing_environment_value: Pay::PaddleBilling.environment,
|
|
10
|
+
paddle__billing_client_token_value: Pay::PaddleBilling.client_token,
|
|
11
|
+
} %>
|
|
12
|
+
|
|
13
|
+
<div>
|
|
14
|
+
<%= poetry_button(variant: :outline, href: billing_path) { t("back") } %>
|
|
15
|
+
</div>
|
|
16
|
+
<% end %>
|
|
17
|
+
</div>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<%# Poetry recreation of Jumpstart's billing/subscriptions/payment_methods/new:
|
|
2
|
+
the payment-details page (Stripe, Paddle and Lemon Squeezy customers are
|
|
3
|
+
redirected by the controller before this renders). Same processor
|
|
4
|
+
partials and conditions as the engine. %>
|
|
5
|
+
<% content_for :title, t(".title") %>
|
|
6
|
+
|
|
7
|
+
<div class="flex flex-col gap-6">
|
|
8
|
+
<header class="flex flex-col gap-3">
|
|
9
|
+
<%= poetry_breadcrumb do |crumb| %>
|
|
10
|
+
<% crumb.with_item(t(".billing"), href: billing_path) %>
|
|
11
|
+
<% crumb.with_item(t(".title")) %>
|
|
12
|
+
<% end %>
|
|
13
|
+
<h1 class="text-2xl font-semibold tracking-tight"><%= t(".title") %></h1>
|
|
14
|
+
</header>
|
|
15
|
+
|
|
16
|
+
<% if @subscription.past_due? || @subscription.unpaid? %>
|
|
17
|
+
<%= poetry_alert(variant: :destructive) do |alert| %>
|
|
18
|
+
<% alert.with_icon(name: :"triangle-alert") %>
|
|
19
|
+
<% alert.with_title { t(".past_due") } %>
|
|
20
|
+
<% end %>
|
|
21
|
+
<% end %>
|
|
22
|
+
|
|
23
|
+
<%= render "billing/subscriptions/payment_methods/forms/fake_processor", subscription: @subscription if @payment_processor.fake_processor? %>
|
|
24
|
+
<%= render "billing/subscriptions/payment_methods/forms/braintree", subscription: @subscription if Jumpstart.config.braintree? && @payment_processor.braintree? %>
|
|
25
|
+
<%= render "billing/subscriptions/payment_methods/forms/paypal", subscription: @subscription if Jumpstart.config.paypal? && @payment_processor.braintree? %>
|
|
26
|
+
</div>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<%# Poetry recreation of Jumpstart's billing/subscriptions/resumes/show. The
|
|
2
|
+
PATCH form keeps the engine's route; the confirmation is an AlertDialog
|
|
3
|
+
whose action submits it (form= attribute) instead of data-turbo-confirm. %>
|
|
4
|
+
<% content_for :title, t(".title") %>
|
|
5
|
+
|
|
6
|
+
<div class="flex max-w-xl flex-col gap-8">
|
|
7
|
+
<header class="flex flex-col gap-1">
|
|
8
|
+
<h1 class="text-2xl font-semibold tracking-tight"><%= t(".title") %></h1>
|
|
9
|
+
<p class="text-sm text-muted-foreground"><%= t(".resume") %></p>
|
|
10
|
+
</header>
|
|
11
|
+
|
|
12
|
+
<%= poetry_card do |card| %>
|
|
13
|
+
<%= render partial: "billing/subscriptions/summary", locals: { subscription: @subscription, heading_tag: :h2 } %>
|
|
14
|
+
<% end %>
|
|
15
|
+
|
|
16
|
+
<%= form_with url: billing_subscription_resume_path(@subscription), method: :patch, id: "resume-subscription-form" do |f| %><% end %>
|
|
17
|
+
|
|
18
|
+
<div class="flex flex-wrap items-center justify-between gap-3">
|
|
19
|
+
<%= poetry_button(variant: :outline, href: billing_path) { t(".back") } %>
|
|
20
|
+
|
|
21
|
+
<%= poetry_alert_dialog do |dialog| %>
|
|
22
|
+
<% dialog.with_trigger { t(".button") } %>
|
|
23
|
+
<% dialog.with_title { t("are_you_sure") } %>
|
|
24
|
+
<% dialog.with_description { t(".resume") } %>
|
|
25
|
+
<% dialog.with_cancel { t("cancel") } %>
|
|
26
|
+
<% dialog.with_action(type: :submit, form: "resume-subscription-form", data: { turbo_submits_with: t(".processing") }) { t(".button") } %>
|
|
27
|
+
<% end %>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<%# Poetry recreation of Jumpstart's billing/subscriptions/upcomings/show:
|
|
2
|
+
the Stripe upcoming-invoice preview (@invoice) as a line-item table with
|
|
3
|
+
subtotal, tax and total footer rows. %>
|
|
4
|
+
<% content_for :title, t(".title") %>
|
|
5
|
+
|
|
6
|
+
<div class="flex flex-col gap-8">
|
|
7
|
+
<header class="flex flex-col gap-1">
|
|
8
|
+
<h1 class="text-2xl font-semibold tracking-tight"><%= t(".title") %></h1>
|
|
9
|
+
<p class="text-sm text-muted-foreground"><%= t(".description", product: Jumpstart.config.application_name) %></p>
|
|
10
|
+
</header>
|
|
11
|
+
|
|
12
|
+
<%= poetry_card do |card| %>
|
|
13
|
+
<%= render partial: "billing/subscriptions/summary", locals: { subscription: @subscription, heading_tag: :h2 } %>
|
|
14
|
+
<% end %>
|
|
15
|
+
|
|
16
|
+
<section class="flex flex-col gap-4" aria-labelledby="upcoming-invoice-period">
|
|
17
|
+
<h2 id="upcoming-invoice-period" class="text-lg font-semibold tracking-tight"><%= l Time.at(@invoice.period_end).to_date, format: :long %></h2>
|
|
18
|
+
|
|
19
|
+
<div class="overflow-hidden rounded-lg border">
|
|
20
|
+
<%= poetry_table do %>
|
|
21
|
+
<%= poetry_table_caption(class: "sr-only") { t(".title") } %>
|
|
22
|
+
<%= poetry_table_header do %>
|
|
23
|
+
<%= poetry_table_row do %>
|
|
24
|
+
<%= poetry_table_head { t(".line_items.description") } %>
|
|
25
|
+
<%= poetry_table_head(class: "text-right") { t(".line_items.quantity") } %>
|
|
26
|
+
<%= poetry_table_head(class: "text-right") { t(".line_items.unit_price") } %>
|
|
27
|
+
<%= poetry_table_head(class: "text-right") { t(".line_items.total") } %>
|
|
28
|
+
<% end %>
|
|
29
|
+
<% end %>
|
|
30
|
+
<%= poetry_table_body do %>
|
|
31
|
+
<% @invoice.lines.auto_paging_each do |line_item| %>
|
|
32
|
+
<%= poetry_table_row(id: line_item.id) do %>
|
|
33
|
+
<%= poetry_table_cell do %>
|
|
34
|
+
<div><%= line_item.description %></div>
|
|
35
|
+
<div class="text-xs text-muted-foreground">
|
|
36
|
+
<%= l Time.at(line_item.period.start).to_date, format: :long %> -
|
|
37
|
+
<%= l Time.at(line_item.period.end).to_date, format: :long %>
|
|
38
|
+
</div>
|
|
39
|
+
<% end %>
|
|
40
|
+
<%= poetry_table_cell(class: "text-right tabular-nums") { line_item.quantity } %>
|
|
41
|
+
<%= poetry_table_cell(class: "text-right tabular-nums") { Pay::Currency.format line_item.pricing.unit_amount_decimal, currency: line_item.currency } %>
|
|
42
|
+
<%= poetry_table_cell(class: "text-right tabular-nums") { Pay::Currency.format line_item.amount, currency: line_item.currency } %>
|
|
43
|
+
<% end %>
|
|
44
|
+
<% end %>
|
|
45
|
+
<% end %>
|
|
46
|
+
<%= poetry_table_footer do %>
|
|
47
|
+
<%= poetry_table_row do %>
|
|
48
|
+
<%= poetry_table_cell(colspan: 3, class: "text-right font-medium") { t(".subtotal", default: "Subtotal") } %>
|
|
49
|
+
<%= poetry_table_cell(class: "text-right tabular-nums") { Pay::Currency.format @invoice.subtotal, currency: @invoice.currency } %>
|
|
50
|
+
<% end %>
|
|
51
|
+
<%= poetry_table_row do %>
|
|
52
|
+
<%= poetry_table_cell(colspan: 3, class: "text-right font-medium") { t(".tax", default: "Tax") } %>
|
|
53
|
+
<%= poetry_table_cell(class: "text-right tabular-nums") { Pay::Currency.format (@invoice.total - @invoice.total_excluding_tax), currency: @invoice.currency } %>
|
|
54
|
+
<% end %>
|
|
55
|
+
<%= poetry_table_row do %>
|
|
56
|
+
<%= poetry_table_cell(colspan: 3, class: "text-right font-semibold") { t(".total", default: "Total") } %>
|
|
57
|
+
<%= poetry_table_cell(class: "text-right font-semibold tabular-nums") { Pay::Currency.format @invoice.total, currency: @invoice.currency } %>
|
|
58
|
+
<% end %>
|
|
59
|
+
<% end %>
|
|
60
|
+
<% end %>
|
|
61
|
+
</div>
|
|
62
|
+
</section>
|
|
63
|
+
|
|
64
|
+
<div>
|
|
65
|
+
<%= poetry_button(variant: :outline, href: billing_path) { t(".back") } %>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<%# Poetry recreation of Jumpstart's pricing/show: the plan grid with the
|
|
2
|
+
monthly/yearly switch. The pricing Stimulus controller, its targets,
|
|
3
|
+
actions, class values and the data-turbo-prefetch guard are the switcher
|
|
4
|
+
contract - kept. The plan cards come from billing/subscriptions/_plan;
|
|
5
|
+
each card's action is evaluated inside that layout partial so the lazy
|
|
6
|
+
plan.* keys (contact_us, start_trial, get_started) resolve as before.
|
|
7
|
+
Without plans the page says so, with a link to add one for staff. %>
|
|
8
|
+
<% content_for :title, t(".heading") %>
|
|
9
|
+
|
|
10
|
+
<div class="mx-auto w-full max-w-5xl px-4 py-10 lg:px-6">
|
|
11
|
+
<header class="flex flex-col items-center gap-2 text-center">
|
|
12
|
+
<h1 class="text-3xl font-semibold tracking-tight"><%= t(".heading") %></h1>
|
|
13
|
+
<p class="text-lg text-muted-foreground"><%= t(".subhead") %></p>
|
|
14
|
+
</header>
|
|
15
|
+
|
|
16
|
+
<% if @monthly_plans.any? || @yearly_plans.any? %>
|
|
17
|
+
<div data-controller="pricing"
|
|
18
|
+
data-pricing-active-frequency-class="bg-background text-foreground shadow-xs"
|
|
19
|
+
data-pricing-inactive-frequency-class="text-muted-foreground"
|
|
20
|
+
data-pricing-inactive-plans-class="hidden"
|
|
21
|
+
data-pricing-hidden-toggle-class="hidden"
|
|
22
|
+
class="mt-10 flex flex-col items-center gap-8">
|
|
23
|
+
<div data-pricing-target="toggle" role="group" aria-label="<%= t(".billing_interval", default: "Billing interval") %>" class="hidden flex items-center gap-1 rounded-full border bg-muted p-1">
|
|
24
|
+
<%= poetry_button(variant: :ghost, size: :sm, class: "rounded-full", data: { action: "pricing#switch", pricing_target: "frequency", frequency: "monthly" }) { t(".monthly") } %>
|
|
25
|
+
<%= poetry_button(variant: :ghost, size: :sm, class: "rounded-full", data: { action: "pricing#switch", pricing_target: "frequency", frequency: "yearly" }) { t(".yearly") } %>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<div data-turbo-prefetch="false" class="w-full">
|
|
29
|
+
<div data-pricing-target="plans" data-frequency="monthly" class="<%= class_names("grid gap-6 sm:grid-cols-2 lg:grid-cols-none lg:grid-flow-col lg:auto-cols-fr", "mx-auto max-w-sm sm:grid-cols-1": @monthly_plans.one?) %>">
|
|
30
|
+
<% @monthly_plans.each do |plan| %>
|
|
31
|
+
<%= render layout: "billing/subscriptions/plan", locals: { plan: plan } do %>
|
|
32
|
+
<% if plan.contact_url.present? %>
|
|
33
|
+
<%= poetry_button(variant: :outline, href: plan.contact_url, class: "w-full") { t(".contact_us") } %>
|
|
34
|
+
<% else %>
|
|
35
|
+
<%= poetry_button(href: checkout_path(plan: plan), class: "w-full") { pricing_cta(plan) } %>
|
|
36
|
+
<% end %>
|
|
37
|
+
<% end %>
|
|
38
|
+
<% end %>
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<div data-pricing-target="plans" data-frequency="yearly" class="<%= class_names("hidden grid gap-6 sm:grid-cols-2 lg:grid-cols-none lg:grid-flow-col lg:auto-cols-fr", "mx-auto max-w-sm sm:grid-cols-1": @yearly_plans.one?) %>">
|
|
42
|
+
<% @yearly_plans.each do |plan| %>
|
|
43
|
+
<%= render layout: "billing/subscriptions/plan", locals: { plan: plan } do %>
|
|
44
|
+
<% if plan.contact_url.present? %>
|
|
45
|
+
<%= poetry_button(variant: :outline, href: plan.contact_url, class: "w-full") { t(".contact_us") } %>
|
|
46
|
+
<% else %>
|
|
47
|
+
<%= poetry_button(href: checkout_path(plan: plan), class: "w-full") { pricing_cta(plan) } %>
|
|
48
|
+
<% end %>
|
|
49
|
+
<% end %>
|
|
50
|
+
<% end %>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
<% else %>
|
|
55
|
+
<%= poetry_empty(media_variant: :icon, title_tag: :h2, class: "mt-10 rounded-lg border border-dashed py-12") do |empty| %>
|
|
56
|
+
<% empty.with_media { poetry_icon(name: :"credit-card") } %>
|
|
57
|
+
<% empty.with_title { t(".no_plans") } %>
|
|
58
|
+
<%= poetry_button(variant: :outline, href: madmin_plans_path) { t(".add_plan") } if current_user&.staff? %>
|
|
59
|
+
<% end %>
|
|
60
|
+
<% end %>
|
|
61
|
+
</div>
|
data/lib/generators/poetry_jumpstart_pro/install/templates/checkouts/checkouts/_testimonial.html.erb
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<%# Poetry recreation of Jumpstart's checkouts/_testimonial: the quote card
|
|
2
|
+
shown beside the checkout on large screens (same copy and attribution). %>
|
|
3
|
+
<div class="hidden lg:block">
|
|
4
|
+
<%= poetry_card do |card| %>
|
|
5
|
+
<figure class="flex flex-col gap-4">
|
|
6
|
+
<blockquote class="text-lg text-muted-foreground">
|
|
7
|
+
<p><%= t("checkouts.testimonial", product: Jumpstart.config.application_name) %></p>
|
|
8
|
+
</blockquote>
|
|
9
|
+
<figcaption class="flex items-center gap-3">
|
|
10
|
+
<%= poetry_avatar(src: "https://avatars1.githubusercontent.com/u/67093?s=40&v=4", label: "Chris Oliver", size: :sm) { "CO" } %>
|
|
11
|
+
<cite class="text-sm font-semibold not-italic">Chris Oliver</cite>
|
|
12
|
+
</figcaption>
|
|
13
|
+
</figure>
|
|
14
|
+
<% end %>
|
|
15
|
+
</div>
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
<%# Poetry recreation of Jumpstart's checkouts/show. Stripe renders its
|
|
2
|
+
embedded checkout (checkouts/forms/_stripe); every other processor gets
|
|
3
|
+
the plan summary beside the account + payment-method column. The
|
|
4
|
+
id="recurringTotal" element (updated by the Paddle controllers), the
|
|
5
|
+
processor partials with their plan local, and their conditions are the
|
|
6
|
+
engine's contract - kept. The copy is this gem's own, with defaults, so
|
|
7
|
+
a host can localize it. %>
|
|
8
|
+
<% content_for :title, t(".title") %>
|
|
9
|
+
|
|
10
|
+
<% progress = capture do %>
|
|
11
|
+
<nav aria-label="<%= t(".progress", default: "Progress") %>">
|
|
12
|
+
<ol class="flex flex-wrap items-center justify-center gap-3">
|
|
13
|
+
<li>
|
|
14
|
+
<%= poetry_link(href: pricing_path, underline: :none, class: "flex items-center gap-3 rounded-md") do %>
|
|
15
|
+
<span class="flex size-8 items-center justify-center rounded-full bg-primary text-primary-foreground">
|
|
16
|
+
<%= poetry_icon(name: :check, class: "size-4", label: t(".completed", default: "Completed")) %>
|
|
17
|
+
</span>
|
|
18
|
+
<span class="text-sm font-medium"><%= t("billing.show.choose_plan") %></span>
|
|
19
|
+
<% end %>
|
|
20
|
+
</li>
|
|
21
|
+
<li aria-hidden="true" class="h-px w-8 bg-primary"></li>
|
|
22
|
+
<li aria-current="step" class="flex items-center gap-3">
|
|
23
|
+
<span class="flex size-8 items-center justify-center rounded-full border-2 border-primary text-sm font-semibold text-primary">2</span>
|
|
24
|
+
<span class="text-sm font-medium"><%= t(".payment_method") %></span>
|
|
25
|
+
</li>
|
|
26
|
+
</ol>
|
|
27
|
+
</nav>
|
|
28
|
+
<% end %>
|
|
29
|
+
|
|
30
|
+
<% if Jumpstart.config.stripe? %>
|
|
31
|
+
<div class="mx-auto w-full max-w-5xl px-4 py-10 lg:px-6">
|
|
32
|
+
<div class="flex flex-col gap-8">
|
|
33
|
+
<%= progress %>
|
|
34
|
+
<h1 class="text-center text-2xl font-semibold tracking-tight"><%= t(".title") %></h1>
|
|
35
|
+
<%= render "checkouts/forms/stripe", client_secret: @checkout_session.client_secret %>
|
|
36
|
+
<%= render "checkouts/testimonial" %>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
<% else %>
|
|
40
|
+
<% amount = pay_amount_to_currency(@plan) %>
|
|
41
|
+
<% interval = formatted_plan_interval(@plan) %>
|
|
42
|
+
<div class="mx-auto w-full max-w-5xl px-4 py-10 lg:px-6">
|
|
43
|
+
<div class="flex flex-col gap-10">
|
|
44
|
+
<%= progress %>
|
|
45
|
+
|
|
46
|
+
<div class="grid gap-8 lg:grid-cols-2 lg:gap-16">
|
|
47
|
+
<div class="flex flex-col gap-6">
|
|
48
|
+
<%= poetry_card(title_tag: :h1) do |card| %>
|
|
49
|
+
<% if @plan.has_trial? %>
|
|
50
|
+
<% card.with_title { t(".trial_title", default: "%{plan}, free to start", plan: @plan.name) } %>
|
|
51
|
+
<p class="text-3xl font-semibold tracking-tight">
|
|
52
|
+
<%= t(".trial_length", default: "%{count} day trial", count: @plan.trial_period_days) %>
|
|
53
|
+
</p>
|
|
54
|
+
<p class="mt-1 text-muted-foreground">
|
|
55
|
+
<%= t(".trial_then", default: "then") %>
|
|
56
|
+
<span id="recurringTotal" class="font-medium text-foreground tabular-nums"><%= amount %></span>
|
|
57
|
+
<%= t(".trial_interval", default: "per %{interval}", interval: interval) %>
|
|
58
|
+
</p>
|
|
59
|
+
<% else %>
|
|
60
|
+
<% card.with_title { t(".subscribe_title", default: "%{plan} subscription", plan: @plan.name) } %>
|
|
61
|
+
<p class="flex flex-wrap items-baseline gap-x-2">
|
|
62
|
+
<span id="recurringTotal" class="text-4xl font-semibold tracking-tight tabular-nums"><%= amount %></span>
|
|
63
|
+
<span class="text-sm font-medium text-muted-foreground">
|
|
64
|
+
<%= @plan.unit_label? ? t(".per_unit_interval", default: "per %{unit}, every %{interval}", unit: @plan.unit_label, interval: interval) : t(".per_interval", default: "every %{interval}", interval: interval) %>
|
|
65
|
+
</span>
|
|
66
|
+
</p>
|
|
67
|
+
<% end %>
|
|
68
|
+
|
|
69
|
+
<% if @plan.features.any? %>
|
|
70
|
+
<ul class="mt-6 hidden flex-col gap-2 text-sm text-muted-foreground lg:flex">
|
|
71
|
+
<% @plan.features.each do |plan_feature| %>
|
|
72
|
+
<li class="flex items-start gap-2">
|
|
73
|
+
<%= poetry_icon(name: :check, class: "mt-0.5 size-4 shrink-0 text-primary") %>
|
|
74
|
+
<span><%= plan_feature %></span>
|
|
75
|
+
</li>
|
|
76
|
+
<% end %>
|
|
77
|
+
</ul>
|
|
78
|
+
<% end %>
|
|
79
|
+
<% end %>
|
|
80
|
+
|
|
81
|
+
<%= render "checkouts/testimonial" %>
|
|
82
|
+
</div>
|
|
83
|
+
|
|
84
|
+
<div class="flex flex-col gap-6">
|
|
85
|
+
<h2 class="hidden text-2xl font-semibold tracking-tight lg:block"><%= t(".title") %></h2>
|
|
86
|
+
|
|
87
|
+
<%= poetry_card(title_tag: :h2) do |card| %>
|
|
88
|
+
<% card.with_title { t(".account") } %>
|
|
89
|
+
<div class="flex items-center gap-3">
|
|
90
|
+
<%= account_avatar current_account %>
|
|
91
|
+
<span class="font-medium"><%= current_account.name %></span>
|
|
92
|
+
</div>
|
|
93
|
+
<% end %>
|
|
94
|
+
|
|
95
|
+
<%= poetry_card(title_tag: :h2) do |card| %>
|
|
96
|
+
<% card.with_title { t(".payment_method") } %>
|
|
97
|
+
<div class="flex flex-col gap-4">
|
|
98
|
+
<%= render "checkouts/forms/paddle_billing", plan: @plan if Jumpstart.config.paddle_billing? %>
|
|
99
|
+
<%= render "checkouts/forms/braintree", plan: @plan if Jumpstart.config.braintree? %>
|
|
100
|
+
<%= render "checkouts/forms/paypal", plan: @plan if Jumpstart.config.paypal? %>
|
|
101
|
+
|
|
102
|
+
<p class="text-center text-sm text-muted-foreground">
|
|
103
|
+
<% if @plan.has_trial? %>
|
|
104
|
+
<%= t(".trial_terms", default: "Nothing is charged during the trial. From %{date}, %{amount} per %{interval} is billed to this payment method; cancel before then and you pay nothing.",
|
|
105
|
+
date: l(@plan.trial_period_days.days.from_now.to_date, format: :long), amount: amount, interval: interval) %>
|
|
106
|
+
<% else %>
|
|
107
|
+
<%= t(".subscription_terms", default: "Subscribing authorizes %{name} to charge this payment method now and on every renewal, as set out in our terms.",
|
|
108
|
+
name: Jumpstart.config.application_name) %>
|
|
109
|
+
<% end %>
|
|
110
|
+
</p>
|
|
111
|
+
</div>
|
|
112
|
+
<% end %>
|
|
113
|
+
|
|
114
|
+
<p class="flex items-center justify-center gap-2 text-center text-sm text-muted-foreground">
|
|
115
|
+
<%= poetry_icon(name: :"circle-question-mark", class: "size-4 shrink-0") %>
|
|
116
|
+
<span>
|
|
117
|
+
<%= t(".help") %>
|
|
118
|
+
<%= t(".contact_html", link: poetry_link(href: "mailto:#{Jumpstart.config.support_email}?subject=#{ERB::Util.url_encode(t(".contact_subject", product: Jumpstart.config.application_name))}") { t(".contact_support") }) %>
|
|
119
|
+
</span>
|
|
120
|
+
</p>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
<% end %>
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<%# Poetry recreation of Jumpstart's dashboard/show, the signed-in home: a
|
|
2
|
+
page header with a welcome and, for staff, the Admin action; a note on
|
|
3
|
+
where the page lives; then a card grid of the account's everyday
|
|
4
|
+
destinations. The cards are a starting point - swap them for your app's
|
|
5
|
+
own content. %>
|
|
6
|
+
<% content_for :title, t(".title") %>
|
|
7
|
+
<% destinations = [
|
|
8
|
+
[t(".profile", default: "Profile"), edit_registration_path, :"user-round",
|
|
9
|
+
t(".profile_description", default: "Your name, avatar, language and theme.")],
|
|
10
|
+
[t(".security", default: "Password and security"), edit_account_password_path, :"lock-keyhole",
|
|
11
|
+
t(".security_description", default: "Change your password and turn on two-factor authentication.")],
|
|
12
|
+
[t(".accounts", default: "Accounts"), accounts_path, :users,
|
|
13
|
+
t(".accounts_description", default: "Your personal account and the teams you belong to.")],
|
|
14
|
+
[t(".notifications", default: "Notifications"), notifications_path, :bell,
|
|
15
|
+
t(".notifications_description", default: "Everything that happened while you were away.")],
|
|
16
|
+
[t(".api_tokens", default: "API tokens"), api_tokens_path, :"key-round",
|
|
17
|
+
t(".api_tokens_description", default: "Personal tokens for scripts and integrations.")]
|
|
18
|
+
] %>
|
|
19
|
+
<% if Jumpstart.config.payments_enabled? && Current.account_billing? %>
|
|
20
|
+
<% destinations << [t(".billing", default: "Billing"), billing_path, :"credit-card",
|
|
21
|
+
t(".billing_description", default: "Your plan, payment method and receipts.")] %>
|
|
22
|
+
<% end %>
|
|
23
|
+
|
|
24
|
+
<div class="mx-auto w-full max-w-5xl px-4 py-10 lg:px-6">
|
|
25
|
+
<header class="flex flex-col gap-4">
|
|
26
|
+
<div class="flex flex-wrap items-end justify-between gap-4">
|
|
27
|
+
<div class="space-y-1">
|
|
28
|
+
<h1 class="text-3xl font-semibold tracking-tight"><%= t(".title") %></h1>
|
|
29
|
+
<p class="text-sm text-muted-foreground"><%= t(".welcome", default: "Welcome back, %{name}.", name: current_user.first_name.presence || current_user.name) %></p>
|
|
30
|
+
</div>
|
|
31
|
+
<% if current_user.staff? %>
|
|
32
|
+
<%= poetry_button(variant: :outline, href: madmin_root_path, data: { turbo: false }) do |button| %>
|
|
33
|
+
<% button.with_leading { poetry_icon(name: :"shield-check") } %>
|
|
34
|
+
<%= t(".admin", default: "Admin") %>
|
|
35
|
+
<% end %>
|
|
36
|
+
<% end %>
|
|
37
|
+
</div>
|
|
38
|
+
<%= poetry_separator %>
|
|
39
|
+
</header>
|
|
40
|
+
|
|
41
|
+
<%= poetry_alert(class: "mt-8") do |note| %>
|
|
42
|
+
<% note.with_icon(name: :"layout-dashboard") %>
|
|
43
|
+
<% note.with_title { t(".customize_title", default: "This page is yours to build") } %>
|
|
44
|
+
<p><%= t(".customize", default: "Edit it in") %> <%= tag.code("app/views/dashboard/show.html.erb", class: "font-mono text-xs") %></p>
|
|
45
|
+
<% end %>
|
|
46
|
+
|
|
47
|
+
<section class="mt-8 space-y-4" aria-labelledby="dashboard-destinations">
|
|
48
|
+
<h2 id="dashboard-destinations" class="text-lg font-semibold tracking-tight"><%= t(".destinations", default: "Your account") %></h2>
|
|
49
|
+
|
|
50
|
+
<div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
|
51
|
+
<% destinations.each do |label, path, icon, description| %>
|
|
52
|
+
<%= poetry_card do |card| %>
|
|
53
|
+
<% card.with_title { poetry_link(href: path, underline: :hover) { label } } %>
|
|
54
|
+
<% card.with_action { poetry_icon(name: icon, class: "size-5 text-muted-foreground") } %>
|
|
55
|
+
<p class="text-sm text-muted-foreground"><%= description %></p>
|
|
56
|
+
<% end %>
|
|
57
|
+
<% end %>
|
|
58
|
+
</div>
|
|
59
|
+
</section>
|
|
60
|
+
</div>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<%# Poetry recreation of Jumpstart's errors/404. Self-contained on purpose:
|
|
2
|
+
this page renders while the rest of the app may be failing, so it uses
|
|
3
|
+
nothing that touches the database - the status, a plain-language message,
|
|
4
|
+
and a way home. The status number stays a bare <div> (tests assert on it). %>
|
|
5
|
+
<div class="mx-auto flex w-full max-w-5xl flex-col items-center px-4 py-24 text-center lg:px-6">
|
|
6
|
+
<div class="text-7xl font-bold tracking-tighter tabular-nums">404</div>
|
|
7
|
+
<h1 class="mt-6 max-w-md text-2xl font-semibold tracking-tight sm:text-3xl"><%= t(".message", default: "Sorry, the page you are looking for could not be found.") %></h1>
|
|
8
|
+
<p class="mt-3 max-w-md text-muted-foreground"><%= t(".hint", default: "Check the address for typos, or head back to the homepage.") %></p>
|
|
9
|
+
<div class="mt-8">
|
|
10
|
+
<%= poetry_button(size: :lg, href: root_path) { t(".back", default: "Back to home") } %>
|
|
11
|
+
</div>
|
|
12
|
+
</div>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<%# Poetry recreation of Jumpstart's errors/500. Self-contained on purpose:
|
|
2
|
+
this page renders while the rest of the app may be failing, so it uses
|
|
3
|
+
nothing that touches the database - the status, a plain-language message,
|
|
4
|
+
and a way home. The status number stays a bare <div> (tests assert on it). %>
|
|
5
|
+
<div class="mx-auto flex w-full max-w-5xl flex-col items-center px-4 py-24 text-center lg:px-6">
|
|
6
|
+
<div class="text-7xl font-bold tracking-tighter tabular-nums">500</div>
|
|
7
|
+
<h1 class="mt-6 max-w-md text-2xl font-semibold tracking-tight sm:text-3xl"><%= t(".message", default: "Sorry, we had a problem loading this page.") %></h1>
|
|
8
|
+
<p class="mt-3 max-w-md text-muted-foreground"><%= t(".hint", default: "The problem is on our side. Please try again in a moment.") %></p>
|
|
9
|
+
<div class="mt-8">
|
|
10
|
+
<%= poetry_button(size: :lg, href: root_path) { t(".back", default: "Back to home") } %>
|
|
11
|
+
</div>
|
|
12
|
+
</div>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<%# Poetry recreation of Jumpstart's errors/show, the fallback for every
|
|
2
|
+
4xx/5xx without a page of its own (406, 422, ...). Self-contained on
|
|
3
|
+
purpose: nothing here touches the database - the status (with its
|
|
4
|
+
standard name), a plain-language message, and a way home. The status
|
|
5
|
+
number stays a bare <div> (tests assert on it). %>
|
|
6
|
+
<div class="mx-auto flex w-full max-w-5xl flex-col items-center px-4 py-24 text-center lg:px-6">
|
|
7
|
+
<div class="text-7xl font-bold tracking-tighter tabular-nums"><%= @status %></div>
|
|
8
|
+
<% if (status_name = Rack::Utils::HTTP_STATUS_CODES[@status]) %>
|
|
9
|
+
<p class="mt-2 text-sm font-medium text-muted-foreground"><%= status_name %></p>
|
|
10
|
+
<% end %>
|
|
11
|
+
<h1 class="mt-6 max-w-md text-2xl font-semibold tracking-tight sm:text-3xl"><%= t(".message", default: "Sorry, we couldn't complete your request.") %></h1>
|
|
12
|
+
<p class="mt-3 max-w-md text-muted-foreground"><%= t(".hint", default: "Try again, or head back to the homepage.") %></p>
|
|
13
|
+
<div class="mt-8">
|
|
14
|
+
<%= poetry_button(size: :lg, href: root_path) { t(".back", default: "Back to home") } %>
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
data/lib/generators/poetry_jumpstart_pro/install/templates/madmin/madmin/dashboard/show.html.erb
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<%# Poetry recreation of Jumpstart's madmin dashboard/show: the revenue and
|
|
2
|
+
account KPIs as poetry stats, one metric each. Madmin keeps its own layout
|
|
3
|
+
and stylesheet (the host's Tailwind/Poetry CSS is not loaded there), so
|
|
4
|
+
the grid rides madmin's .metrics/.metric containers - the frame that
|
|
5
|
+
layout paints - and each cell holds one poetry_stat. %>
|
|
6
|
+
<% content_for :title, "Dashboard" %>
|
|
7
|
+
|
|
8
|
+
<header class="header">
|
|
9
|
+
<h1>Dashboard</h1>
|
|
10
|
+
</header>
|
|
11
|
+
|
|
12
|
+
<section>
|
|
13
|
+
<div class="metrics">
|
|
14
|
+
<div class="metric">
|
|
15
|
+
<%= poetry_stat(label: "Total Revenue") { number_to_currency @total_revenue } %>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<div class="metric">
|
|
19
|
+
<%= poetry_stat(label: "Revenue Last 12mo") { number_to_currency @last_12_mos } %>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<div class="metric">
|
|
23
|
+
<%= poetry_stat(label: "Last Month's Revenue") { number_to_currency @last_month } %>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<div class="metric">
|
|
27
|
+
<%= poetry_stat(label: "This Month's Revenue To Date") { number_to_currency @this_month } %>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<div class="metrics">
|
|
32
|
+
<div class="metric">
|
|
33
|
+
<%= poetry_stat(label: "Users") { number_with_delimiter ::User.count } %>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<div class="metric">
|
|
37
|
+
<%= poetry_stat(label: "Active Subscriptions") { number_with_delimiter ::Pay::Subscription.active.count } %>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
</section>
|