Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/controllers/concerns/authentication.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def request_authentication
end

def after_authentication_url
session.delete(:return_to_after_authenticating) || root_url
session.delete(:return_to_after_authenticating) || dashboard_url
end

def start_new_session_for(user)
Expand Down
4 changes: 4 additions & 0 deletions app/controllers/dashboards_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class DashboardsController < ApplicationController
def show
end
end
28 changes: 28 additions & 0 deletions app/controllers/users/stories_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
class Users::StoriesController < ApplicationController
def show
@user = Current.user
end

def update
@user = Current.user

if @user.update(story_params)
respond_to do |format|
format.turbo_stream do
render turbo_stream: turbo_stream.append(
"flash", partial: "shared/toast", locals: { type: :notice, message: "Saved." }
)
end
format.html { redirect_to users_story_path, notice: "Saved." }
end
else
render :show, status: :unprocessable_entity
end
end

private

def story_params
params.require(:user).permit(:background, :family, :formative_experiences)
end
end
29 changes: 29 additions & 0 deletions app/views/dashboards/show.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<div class="mx-auto max-w-4xl w-full px-4 py-12">
<h1 class="font-serif font-medium text-4xl tracking-tight text-ink">Welcome to your workspace</h1>
<p class="mt-3 max-w-2xl text-ink-soft">
Take your time exploring. There's no rush to complete anything &mdash; move through it at your
own pace, and come back whenever you're ready.
</p>

<h2 class="mt-10 font-medium text-ink">Your story</h2>

<div class="mt-4 grid gap-4 sm:grid-cols-2">
<%= link_to users_story_path,
class: "block rounded-2xl border border-line bg-surface p-6 shadow-sm hover:shadow-md transition" do %>
<h3 class="font-serif font-medium text-xl text-ink">About you</h3>
<p class="mt-2 text-ink-soft">
Share your background, family, and experiences that shaped who you are. This creates a
personal record for your family and provides context for your advisors.
</p>
<% end %>

<%= link_to scenarios_path,
class: "block rounded-2xl border border-line bg-surface p-6 shadow-sm hover:shadow-md transition" do %>
<h3 class="font-serif font-medium text-xl text-ink">Explore options</h3>
<p class="mt-2 text-ink-soft">
Experiment with allocations and possibilities to compare different approaches and potential
outcomes. Explore at your own pace to find what aligns with your values and goals.
</p>
<% end %>
</div>
</div>
3 changes: 2 additions & 1 deletion app/views/layouts/application.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

<body class="min-h-screen bg-canvas">
<nav class="sticky top-0 z-50 flex h-13 items-center border-b border-line bg-surface px-6 sm:px-9">
<%= link_to root_path, class: "flex items-center gap-2 font-serif text-lg tracking-tight text-ink hover:text-ink" do %>
<%= link_to(authenticated? ? dashboard_path : root_path, class: "flex items-center gap-2 font-serif text-lg tracking-tight text-ink hover:text-ink") do %>
<% if Current.organization&.logo&.attached? %>
<%= image_tag url_for(Current.organization.logo), alt: "#{Current.organization.name} logo", class: "h-7 w-auto" %>
<% end %>
Expand All @@ -41,6 +41,7 @@
<%= link_to "Mailer previews", "/rails/mailers", class: "text-ink-soft hover:text-ink" %>
<% end %>
<% if authenticated? %>
<%= link_to "About you", users_story_path, class: "text-ink-soft hover:text-ink" %>
<%= link_to "Explore options", scenarios_path, class: "text-ink-soft hover:text-ink" %>
<% if Current.user&.admin_of?(Current.organization) %>
<%= link_to "Admin Dashboard", admin_dashboard_path, class: "text-ink-soft hover:text-ink" %>
Expand Down
14 changes: 2 additions & 12 deletions app/views/shared/_flash.html.erb
Original file line number Diff line number Diff line change
@@ -1,17 +1,7 @@
<%# locals: () %>
<div class="fixed top-16 right-4 z-40 flex w-full max-w-sm flex-col gap-2 sm:right-6">
<div id="flash" class="fixed top-16 right-4 z-40 flex w-full max-w-sm flex-col gap-2 sm:right-6">
<% flash.each do |type, message| %>
<% next if message.blank? %>
<% alert = type.to_s == "alert" %>
<div id="<%= type %>"
data-controller="toast"
class="flex translate-x-2 items-start gap-3 rounded-lg border-l-4 bg-surface px-4 py-3 opacity-0 shadow-lg transition duration-300 ease-out <%= alert ? "border-danger" : "border-success" %>">
<span class="mt-1.5 h-2 w-2 shrink-0 rounded-full <%= alert ? "bg-danger" : "bg-success" %>" aria-hidden="true"></span>
<p class="flex-1 text-sm font-medium text-ink"><%= message %></p>
<button type="button"
data-action="toast#close"
aria-label="Dismiss"
class="-mr-1 shrink-0 text-lg leading-none text-ink-faint hover:text-ink">&times;</button>
</div>
<%= render "shared/toast", type: type, message: message %>
<% end %>
</div>
12 changes: 12 additions & 0 deletions app/views/shared/_toast.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<%# locals: (type:, message:) %>
<% alert = type.to_s == "alert" %>
<div id="<%= type %>"
data-controller="toast"
class="flex translate-x-2 items-start gap-3 rounded-lg border-l-4 bg-surface px-4 py-3 opacity-0 shadow-lg transition duration-300 ease-out <%= alert ? "border-danger" : "border-success" %>">
<span class="mt-1.5 h-2 w-2 shrink-0 rounded-full <%= alert ? "bg-danger" : "bg-success" %>" aria-hidden="true"></span>
<p class="flex-1 text-sm font-medium text-ink"><%= message %></p>
<button type="button"
data-action="toast#close"
aria-label="Dismiss"
class="-mr-1 shrink-0 text-lg leading-none text-ink-faint hover:text-ink">&times;</button>
</div>
39 changes: 39 additions & 0 deletions app/views/users/stories/show.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<div class="mx-auto max-w-2xl w-full px-4 py-16">
<div class="rounded-2xl border border-line bg-surface p-8 shadow-sm">
<h1 class="font-serif font-medium text-3xl tracking-tight text-ink">About you</h1>
<p class="mt-3 text-ink-soft">
Share your background, family, and experiences that shaped who you are. This creates a
personal record for your family and provides context for your advisors.
</p>

<%= form_with url: users_story_path, method: :patch, scope: :user, class: "contents",
data: { controller: "debounced-form", action: "input->debounced-form#submit" } do |form| %>
<% if @user.errors.any? %>
<div class="mt-5 py-2 px-3 bg-danger-tint text-danger font-medium rounded-lg" id="error_explanation">
<ul class="list-disc list-inside">
<% @user.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>

<div class="my-5">
<%= form.label :background, "Background", class: "text-sm font-medium text-ink" %>
<%= form.text_area :background, rows: 5, placeholder: "Where you're from, your work, the path that brought you here.", class: "block shadow-sm rounded-md border border-line bg-surface px-3 py-2 mt-2 w-full focus:border-accent focus:outline-none focus:ring-2 focus:ring-accent/10" %>
</div>

<div class="my-5">
<%= form.label :family, "Family", class: "text-sm font-medium text-ink" %>
<%= form.text_area :family, rows: 5, placeholder: "The people who matter most and the family story you want to carry forward.", class: "block shadow-sm rounded-md border border-line bg-surface px-3 py-2 mt-2 w-full focus:border-accent focus:outline-none focus:ring-2 focus:ring-accent/10" %>
</div>

<div class="my-5">
<%= form.label :formative_experiences, "Experiences that shaped you", class: "text-sm font-medium text-ink" %>
<%= form.text_area :formative_experiences, rows: 5, placeholder: "Moments, people, or turning points that shaped your values.", class: "block shadow-sm rounded-md border border-line bg-surface px-3 py-2 mt-2 w-full focus:border-accent focus:outline-none focus:ring-2 focus:ring-accent/10" %>
</div>

<p class="mt-6 text-sm text-ink-faint">Your answers save automatically as you type.</p>
<% end %>
</div>
</div>
2 changes: 2 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
Rails.application.routes.draw do
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
resource :home
resource :dashboard, only: :show
resources :passwords, param: :token
resource :registration, only: %i[ new create ]
resource :email_confirmation, only: %i[ new create show ]
Expand All @@ -11,6 +12,7 @@
get :confirm, on: :member
end
resource :profile, only: %i[ show update ]
resource :story, only: %i[ show update ]
end
resource :session

Expand Down
7 changes: 7 additions & 0 deletions db/migrate/20260702195446_add_about_you_to_users.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class AddAboutYouToUsers < ActiveRecord::Migration[8.1]
def change
add_column :users, :background, :text
add_column :users, :family, :text
add_column :users, :formative_experiences, :text
end
end
5 changes: 4 additions & 1 deletion db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 29 additions & 0 deletions test/controllers/dashboards_controller_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
require "test_helper"

class DashboardsControllerTest < ActionDispatch::IntegrationTest
test "requires authentication" do
get dashboard_url
assert_redirected_to new_session_path
end

test "renders the workspace dashboard for a signed-in member" do
sign_in_as(users(:one))

get dashboard_url

assert_response :success
assert_select "h1", "Welcome to your workspace"
assert_select "a[href=?]", users_story_path, text: "About you"
assert_select "a[href=?]", scenarios_path, text: "Explore options"
# The nav brand/logo links back to the dashboard for signed-in users.
assert_select "nav a[href=?]", dashboard_path
end

test "a signed-in non-member is redirected to the apex" do
sign_in_as(users(:two)) # member of boston, not arlington

get dashboard_url

assert_redirected_to root_url(subdomain: false)
end
end
2 changes: 1 addition & 1 deletion test/controllers/email_confirmations_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class EmailConfirmationsControllerTest < ActionDispatch::IntegrationTest
get email_confirmation_path(token: token)

assert @user.reload.confirmed?
assert_redirected_to root_path
assert_redirected_to dashboard_path
assert cookies[:session_id]
end

Expand Down
7 changes: 4 additions & 3 deletions test/controllers/home_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,17 @@ class HomeControllerTest < ActionDispatch::IntegrationTest
assert_select "h1", "Your Legacy Starts Here"
assert_select "a[href=?]", new_registration_path, text: "Sign up"
assert_select "a[href=?]", new_session_path, text: "Log in"
# The nav brand/logo links to the marketing home when signed out.
assert_select "nav a[href=?]", root_path
end

test "show offers explore options and sign out when signed in" do
test "show still renders the marketing page for a signed-in member" do
sign_in_as(users(:one))

get root_url

assert_response :success
assert_select "a[href=?]", scenarios_path, text: "Explore options"
assert_select "button", text: "Sign out"
assert_select "h1", "Your Legacy Starts Here"
end

test "a signed-in non-member is redirected to the apex" do
Expand Down
4 changes: 2 additions & 2 deletions test/controllers/magic_links_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class MagicLinksControllerTest < ActionDispatch::IntegrationTest

get magic_link_path(token: token)

assert_redirected_to root_url
assert_redirected_to dashboard_url
assert cookies[:session_id]
end

Expand All @@ -70,7 +70,7 @@ class MagicLinksControllerTest < ActionDispatch::IntegrationTest
get magic_link_path(token: token)

assert user.reload.confirmed?
assert_redirected_to root_url
assert_redirected_to dashboard_url
assert cookies[:session_id]
end

Expand Down
2 changes: 1 addition & 1 deletion test/controllers/sessions_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest
test "create with valid credentials" do
post session_path, params: { email_address: @user.email_address, password: "password" }

assert_redirected_to root_url
assert_redirected_to dashboard_url
assert cookies[:session_id]
end

Expand Down
64 changes: 64 additions & 0 deletions test/controllers/users/stories_controller_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
require "test_helper"

class Users::StoriesControllerTest < ActionDispatch::IntegrationTest
test "show requires authentication" do
get users_story_path
assert_redirected_to new_session_path
end

test "show for an authenticated user" do
sign_in_as users(:one)
get users_story_path
assert_response :success
assert_select "h1", "About you"
end

test "a user can save their background, family, and formative experiences" do
user = users(:one)
sign_in_as user

patch users_story_path, params: {
user: {
background: "Grew up in Arlington.",
family: "Two kids.",
formative_experiences: "A mentor changed my path."
}
}

assert_redirected_to users_story_path
user.reload
assert_equal "Grew up in Arlington.", user.background
assert_equal "Two kids.", user.family
assert_equal "A mentor changed my path.", user.formative_experiences
end

test "autosave (turbo_stream) persists and responds with a Saved toast without redirecting" do
user = users(:one)
sign_in_as user

patch users_story_path, params: { user: { background: "Autosaved text." } }, as: :turbo_stream

assert_response :success
assert_equal "text/vnd.turbo-stream.html", response.media_type
# Appends a toast into the flash container rather than navigating away.
assert_match %r{turbo-stream action="append" target="flash"}, response.body
assert_match "Saved.", response.body
assert_equal "Autosaved text.", user.reload.background
end

test "a user can clear their story fields" do
user = users(:one)
user.update!(background: "Something", family: "Someone", formative_experiences: "A moment")
sign_in_as user

patch users_story_path, params: {
user: { background: "", family: "", formative_experiences: "" }
}

assert_redirected_to users_story_path
user.reload
assert_equal "", user.background
assert_equal "", user.family
assert_equal "", user.formative_experiences
end
end
Loading