mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-07-19 05:09:38 +02:00
New Settings Menu, Routes and Controllers Organization (#641)
* Add new settings routes and controllers * Add new settings view, restructure controllers and routes * Fix lint errors
This commit is contained in:
parent
39d57a167e
commit
9bda7efc3f
52 changed files with 771 additions and 203 deletions
|
@ -2,6 +2,18 @@ class AccountsController < ApplicationController
|
|||
include Filterable
|
||||
before_action :set_account, only: %i[ show update destroy sync ]
|
||||
|
||||
def index
|
||||
@accounts = Current.family.accounts
|
||||
end
|
||||
|
||||
def summary
|
||||
snapshot = Current.family.snapshot(@period)
|
||||
@net_worth_series = snapshot[:net_worth_series]
|
||||
@asset_series = snapshot[:asset_series]
|
||||
@liability_series = snapshot[:liability_series]
|
||||
@account_groups = Current.family.accounts.by_group(period: @period, currency: Current.family.currency)
|
||||
end
|
||||
|
||||
def new
|
||||
@account = Account.new(
|
||||
balance: nil,
|
||||
|
|
|
@ -8,4 +8,13 @@ class PagesController < ApplicationController
|
|||
@liability_series = snapshot[:liability_series]
|
||||
@account_groups = Current.family.accounts.by_group(period: @period, currency: Current.family.currency)
|
||||
end
|
||||
|
||||
def changelog
|
||||
end
|
||||
|
||||
def feedback
|
||||
end
|
||||
|
||||
def invites
|
||||
end
|
||||
end
|
||||
|
|
7
app/controllers/settings/billings_controller.rb
Normal file
7
app/controllers/settings/billings_controller.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
class Settings::BillingsController < ApplicationController
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
end
|
||||
end
|
46
app/controllers/settings/hostings_controller.rb
Normal file
46
app/controllers/settings/hostings_controller.rb
Normal file
|
@ -0,0 +1,46 @@
|
|||
class Settings::HostingsController < ApplicationController
|
||||
before_action :verify_hosting_mode
|
||||
|
||||
def show
|
||||
end
|
||||
|
||||
def update
|
||||
if all_updates_valid?
|
||||
hosting_params.keys.each do |key|
|
||||
Setting.send("#{key}=", hosting_params[key].strip)
|
||||
end
|
||||
|
||||
redirect_to settings_hosting_path, notice: t(".success")
|
||||
else
|
||||
flash.now[:error] = @errors.first.message
|
||||
render :edit, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def all_updates_valid?
|
||||
@errors = ActiveModel::Errors.new(Setting)
|
||||
hosting_params.keys.each do |key|
|
||||
setting = Setting.new(var: key)
|
||||
setting.value = hosting_params[key].strip
|
||||
|
||||
unless setting.valid?
|
||||
@errors.merge!(setting.errors)
|
||||
end
|
||||
end
|
||||
|
||||
if hosting_params[:upgrades_mode] == "auto" && hosting_params[:render_deploy_hook].blank?
|
||||
@errors.add(:render_deploy_hook, t("settings.hostings.update.render_deploy_hook_error"))
|
||||
end
|
||||
|
||||
@errors.empty?
|
||||
end
|
||||
|
||||
def hosting_params
|
||||
params.require(:setting).permit(:render_deploy_hook, :upgrades_mode, :upgrades_target)
|
||||
end
|
||||
|
||||
def verify_hosting_mode
|
||||
head :not_found unless self_hosted?
|
||||
end
|
||||
end
|
7
app/controllers/settings/notifications_controller.rb
Normal file
7
app/controllers/settings/notifications_controller.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
class Settings::NotificationsController < ApplicationController
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
end
|
||||
end
|
7
app/controllers/settings/preferences_controller.rb
Normal file
7
app/controllers/settings/preferences_controller.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
class Settings::PreferencesController < ApplicationController
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
end
|
||||
end
|
|
@ -1,5 +1,5 @@
|
|||
class SettingsController < ApplicationController
|
||||
def edit
|
||||
class Settings::ProfilesController < ApplicationController
|
||||
def show
|
||||
end
|
||||
|
||||
def update
|
7
app/controllers/settings/securities_controller.rb
Normal file
7
app/controllers/settings/securities_controller.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
class Settings::SecuritiesController < ApplicationController
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
end
|
||||
end
|
|
@ -1,46 +0,0 @@
|
|||
class Settings::SelfHostingController < ApplicationController
|
||||
before_action :verify_self_hosting_enabled
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
if all_updates_valid?
|
||||
self_hosting_params.keys.each do |key|
|
||||
Setting.send("#{key}=", self_hosting_params[key].strip)
|
||||
end
|
||||
|
||||
redirect_to edit_settings_self_hosting_path, notice: t(".success")
|
||||
else
|
||||
flash.now[:error] = @errors.first.message
|
||||
render :edit, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def all_updates_valid?
|
||||
@errors = ActiveModel::Errors.new(Setting)
|
||||
self_hosting_params.keys.each do |key|
|
||||
setting = Setting.new(var: key)
|
||||
setting.value = self_hosting_params[key].strip
|
||||
|
||||
unless setting.valid?
|
||||
@errors.merge!(setting.errors)
|
||||
end
|
||||
end
|
||||
|
||||
if self_hosting_params[:upgrades_mode] == "auto" && self_hosting_params[:render_deploy_hook].blank?
|
||||
@errors.add(:render_deploy_hook, t("settings.self_hosting.update.render_deploy_hook_error"))
|
||||
end
|
||||
|
||||
@errors.empty?
|
||||
end
|
||||
|
||||
def self_hosting_params
|
||||
params.require(:setting).permit(:render_deploy_hook, :upgrades_mode, :upgrades_target)
|
||||
end
|
||||
|
||||
def verify_self_hosting_enabled
|
||||
head :not_found unless self_hosted?
|
||||
end
|
||||
end
|
|
@ -1,6 +1,9 @@
|
|||
class Transactions::CategoriesController < ApplicationController
|
||||
before_action :set_category, only: [ :update, :destroy ]
|
||||
|
||||
def index
|
||||
end
|
||||
|
||||
def create
|
||||
if Current.family.transaction_categories.create(category_params)
|
||||
redirect_to transactions_path, notice: t(".success")
|
||||
|
|
4
app/controllers/transactions/merchants_controller.rb
Normal file
4
app/controllers/transactions/merchants_controller.rb
Normal file
|
@ -0,0 +1,4 @@
|
|||
class Transactions::MerchantsController < ApplicationController
|
||||
def index
|
||||
end
|
||||
end
|
4
app/controllers/transactions/rules_controller.rb
Normal file
4
app/controllers/transactions/rules_controller.rb
Normal file
|
@ -0,0 +1,4 @@
|
|||
class Transactions::RulesController < ApplicationController
|
||||
def index
|
||||
end
|
||||
end
|
|
@ -38,21 +38,16 @@ module ApplicationHelper
|
|||
end
|
||||
|
||||
def sidebar_link_to(name, path, options = {})
|
||||
base_class_names = [ "block", "border", "border-transparent", "rounded-xl", "-ml-2", "p-2", "text-sm", "font-medium", "text-gray-500", "flex", "items-center" ]
|
||||
hover_class_names = [ "hover:bg-white", "hover:border-alpha-black-50", "hover:text-gray-900", "hover:shadow-xs" ]
|
||||
current_page_class_names = [ "bg-white", "border-alpha-black-50", "text-gray-900", "shadow-xs" ]
|
||||
is_current = current_page?(path) || (request.path.start_with?(path) && path != "/")
|
||||
|
||||
link_class_names = if current_page?(path) || (request.path.start_with?(path) && path != "/")
|
||||
base_class_names.delete("border-transparent")
|
||||
base_class_names + hover_class_names + current_page_class_names
|
||||
else
|
||||
base_class_names + hover_class_names
|
||||
end
|
||||
classes = [
|
||||
"flex items-center gap-2 px-3 py-2 rounded-xl border text-sm font-medium text-gray-500",
|
||||
(is_current ? "bg-white text-gray-900 shadow-xs border-alpha-black-50" : "hover:bg-gray-100 border-transparent")
|
||||
].compact.join(" ")
|
||||
|
||||
merged_options = options.reverse_merge(class: link_class_names.join(" ")).except(:icon)
|
||||
|
||||
link_to path, merged_options do
|
||||
lucide_icon(options[:icon], class: "w-5 h-5 mr-2") + name
|
||||
link_to path, **options.merge(class: classes), aria: { current: ("page" if current_page?(path)) } do
|
||||
concat(lucide_icon(options[:icon], class: "w-5 h-5")) if options[:icon]
|
||||
concat(name)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
2
app/helpers/settings/hosting_helper.rb
Normal file
2
app/helpers/settings/hosting_helper.rb
Normal file
|
@ -0,0 +1,2 @@
|
|||
module Settings::HostingHelper
|
||||
end
|
|
@ -1,2 +0,0 @@
|
|||
module Settings::SelfHostingHelper
|
||||
end
|
9
app/helpers/settings_helper.rb
Normal file
9
app/helpers/settings_helper.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
module SettingsHelper
|
||||
def next_setting(title, path)
|
||||
render partial: "settings/nav_link_large", locals: { path: path, direction: "next", title: title }
|
||||
end
|
||||
|
||||
def previous_setting(title, path)
|
||||
render partial: "settings/nav_link_large", locals: { path: path, direction: "previous", title: title }
|
||||
end
|
||||
end
|
|
@ -1,13 +1,17 @@
|
|||
import { Controller } from "@hotwired/stimulus"
|
||||
import { install, uninstall } from "@github/hotkey"
|
||||
import { Controller } from "@hotwired/stimulus";
|
||||
import { install, uninstall } from "@github/hotkey";
|
||||
|
||||
// Connects to data-controller="hotkey"
|
||||
export default class extends Controller {
|
||||
connect() {
|
||||
install(this.element)
|
||||
install(this.element);
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
uninstall(this.element)
|
||||
uninstall(this.element);
|
||||
}
|
||||
|
||||
navigateBack(event) {
|
||||
window.history.back();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,17 +38,17 @@ export default {
|
|||
900: "rgba(255, 255, 255, 0.7)",
|
||||
},
|
||||
"alpha-black": {
|
||||
25: "rgba(20, 20, 20, 0.03)",
|
||||
50: "rgba(20, 20, 20, 0.05)",
|
||||
100: "rgba(20, 20, 20, 0.08)",
|
||||
200: "rgba(20, 20, 20, 0.1)",
|
||||
300: "rgba(20, 20, 20, 0.15)",
|
||||
400: "rgba(20, 20, 20, 0.2)",
|
||||
500: "rgba(20, 20, 20, 0.3)",
|
||||
600: "rgba(20, 20, 20, 0.4)",
|
||||
700: "rgba(20, 20, 20, 0.5)",
|
||||
800: "rgba(20, 20, 20, 0.6)",
|
||||
900: "rgba(20, 20, 20, 0.7)",
|
||||
25: "rgba(11, 11, 11, 0.03)",
|
||||
50: "rgba(11, 11, 11, 0.05)",
|
||||
100: "rgba(11, 11, 11, 0.08)",
|
||||
200: "rgba(11, 11, 11, 0.1)",
|
||||
300: "rgba(11, 11, 11, 0.15)",
|
||||
400: "rgba(11, 11, 11, 0.2)",
|
||||
500: "rgba(11, 11, 11, 0.3)",
|
||||
600: "rgba(11, 11, 11, 0.4)",
|
||||
700: "rgba(11, 11, 11, 0.5)",
|
||||
800: "rgba(11, 11, 11, 0.6)",
|
||||
900: "rgba(11, 11, 11, 0.7)",
|
||||
},
|
||||
red: {
|
||||
25: "#FFFBFB",
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
<% content_for :sidebar do %>
|
||||
<%= render "settings/nav" %>
|
||||
<% end %>
|
||||
<div class="space-y-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<h1 class="text-xl font-medium text-gray-900">Accounts</h1>
|
||||
|
@ -6,7 +9,7 @@
|
|||
<span><%= t(".new_account") %></span>
|
||||
<% end %>
|
||||
</div>
|
||||
<% if Current.family.accounts.empty? %>
|
||||
<% if @accounts.empty? %>
|
||||
<div class="flex justify-center items-center h-[800px] text-sm">
|
||||
<div class="text-center flex flex-col items-center max-w-[300px]">
|
||||
<p class="text-gray-900 mb-1 font-medium">No accounts yet</p>
|
||||
|
@ -19,8 +22,8 @@
|
|||
</div>
|
||||
<% else %>
|
||||
<div>
|
||||
<% Current.family.accounts.by_provider.each do |item| %>
|
||||
<details class="bg-white group p-4 border border-alpha-black-25 shadow-xs rounded-xl">
|
||||
<% @accounts.by_provider.each do |item| %>
|
||||
<details open class="bg-white group p-4 border border-alpha-black-25 shadow-xs rounded-xl">
|
||||
<summary class="flex items-center gap-2">
|
||||
<%= lucide_icon("chevron-down", class: "hidden group-open:block w-5 h-5 text-gray-500") %>
|
||||
<%= lucide_icon("chevron-right", class: "group-open:hidden w-5 h-5 text-gray-500") %>
|
||||
|
@ -54,4 +57,12 @@
|
|||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="flex justify-between gap-4">
|
||||
<% if self_hosted? %>
|
||||
<%= previous_setting("Self Hosting", settings_hosting_path) %>
|
||||
<% else %>
|
||||
<%= previous_setting("Billing", settings_billing_path) %>
|
||||
<% end %>
|
||||
<%= next_setting("Categories", transactions_categories_path) %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
76
app/views/accounts/summary.html.erb
Normal file
76
app/views/accounts/summary.html.erb
Normal file
|
@ -0,0 +1,76 @@
|
|||
<div class="space-y-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<h1 class="text-xl font-medium text-gray-900">Accounts</h1>
|
||||
<%= link_to new_account_path, class: "flex text-white text-sm font-medium items-center gap-1 bg-gray-900 rounded-lg p-2", data: { turbo_frame: "modal" } do %>
|
||||
<%= lucide_icon("plus", class: "w-5 h-5") %>
|
||||
<span><%= t(".new") %></span>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="bg-white rounded-xl shadow-xs border border-alpha-black-100 flex divide-x divide-gray-200">
|
||||
<div class="w-1/2 p-4 flex items-stretch justify-between">
|
||||
<div class="space-y-2 grow">
|
||||
<%= render partial: "shared/balance_heading", locals: {
|
||||
label: "Assets",
|
||||
period: @period,
|
||||
balance: Current.family.assets,
|
||||
trend: @asset_series.trend
|
||||
} %>
|
||||
</div>
|
||||
<div
|
||||
data-controller="trendline"
|
||||
id="assetsTrendline"
|
||||
class="h-full w-2/5"
|
||||
data-trendline-series-value="<%= @asset_series.to_json %>"
|
||||
data-trendline-classification-value="asset"></div>
|
||||
</div>
|
||||
<div class="w-1/2 p-4 flex items-stretch justify-between">
|
||||
<div class="space-y-2 grow">
|
||||
<%= render partial: "shared/balance_heading", locals: {
|
||||
label: "Liabilities",
|
||||
period: @period,
|
||||
size: "md",
|
||||
balance: Current.family.liabilities,
|
||||
trend: @liability_series.trend
|
||||
} %>
|
||||
</div>
|
||||
<div
|
||||
data-controller="trendline"
|
||||
id="liabilitiesTrendline"
|
||||
class="h-full w-2/5"
|
||||
data-trendline-series-value="<%= @liability_series.to_json %>"
|
||||
data-trendline-classification-value="liability"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-4 bg-white rounded-xl shadow-xs border border-alpha-black-25 space-y-4">
|
||||
<div class="flex justify-between items-center mb-5">
|
||||
<h2 class="text-lg font-medium text-gray-900">Assets</h2>
|
||||
<div class="flex items-center gap-2">
|
||||
<%= link_to new_account_path, class: "flex items-center gap-1 p-2 text-gray-900 text-sm font-medium bg-gray-50 rounded-lg hover:bg-gray-100", data: { turbo_frame: "modal" } do %>
|
||||
<%= lucide_icon("plus", class: "w-5 h-5 text-gray-500") %>
|
||||
<p><%= t(".new") %></p>
|
||||
<% end %>
|
||||
<%= form_with url: summary_accounts_path, method: :get, class: "flex items-center gap-4", data: { controller: "auto-submit-form" } do %>
|
||||
<%= render partial: "shared/period_select", locals: { value: @period.name } %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<%= render partial: "pages/account_percentages_bar", locals: { account_groups: @account_groups[:assets].children } %>
|
||||
<%= render partial: "pages/account_percentages_table", locals: { account_groups: @account_groups[:assets].children } %>
|
||||
</div>
|
||||
<div class="p-4 bg-white rounded-xl shadow-xs border border-alpha-black-25 space-y-4">
|
||||
<div class="flex justify-between items-center mb-5">
|
||||
<h2 class="text-lg font-medium text-gray-900">Liabilities</h2>
|
||||
<div class="flex items-center gap-2">
|
||||
<%= link_to new_account_path, class: "flex items-center gap-1 p-2 text-gray-900 text-sm font-medium bg-gray-50 rounded-lg hover:bg-gray-100", data: { turbo_frame: "modal" } do %>
|
||||
<%= lucide_icon("plus", class: "w-5 h-5 text-gray-500") %>
|
||||
<p><%= t(".new") %></p>
|
||||
<% end %>
|
||||
<%= form_with url: summary_accounts_path, method: :get, class: "flex items-center gap-4", data: { controller: "auto-submit-form" } do %>
|
||||
<%= render partial: "shared/period_select", locals: { value: @period.name } %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<%= render partial: "pages/account_percentages_bar", locals: { account_groups: @account_groups[:liabilities].children } %>
|
||||
<%= render partial: "pages/account_percentages_table", locals: { account_groups: @account_groups[:liabilities].children } %>
|
||||
</div>
|
||||
</div>
|
88
app/views/layouts/_sidebar.html.erb
Normal file
88
app/views/layouts/_sidebar.html.erb
Normal file
|
@ -0,0 +1,88 @@
|
|||
<div class="flex items-center justify-between">
|
||||
<%= link_to root_path do %>
|
||||
<%= image_tag "logo.svg", alt: "Maybe", class: "h-[22px]" %>
|
||||
<% end %>
|
||||
<div id="user-menu" data-controller="menu">
|
||||
<button data-menu-target="button">
|
||||
<div class="text-white w-9 h-9 bg-gray-400 rounded-full flex items-center justify-center text-lg uppercase"><%= Current.user.email.first %></div>
|
||||
</button>
|
||||
<div data-menu-target="content" class="hidden absolute w-[240px] z-10 top-10 left-[255px] top-[72px] bg-white rounded-sm shadow-xs border border-alpha-black-25">
|
||||
<div class="p-3 flex items-center gap-3">
|
||||
<div class="text-white shrink-0 w-9 h-9 bg-gray-400 rounded-full flex items-center justify-center text-lg uppercase"><%= Current.user.email.first %></div>
|
||||
<div>
|
||||
<span class="text-gray-900 font-medium text-sm"><%= Current.user.first_name %> <%= Current.user.last_name %></span>
|
||||
<span class="text-gray-500 text-sm"><%= Current.user.email %></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="border-t border-b border-alpha-black-100 p-1">
|
||||
<%= link_to settings_profile_path, class: "flex gap-2 items-center hover:bg-gray-50 rounded-lg px-3 py-2" do %>
|
||||
<%= lucide_icon("settings", class: "w-5 h-5 text-gray-500 shrink-0") %>
|
||||
<span class="text-gray-900 text-sm">Settings</span>
|
||||
<% end %>
|
||||
<div class="flex justify-between items-center gap-2">
|
||||
<div class="flex items-center gap-2 rounded-lg px-3 py-2">
|
||||
<%= lucide_icon("app-window", class: "w-5 h-5 text-gray-500 shrink-0") %>
|
||||
<div>
|
||||
<span class="text-gray-900 text-sm">Demo mode</span>
|
||||
<span class="text-gray-500 text-xs block">Coming soon...</span>
|
||||
</div>
|
||||
</div>
|
||||
<%# TODO: This will be a form toggle when implemented %>
|
||||
<div class="relative inline-block cursor-not-allowed" title="Coming soon...">
|
||||
<label class="cursor-not-allowed block bg-gray-100 w-9 h-5 rounded-full after:content-[''] after:block after:absolute after:top-0.5 after:left-0.5 after:bg-white after:w-4 after:h-4 after:rounded-full after:transition-transform after:duration-300 after:ease-in-out peer-checked:bg-green-600 peer-checked:after:translate-x-4"></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="border-t border-b border-alpha-black-100 p-1">
|
||||
<%= link_to changelog_path, class: "flex gap-2 items-center hover:bg-gray-50 rounded-lg px-3 py-2" do %>
|
||||
<%= lucide_icon("box", class: "w-5 h-5 text-gray-500 shrink-0") %>
|
||||
<span class="text-gray-900 text-sm">Changelog</span>
|
||||
<% end %>
|
||||
<%= link_to feedback_path, class: "flex gap-2 items-center hover:bg-gray-50 rounded-lg px-3 py-2" do %>
|
||||
<%= lucide_icon("megaphone", class: "w-5 h-5 text-gray-500 shrink-0") %>
|
||||
<span class="text-gray-900 text-sm">Feedback</span>
|
||||
<% end %>
|
||||
<%= link_to "https://link.maybe.co/discord", class: "flex gap-2 items-center hover:bg-gray-50 rounded-lg px-3 py-2" do %>
|
||||
<%= lucide_icon("message-square-more", class: "w-5 h-5 text-gray-500 shrink-0") %>
|
||||
<span class="text-gray-900 text-sm">Contact</span>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="p-1">
|
||||
<%= button_to session_path, method: :delete, class: "w-full text-red-400 flex gap-1 items-center hover:bg-gray-50 rounded-lg px-3 py-2" do %>
|
||||
<%= lucide_icon("log-out", class: "w-5 h-5 shrink-0") %>
|
||||
<span class="text-sm">Logout</span>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<nav>
|
||||
<ul class="mt-6 space-y-1">
|
||||
<li>
|
||||
<%= sidebar_link_to t(".dashboard"), root_path, icon: "layout-grid" %>
|
||||
</li>
|
||||
<li>
|
||||
<%= sidebar_link_to t(".accounts"), summary_accounts_path, icon: "layers" %>
|
||||
</li>
|
||||
<li>
|
||||
<%= sidebar_link_to t(".transactions"), transactions_path, icon: "credit-card" %>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<div class="flex flex-col mt-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<%= link_to accounts_path, class: "text-xs uppercase text-gray-500 font-bold tracking-wide" do %>
|
||||
<%= t(".accounts") %>
|
||||
<% end %>
|
||||
<%= link_to new_account_path, class: "block hover:bg-gray-100 p-2 text-sm font-semibold text-gray-900 flex items-center rounded", title: t(".new_account"), data: { turbo_frame: "modal" } do %>
|
||||
<%= lucide_icon("plus", class: "w-5 h-5 text-gray-500") %>
|
||||
<% end %>
|
||||
</div>
|
||||
<%= link_to new_account_path, class: "flex items-center gap-4 px-2 py-3 mb-1 text-gray-500 text-sm font-medium rounded-[10px] hover:bg-gray-100", data: { turbo_frame: "modal" } do %>
|
||||
<%= lucide_icon("plus", class: "w-5 h-5") %>
|
||||
<p><%= t(".new_account") %></p>
|
||||
<% end %>
|
||||
<% account_groups.each do |group| %>
|
||||
<%= render "accounts/account_list", group: group %>
|
||||
<% end %>
|
||||
</div>
|
|
@ -25,73 +25,28 @@
|
|||
<body class="h-full">
|
||||
<div id="notification-tray" class="fixed z-50 space-y-1 top-6 right-6"></div>
|
||||
<%= safe_join(flash.map { |type, message| notification(message, type: type) }) %>
|
||||
<div class="flex">
|
||||
<div class="flex-col p-5 min-w-80">
|
||||
<div class="flex items-center justify-between">
|
||||
<%= link_to root_path do %>
|
||||
<%= image_tag "logo.svg", alt: "Maybe", class: "h-[22px]" %>
|
||||
<% end %>
|
||||
<div class="relative" data-controller="menu">
|
||||
<button data-menu-target="button">
|
||||
<div class="text-white w-9 h-9 bg-gray-400 rounded-full flex items-center justify-center text-lg uppercase"><%= Current.user.email.first %></div>
|
||||
</button>
|
||||
<div
|
||||
data-menu-target="content"
|
||||
class="hidden absolute min-w-[200px] z-10 top-10 right-0 bg-white p-1 rounded-sm shadow-xs border border-alpha-black-25 w-fit">
|
||||
<%= link_to edit_settings_path, class: "flex gap-1 items-center hover:bg-gray-50 rounded-md p-2" do %>
|
||||
<%= lucide_icon("pencil-line", class: "w-5 h-5 text-gray-500 shrink-0") %>
|
||||
<span class="text-gray-900 text-sm">General Settings</span>
|
||||
<% end %>
|
||||
<% if self_hosted? %>
|
||||
<%= link_to edit_settings_self_hosting_path, class: "flex gap-1 items-center hover:bg-gray-50 rounded-md p-2" do %>
|
||||
<%= lucide_icon("pencil-line", class: "w-5 h-5 text-gray-500 shrink-0") %>
|
||||
<span class="text-gray-900 text-sm">Self Host Settings</span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<%= button_to session_path, method: :delete, class: "w-full text-gray-900 flex gap-1 items-center hover:bg-gray-50 rounded-md p-2" do %>
|
||||
<%= lucide_icon("log-out", class: "w-5 h-5 shrink-0") %>
|
||||
<span class="text-sm">Logout</span>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<nav>
|
||||
<ul class="mt-6 space-y-1">
|
||||
<li>
|
||||
<%= sidebar_link_to t(".dashboard"), root_path, icon: "layout-grid" %>
|
||||
</li>
|
||||
<li>
|
||||
<%= sidebar_link_to t(".accounts"), accounts_path, icon: "layers" %>
|
||||
</li>
|
||||
<li>
|
||||
<%= sidebar_link_to t(".transactions"), transactions_path, icon: "credit-card" %>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<div class="flex flex-col mt-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<%= link_to accounts_path, class: "text-xs uppercase text-gray-500 font-bold tracking-wide" do %>
|
||||
<%= t(".accounts") %>
|
||||
<% end %>
|
||||
<%= link_to new_account_path, class: "block hover:bg-gray-100 p-2 text-sm font-semibold text-gray-900 flex items-center rounded", title: t(".new_account"), data: { turbo_frame: "modal" } do %>
|
||||
<%= lucide_icon("plus", class: "w-5 h-5 text-gray-500") %>
|
||||
<% end %>
|
||||
</div>
|
||||
<%= link_to new_account_path, class: "flex items-center gap-4 px-2 py-3 mb-1 text-gray-500 text-sm font-medium rounded-[10px] hover:bg-gray-100", data: { turbo_frame: "modal" } do %>
|
||||
<%= lucide_icon("plus", class: "w-5 h-5") %>
|
||||
<p><%= t(".new_account") %></p>
|
||||
<% end %>
|
||||
<% account_groups.each do |group| %>
|
||||
<%= render "accounts/account_list", group: group %>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="flex h-full">
|
||||
<div class="p-6 w-80 shrink-0 h-full overflow-y-auto">
|
||||
<% if content_for?(:sidebar) %>
|
||||
<%= yield :sidebar %>
|
||||
<% else %>
|
||||
<%= render "layouts/sidebar" %>
|
||||
<% end %>
|
||||
</div>
|
||||
<main class="flex-grow px-20 py-6">
|
||||
<main class="grow px-20 py-6 h-full overflow-y-auto">
|
||||
<%= yield %>
|
||||
</main>
|
||||
</div>
|
||||
<%= turbo_frame_tag "modal" %>
|
||||
<%= render "shared/custom_confirm_modal" %>
|
||||
<%= render "shared/upgrade_notification" %>
|
||||
<% if self_hosted? %>
|
||||
<div class="flex items-center py-0.5 px-0.5 gap-1 fixed bottom-2 right-2 shadow-xs border border-alpha-black-50 rounded-md bg-white">
|
||||
<p class="text-xs text-gray-500 pl-2">Self-hosted Maybe: <%= Maybe.version.to_release_tag %></p>
|
||||
<%= link_to settings_hosting_path, class: "flex gap-1 items-center hover:bg-gray-50 rounded-md p-2" do %>
|
||||
<%= lucide_icon("settings", class: "w-4 h-4 text-gray-500 shrink-0") %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -15,6 +15,6 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="bg-white border border-alpha-black-25 shadow-xs rounded-lg divide-y divide-alpha-black-50">
|
||||
<%= render partial: "account_group_disclosure", collection: account_groups, as: :accountable_group %>
|
||||
<%= render partial: "pages/account_group_disclosure", collection: account_groups, as: :accountable_group %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
15
app/views/pages/changelog.html.erb
Normal file
15
app/views/pages/changelog.html.erb
Normal file
|
@ -0,0 +1,15 @@
|
|||
<% content_for :sidebar do %>
|
||||
<%= render "settings/nav" %>
|
||||
<% end %>
|
||||
<div class="space-y-4">
|
||||
<h1 class="text-gray-900 text-xl font-medium mb-4">What's New</h1>
|
||||
<div class="bg-white shadow-xs border border-alpha-black-25 rounded-xl p-4">
|
||||
<div class="flex justify-center items-center py-20">
|
||||
<p class="text-gray-500">Changelog coming soon...</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between gap-4">
|
||||
<%= previous_setting("Rules", transactions_rules_path) %>
|
||||
<%= next_setting("Feedback", feedback_path) %>
|
||||
</div>
|
||||
</div>
|
15
app/views/pages/feedback.html.erb
Normal file
15
app/views/pages/feedback.html.erb
Normal file
|
@ -0,0 +1,15 @@
|
|||
<% content_for :sidebar do %>
|
||||
<%= render "settings/nav" %>
|
||||
<% end %>
|
||||
<div class="space-y-4">
|
||||
<h1 class="text-gray-900 text-xl font-medium mb-4">Feedback</h1>
|
||||
<div class="bg-white shadow-xs border border-alpha-black-25 rounded-xl p-4">
|
||||
<div class="flex justify-center items-center py-20">
|
||||
<p class="text-gray-500">Feedback coming soon...</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between gap-4">
|
||||
<%= previous_setting("What's New", changelog_path) %>
|
||||
<%= next_setting("Invite friends", invites_path) %>
|
||||
</div>
|
||||
</div>
|
14
app/views/pages/invites.html.erb
Normal file
14
app/views/pages/invites.html.erb
Normal file
|
@ -0,0 +1,14 @@
|
|||
<% content_for :sidebar do %>
|
||||
<%= render "settings/nav" %>
|
||||
<% end %>
|
||||
<div class="space-y-4">
|
||||
<h1 class="text-gray-900 text-xl font-medium mb-4">Invite friends</h1>
|
||||
<div class="bg-white shadow-xs border border-alpha-black-25 rounded-xl p-4">
|
||||
<div class="flex justify-center items-center py-20">
|
||||
<p class="text-gray-500">Invite friends coming soon...</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between gap-4">
|
||||
<%= previous_setting("Feedback", feedback_path) %>
|
||||
</div>
|
||||
</div>
|
56
app/views/settings/_nav.html.erb
Normal file
56
app/views/settings/_nav.html.erb
Normal file
|
@ -0,0 +1,56 @@
|
|||
<div class="flex items-center gap-1 mb-6">
|
||||
<%= link_to root_path, class: "flex items-center gap-1 text-gray-900 font-medium text-sm" do %>
|
||||
<%= lucide_icon "chevron-left", class: "w-5 h-5 text-gray-500" %>
|
||||
<span>Back</span>
|
||||
<% end %>
|
||||
<span data-controller="hotkey" data-hotkey="Escape" data-action="hotkey#navigateBack" class="uppercase bg-gray-100 rounded-sm px-1 py-0.5 text-xs text-gray-500 shadow-sm ml-1">
|
||||
esc
|
||||
</span>
|
||||
</div>
|
||||
<nav class="space-y-4">
|
||||
<section class="space-y-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<h3 class="uppercase text-gray-500 font-medium text-xs">General</h3>
|
||||
<div class="h-px bg-alpha-black-100 w-full"></div>
|
||||
</div>
|
||||
<ul class="space-y-1">
|
||||
<li>
|
||||
<%= sidebar_link_to t(".profile_label"), settings_profile_path, icon: "circle-user" %>
|
||||
<%= sidebar_link_to t(".preferences_label"), settings_preferences_path, icon: "bolt" %>
|
||||
<%= sidebar_link_to t(".notifications_label"), settings_notifications_path, icon: "bell-dot" %>
|
||||
<%= sidebar_link_to t(".security_label"), settings_security_path, icon: "shield-check" %>
|
||||
<%= sidebar_link_to t(".billing_label"), settings_billing_path, icon: "circle-dollar-sign" %>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="space-y-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<h3 class="uppercase text-gray-500 font-medium text-xs">Setup</h3>
|
||||
<div class="h-px bg-alpha-black-100 w-full"></div>
|
||||
</div>
|
||||
<ul class="space-y-1">
|
||||
<li>
|
||||
<% if self_hosted? %>
|
||||
<%= sidebar_link_to t(".self_hosting_label"), settings_hosting_path, icon: "database" %>
|
||||
<% end %>
|
||||
<%= sidebar_link_to t(".accounts_label"), accounts_path, icon: "layers" %>
|
||||
<%= sidebar_link_to t(".categories_label"), transactions_categories_path, icon: "tags" %>
|
||||
<%= sidebar_link_to t(".merchants_label"), transactions_merchants_path, icon: "store" %>
|
||||
<%= sidebar_link_to t(".rules_label"), transactions_rules_path, icon: "list-checks" %>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="space-y-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<h3 class="uppercase text-gray-500 font-medium text-xs">More</h3>
|
||||
<div class="h-px bg-alpha-black-100 w-full"></div>
|
||||
</div>
|
||||
<ul class="space-y-1">
|
||||
<li>
|
||||
<%= sidebar_link_to t(".whats_new_label"), changelog_path, icon: "box" %>
|
||||
<%= sidebar_link_to t(".feedback_label"), feedback_path, icon: "megaphone" %>
|
||||
<%= sidebar_link_to t(".invite_label"), invites_path, icon: "gift" %>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</nav>
|
17
app/views/settings/_nav_link_large.html.erb
Normal file
17
app/views/settings/_nav_link_large.html.erb
Normal file
|
@ -0,0 +1,17 @@
|
|||
<%# locals: path, direction, title %>
|
||||
<%= link_to path, class: "w-full bg-white hover:bg-gray-50 rounded-xl border border-alpha-black-25 shadow-xs p-4 flex items-center justify-between" do %>
|
||||
<% if direction == 'previous' %>
|
||||
<div class="w-5 h-5 text-gray-500">
|
||||
<%= lucide_icon("arrow-left") %>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="<%= "flex-grow" if direction == "next" %> <%= "text-right" if direction == "previous" %>">
|
||||
<span class="block text-sm text-gray-500"><%= t(".#{direction}") %></span>
|
||||
<span class="block text-sm font-medium text-gray-900"><%= title %></span>
|
||||
</div>
|
||||
<% if direction == 'next' %>
|
||||
<div class="w-5 h-5 text-gray-500">
|
||||
<%= lucide_icon("arrow-right") %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
19
app/views/settings/billings/show.html.erb
Normal file
19
app/views/settings/billings/show.html.erb
Normal file
|
@ -0,0 +1,19 @@
|
|||
<% content_for :sidebar do %>
|
||||
<%= render "settings/nav" %>
|
||||
<% end %>
|
||||
<div class="space-y-4">
|
||||
<h1 class="text-gray-900 text-xl font-medium mb-4">Billing</h1>
|
||||
<div class="bg-white shadow-xs border border-alpha-black-25 rounded-xl p-4">
|
||||
<div class="flex justify-center items-center py-20">
|
||||
<p class="text-gray-500">Billing settings coming soon...</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between gap-4">
|
||||
<%= previous_setting("Security", settings_security_path) %>
|
||||
<% if self_hosted? %>
|
||||
<%= next_setting("Self Hosting", settings_hosting_path) %>
|
||||
<% else %>
|
||||
<%= next_setting("Accounts", accounts_path) %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
|
@ -1,17 +0,0 @@
|
|||
<h1 class="text-3xl font-semibold font-display">Update settings</h1>
|
||||
<%= form_with model: Current.user, url: settings_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" } %>
|
||||
<% 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 %>
|
||||
<div class="fixed right-5 bottom-5">
|
||||
<button type="submit" class="flex items-center justify-center w-12 h-12 mb-2 bg-black rounded-full shrink-0 grow-0 hover:bg-gray-600">
|
||||
<%= inline_svg_tag("icn-check.svg", class: "text-white fill-current") %>
|
||||
</button>
|
||||
</div>
|
||||
<% end %>
|
|
@ -1,11 +1,14 @@
|
|||
<% content_for :sidebar do %>
|
||||
<%= render "settings/nav" %>
|
||||
<% end %>
|
||||
<div class="space-y-4">
|
||||
<h1 class="text-3xl font-semibold font-display">Edit Self Hosting Settings</h1>
|
||||
<h1 class="text-3xl font-semibold font-display">Self Hosting</h1>
|
||||
<hr>
|
||||
<%= form_with model: Setting.new, url: settings_self_hosting_path, method: :patch, local: true, html: { class: "space-y-4" } do |form| %>
|
||||
<%= form_with model: Setting.new, url: settings_hosting_path, method: :patch, local: true, html: { class: "space-y-4" } do |form| %>
|
||||
<section class="space-y-3">
|
||||
<h2 class="text-2xl font-semibold">Render Deploy Hook</h2>
|
||||
<p class="text-gray-500">You must fill this in so your app can trigger upgrades when Maybe releases upgrades. Learn more about deploy hooks and how they work in the <%= link_to "Render documentation", "https://docs.render.com/docs/deploy-hooks", target: "_blank", rel: "noopener noreferrer", class: "text-blue-500 hover:underline" %>.</p>
|
||||
<%= form.text_field :render_deploy_hook, label: "Render Deploy Hook", placeholder: "https://api.render.com/deploy/srv-xyz...", value: Setting.render_deploy_hook %>
|
||||
<%= form.url_field :render_deploy_hook, label: "Render Deploy Hook", placeholder: "https://api.render.com/deploy/srv-xyz...", value: Setting.render_deploy_hook %>
|
||||
</section>
|
||||
<section class="space-y-3">
|
||||
<h2 class="text-2xl font-semibold">Auto Upgrades Setting</h2>
|
||||
|
@ -37,4 +40,8 @@
|
|||
</button>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="flex justify-between gap-4">
|
||||
<%= previous_setting("Billing", settings_billing_path) %>
|
||||
<%= next_setting("Accounts", accounts_path) %>
|
||||
</div>
|
||||
</div>
|
15
app/views/settings/notifications/show.html.erb
Normal file
15
app/views/settings/notifications/show.html.erb
Normal file
|
@ -0,0 +1,15 @@
|
|||
<% content_for :sidebar do %>
|
||||
<%= render "settings/nav" %>
|
||||
<% end %>
|
||||
<div class="space-y-4">
|
||||
<h1 class="text-gray-900 text-xl font-medium mb-4">Notifications</h1>
|
||||
<div class="bg-white shadow-xs border border-alpha-black-25 rounded-xl p-4">
|
||||
<div class="flex justify-center items-center py-20">
|
||||
<p class="text-gray-500">Notifications coming soon...</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between gap-4">
|
||||
<%= previous_setting("Preferences", settings_preferences_path) %>
|
||||
<%= next_setting("Security", settings_security_path) %>
|
||||
</div>
|
||||
</div>
|
15
app/views/settings/preferences/show.html.erb
Normal file
15
app/views/settings/preferences/show.html.erb
Normal file
|
@ -0,0 +1,15 @@
|
|||
<% content_for :sidebar do %>
|
||||
<%= render "settings/nav" %>
|
||||
<% end %>
|
||||
<div class="space-y-4">
|
||||
<h1 class="text-gray-900 text-xl font-medium mb-4">Preferences</h1>
|
||||
<div class="bg-white shadow-xs border border-alpha-black-25 rounded-xl p-4">
|
||||
<div class="flex justify-center items-center py-20">
|
||||
<p class="text-gray-500">Preferences coming soon...</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between gap-4">
|
||||
<%= previous_setting("Account", settings_profile_path) %>
|
||||
<%= next_setting("Notifications", settings_notifications_path) %>
|
||||
</div>
|
||||
</div>
|
25
app/views/settings/profiles/show.html.erb
Normal file
25
app/views/settings/profiles/show.html.erb
Normal file
|
@ -0,0 +1,25 @@
|
|||
<% content_for :sidebar do %>
|
||||
<%= render "settings/nav" %>
|
||||
<% end %>
|
||||
<div class="space-y-4">
|
||||
<h1 class="text-gray-900 text-xl font-medium mb-4">Account</h1>
|
||||
<%= 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" } %>
|
||||
<% 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 %>
|
||||
<div class="fixed right-5 bottom-5">
|
||||
<button type="submit" class="flex items-center justify-center w-12 h-12 mb-2 bg-black rounded-full shrink-0 grow-0 hover:bg-gray-600">
|
||||
<%= inline_svg_tag("icn-check.svg", class: "text-white fill-current") %>
|
||||
</button>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="flex gap-4">
|
||||
<%= next_setting("Preferences", settings_preferences_path) %>
|
||||
</div>
|
||||
</div>
|
15
app/views/settings/securities/show.html.erb
Normal file
15
app/views/settings/securities/show.html.erb
Normal file
|
@ -0,0 +1,15 @@
|
|||
<% content_for :sidebar do %>
|
||||
<%= render "settings/nav" %>
|
||||
<% end %>
|
||||
<div class="space-y-4">
|
||||
<h1 class="text-gray-900 text-xl font-medium mb-4">Security</h1>
|
||||
<div class="bg-white shadow-xs border border-alpha-black-25 rounded-xl p-4">
|
||||
<div class="flex justify-center items-center py-20">
|
||||
<p class="text-gray-500">Security settings coming soon...</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between gap-4">
|
||||
<%= previous_setting("Notifications", settings_notifications_path) %>
|
||||
<%= next_setting("Billing", settings_billing_path) %>
|
||||
</div>
|
||||
</div>
|
15
app/views/transactions/categories/index.html.erb
Normal file
15
app/views/transactions/categories/index.html.erb
Normal file
|
@ -0,0 +1,15 @@
|
|||
<% content_for :sidebar do %>
|
||||
<%= render "settings/nav" %>
|
||||
<% end %>
|
||||
<div class="space-y-4">
|
||||
<h1 class="text-gray-900 text-xl font-medium mb-4">Categories</h1>
|
||||
<div class="bg-white shadow-xs border border-alpha-black-25 rounded-xl p-4">
|
||||
<div class="flex justify-center items-center py-20">
|
||||
<p class="text-gray-500">Transaction categories coming soon...</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between gap-4">
|
||||
<%= previous_setting("Accounts", accounts_path) %>
|
||||
<%= next_setting("Merchants", transactions_merchants_path) %>
|
||||
</div>
|
||||
</div>
|
15
app/views/transactions/merchants/index.html.erb
Normal file
15
app/views/transactions/merchants/index.html.erb
Normal file
|
@ -0,0 +1,15 @@
|
|||
<% content_for :sidebar do %>
|
||||
<%= render "settings/nav" %>
|
||||
<% end %>
|
||||
<div class="space-y-4">
|
||||
<h1 class="text-gray-900 text-xl font-medium mb-4">Merchants</h1>
|
||||
<div class="bg-white shadow-xs border border-alpha-black-25 rounded-xl p-4">
|
||||
<div class="flex justify-center items-center py-20">
|
||||
<p class="text-gray-500">Manage transaction merchants coming soon...</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between gap-4">
|
||||
<%= previous_setting("Categories", transactions_categories_path) %>
|
||||
<%= next_setting("Rules", transactions_rules_path) %>
|
||||
</div>
|
||||
</div>
|
15
app/views/transactions/rules/index.html.erb
Normal file
15
app/views/transactions/rules/index.html.erb
Normal file
|
@ -0,0 +1,15 @@
|
|||
<% content_for :sidebar do %>
|
||||
<%= render "settings/nav" %>
|
||||
<% end %>
|
||||
<div class="space-y-4">
|
||||
<h1 class="text-gray-900 text-xl font-medium mb-4">Rules</h1>
|
||||
<div class="bg-white shadow-xs border border-alpha-black-25 rounded-xl p-4">
|
||||
<div class="flex justify-center items-center py-20">
|
||||
<p class="text-gray-500">Transaction rules coming soon...</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between gap-4">
|
||||
<%= previous_setting("Merchants", transactions_merchants_path) %>
|
||||
<%= next_setting("What's New", changelog_path) %>
|
||||
</div>
|
||||
</div>
|
|
@ -16,6 +16,8 @@ en:
|
|||
placeholder: Example account name
|
||||
select_accountable_type: What would you like to add?
|
||||
title: Add an account
|
||||
summary:
|
||||
new: New account
|
||||
sync:
|
||||
success: Account sync started
|
||||
update:
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
---
|
||||
en:
|
||||
layouts:
|
||||
application:
|
||||
accounts: Accounts
|
||||
dashboard: Dashboard
|
||||
new_account: New account
|
||||
transactions: Transactions
|
||||
auth:
|
||||
or: or
|
||||
privacy_policy: Privacy Policy
|
||||
|
@ -13,3 +8,8 @@ en:
|
|||
sign_up: create an account
|
||||
terms_of_service: Terms of Service
|
||||
your_account: Your account
|
||||
sidebar:
|
||||
accounts: Accounts
|
||||
dashboard: Dashboard
|
||||
new_account: New account
|
||||
transactions: Transactions
|
||||
|
|
|
@ -1,8 +1,25 @@
|
|||
---
|
||||
en:
|
||||
settings:
|
||||
self_hosting:
|
||||
hostings:
|
||||
update:
|
||||
render_deploy_hook_error: Render deploy hook must be provided to enable auto
|
||||
upgrades
|
||||
success: Settings updated successfully.
|
||||
nav:
|
||||
accounts_label: Accounts
|
||||
billing_label: Billing
|
||||
categories_label: Categories
|
||||
feedback_label: Feedback
|
||||
invite_label: Invite friends
|
||||
merchants_label: Merchants
|
||||
notifications_label: Notifications
|
||||
preferences_label: Preferences
|
||||
profile_label: Account
|
||||
rules_label: Rules
|
||||
security_label: Security
|
||||
self_hosting_label: Self Hosting
|
||||
whats_new_label: What's New
|
||||
nav_link_large:
|
||||
next: Next
|
||||
previous: Back
|
||||
|
|
|
@ -1,24 +1,39 @@
|
|||
Rails.application.routes.draw do
|
||||
mount GoodJob::Engine => "jobs"
|
||||
|
||||
get "changelog" => "pages#changelog", as: :changelog
|
||||
get "feedback" => "pages#feedback", as: :feedback
|
||||
get "invites" => "pages#invites", as: :invites
|
||||
|
||||
resource :registration
|
||||
resource :session
|
||||
resource :password_reset
|
||||
resource :password
|
||||
|
||||
resource :settings, only: %i[edit update] do
|
||||
resource :self_hosting, only: %i[edit update], controller: "settings/self_hosting"
|
||||
namespace :settings do
|
||||
resource :profile, only: %i[show update]
|
||||
resource :preferences, only: %i[show update]
|
||||
resource :notifications, only: %i[show update]
|
||||
resource :billing, only: %i[show update]
|
||||
resource :hosting, only: %i[show update]
|
||||
resource :security, only: %i[show update]
|
||||
end
|
||||
|
||||
namespace :transactions do
|
||||
resources :categories
|
||||
|
||||
# TODO: These are *placeholders*
|
||||
# Uncomment `only` and add the necessary actions as they are implemented.
|
||||
resources :rules, only: [ :index ]
|
||||
resources :merchants, only: [ :index ]
|
||||
end
|
||||
|
||||
resources :transactions do
|
||||
match "search" => "transactions#search", on: :collection, via: [ :get, :post ], as: :search
|
||||
end
|
||||
|
||||
namespace :transactions do
|
||||
resources :categories
|
||||
end
|
||||
|
||||
resources :accounts, shallow: true do
|
||||
get :summary, on: :collection
|
||||
post :sync, on: :member
|
||||
resources :valuations
|
||||
end
|
||||
|
|
|
@ -12,9 +12,10 @@ class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
|
|||
fill_in "Password", with: "password"
|
||||
click_button "Log in"
|
||||
end
|
||||
assert_text "Dashboard", wait: 5
|
||||
find('[data-controller="menu"]').click
|
||||
end
|
||||
|
||||
def sign_out
|
||||
find("#user-menu").click
|
||||
click_button "Logout"
|
||||
assert_text "Sign in to your account"
|
||||
end
|
||||
end
|
||||
|
|
0
test/controllers/settings/billings_controller_test.rb
Normal file
0
test/controllers/settings/billings_controller_test.rb
Normal file
|
@ -1,6 +1,6 @@
|
|||
require "test_helper"
|
||||
|
||||
class Settings::SelfHostingControllerTest < ActionDispatch::IntegrationTest
|
||||
class Settings::HostingsControllerTest < ActionDispatch::IntegrationTest
|
||||
setup do
|
||||
ENV["SELF_HOSTING_ENABLED"] = "true"
|
||||
sign_in users(:family_admin)
|
||||
|
@ -9,14 +9,14 @@ class Settings::SelfHostingControllerTest < ActionDispatch::IntegrationTest
|
|||
test "cannot edit when self hosting is disabled" do
|
||||
ENV["SELF_HOSTING_ENABLED"] = "false"
|
||||
|
||||
get edit_settings_self_hosting_url
|
||||
get settings_hosting_url
|
||||
assert :not_found
|
||||
|
||||
patch settings_self_hosting_url, params: { setting: { render_deploy_hook: "https://example.com" } }
|
||||
patch settings_hosting_url, params: { setting: { render_deploy_hook: "https://example.com" } }
|
||||
assert :not_found
|
||||
end
|
||||
test "should get edit when self hosting is enabled" do
|
||||
get edit_settings_self_hosting_url
|
||||
get settings_hosting_url
|
||||
assert_response :success
|
||||
end
|
||||
|
||||
|
@ -24,7 +24,7 @@ class Settings::SelfHostingControllerTest < ActionDispatch::IntegrationTest
|
|||
NEW_RENDER_DEPLOY_HOOK = "https://api.render.com/deploy/srv-abc123"
|
||||
assert_nil Setting.render_deploy_hook
|
||||
|
||||
patch settings_self_hosting_url, params: { setting: { render_deploy_hook: NEW_RENDER_DEPLOY_HOOK } }
|
||||
patch settings_hosting_url, params: { setting: { render_deploy_hook: NEW_RENDER_DEPLOY_HOOK } }
|
||||
|
||||
assert_equal NEW_RENDER_DEPLOY_HOOK, Setting.render_deploy_hook
|
||||
end
|
11
test/controllers/settings/notifications_controller_test.rb
Normal file
11
test/controllers/settings/notifications_controller_test.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
require "test_helper"
|
||||
|
||||
class Settings::NotificationsControllerTest < ActionDispatch::IntegrationTest
|
||||
setup do
|
||||
sign_in users(:family_admin)
|
||||
end
|
||||
test "get" do
|
||||
get settings_notifications_url
|
||||
assert_response :success
|
||||
end
|
||||
end
|
11
test/controllers/settings/preferences_controller_test.rb
Normal file
11
test/controllers/settings/preferences_controller_test.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
require "test_helper"
|
||||
|
||||
class Settings::PreferencesControllerTest < ActionDispatch::IntegrationTest
|
||||
setup do
|
||||
sign_in users(:family_admin)
|
||||
end
|
||||
test "get" do
|
||||
get settings_preferences_url
|
||||
assert_response :success
|
||||
end
|
||||
end
|
11
test/controllers/settings/profiles_controller_test.rb
Normal file
11
test/controllers/settings/profiles_controller_test.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
require "test_helper"
|
||||
|
||||
class Settings::ProfilesControllerTest < ActionDispatch::IntegrationTest
|
||||
setup do
|
||||
sign_in @user = users(:family_admin)
|
||||
end
|
||||
test "get" do
|
||||
get settings_profile_url
|
||||
assert_response :success
|
||||
end
|
||||
end
|
11
test/controllers/settings/securities_controller_test.rb
Normal file
11
test/controllers/settings/securities_controller_test.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
require "test_helper"
|
||||
|
||||
class Settings::SecuritiesControllerTest < ActionDispatch::IntegrationTest
|
||||
setup do
|
||||
sign_in users(:family_admin)
|
||||
end
|
||||
test "get" do
|
||||
get settings_security_url
|
||||
assert_response :success
|
||||
end
|
||||
end
|
|
@ -1,20 +0,0 @@
|
|||
require "application_system_test_case"
|
||||
|
||||
class AccountsTest < ApplicationSystemTestCase
|
||||
setup do
|
||||
sign_in @user = users(:family_admin)
|
||||
end
|
||||
|
||||
test "should create account" do
|
||||
skip("Disabling this test for now, UI is changing to quickly to do systems testing")
|
||||
|
||||
click_on "New account"
|
||||
click_on "Credit Card"
|
||||
within "form" do
|
||||
fill_in "Name", with: "VISA"
|
||||
fill_in "Balance", with: "1000"
|
||||
click_on "Submit"
|
||||
end
|
||||
assert_text "$1,000"
|
||||
end
|
||||
end
|
66
test/system/settings_test.rb
Normal file
66
test/system/settings_test.rb
Normal file
|
@ -0,0 +1,66 @@
|
|||
require "application_system_test_case"
|
||||
|
||||
class SettingsTest < ApplicationSystemTestCase
|
||||
setup do
|
||||
sign_in @user = users(:family_admin)
|
||||
|
||||
@settings_links = [
|
||||
[ "Account", "Account", settings_profile_path ],
|
||||
[ "Preferences", "Preferences", settings_preferences_path ],
|
||||
[ "Notifications", "Notifications", settings_notifications_path ],
|
||||
[ "Security", "Security", settings_security_path ],
|
||||
[ "Billing", "Billing", settings_billing_path ],
|
||||
[ "Accounts", "Accounts", accounts_path ],
|
||||
[ "Categories", "Categories", transactions_categories_path ],
|
||||
[ "Merchants", "Merchants", transactions_merchants_path ],
|
||||
[ "Rules", "Rules", transactions_rules_path ],
|
||||
[ "What's New", "What's New", changelog_path ],
|
||||
[ "Feedback", "Feedback", feedback_path ],
|
||||
[ "Invite friends", "Invite friends", invites_path ]
|
||||
]
|
||||
end
|
||||
|
||||
test "can access settings from sidebar" do
|
||||
open_settings_from_sidebar
|
||||
assert_selector "h1", text: "Account"
|
||||
assert_current_path settings_profile_path
|
||||
end
|
||||
|
||||
test "all settings views and links are accessible" do
|
||||
open_settings_from_sidebar
|
||||
|
||||
@settings_links.each_with_index do |(link_text, header_text, path), index|
|
||||
next_setting_path = @settings_links[index + 1][2] if index < @settings_links.size - 1
|
||||
prev_setting_path = @settings_links[index - 1][2] if index > 0
|
||||
|
||||
find_link(link_text, exact: true).click
|
||||
|
||||
assert_selector "h1", text: header_text
|
||||
assert_current_path path
|
||||
assert_link "Next", href: next_setting_path if next_setting_path.present?
|
||||
assert_link "Back", href: prev_setting_path if prev_setting_path.present?
|
||||
end
|
||||
|
||||
# Conditional nav items don't show by default
|
||||
assert_no_text "Self Hosting"
|
||||
end
|
||||
|
||||
test "can see conditional nav items" do
|
||||
ENV["SELF_HOSTING_ENABLED"] = "true"
|
||||
|
||||
open_settings_from_sidebar
|
||||
|
||||
click_link "Self Hosting"
|
||||
assert_selector "h1", text: "Self Hosting"
|
||||
end
|
||||
|
||||
test "clicking back or hitting escape key takes user back page they opened settings from" do
|
||||
# TODO: Implement test for back navigation and escape key functionality.
|
||||
end
|
||||
|
||||
private
|
||||
def open_settings_from_sidebar
|
||||
find("#user-menu").click
|
||||
click_link "Settings"
|
||||
end
|
||||
end
|
|
@ -1,3 +1,7 @@
|
|||
# Require individual test files to enable these as needed
|
||||
ENV["SELF_HOSTING_ENABLED"] = "false"
|
||||
ENV["UPGRADES_ENABLED"] = "false"
|
||||
|
||||
ENV["RAILS_ENV"] ||= "test"
|
||||
require_relative "../config/environment"
|
||||
require "rails/test_help"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue