Skip to content

Move subscription settings page content into a LiveView#6170

Open
sanne-san wants to merge 10 commits intomasterfrom
sanne-subscription-settings-liveview
Open

Move subscription settings page content into a LiveView#6170
sanne-san wants to merge 10 commits intomasterfrom
sanne-subscription-settings-liveview

Conversation

@sanne-san
Copy link
Contributor

Changes

Prepares the page to host the choose_plan modal as a LiveComponent in a follow-up PR. Pure refactor, no UX changes.

  • Extract subscription page content into a new SubscriptionSettings LiveView
  • Move data loading out of the controller and into the LiveView
  • Embed the LiveView in the existing settings layout via live_render

Tests

  • This PR does not require tests

Changelog

  • This PR does not make a user-facing change

Documentation

  • This change does not need a documentation update

Dark mode

  • This PR does not change the UI

Prepares the page to host the choose_plan modal as a LiveComponent in a follow-up PR. Pure refactor, no UX changes.
- Extract subscription page content into a new SubscriptionSettings LiveView
- Move data loading out of the controller and into the LiveView
- Embed the LiveView in the existing settings layout via live_render
@sanne-san sanne-san requested a review from a team March 17, 2026 15:46
Copy link
Contributor

@ukutaht ukutaht left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, just a couple comments

- Render SubscriptionSettings LiveView directly from the router instead of via a controller action and template
- Update the shared settings layout to work without a request object
- Move view helpers from SettingsView to the billing components module
@sanne-san sanne-san force-pushed the sanne-subscription-settings-liveview branch from eabfad4 to 11ad786 Compare March 18, 2026 11:24
@sanne-san sanne-san requested a review from ukutaht March 18, 2026 11:49
sanne-san and others added 4 commits March 18, 2026 15:14
Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
@sanne-san sanne-san force-pushed the sanne-subscription-settings-liveview branch from 499427c to 73ab60f Compare March 18, 2026 15:13
- Move billing helpers to a dedicated Helpers module
- Add a CurrentPath plug to the settings pipeline so we can avoid all the branching in the layout template
- Remove conn dependency from the settings layout
@sanne-san sanne-san force-pushed the sanne-subscription-settings-liveview branch from 73ab60f to 2c9f483 Compare March 18, 2026 15:25
@sanne-san sanne-san requested a review from zoldar March 18, 2026 15:49
|> assign(:team_member_usage, team_member_usage)
|> assign(:notification_type, notification_type)
|> assign(:total_pageview_usage_domain, total_pageview_usage_domain)
|> assign(:current_path, "settings/billing/subscription")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assign should be no longer needed - plug should provide it in the context already 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tried removing it but it breaks; the plug runs on the HTTP request, but the LiveView uses a WebSocket which doesn't inherit it.

Copy link
Contributor

@zoldar zoldar Mar 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, my wrong, for some reason I started thinking assigns from conn carry over to LV, which obviously is not the case argh. There will be more LVs, for each setting screen, I presume. We can still make something executed commonly for all LVs though. There's a mechanism for that, similar to plugs but specifically for LV: https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html#on_mount/1

Ideally, we'd wrap this and all future LV routes for settings in something like this:

  live_session :settings, on_mount: PlausibleWeb.Live.SettingsContext do
    scope alias: Live, assigns: %{connect_live_socket: true} do
      live "/billing/subscription", SubscriptionSettings, :subscription, as: :settings
    end
  end

https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.Router.html#live_session/3 brings a number of additional benefits:

  • settings layout is consistently applied, so we can skip setting it in every LV's mount (more on that below)
  • navigating between settings LVs can be potentially made more seamless by using navigate redirects which avoid full page reloads

I'm not sure if scope alias will work in this case - you might need to provide a full module path in live path definition, like PlausibleWeb.Live.SubscriptionSettings, but maybe not.

As for the context hook module, it's unfortunately tad more hairy than plug because we have to extract URI and need a lifecycle hook for that:

defmodule PlausibleWeb.Live.SettingsContext do
  import Phoenix.LiveView

  def on_mount(_arg, _params, _session, socket) do
    socket = attach_hook(socket, :get_current_path, :handle_params, &get_current_path/3)
    {:cont, socket, layout: {PlausibleWeb.Layouts, :settings}}
  end

  defp get_current_path(_params, url, socket) do
    %{path: request_path} = URI.parse(url)

    {:cont, assign(socket, :current_path, current_path}
  end
end

The above handles both, setting the layout and setting the current_path and potentially other assigns that might be shared in the context of settings LVs.

NOTE: I have not tested that code. If you stumble upon any issues implementing it and get stuck, please shout and we can try to sort this out.

- Use `conn.request_path` instead of `Path.join` in CurrentPath plug
- Remove unused `%Plug.Conn{}` clause from `account_settings_sidebar`
- Use dot notation for always-present assigns in `account_settings_sidebar`
Comment on lines +99 to +100
current_team = assigns.current_team
current_team_role = assigns.current_team_role
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These assigns are indeed always set if AuthPlug is present in the pipeline - we just need to keep in mind that they both might be nil. But we should be good here 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants