From 7c5ddd674d32dff8c04a1c0b4235bd0d01a2cb1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Mata?= Date: Wed, 22 Oct 2025 19:14:03 +0200 Subject: [PATCH] Make branding configurable (#173) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove orphan function * Add centralized branding helpers and update locales * Remove _plus and add (proper) brand * No longer Sure, configurable * Consistency with compose file naming * Missed `product_name` mapping * Fix brand/product name in mailers * Product name in email reset flow * Fix i18n errors/tests * Fix password mailer brand/product name (again) * Missed hardcoded `Sure` in onboarding goals Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Signed-off-by: Juan José Mata * PR nitpick on documentation * Missing interpolation key for invited UI * Orphan assets * New logos --------- Signed-off-by: Juan José Mata Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .env.example | 4 + app/assets/images/apple-logo.png | Bin 2923 -> 0 bytes app/assets/images/empower-logo.jpeg | Bin 13383 -> 0 bytes app/assets/images/logo-color.png | Bin 9326 -> 895 bytes app/assets/images/logomark-color.svg | 41 +---- app/assets/images/logomark.svg | 42 +---- app/helpers/application_helper.rb | 8 + app/mailers/application_mailer.rb | 23 ++- app/mailers/email_confirmation_mailer.rb | 2 +- app/mailers/invitation_mailer.rb | 6 +- app/mailers/password_mailer.rb | 2 +- app/models/demo/generator.rb | 4 - app/models/provider/simplefin.rb | 2 +- .../accounts/_account_sidebar_tabs.html.erb | 2 +- .../doorkeeper/authorizations/new.html.erb | 2 +- app/views/import/confirms/_mappings.html.erb | 2 +- .../invitation_mailer/invite_email.html.erb | 9 +- app/views/invitations/new.html.erb | 2 +- app/views/layouts/auth.html.erb | 2 +- app/views/layouts/shared/_footer.html.erb | 2 +- app/views/layouts/shared/_head.html.erb | 4 +- app/views/onboardings/goals.html.erb | 4 +- app/views/pages/feedback.html.erb | 2 +- .../password_mailer/password_reset.html.erb | 2 +- app/views/pwa/manifest.json.erb | 6 +- app/views/settings/billings/show.html.erb | 4 +- .../hostings/_invite_code_settings.html.erb | 2 +- app/views/settings/profiles/show.html.erb | 2 +- config/initializers/brand.rb | 4 + config/locales/defaults/en.yml | 3 + config/locales/defaults/nb.yml | 3 + config/locales/defaults/tr.yml | 3 + .../locales/mailers/invitation_mailer/en.yml | 2 +- .../locales/mailers/invitation_mailer/nb.yml | 10 +- .../locales/mailers/invitation_mailer/tr.yml | 2 +- .../views/email_confirmation_mailer/en.yml | 2 +- .../views/email_confirmation_mailer/nb.yml | 20 +-- .../views/email_confirmation_mailer/tr.yml | 2 +- config/locales/views/imports/en.yml | 2 +- config/locales/views/imports/nb.yml | 2 +- config/locales/views/imports/tr.yml | 10 +- config/locales/views/invitation_mailer/en.yml | 4 +- config/locales/views/invitation_mailer/nb.yml | 16 +- config/locales/views/invitations/nb.yml | 36 ++--- config/locales/views/layout/en.yml | 2 +- config/locales/views/layout/nb.yml | 24 +-- config/locales/views/onboardings/en.yml | 2 +- config/locales/views/onboardings/nb.yml | 56 +++---- config/locales/views/password_mailer/en.yml | 4 +- config/locales/views/password_mailer/nb.yml | 20 +-- config/locales/views/password_mailer/tr.yml | 4 +- config/locales/views/registrations/nb.yml | 48 +++--- config/locales/views/settings/api_keys/nb.yml | 148 +++++++++--------- config/locales/views/settings/en.yml | 2 +- config/locales/views/settings/hostings/en.yml | 2 +- config/locales/views/settings/hostings/nb.yml | 54 +++---- config/locales/views/settings/nb.yml | 2 +- config/locales/views/settings/tr.yml | 2 +- config/locales/views/subscriptions/en.yml | 2 +- config/locales/views/subscriptions/nb.yml | 8 +- config/locales/views/subscriptions/tr.yml | 2 +- docs/hosting/docker.md | 2 +- public/android-chrome-192x192.png | Bin 17715 -> 2842 bytes public/android-chrome-512x512.png | Bin 72063 -> 15483 bytes public/apple-touch-icon.png | Bin 16430 -> 3165 bytes public/favicon-16x16.png | Bin 695 -> 267 bytes public/favicon-32x32.png | Bin 1521 -> 474 bytes public/favicon.ico | Bin 15406 -> 9413 bytes public/logo-pwa.png | Bin 225225 -> 11654 bytes public/mstile-150x150.png | Bin 2072 -> 2605 bytes public/safari-pinned-tab.svg | 20 +-- .../onboardings_controller_test.rb | 2 +- .../mailers/email_confirmation_mailer_test.rb | 2 +- test/system/onboardings_test.rb | 4 +- 74 files changed, 348 insertions(+), 366 deletions(-) delete mode 100644 app/assets/images/apple-logo.png delete mode 100644 app/assets/images/empower-logo.jpeg create mode 100644 config/initializers/brand.rb diff --git a/.env.example b/.env.example index c6fc1173f..0f33b8eb9 100644 --- a/.env.example +++ b/.env.example @@ -62,6 +62,10 @@ POSTGRES_USER=postgres # This is the domain that your Sure instance will be hosted at. It is used to generate links in emails and other places. APP_DOMAIN= +# Product/Brand Name +PRODUCT_NAME= +BRAND_NAME= + # Disable enforcing SSL connections # DISABLE_SSL=true diff --git a/app/assets/images/apple-logo.png b/app/assets/images/apple-logo.png deleted file mode 100644 index 107a7858e8d431e3e953cd4a424277fb48ba96ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2923 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 ArT_o{ diff --git a/app/assets/images/empower-logo.jpeg b/app/assets/images/empower-logo.jpeg deleted file mode 100644 index 7193dcc29d305f6156bdd42d773f6961c230d295..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13383 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 cYfg$J2#SSayZ`_I07*qoM6N<$f<+lc-~a#s diff --git a/app/assets/images/logomark-color.svg b/app/assets/images/logomark-color.svg index d7556c509..3eec59196 100644 --- a/app/assets/images/logomark-color.svg +++ b/app/assets/images/logomark-color.svg @@ -1,35 +1,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + \ No newline at end of file diff --git a/app/assets/images/logomark.svg b/app/assets/images/logomark.svg index 332f7bd32..a8f2dc7d2 100644 --- a/app/assets/images/logomark.svg +++ b/app/assets/images/logomark.svg @@ -1,36 +1,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + \ No newline at end of file diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index bfd6bc208..3bb144300 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,6 +1,14 @@ module ApplicationHelper include Pagy::Frontend + def product_name + Rails.configuration.x.product_name + end + + def brand_name + Rails.configuration.x.brand_name + end + def styled_form_with(**options, &block) options[:builder] = StyledFormBuilder form_with(**options, &block) diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb index 7ab4f5d27..cbf81594b 100644 --- a/app/mailers/application_mailer.rb +++ b/app/mailers/application_mailer.rb @@ -1,4 +1,25 @@ class ApplicationMailer < ActionMailer::Base - default from: email_address_with_name(ENV.fetch("EMAIL_SENDER", "sender@sure.local"), "Sure Finance") + default from: email_address_with_name( + ENV.fetch("EMAIL_SENDER", "sender@sure.local"), + "#{Rails.configuration.x.brand_name} #{Rails.configuration.x.product_name}" + ) layout "mailer" + + before_action :assign_branding + + helper_method :product_name, :brand_name + + private + def assign_branding + @product_name = product_name + @brand_name = brand_name + end + + def product_name + Rails.configuration.x.product_name + end + + def brand_name + Rails.configuration.x.brand_name + end end diff --git a/app/mailers/email_confirmation_mailer.rb b/app/mailers/email_confirmation_mailer.rb index 3ad99b965..dafea19e9 100644 --- a/app/mailers/email_confirmation_mailer.rb +++ b/app/mailers/email_confirmation_mailer.rb @@ -6,7 +6,7 @@ class EmailConfirmationMailer < ApplicationMailer # def confirmation_email @user = params[:user] - @subject = t(".subject") + @subject = t(".subject", product_name: product_name) @cta = t(".cta") @confirmation_url = new_email_confirmation_url(token: @user.generate_token_for(:email_confirmation)) diff --git a/app/mailers/invitation_mailer.rb b/app/mailers/invitation_mailer.rb index d43a42fe6..9b90676c5 100644 --- a/app/mailers/invitation_mailer.rb +++ b/app/mailers/invitation_mailer.rb @@ -5,7 +5,11 @@ class InvitationMailer < ApplicationMailer mail( to: @invitation.email, - subject: t(".subject", inviter: @invitation.inviter.display_name) + subject: t( + ".subject", + inviter: @invitation.inviter.display_name, + product: product_name + ) ) end end diff --git a/app/mailers/password_mailer.rb b/app/mailers/password_mailer.rb index 8bacfbfab..d842c8985 100644 --- a/app/mailers/password_mailer.rb +++ b/app/mailers/password_mailer.rb @@ -1,7 +1,7 @@ class PasswordMailer < ApplicationMailer def password_reset @user = params[:user] - @subject = t(".subject") + @subject = t(".subject", product_name: product_name) @cta = t(".cta") mail to: @user.email, subject: @subject diff --git a/app/models/demo/generator.rb b/app/models/demo/generator.rb index e45771dfa..6e623cdcd 100644 --- a/app/models/demo/generator.rb +++ b/app/models/demo/generator.rb @@ -146,10 +146,6 @@ class Demo::Generator raise ActiveRecord::RecordNotFound, "No admin user with email #{email} found in family ##{family.id}" end - def partner_email_for(email) - "partner_#{email}" - end - def create_family_and_users!(family_name, email, onboarded:, subscribed:) family = Family.create!( name: family_name, diff --git a/app/models/provider/simplefin.rb b/app/models/provider/simplefin.rb index 264f0aa30..eca6e77fe 100644 --- a/app/models/provider/simplefin.rb +++ b/app/models/provider/simplefin.rb @@ -1,7 +1,7 @@ class Provider::Simplefin include HTTParty - headers "User-Agent" => "Sure Finance SimpleFin Client" + headers "User-Agent" => "#{Rails.configuration.x.product_name} Finance SimpleFin Client" default_options.merge!(verify: true, ssl_verify_mode: :peer) def initialize diff --git a/app/views/accounts/_account_sidebar_tabs.html.erb b/app/views/accounts/_account_sidebar_tabs.html.erb index e3f44c671..8aba2d7c9 100644 --- a/app/views/accounts/_account_sidebar_tabs.html.erb +++ b/app/views/accounts/_account_sidebar_tabs.html.erb @@ -12,7 +12,7 @@ <%= icon("chevron-down", color: "warning", class: "group-open:transform group-open:rotate-180") %>
-

Sure uses third party providers to fetch historical exchange rates, security prices, and more. This data is required to calculate accurate historical account balances.

+

<%= product_name %> uses third party providers to fetch historical exchange rates, security prices, and more. This data is required to calculate accurate historical account balances.

<%= link_to "Configure your providers here.", settings_hosting_path, class: "text-yellow-600 underline" %> diff --git a/app/views/doorkeeper/authorizations/new.html.erb b/app/views/doorkeeper/authorizations/new.html.erb index 6bd9859dd..c925ec722 100644 --- a/app/views/doorkeeper/authorizations/new.html.erb +++ b/app/views/doorkeeper/authorizations/new.html.erb @@ -71,6 +71,6 @@

- By authorizing, you allow this app to access your Sure data according to the permissions above. + By authorizing, you allow this app to access your <%= product_name %> data according to the permissions above.

diff --git a/app/views/import/confirms/_mappings.html.erb b/app/views/import/confirms/_mappings.html.erb index bd27ff328..2bb31ee8f 100644 --- a/app/views/import/confirms/_mappings.html.erb +++ b/app/views/import/confirms/_mappings.html.erb @@ -43,7 +43,7 @@

<%= t(".csv_mapping_label", mapping: mapping_label(mapping_class)) %>

-

<%= t(".maybe_mapping_label", mapping: mapping_label(mapping_class)) %>

+

<%= t(".sure_mapping_label", mapping: mapping_label(mapping_class), product_name: product_name) %>

<%= t(".rows_label") %>

diff --git a/app/views/invitation_mailer/invite_email.html.erb b/app/views/invitation_mailer/invite_email.html.erb index 04a702914..0f45f9d44 100644 --- a/app/views/invitation_mailer/invite_email.html.erb +++ b/app/views/invitation_mailer/invite_email.html.erb @@ -1,9 +1,12 @@ -

<%= t(".greeting") %>

+

<%= t(".greeting", product: product_name) %>

- <%= t(".body", + <%= t( + ".body", inviter: @invitation.inviter.display_name, - family: @invitation.family.name).html_safe %> + family: @invitation.family.name, + product: product_name + ).html_safe %>

<%= link_to t(".accept_button"), @accept_url, class: "button" %> diff --git a/app/views/invitations/new.html.erb b/app/views/invitations/new.html.erb index 6968f72dc..9dfebe959 100644 --- a/app/views/invitations/new.html.erb +++ b/app/views/invitations/new.html.erb @@ -1,5 +1,5 @@ <%= render DS::Dialog.new do |dialog| %> - <% dialog.with_header(title: t(".title"), subtitle: t(".subtitle")) %> + <% dialog.with_header(title: t(".title"), subtitle: t(".subtitle", product: product_name)) %> <% dialog.with_body do %> <%= styled_form_with model: @invitation, class: "space-y-4", data: { turbo: false } do |form| %> diff --git a/app/views/layouts/auth.html.erb b/app/views/layouts/auth.html.erb index 56be3236b..5622cf46a 100644 --- a/app/views/layouts/auth.html.erb +++ b/app/views/layouts/auth.html.erb @@ -26,7 +26,7 @@ <% end %> <% if controller_name == "sessions" %> <% elsif controller_name == "registrations" %>