From 5a5f13b46bbbceef59e50f877837845b36315250 Mon Sep 17 00:00:00 2001 From: Zach Gollwitzer Date: Thu, 25 Apr 2024 07:54:56 -0400 Subject: [PATCH] Add new settings profile and preferences pages (#672) * Add new settings profile and preferences pages * Fix lint errors --- app/assets/images/dark-mode-preview.png | Bin 0 -> 13096 bytes app/assets/images/light-mode-preview.png | Bin 0 -> 11276 bytes app/assets/images/system-mode-preview.png | Bin 0 -> 20202 bytes .../stylesheets/application.tailwind.css | 7 +- .../settings/preferences_controller.rb | 18 ++++ .../settings/profiles_controller.rb | 8 +- app/helpers/settings_helper.rb | 5 ++ .../auto_submit_form_controller.js | 9 +- app/models/user.rb | 2 + app/views/settings/_section.html.erb | 12 +++ app/views/settings/preferences/show.html.erb | 41 +++++++-- app/views/settings/profiles/show.html.erb | 80 ++++++++++++++---- config/locales/views/settings/en.yml | 32 +++++++ .../20240425000110_add_role_to_users.rb | 6 ++ db/schema.rb | 4 +- 15 files changed, 192 insertions(+), 32 deletions(-) create mode 100644 app/assets/images/dark-mode-preview.png create mode 100644 app/assets/images/light-mode-preview.png create mode 100644 app/assets/images/system-mode-preview.png create mode 100644 app/views/settings/_section.html.erb create mode 100644 db/migrate/20240425000110_add_role_to_users.rb diff --git a/app/assets/images/dark-mode-preview.png b/app/assets/images/dark-mode-preview.png new file mode 100644 index 0000000000000000000000000000000000000000..f6b1a01699055ad4243ffeb94ebb538c989ea038 GIT binary patch literal 13096 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 { - element.addEventListener("input", this.handleInput); + element.addEventListener(this.triggerEventValue, this.handleInput); }); } disconnect() { this.autoTargets.forEach((element) => { - element.removeEventListener("input", this.handleInput); + element.removeEventListener(this.triggerEventValue, this.handleInput); }); } diff --git a/app/models/user.rb b/app/models/user.rb index a0bd8ada..8cbd8fb1 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -7,6 +7,8 @@ class User < ApplicationRecord validates :email, presence: true, uniqueness: true normalizes :email, with: ->(email) { email.strip.downcase } + enum :role, { member: "member", admin: "admin" }, validate: true + generates_token_for :password_reset, expires_in: 15.minutes do password_salt&.last(10) end diff --git a/app/views/settings/_section.html.erb b/app/views/settings/_section.html.erb new file mode 100644 index 00000000..cd0e3a3f --- /dev/null +++ b/app/views/settings/_section.html.erb @@ -0,0 +1,12 @@ +<%# locals: (title:, subtitle: nil, content:) %> +
+
+

<%= title %>

+ <% if subtitle.present? %> +

<%= subtitle %>

+ <% end %> +
+
+ <%= content %> +
+
diff --git a/app/views/settings/preferences/show.html.erb b/app/views/settings/preferences/show.html.erb index 37a1ead2..b32fd568 100644 --- a/app/views/settings/preferences/show.html.erb +++ b/app/views/settings/preferences/show.html.erb @@ -2,12 +2,43 @@ <%= render "settings/nav" %> <% end %>
-

Preferences

-
-
-

Preferences coming soon...

+

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

+ <%= settings_section title: t(".general_title"), subtitle: t(".general_subtitle") do %> +
+ <%= form_with model: Current.user, url: settings_preferences_path, html: { class: "space-y-4", data: { controller: "auto-submit-form" } } do |form| %> + <%= form.fields_for :family_attributes do |family_fields| %> + <%= family_fields.select :currency, options_for_select(Money::Currency.popular.map { |currency| ["#{currency.iso_code} (#{currency.name})", currency.iso_code] }, selected: Current.family.currency), { label: "Currency" }, { data: { auto_submit_form_target: "auto" } } %> + <% end %> + <% end %>
-
+ <% end %> + <%= settings_section title: t(".theme_title"), subtitle: t(".theme_subtitle") do %> +
+ <%= form_with model: Current.user, url: settings_preferences_path, local: true, html: { class: "flex justify-between items-center" } do |form| %> +
+ <%= image_tag("light-mode-preview.png", alt: "Light Theme Preview", class: "h-44 mb-4") %> +
+ <%= form.radio_button :theme, t(".theme_light"), checked: true %> + <%= form.label :theme_light, t(".theme_light"), value: "light" %> +
+
+
+ <%= image_tag("dark-mode-preview.png", alt: "Dark Theme Preview", class: "h-44 mb-4") %> +
+ <%= form.radio_button :theme, t(".theme_dark"), disabled: true, class: "cursor-not-allowed" %> + <%= form.label :theme_dark, t(".theme_dark"), value: "dark" %> +
+
+
+ <%= image_tag("system-mode-preview.png", alt: "System Theme Preview", class: "h-44 mb-4") %> +
+ <%= form.radio_button :theme, t(".theme_system"), disabled: true, class: "cursor-not-allowed" %> + <%= form.label :theme_system, t(".theme_system"), value: "system" %> +
+
+ <% end %> +
+ <% end %>
<%= previous_setting("Account", settings_profile_path) %> <%= next_setting("Notifications", settings_notifications_path) %> diff --git a/app/views/settings/profiles/show.html.erb b/app/views/settings/profiles/show.html.erb index a6fb7fb9..2c0a9ade 100644 --- a/app/views/settings/profiles/show.html.erb +++ b/app/views/settings/profiles/show.html.erb @@ -2,23 +2,71 @@ <%= render "settings/nav" %> <% end %>
-

Account

- <%= form_with model: Current.user, url: settings_profile_path, html: { class: "space-y-4" } do |form| %> - <%= form.fields_for :family_attributes do |family_fields| %> - <%= family_fields.text_field :name, placeholder: "Family name", value: Current.family.name, label: "Family name" %> - <%= family_fields.select :currency, options_for_select(Money::Currency.popular.map { |currency| ["#{currency.iso_code} (#{currency.name})", currency.iso_code] }, selected: Current.family.currency), { label: "Currency" } %> +

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

+
+ <%= settings_section title: t(".profile_title"), subtitle: t(".profile_subtitle") do %> +
+
+ <%= lucide_icon "image-plus", class: "w-6 h-6 text-gray-500" %> +
+
+

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

+ +
+
+
+ <%= form_with model: Current.user, url: settings_profile_path, html: { class: "space-y-4" } do |form| %> +
+ <%= form.text_field :first_name, placeholder: "First name", value: Current.user.first_name, label: true %> + <%= form.text_field :last_name, placeholder: "Last name", value: Current.user.last_name, label: true %> +
+
+ <%= form.submit t(".save"), class: "bg-gray-900 text-white rounded-lg px-3 py-2" %> +
+ <% end %> +
<% end %> - <%= form.text_field :first_name, placeholder: "First name", value: Current.user.first_name, label: true %> - <%= form.text_field :last_name, placeholder: "Last name", value: Current.user.last_name, label: true %> - <%= form.email_field :email, placeholder: "Email", value: Current.user.email, label: true %> - <%= form.password_field :password, label: true %> - <%= form.password_field :password_confirmation, label: true %> -
- -
- <% end %> + <%= settings_section title: t(".household_title"), subtitle: t(".household_subtitle") do %> +
+ <%= form_with model: Current.user, url: settings_profile_path, html: { class: "space-y-4", data: { controller: "auto-submit-form", "auto-submit-form-trigger-event-value": "blur" } } do |form| %> + <%= form.fields_for :family_attributes do |family_fields| %> + <%= family_fields.text_field :name, placeholder: t(".household_form_input_placeholder"), value: Current.family.name, label: t(".household_form_label"), disabled: !Current.user.admin?, "data-auto-submit-form-target": "auto" %> + <% end %> + <% end %> +
+
+

<%= Current.family.name %> · <%= Current.family.users.size %>

+
+
+
+

<%= Current.user.first_name.first %>

+
+

<%= Current.user.first_name %> <%= Current.user.last_name %>

+
+

<%= Current.user.role %>

+
+
+
+ +
+
+
+ <% end %> + <%= settings_section title: t(".danger_zone_title") do %> +
+
+

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

+

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

+
+ +
+ <% end %> +
<%= next_setting("Preferences", settings_preferences_path) %>
diff --git a/config/locales/views/settings/en.yml b/config/locales/views/settings/en.yml index 7ef300ad..1ec712e0 100644 --- a/config/locales/views/settings/en.yml +++ b/config/locales/views/settings/en.yml @@ -23,3 +23,35 @@ en: nav_link_large: next: Next previous: Back + preferences: + show: + general_subtitle: Configure your preferences + general_title: General + page_title: Preferences + theme_dark: Dark + theme_light: Light + theme_subtitle: Choose a preferred theme for the app (coming soon...) + theme_system: System + theme_title: Theme + update: + success: Preferences updated successfully. + profiles: + show: + add_member: Add Member + danger_zone_title: Danger Zone + delete_account: Delete Account + delete_account_warning: Deleting your account will permanently remove all + your data and cannot be undone. + household_form_input_placeholder: Enter household name + household_form_label: Household name + household_subtitle: Invite family members, partners and other inviduals. Invitees + can login to your household and access your shared accounts. + household_title: Household + page_title: Account + profile_image_choose: Choose + profile_image_type: JPG, GIF or PNG. 5MB max. + profile_subtitle: Customize how you appear on Maybe + profile_title: Profile + save: Save + update: + success: Profile updated successfully. diff --git a/db/migrate/20240425000110_add_role_to_users.rb b/db/migrate/20240425000110_add_role_to_users.rb new file mode 100644 index 00000000..4bf8dca5 --- /dev/null +++ b/db/migrate/20240425000110_add_role_to_users.rb @@ -0,0 +1,6 @@ +class AddRoleToUsers < ActiveRecord::Migration[7.2] + def change + create_enum :user_role, %w[admin member] + add_column :users, :role, :user_role, default: "member", null: false + end +end diff --git a/db/schema.rb b/db/schema.rb index ad15f1b2..924ce938 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.2].define(version: 2024_04_11_102931) do +ActiveRecord::Schema[7.2].define(version: 2024_04_25_000110) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -18,6 +18,7 @@ ActiveRecord::Schema[7.2].define(version: 2024_04_11_102931) do # Custom types defined in this database. # Note that some types may not work with other database engines. Be careful if changing database. create_enum "account_status", ["ok", "syncing", "error"] + create_enum "user_role", ["admin", "member"] create_table "account_balances", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| t.uuid "account_id", null: false @@ -244,6 +245,7 @@ ActiveRecord::Schema[7.2].define(version: 2024_04_11_102931) do t.datetime "last_login_at" t.string "last_prompted_upgrade_commit_sha" t.string "last_alerted_upgrade_commit_sha" + t.enum "role", default: "member", null: false, enum_type: "user_role" t.index ["email"], name: "index_users_on_email", unique: true t.index ["family_id"], name: "index_users_on_family_id" end