From 0398edf57e94624fb68c46c69cb27fb88ef59be9 Mon Sep 17 00:00:00 2001 From: Zach Gollwitzer Date: Wed, 30 Apr 2025 12:31:11 -0400 Subject: [PATCH] Fix dashboard mobile issues --- app/assets/tailwind/maybe-design-system.css | 14 +++++ app/helpers/application_helper.rb | 5 ++ app/helpers/forms_helper.rb | 22 ------- .../controllers/app_layout_controller.js | 45 ++++++++++---- .../controllers/intercom_controller.js | 8 +++ app/models/balance_sheet.rb | 4 +- app/models/family.rb | 4 ++ app/models/period.rb | 4 ++ .../accounts/_account_sidebar_tabs.html.erb | 2 +- app/views/accounts/show/_chart.html.erb | 6 +- app/views/layouts/application.html.erb | 34 ++++++++-- app/views/layouts/shared/_htmldoc.html.erb | 4 +- app/views/onboardings/preferences.html.erb | 2 +- app/views/pages/dashboard.html.erb | 14 ++++- .../pages/dashboard/_balance_sheet.html.erb | 62 +++++++------------ .../pages/dashboard/_group_weight.html.erb | 10 +++ .../pages/dashboard/_net_worth_chart.html.erb | 9 ++- app/views/pages/feedback.html.erb | 3 +- app/views/settings/preferences/show.html.erb | 2 +- app/views/shared/_money_field.html.erb | 2 +- app/views/users/_user_menu.html.erb | 4 +- lib/money/currency.rb | 6 ++ 22 files changed, 172 insertions(+), 94 deletions(-) delete mode 100644 app/helpers/forms_helper.rb create mode 100644 app/javascript/controllers/intercom_controller.js create mode 100644 app/views/pages/dashboard/_group_weight.html.erb diff --git a/app/assets/tailwind/maybe-design-system.css b/app/assets/tailwind/maybe-design-system.css index 009d1da3..e23c4d49 100644 --- a/app/assets/tailwind/maybe-design-system.css +++ b/app/assets/tailwind/maybe-design-system.css @@ -243,6 +243,20 @@ color: theme(colors.white) !important; } +/* Transition when expanding a sidebar */ +@utility from-zero-width-transition { + transition-property: width, opacity; + transition-duration: 0.5s, 0.7s; + transition-timing-function: linear; +} + +/* Transition when collapsing a sidebar */ +@utility to-zero-width-transition { + transition-property: width, opacity; + transition-duration: 0.3s, 0.2s; + transition-timing-function: linear; +} + @layer base { [data-theme="dark"] { --color-success: var(--color-green-500); diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index d612b71f..80773704 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,6 +1,11 @@ module ApplicationHelper include Pagy::Frontend + def styled_form_with(**options, &block) + options[:builder] = StyledFormBuilder + form_with(**options, &block) + end + def icon(key, size: "md", color: "default", custom: false, as_button: false, **opts) extra_classes = opts.delete(:class) sizes = { xs: "w-3 h-3", sm: "w-4 h-4", md: "w-5 h-5", lg: "w-6 h-6", xl: "w-7 h-7", "2xl": "w-8 h-8" } diff --git a/app/helpers/forms_helper.rb b/app/helpers/forms_helper.rb deleted file mode 100644 index dfa5c3b5..00000000 --- a/app/helpers/forms_helper.rb +++ /dev/null @@ -1,22 +0,0 @@ -module FormsHelper - def styled_form_with(**options, &block) - options[:builder] = StyledFormBuilder - form_with(**options, &block) - end - - def modal_form_wrapper(title:, subtitle: nil, overflow_visible: false, &block) - content = capture &block - - render partial: "shared/modal_form", locals: { title:, subtitle:, content:, overflow_visible: } - end - - def period_select(form:, selected:, classes: "border border-secondary bg-container-inset rounded-lg text-sm pr-7 cursor-pointer text-primary focus:outline-hidden focus:ring-0") - periods_for_select = Period.all.map { |period| [ period.label_short, period.key ] } - - form.select(:period, periods_for_select, { selected: selected.key }, class: classes, data: { "auto-submit-form-target": "auto" }) - end - - def currencies_for_select - Money::Currency.all_instances.sort_by { |currency| [ currency.priority, currency.name ] } - end -end diff --git a/app/javascript/controllers/app_layout_controller.js b/app/javascript/controllers/app_layout_controller.js index 58fa0fd5..c9639155 100644 --- a/app/javascript/controllers/app_layout_controller.js +++ b/app/javascript/controllers/app_layout_controller.js @@ -3,7 +3,12 @@ import { Controller } from "@hotwired/stimulus"; // Connects to data-controller="dialog" export default class extends Controller { static targets = ["leftSidebar", "rightSidebar", "mobileSidebar"]; - static classes = ["leftSidebar", "rightSidebar"]; + static classes = [ + "expandedSidebar", + "collapsedSidebar", + "expandedTransition", + "collapsedTransition", + ]; openMobileSidebar() { this.mobileSidebarTarget.classList.remove("hidden"); @@ -14,19 +19,37 @@ export default class extends Controller { } toggleLeftSidebar() { - this.#updateUserPreference( - "show_sidebar", - this.leftSidebarTarget.classList.contains("hidden"), - ); - this.leftSidebarTarget.classList.toggle("hidden"); + const isOpen = this.leftSidebarTarget.classList.contains("w-full"); + this.#updateUserPreference("show_sidebar", !isOpen); + this.#toggleSidebarWidth(this.leftSidebarTarget, isOpen); } toggleRightSidebar() { - this.#updateUserPreference( - "show_ai_sidebar", - this.rightSidebarTarget.classList.contains("hidden"), - ); - this.rightSidebarTarget.classList.toggle("hidden"); + const isOpen = this.rightSidebarTarget.classList.contains("w-full"); + this.#updateUserPreference("show_ai_sidebar", !isOpen); + this.#toggleSidebarWidth(this.rightSidebarTarget, isOpen); + } + + #toggleSidebarWidth(el, isCurrentlyOpen) { + if (isCurrentlyOpen) { + el.classList.remove(...this.expandedSidebarClasses); + el.classList.add(...this.collapsedSidebarClasses); + + // Wait for existing transition to finish + setTimeout(() => { + el.classList.remove(this.expandedTransitionClass); + el.classList.add(this.collapsedTransitionClass); + }, 1000); + } else { + el.classList.add(...this.expandedSidebarClasses); + el.classList.remove(...this.collapsedSidebarClasses); + + // Wait for existing transition to finish + setTimeout(() => { + el.classList.add(this.expandedTransitionClass); + el.classList.remove(this.collapsedTransitionClass); + }, 1000); + } } #updateUserPreference(field, value) { diff --git a/app/javascript/controllers/intercom_controller.js b/app/javascript/controllers/intercom_controller.js new file mode 100644 index 00000000..f22d1db8 --- /dev/null +++ b/app/javascript/controllers/intercom_controller.js @@ -0,0 +1,8 @@ +import { Controller } from "@hotwired/stimulus"; + +// Connects to data-controller="intercom" +export default class extends Controller { + show() { + Intercom("show"); + } +} diff --git a/app/models/balance_sheet.rb b/app/models/balance_sheet.rb index 21b4aeca..e9b57211 100644 --- a/app/models/balance_sheet.rb +++ b/app/models/balance_sheet.rb @@ -27,12 +27,14 @@ class BalanceSheet key: "asset", display_name: "Assets", icon: "blocks", + total_money: total_assets_money, account_groups: account_groups("asset") ), ClassificationGroup.new( key: "liability", display_name: "Debts", icon: "scale", + total_money: total_liabilities_money, account_groups: account_groups("liability") ) ] @@ -75,7 +77,7 @@ class BalanceSheet end private - ClassificationGroup = Struct.new(:key, :display_name, :icon, :account_groups, keyword_init: true) + ClassificationGroup = Struct.new(:key, :display_name, :icon, :total_money, :account_groups, keyword_init: true) AccountGroup = Struct.new(:key, :name, :accountable_type, :classification, :total, :total_money, :weight, :accounts, :color, :missing_rates?, keyword_init: true) def active_accounts diff --git a/app/models/family.rb b/app/models/family.rb index caaa4134..1ab64523 100644 --- a/app/models/family.rb +++ b/app/models/family.rb @@ -146,6 +146,10 @@ class Family < ApplicationRecord false end + def missing_data_provider? + requires_data_provider? && Provider::Registry.get_provider(:synth).nil? + end + def primary_user users.order(:created_at).first end diff --git a/app/models/period.rb b/app/models/period.rb index 2cceb743..2fbcd30b 100644 --- a/app/models/period.rb +++ b/app/models/period.rb @@ -84,6 +84,10 @@ class Period def all PERIODS.map { |key, period| from_key(key) } end + + def as_options + all.map { |period| [ period.label_short, period.key ] } + end end PERIODS.each do |key, period| diff --git a/app/views/accounts/_account_sidebar_tabs.html.erb b/app/views/accounts/_account_sidebar_tabs.html.erb index 29691281..1ed98300 100644 --- a/app/views/accounts/_account_sidebar_tabs.html.erb +++ b/app/views/accounts/_account_sidebar_tabs.html.erb @@ -1,7 +1,7 @@ <%# locals: (family:, active_account_group_tab:) %>
- <% if family.requires_data_provider? && Provider::Registry.get_provider(:synth).nil? || true %> + <% if family.missing_data_provider? %>
diff --git a/app/views/accounts/show/_chart.html.erb b/app/views/accounts/show/_chart.html.erb index 9910fee0..8d82afa6 100644 --- a/app/views/accounts/show/_chart.html.erb +++ b/app/views/accounts/show/_chart.html.erb @@ -24,7 +24,11 @@ data: { "auto-submit-form-target": "auto" } %> <% end %> - <%= period_select form: form, selected: period %> + <%= form.select :period, + Period.as_options, + { selected: period.key }, + data: { "auto-submit-form-target": "auto" }, + class: "border border-secondary font-medium rounded-lg px-3 py-2 text-sm pr-7 cursor-pointer text-primary focus:outline-hidden focus:ring-0" %>
<% end %>
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index b3c3ee4f..e2d9a2c2 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -6,15 +6,23 @@ ] %> <% desktop_nav_items = mobile_nav_items.reject { |item| item[:mobile_only] } %> +<% expanded_sidebar_class = "w-full opacity-100" %> +<% collapsed_sidebar_class = "w-0 opacity-0" %> +<% collapsed_transition_class = "from-zero-width-transition" %> +<% expanded_transition_class = "to-zero-width-transition" %> <%= render "layouts/shared/htmldoc" do %>