Skip to content

Commit

Permalink
fixup implement user session storage for liveviews
Browse files Browse the repository at this point in the history
taken fromhttps://fly.io/phoenix-files/saving-and-restoring-liveview-state/
  • Loading branch information
electronicbites committed Aug 15, 2024
1 parent 129ad28 commit 8b53154
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 15 deletions.
33 changes: 19 additions & 14 deletions assets/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,37 @@
//

// Include phoenix_html to handle method=PUT/DELETE in forms and buttons.
import "phoenix_html"
import "phoenix_html";
// Establish Phoenix Socket and LiveView configuration.
import { Socket } from "phoenix"
import { LiveSocket } from "phoenix_live_view"
import topbar from "../vendor/topbar"
import { Socket } from "phoenix";
import { LiveSocket } from "phoenix_live_view";
import topbar from "../vendor/topbar";

import { Hooks } from "./hooks"
import { Hooks } from "./hooks";
import * as LocalStateStore from "./hooks/local_state_store";

let csrfToken = document
.querySelector("meta[name='csrf-token']")
.getAttribute("content");

Hooks.LocalStateStore = LocalStateStore.hooks;

let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
let liveSocket = new LiveSocket("/live", Socket, {
hooks: Hooks,
longPollFallbackMs: 2500,
params: { _csrf_token: csrfToken }
})
params: { _csrf_token: csrfToken },
});

// Show progress bar on live navigation and form submits
topbar.config({ barColors: { 0: "#29d" }, shadowColor: "rgba(0, 0, 0, .3)" })
window.addEventListener("phx:page-loading-start", _info => topbar.show(300))
window.addEventListener("phx:page-loading-stop", _info => topbar.hide())
topbar.config({ barColors: { 0: "#29d" }, shadowColor: "rgba(0, 0, 0, .3)" });
window.addEventListener("phx:page-loading-start", (_info) => topbar.show(300));
window.addEventListener("phx:page-loading-stop", (_info) => topbar.hide());

// connect if there are any LiveViews on the page
liveSocket.connect()
liveSocket.connect();

// expose liveSocket on window for web console debug logs and latency simulation:
// >> liveSocket.enableDebug()
// >> liveSocket.enableLatencySim(1000) // enabled for duration of browser session
// >> liveSocket.disableLatencySim()
window.liveSocket = liveSocket

window.liveSocket = liveSocket;
42 changes: 42 additions & 0 deletions lib/radiator_web/live/episode_live/index.ex
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
defmodule RadiatorWeb.EpisodeLive.Index do
use RadiatorWeb, :live_view
require Logger

alias Radiator.Outline
alias Radiator.Outline.Dispatch
Expand Down Expand Up @@ -119,6 +120,47 @@ defmodule RadiatorWeb.EpisodeLive.Index do
{:noreply, socket}
end

defp restore_from_token(nil), do: {:ok, nil}

defp restore_from_token(token) do
salt = Application.get_env(:radiator, RadiatorWeb.Endpoint)[:live_view][:signing_salt]
# Max age is 1 day. 86,400 seconds
case Phoenix.Token.decrypt(RadiatorWeb.Endpoint, salt, token, max_age: 86_400) do
{:ok, data} ->
{:ok, data}

{:error, reason} ->
# handles `:invalid`, `:expired` and possibly other things?
{:error, "Failed to restore previous state. Reason: #{inspect(reason)}."}
end
end

defp serialize_to_token(state_data) do
salt = Application.get_env(:radiator, RadiatorWeb.Endpoint)[:live_view][:signing_salt]
Phoenix.Token.encrypt(RadiatorWeb.Endpoint, salt, state_data)
end

# Push a websocket event down to the browser's JS hook.
# Clear any settings for the current my_storage_key.
defp clear_browser_storage(socket) do
push_event(socket, "clear", %{key: socket.assigns.my_storage_key})
end

def handle_event("something_happened_and_i_want_to_store", _params, socket) do
# This represents the special state you want to store. It may come from the
# socket.assigns. It's specific to your LiveView.
state_to_store = socket.assigns.state

socket =
socket
|> push_event("store", %{
key: socket.assigns.my_storage_key,
data: serialize_to_token(state_to_store)
})

{:noreply, socket}
end

def handle_event("create_node", params, socket) do
user = socket.assigns.current_user
episode = socket.assigns.selected_episode
Expand Down
2 changes: 1 addition & 1 deletion lib/radiator_web/live/episode_live/index.html.heex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div class="grid grid-cols-12 gap-24">
<div class="grid grid-cols-12 gap-24" id="main-grid" phx-hook="LocalStateStore">
<aside class="col-span-12 sm:col-span-4">
<button
:if={@action != :new_episode}
Expand Down

0 comments on commit 8b53154

Please sign in to comment.