diff --git a/app/controllers/strategies_controller.rb b/app/controllers/strategies_controller.rb new file mode 100644 index 0000000..50a20c2 --- /dev/null +++ b/app/controllers/strategies_controller.rb @@ -0,0 +1,60 @@ +class StrategiesController < ApplicationController + before_action :set_strategy, only: [ :show, :edit, :update, :destroy ] + + def index + @strategies = Strategy.all + end + + def show;end + + def new + @strategy = Strategy.new + @wallets = current_user.wallets + end + + def create + @strategy = Strategy.new(strategy_params) + + if @strategy.save + respond_to do |format| + format.turbo_stream + format.html { redirect_to strategies_path, notice: "Strategy created successfully!" } + end + else + render :new, status: :unprocessable_entity + end + end + + def edit;end + + def update + if @strategy.update(strategy_params) + respond_to do |format| + format.turbo_stream + format.html { redirect_to strategies_path, notice: "Strategy updated successfully!" } + end + else + render :edit, status: :unprocessable_entity + end + end + + def destroy + @strategy.destroy + respond_to do |format| + format.turbo_stream + format.html { redirect_to strategies_path, notice: "Strategy deleted successfully!" } + end + end + + private + + def strategy_params + params.require(:strategy).permit(:title, :wallet_id) + end + + def set_strategy + @strategy = Strategy.find(params[:id]) + rescue ActiveRecord::RecordNotFound + redirect_to strategies_path, alert: "Strategy not found!" + end +end diff --git a/app/controllers/strategy_rules_controller.rb b/app/controllers/strategy_rules_controller.rb new file mode 100644 index 0000000..1cd8dde --- /dev/null +++ b/app/controllers/strategy_rules_controller.rb @@ -0,0 +1,64 @@ +class StrategyRulesController < ApplicationController + before_action :set_strategy_rule, only: [ :show, :edit, :update, :destroy ] + before_action :set_strategies, only: [ :new, :create, :edit, :update ] + + def index + @strategy_rules = StrategyRule.all + end + + def show; end + + def new + @strategy_rule = StrategyRule.new + end + + def create + @strategy_rule = StrategyRule.new(strategy_rules_params) + + if @strategy_rule.save + respond_to do |format| + format.turbo_stream + format.html { redirect_to strategy_rules_path, notice: "Strategy rule created successfully!" } + end + else + render :new, status: :unprocessable_entity + end + end + + def edit; end + + def update + if @strategy_rule.update(strategy_rules_params) + respond_to do |format| + format.turbo_stream + format.html { redirect_to strategy_rules_path, notice: "Strategy rules updated successfully!" } + end + else + render :edit, status: :unprocessable_entity + end + end + + def destroy + @strategy_rule.destroy + respond_to do |format| + format.turbo_stream + format.html { redirect_to strategy_rules_path, notice: "Strategy rule deleted successfully!" } + end + end + + private + + def strategy_rules_params + params.require(:strategy_rule).permit(:strategy_id, :asset_kind, :min_percentage, :max_percentage, :rule_type) + end + + def set_strategy_rule + @strategy_rule = StrategyRule.find(params[:id]) + rescue ActiveRecord::RecordNotFound + redirect_to strategy_rules_path, alert: "Strategy rule not found!" + end + + def set_strategies + @strategies = Strategy.all + end +end diff --git a/app/javascript/controllers/rule_type_toggle_controller.js b/app/javascript/controllers/rule_type_toggle_controller.js new file mode 100644 index 0000000..0ce0cc3 --- /dev/null +++ b/app/javascript/controllers/rule_type_toggle_controller.js @@ -0,0 +1,22 @@ +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + connect() { + this.toggle() + } + + toggle() { + const percentageRadio = this.element.querySelector('input[value="percentage"]') + const prohibitionRadio = this.element.querySelector('input[value="prohibition"]') + const percentageFields = this.element.querySelector('#percentage-fields') + const prohibitionMessage = this.element.querySelector('#prohibition-message') + + if (percentageRadio && percentageRadio.checked) { + if (percentageFields) percentageFields.classList.remove('hidden') + if (prohibitionMessage) prohibitionMessage.classList.add('hidden') + } else if (prohibitionRadio && prohibitionRadio.checked) { + if (percentageFields) percentageFields.classList.add('hidden') + if (prohibitionMessage) prohibitionMessage.classList.remove('hidden') + } + } +} \ No newline at end of file diff --git a/app/models/strategy_rule.rb b/app/models/strategy_rule.rb index cefd4b3..cd9d567 100644 --- a/app/models/strategy_rule.rb +++ b/app/models/strategy_rule.rb @@ -1,3 +1,45 @@ class StrategyRule < ApplicationRecord belongs_to :strategy + + attr_accessor :rule_type + attr_accessor :min_percentage # Temporário até criar a migration + + validates :asset_kind, presence: true + validates :strategy_id, presence: true + validate :validate_percentage_rule, if: -> { rule_type == 'percentage' } + validate :validate_prohibition_rule, if: -> { rule_type == 'prohibition' } + + # Métodos auxiliares + def prohibition? + max_percentage.nil? && (min_percentage.nil? || min_percentage.blank?) + end + + def percentage_rule? + max_percentage.present? || min_percentage.present? + end + + private + + def validate_percentage_rule + if min_percentage.present? && max_percentage.present? + if min_percentage.to_f > max_percentage.to_f + errors.add(:min_percentage, "deve ser menor ou igual à porcentagem máxima") + end + if min_percentage.to_f < 0 || min_percentage.to_f > 100 + errors.add(:min_percentage, "deve estar entre 0 e 100") + end + if max_percentage.to_f < 0 || max_percentage.to_f > 100 + errors.add(:max_percentage, "deve estar entre 0 e 100") + end + elsif min_percentage.blank? && max_percentage.blank? + errors.add(:base, "Por favor, informe pelo menos a porcentagem mínima ou máxima") + end + end + + def validate_prohibition_rule + # Para proibição, não deve ter porcentagens + if min_percentage.present? || max_percentage.present? + errors.add(:base, "Regras de proibição não devem ter porcentagens definidas") + end + end end diff --git a/app/models/wallet.rb b/app/models/wallet.rb index 50494a9..de47ba0 100644 --- a/app/models/wallet.rb +++ b/app/models/wallet.rb @@ -2,6 +2,7 @@ class Wallet < ApplicationRecord belongs_to :user has_many :holdings has_many :transactions + has_one :strategy enum :status, { active: 1, inactive: 0 } validates :name, presence: true diff --git a/app/views/shared/dashboard/_sidebar.html.erb b/app/views/shared/dashboard/_sidebar.html.erb index 9d1949b..95037aa 100644 --- a/app/views/shared/dashboard/_sidebar.html.erb +++ b/app/views/shared/dashboard/_sidebar.html.erb @@ -35,12 +35,12 @@ Assets <% end %> - + <%= link_to strategies_path, class: "flex items-center space-x-3 px-4 py-3 rounded-lg transition #{current_page?(strategies_path) || controller_name == 'strategies' ? 'bg-yellow-400 text-gray-900' : 'hover:bg-white/10'}" do %> Strategies - + <% end %> diff --git a/app/views/strategies/_form.html.erb b/app/views/strategies/_form.html.erb new file mode 100644 index 0000000..f84cf03 --- /dev/null +++ b/app/views/strategies/_form.html.erb @@ -0,0 +1,37 @@ +<%= form_with(model: strategy, data: { turbo_frame: "_top" }, class: "space-y-6") do |form| %> + <% if strategy.errors.any? %> +
+

<%= pluralize(strategy.errors.count, "error") %> found:

+ +
+ <% end %> + +
+ <%= form.label :wallet_id, "Wallet", class: "block text-sm font-bold text-gray-700 mb-2" %> + <%= form.select :wallet_id, + options_from_collection_for_select(@wallets, :id, :name, strategy.wallet_id), + { prompt: "Select a wallet" }, + class: "w-full px-4 py-3 border-2 border-gray-300 rounded-lg focus:border-yellow-500 focus:ring-2 focus:ring-yellow-200 transition-all outline-none" %> +
+ +
+ <%= form.label :title, "Strategy Title", class: "block text-sm font-bold text-gray-700 mb-2" %> + <%= form.text_field :title, + class: "w-full px-4 py-3 border-2 border-gray-300 rounded-lg focus:border-yellow-500 focus:ring-2 focus:ring-yellow-200 transition-all outline-none", + placeholder: "e.g. Conservative Portfolio", + autofocus: true %> +
+ +
+ <%= form.submit "Save", + class: "flex-1 bg-gradient-to-r from-yellow-500 to-amber-500 hover:from-yellow-600 hover:to-amber-600 text-white font-bold py-4 rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 transform hover:scale-105 cursor-pointer" %> + <%= link_to "Cancel", + strategies_path, + class: "flex-1 bg-gray-200 hover:bg-gray-300 text-gray-800 font-bold py-4 rounded-xl text-center transition-all", + data: { turbo_frame: "_top" } %> +
+<% end %> diff --git a/app/views/strategies/_strategy.html.erb b/app/views/strategies/_strategy.html.erb new file mode 100644 index 0000000..e332f95 --- /dev/null +++ b/app/views/strategies/_strategy.html.erb @@ -0,0 +1,20 @@ +
+
+

+ <%= strategy.title %> +

+
+ +
+
+

Wallet

+

<%= strategy.wallet.name %>

+
+ +
+ <%= link_to "View", strategy_path(strategy), class: "flex-1 bg-gray-100 hover:bg-gray-200 text-gray-800 font-bold py-2 px-4 rounded-lg text-center transition-all" %> + <%= link_to "Edit", edit_strategy_path(strategy), class: "flex-1 bg-yellow-500 hover:bg-yellow-600 text-white font-bold py-2 px-4 rounded-lg text-center transition-all", data: { turbo_frame: "modal" } %> + <%= button_to "Delete", strategy_path(strategy), method: :delete, data: { turbo_confirm: "Are you sure?" }, class: "flex-1 bg-red-500 hover:bg-red-600 text-white font-bold py-2 px-4 rounded-lg transition-all" %> +
+
+
diff --git a/app/views/strategies/create.turbo_stream.erb b/app/views/strategies/create.turbo_stream.erb new file mode 100644 index 0000000..fd7dabe --- /dev/null +++ b/app/views/strategies/create.turbo_stream.erb @@ -0,0 +1,11 @@ +<%= turbo_stream.append "strategies" do %> + <%= render @strategy %> +<% end %> + +<%= turbo_stream.update "modal", "" %> + +<%= turbo_stream.update "flash" do %> +
+ ✓ Strategy created successfully! +
+<% end %> diff --git a/app/views/strategies/destroy.turbo_stream.erb b/app/views/strategies/destroy.turbo_stream.erb new file mode 100644 index 0000000..d049ac0 --- /dev/null +++ b/app/views/strategies/destroy.turbo_stream.erb @@ -0,0 +1,7 @@ +<%= turbo_stream.remove dom_id(@strategy) %> + +<%= turbo_stream.update "flash" do %> +
+ ✓ Strategy deleted successfully! +
+<% end %> diff --git a/app/views/strategies/edit.html.erb b/app/views/strategies/edit.html.erb new file mode 100644 index 0000000..526e238 --- /dev/null +++ b/app/views/strategies/edit.html.erb @@ -0,0 +1,19 @@ +<%= turbo_frame_tag "modal" do %> +
+
+
+
+

Edit Strategy

+ <%= link_to "✕", + strategies_path, + class: "text-gray-400 hover:text-gray-600 text-2xl font-bold", + data: { turbo_frame: "_top" } %> +
+
+ +
+ <%= render "form", strategy: @strategy %> +
+
+
+<% end %> diff --git a/app/views/strategies/index.html.erb b/app/views/strategies/index.html.erb new file mode 100644 index 0000000..471d4d7 --- /dev/null +++ b/app/views/strategies/index.html.erb @@ -0,0 +1,45 @@ +
+
+
+

My Strategies

+

Manage your investment strategies

+
+ <%= link_to new_strategy_path, + class: "group relative inline-flex items-center justify-center gap-2 bg-gradient-to-r from-yellow-500 to-amber-500 hover:from-yellow-600 hover:to-amber-600 text-white font-bold py-4 px-8 rounded-xl shadow-2xl hover:shadow-yellow-500/50 transition-all duration-300 transform hover:scale-105", + data: { turbo_frame: "modal" } do %> + + + + New Strategy + <% end %> +
+ <%= turbo_frame_tag "modal" %> + <% if @strategies.any? %> +
+ <%= render @strategies %> +
+ <% else %> +
+
+
+
+
+ + + + +
+

No strategies registered yet

+

Start building your portfolio with a custom investment strategy!

+ <%= link_to new_strategy_path, + class: "group inline-flex items-center gap-3 bg-gradient-to-r from-yellow-500 to-amber-500 hover:from-yellow-600 hover:to-amber-600 text-white font-bold py-4 px-10 rounded-xl shadow-2xl hover:shadow-yellow-500/50 transition-all duration-300 transform hover:scale-105", + data: { turbo_frame: "modal" } do %> + + + + Create First Strategy + <% end %> +
+
+ <% end %> +
diff --git a/app/views/strategies/new.html.erb b/app/views/strategies/new.html.erb new file mode 100644 index 0000000..73bd17f --- /dev/null +++ b/app/views/strategies/new.html.erb @@ -0,0 +1,18 @@ +<%= turbo_frame_tag "modal" do %> +
+
+
+

New Strategy

+ <%= link_to strategies_path, class: "text-white hover:bg-white/20 rounded-lg p-2 transition-colors", data: { turbo_frame: "_top" } do %> + + + + <% end %> +
+ +
+ <%= render "form", strategy: @strategy %> +
+
+
+<% end %> diff --git a/app/views/strategies/update.turbo_stream.erb b/app/views/strategies/update.turbo_stream.erb new file mode 100644 index 0000000..c14b83d --- /dev/null +++ b/app/views/strategies/update.turbo_stream.erb @@ -0,0 +1,11 @@ +<%= turbo_stream.replace dom_id(@strategy) do %> + <%= render @strategy %> +<% end %> + +<%= turbo_stream.update "modal", "" %> + +<%= turbo_stream.update "flash" do %> +
+ ✓ Strategy updated successfully! +
+<% end %> diff --git a/app/views/strategy_rules/_form.html.erb b/app/views/strategy_rules/_form.html.erb new file mode 100644 index 0000000..50aadba --- /dev/null +++ b/app/views/strategy_rules/_form.html.erb @@ -0,0 +1,166 @@ +<%= form_with(model: strategy_rule, data: { turbo_frame: "_top" }, class: "space-y-6") do |form| %> + <% if strategy_rule.errors[:base].any? %> +
+ +
+ <% end %> + +
+ <%= form.label :strategy_id, "Strategy", class: "block text-sm font-bold text-gray-700 mb-2" %> + <%= form.select :strategy_id, + options_from_collection_for_select(@strategies, :id, :title, strategy_rule.strategy_id), + { prompt: "Select a strategy" }, + class: "w-full px-4 py-3 border-2 #{strategy_rule.errors[:strategy_id].any? ? 'border-red-500' : 'border-gray-300'} rounded-lg focus:border-yellow-500 focus:ring-2 focus:ring-yellow-200 transition-all outline-none" %> + <% if strategy_rule.errors[:strategy_id].any? %> +

+ + + + <%= strategy_rule.errors[:strategy_id].first %> +

+ <% end %> +
+ +
+ <%= form.label :asset_kind, "Asset Type", class: "block text-sm font-bold text-gray-700 mb-2" %> + <%= form.select :asset_kind, + [ + ["Stock", "stock"], + ["Cryptocurrency", "crypto"], + ["ETF", "etf"], + ["Bond", "bond"], + ["Real Estate", "real_estate"], + ["Commodity", "commodity"], + ["Other", "other"] + ], + { include_blank: "Select an asset type" }, + class: "w-full px-4 py-3 border-2 #{strategy_rule.errors[:asset_kind].any? ? 'border-red-500' : 'border-gray-300'} rounded-lg focus:border-yellow-500 focus:ring-2 focus:ring-yellow-200 transition-all outline-none" %> + <% if strategy_rule.errors[:asset_kind].any? %> +

+ + + + <%= strategy_rule.errors[:asset_kind].first %> +

+ <% end %> +
+ +
+ +
+ +
+ + + +
+
+ +
+
+
+ <%= form.label :min_percentage, "Minimum Percentage (%)", class: "block text-sm font-bold text-gray-700 mb-2" %> + <%= form.number_field :min_percentage, + value: strategy_rule.min_percentage, + step: 0.01, + min: 0, + max: 100, + class: "w-full px-4 py-3 border-2 #{strategy_rule.errors[:min_percentage].any? ? 'border-red-500' : 'border-gray-300'} rounded-lg focus:border-yellow-500 focus:ring-2 focus:ring-yellow-200 transition-all outline-none", + placeholder: "0.00" %> + <% if strategy_rule.errors[:min_percentage].any? %> +

+ + + + <%= strategy_rule.errors[:min_percentage].first %> +

+ <% else %> +

e.g., 10.00 for 10%

+ <% end %> +
+ +
+ <%= form.label :max_percentage, "Maximum Percentage (%)", class: "block text-sm font-bold text-gray-700 mb-2" %> + <%= form.number_field :max_percentage, + value: strategy_rule.max_percentage, + step: 0.01, + min: 0, + max: 100, + class: "w-full px-4 py-3 border-2 #{strategy_rule.errors[:max_percentage].any? ? 'border-red-500' : 'border-gray-300'} rounded-lg focus:border-yellow-500 focus:ring-2 focus:ring-yellow-200 transition-all outline-none", + placeholder: "0.00" %> + <% if strategy_rule.errors[:max_percentage].any? %> +

+ + + + <%= strategy_rule.errors[:max_percentage].first %> +

+ <% else %> +

e.g., 30.00 for 30%

+ <% end %> +
+
+ +
+

+ 💡 Tip: The sum of all maximum percentages should not exceed 100% to avoid conflicts. +

+
+
+ +
+
+ + + +
+

Prohibition Rule Active

+

+ This rule will prevent the wallet from having any position in this asset type. +

+
+
+
+
+ +
+ <%= form.submit "Save Rule", + class: "flex-1 bg-gradient-to-r from-yellow-500 to-amber-500 hover:from-yellow-600 hover:to-amber-600 text-white font-bold py-4 rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 transform hover:scale-105 cursor-pointer" %> + <%= link_to "Cancel", + strategy_rules_path, + class: "flex-1 bg-gray-200 hover:bg-gray-300 text-gray-800 font-bold py-4 rounded-xl text-center transition-all", + data: { turbo_frame: "_top" } %> +
+<% end %> diff --git a/app/views/strategy_rules/_strategy_rule.html.erb b/app/views/strategy_rules/_strategy_rule.html.erb new file mode 100644 index 0000000..52d6fde --- /dev/null +++ b/app/views/strategy_rules/_strategy_rule.html.erb @@ -0,0 +1,73 @@ + + +
+ <% if strategy_rule.prohibition? %> + + + + + Prohibition + + <% else %> + + + + + Percentage + + <% end %> +
+ + + +
+ <%= strategy_rule.asset_kind&.humanize || "N/A" %> +
+ <% if strategy_rule.percentage_rule? %> +
+ <% if strategy_rule.min_percentage.present? && strategy_rule.max_percentage.present? %> + <%= number_with_precision(strategy_rule.min_percentage, precision: 2) %>% - <%= number_with_precision(strategy_rule.max_percentage, precision: 2) %>% + <% elsif strategy_rule.min_percentage.present? %> + Min: <%= number_with_precision(strategy_rule.min_percentage, precision: 2) %>% + <% elsif strategy_rule.max_percentage.present? %> + Max: <%= number_with_precision(strategy_rule.max_percentage, precision: 2) %>% + <% end %> +
+ <% end %> + + + + <% if strategy_rule.prohibition? %> + + Not Allowed + + <% else %> + + Allowed + + <% end %> + + + +
+ <%= link_to edit_strategy_rule_path(strategy_rule), + class: "inline-flex items-center gap-2 px-4 py-2.5 bg-gray-800 hover:bg-gray-900 text-white text-sm font-semibold rounded-lg transition-colors duration-200 shadow-sm hover:shadow-md", + data: { turbo_frame: "modal" } do %> + + + + Edit + <% end %> + + <%= button_to strategy_rule_path(strategy_rule), + method: :delete, + form: { data: { turbo_confirm: "Are you sure you want to delete this rule?" }, class: "contents" }, + class: "inline-flex items-center gap-2 px-4 py-2.5 bg-orange-600 hover:bg-orange-700 text-white text-sm font-semibold rounded-lg transition-colors duration-200 shadow-sm hover:shadow-md" do %> + + + + Delete + <% end %> +
+ + \ No newline at end of file diff --git a/app/views/strategy_rules/create.turbo_stream.erb b/app/views/strategy_rules/create.turbo_stream.erb new file mode 100644 index 0000000..c368230 --- /dev/null +++ b/app/views/strategy_rules/create.turbo_stream.erb @@ -0,0 +1,12 @@ +<%= turbo_stream.append "strategy_rules" do %> + <%= render @strategy_rule %> + <% end %> + + <%= turbo_stream.update "modal", "" %> + + <%= turbo_stream.update "flash" do %> +
+ ✓ Strategy rule created successfully! +
+ <% end %> + \ No newline at end of file diff --git a/app/views/strategy_rules/destroy.turbo_stream.erb b/app/views/strategy_rules/destroy.turbo_stream.erb new file mode 100644 index 0000000..9508124 --- /dev/null +++ b/app/views/strategy_rules/destroy.turbo_stream.erb @@ -0,0 +1,7 @@ +<%= turbo_stream.remove dom_id(@strategy_rule) %> + +<%= turbo_stream.update "flash" do %> +
+ ✓ Strategy Rule deleted successfully! +
+<% end %> diff --git a/app/views/strategy_rules/edit.html.erb b/app/views/strategy_rules/edit.html.erb new file mode 100644 index 0000000..7f20b12 --- /dev/null +++ b/app/views/strategy_rules/edit.html.erb @@ -0,0 +1,19 @@ +<%= turbo_frame_tag "modal" do %> +
+
+
+
+

Edit Strategy rule

+ <%= link_to "✕", + strategy_rules_path, + class: "text-gray-900 hover:bg-white/20 rounded-lg p-2 transition-colors", + data: { turbo_frame: "_top" } %> +
+
+ +
+ <%= render "form", strategy_rule: @strategy_rule %> +
+
+
+<% end %> diff --git a/app/views/strategy_rules/index.html.erb b/app/views/strategy_rules/index.html.erb new file mode 100644 index 0000000..e6ce2a2 --- /dev/null +++ b/app/views/strategy_rules/index.html.erb @@ -0,0 +1,64 @@ +
+
+
+

Strategy Rules

+

Manage your strategy rules for <%= @strategy_rules.name %>

+
+ <%= link_to new_strategy_rule_path(@strategy_rules), + class: "inline-flex items-center justify-center gap-2 bg-yellow-500 hover:bg-yellow-600 text-white font-bold py-3 px-6 rounded-lg shadow-lg hover:shadow-xl transition-all duration-200", + data: { turbo_frame: "modal" } do %> + + + + New Rule + <% end %> +
+ + <%= turbo_frame_tag "modal" %> + + <% if @strategy_rules.any? %> +
+
+ + + + + + + + + + + <%= render @strategy_rules %> + +
+ Rule Type + + Value + + Allowed + + Actions +
+
+
+ <% else %> +
+
+ + + +
+

No rules registered yet

+

Start by creating your first rule!

+ <%= link_to new_strategy_rule_path(@strategy_rules), + class: "inline-flex items-center gap-2 bg-yellow-500 hover:bg-yellow-600 text-white font-bold py-3 px-6 rounded-lg shadow-lg hover:shadow-xl transition-all duration-200", + data: { turbo_frame: "modal" } do %> + + + + Create First Rule + <% end %> +
+ <% end %> +
diff --git a/app/views/strategy_rules/new.html.erb b/app/views/strategy_rules/new.html.erb new file mode 100644 index 0000000..87a4482 --- /dev/null +++ b/app/views/strategy_rules/new.html.erb @@ -0,0 +1,18 @@ +<%= turbo_frame_tag "modal" do %> +
+
+
+

New Strategy Rule

+ <%= link_to new_strategy_rule_path, class: "text-white hover:bg-white/20 rounded-lg p-2 transition-colors", data: { turbo_frame: "_top" } do %> + + + + <% end %> +
+ +
+ <%= render "form", strategy_rule: @strategy_rule %> +
+
+
+<% end %> diff --git a/app/views/strategy_rules/update.turbo_stream.erb b/app/views/strategy_rules/update.turbo_stream.erb new file mode 100644 index 0000000..95eee37 --- /dev/null +++ b/app/views/strategy_rules/update.turbo_stream.erb @@ -0,0 +1,11 @@ +<%= turbo_stream.replace dom_id(@strategy_rule) do %> + <%= render @strategy_rule %> +<% end %> + +<%= turbo_stream.update "modal", "" %> + +<%= turbo_stream.update "flash" do %> +
+ ✓ Strategy rule updated successfully! +
+<% end %> diff --git a/config/routes.rb b/config/routes.rb index 71f25f4..3b75d34 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -17,6 +17,8 @@ end resources :instruments + resources :strategies + resources :strategy_rules end # Render dynamic PWA files from app/views/pwa/* (remember to link manifest in application.html.erb) # get "manifest" => "rails/pwa#manifest", as: :pwa_manifest