diff --git a/Gemfile b/Gemfile index a85fd77..da1c7ab 100644 --- a/Gemfile +++ b/Gemfile @@ -8,9 +8,11 @@ gem "rails", "~> 7.1.3", ">= 7.1.3.2" gem "bootsnap", require: false gem "devise" +gem "devise-i18n" gem "image_processing" gem "importmap-rails" gem "jbuilder" +gem "kaminari" gem "packwerk" gem "pg" gem "puma" diff --git a/Gemfile.lock b/Gemfile.lock index e53dc31..790b5f0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -120,6 +120,8 @@ GEM railties (>= 4.1.0) responders warden (~> 1.2.3) + devise-i18n (1.12.0) + devise (>= 4.9.0) drb (2.2.1) erubi (1.12.0) ffi (1.16.3) @@ -143,6 +145,18 @@ GEM actionview (>= 5.0.0) activesupport (>= 5.0.0) json (2.7.1) + kaminari (1.2.2) + activesupport (>= 4.1.0) + kaminari-actionview (= 1.2.2) + kaminari-activerecord (= 1.2.2) + kaminari-core (= 1.2.2) + kaminari-actionview (1.2.2) + actionview + kaminari-core (= 1.2.2) + kaminari-activerecord (1.2.2) + activerecord + kaminari-core (= 1.2.2) + kaminari-core (1.2.2) language_server-protocol (3.17.0.3) loofah (2.22.0) crass (~> 1.0.2) @@ -320,10 +334,12 @@ DEPENDENCIES capybara debug devise + devise-i18n foreman image_processing importmap-rails jbuilder + kaminari packwerk pg puma diff --git a/app/assets/images/hoy.png b/app/assets/images/hoy.png new file mode 100644 index 0000000..7233e20 Binary files /dev/null and b/app/assets/images/hoy.png differ diff --git a/app/packages/accounts/views/accounts/passwords/new.html.erb b/app/packages/accounts/views/accounts/passwords/new.html.erb index f4f02aa..658a6b4 100644 --- a/app/packages/accounts/views/accounts/passwords/new.html.erb +++ b/app/packages/accounts/views/accounts/passwords/new.html.erb @@ -1,6 +1,4 @@ -

Forgot your password?

- -<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }, html: { class: "max-w-sm mx-auto" }) do |f| %> +<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }, html: { class: "max-w-sm mx-auto mt-20" }) do |f| %> <%= render "accounts/shared/error_messages", resource: resource %>
@@ -9,7 +7,7 @@
- <%= f.submit "Send me reset password instructions", class: submit_classes %> + <%= f.submit I18n.t("devise.password.send_me_instructions"), class: submit_classes %>
<%= render "accounts/shared/links" %> diff --git a/app/packages/accounts/views/accounts/registrations/new.html.erb b/app/packages/accounts/views/accounts/registrations/new.html.erb index 169e318..c78de87 100644 --- a/app/packages/accounts/views/accounts/registrations/new.html.erb +++ b/app/packages/accounts/views/accounts/registrations/new.html.erb @@ -1,4 +1,4 @@ -<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { class: "max-w-sm mx-auto" }) do |f| %> +<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { class: "max-w-sm mx-auto mt-20" }) do |f| %> <%= render "accounts/shared/error_messages", resource: resource %>
@@ -7,17 +7,17 @@
- <%= f.label :password, class: label_classes %> + <%= f.label :password, I18n.t("devise.registrations.password"), class: label_classes %> <%= f.password_field :password, autocomplete: "new-password", class: input_classes %>
- <%= f.label :password_confirmation, class: label_classes %> + <%= f.label :password_confirmation, I18n.t("devise.registrations.password_confirmation"), class: label_classes %> <%= f.password_field :password_confirmation, autocomplete: "new-password", class: input_classes %>
- <%= f.submit "Sign up", class: submit_classes %> + <%= f.submit I18n.t("devise.registrations.signup"), class: submit_classes %>
<%= render "accounts/shared/links" %> diff --git a/app/packages/accounts/views/accounts/sessions/new.html.erb b/app/packages/accounts/views/accounts/sessions/new.html.erb index b477142..fc9716d 100644 --- a/app/packages/accounts/views/accounts/sessions/new.html.erb +++ b/app/packages/accounts/views/accounts/sessions/new.html.erb @@ -1,11 +1,11 @@ -<%= form_for(resource, as: resource_name, url: session_path(resource_name), html: { class: "max-w-sm mx-auto" }) do |f| %> +<%= form_for(resource, as: resource_name, url: session_path(resource_name), html: { class: "max-w-sm mx-auto mt-20" }) do |f| %>
<%= f.label :email, class: label_classes %> <%= f.email_field :email, autofocus: true, autocomplete: "email", class: input_classes %>
- <%= f.label :password, class: label_classes %> + <%= f.label :password, I18n.t("devise.sessions.password"), class: label_classes %> <%= f.password_field :password, autocomplete: "current-password", class: input_classes %>
@@ -15,14 +15,12 @@ <%= f.check_box :remember_me, class: "w-4 h-4 border border-gray-300 rounded bg-gray-50 focus:ring-3 focus:ring-blue-300 dark:bg-gray-700 dark:border-gray-600 dark:focus:ring-blue-600 dark:ring-offset-gray-800 dark:focus:ring-offset-gray-800" %> - <%= f.label :remember_me, class: "ms-2 text-sm font-medium text-gray-900 dark:text-gray-300" %> + <%= f.label :remember_me, I18n.t("devise.sessions.remember_me"), class: "ms-2 text-sm font-medium text-gray-900 dark:text-gray-300" %> <% end %> -
- <%= f.submit "Log in", class: submit_classes %> -
+ <%= f.submit I18n.t("devise.sessions.login"), class: submit_classes %> <%= render "accounts/shared/links" %> <% end %> diff --git a/app/packages/accounts/views/accounts/shared/_links.html.erb b/app/packages/accounts/views/accounts/shared/_links.html.erb index 39c092f..b475c4b 100644 --- a/app/packages/accounts/views/accounts/shared/_links.html.erb +++ b/app/packages/accounts/views/accounts/shared/_links.html.erb @@ -1,23 +1,23 @@

<%- if controller_name != 'sessions' %> - <%= link_to "Log in", new_session_path(resource_name) %>
+ <%= link_to I18n.t("devise.shared.login"), new_session_path(resource_name) %>
<% end %> <%- if devise_mapping.registerable? && controller_name != 'registrations' %> - <%= link_to "Sign up", new_registration_path(resource_name) %>
+ <%= link_to I18n.t("devise.shared.signup"), new_registration_path(resource_name) %>
<% end %> <%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %> - <%= link_to "Forgot your password?", new_password_path(resource_name) %>
+ <%= link_to I18n.t("devise.shared.forgot_password?"), new_password_path(resource_name) %>
<% end %> <%- if devise_mapping.confirmable? && controller_name != 'confirmations' %> - <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %>
+ <%= link_to I18n.t("devise.shared.did_not_receive_confirmation?"), new_confirmation_path(resource_name) %>
<% end %> <%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %> - <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %>
+ <%= link_to I18n.t("devise.shared.did_not_receive_unlock_instrutions?"), new_unlock_path(resource_name) %>
<% end %> <%- if devise_mapping.omniauthable? %> diff --git a/app/packages/planning/controllers/pictos_controller.rb b/app/packages/planning/controllers/pictos_controller.rb new file mode 100644 index 0000000..32cd42c --- /dev/null +++ b/app/packages/planning/controllers/pictos_controller.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +class PictosController < ApplicationController + before_action :authenticate_account! + + def index + @pictos = Picto::FindAll + .call( + keyword: params[:q], + enabled: !params[:only_disabled].present?, + page: params[:page] + ).value! + end + + def enable + Picto::Enable + .call(picto_id: params[:id]) + + redirect_to pictos_path(q: params[:q], only_disabled: params[:only_disabled]) + end + + def disable + Picto::Disable + .call(picto_id: params[:id]) + + redirect_to pictos_path(q: params[:q], only_disabled: params[:only_disabled]) + end +end diff --git a/app/packages/planning/controllers/plans/events_controller.rb b/app/packages/planning/controllers/plans/events_controller.rb new file mode 100644 index 0000000..8692ed6 --- /dev/null +++ b/app/packages/planning/controllers/plans/events_controller.rb @@ -0,0 +1,95 @@ +# frozen_string_literal: true + +module Plans + class EventsController < ApplicationController + before_action :authenticate_account! + before_action :load_plan + before_action :load_event, only: %w(edit update destroy) + + def index + @events = Event::FindAll + .call(plan_id: @plan.id) + .value! + end + + def new + @event_form = Event::Create::Form.new + end + + def create + response = Event::Create.call( + **input_data_for_create + ) + + if response.success? + flash[:notice] = "Nuevo evento creado!" + redirect_to plan_events_path(@plan.id) + else + flash.now[:alert] = "Algo ha ido mal!" + @event = response.value.data + render :new + end + end + + def edit + @event_form = Event::Update::Form.new( + @event.attributes + .slice(:plan_id, :picto_id, :title, :day_of_the_week) + .merge(event_id: params[:id]) + ) + end + + def update + response = Event::Update.call( + **input_data_for_update + ) + + if response.success? + flash[:notice] = "Evento editado!" + redirect_to plan_events_path(response.value.id) + else + flash.now[:alert] = "Algo ha ido mal!" + @event_form = response.value.data + render :edit + end + end + + def destroy + Event::Remove.call( + plan_id: @plan.id, + event_id: params[:id] + ) + + redirect_to plan_events_path(@plan.id) + end + + private + + def load_event + @event = Event::Find.call( + plan_id: @plan.id, + event_id: params[:id] + ).value! + end + + def input_data_for_create + params + .require(:event_create_form) + .permit(:picto_id, :title, :day_of_the_week) + .merge(plan_id: @plan.id) + end + + def input_data_for_update + params + .require(:event_update_form) + .permit(:picto_id, :title, :day_of_the_week) + .merge(plan_id: @plan.id, event_id: params[:id]) + end + + def load_plan + @plan = Plan::Find + .call(account_id: current_account.id, plan_id: params[:plan_id]) + .value! + end + end +end diff --git a/app/packages/planning/controllers/plans_controller.rb b/app/packages/planning/controllers/plans_controller.rb index 22cadc0..59aca8f 100644 --- a/app/packages/planning/controllers/plans_controller.rb +++ b/app/packages/planning/controllers/plans_controller.rb @@ -2,7 +2,105 @@ class PlansController < ApplicationController before_action :authenticate_account! + before_action :load_plan, only: %w(edit update destroy) + + def index + @plans = Plan::FindAll + .call(account_id: current_account.id) + .value! + end + + def new + @plan_form = Plan::Create::Form.new + end + + def create + response = Plan::Create.call( + **input_data_for_create + ) + + if response.success? + flash[:notice] = "Nueva planificación creada!" + redirect_to plan_events_path(response.value.id) + else + flash.now[:alert] = "Algo ha ido mal!" + @plan_form = response.value.data + render :new + end + end + + def edit + @plan_form = Plan::Update::Form.new( + @plan.attributes + .slice(:account_id, :name) + .merge(plan_id: params[:id]) + ) + end + + def update + response = Plan::Update.call( + **input_data_for_update + ) + + if response.success? + flash[:notice] = "Planificación editada!" + redirect_to plan_events_path(response.value.id) + else + flash.now[:alert] = "Algo ha ido mal!" + @plan = response.value.data + render :edit + end + end + + def activate + response = Plan::Activate.call( + account_id: current_account.id, plan_id: params[:id] + ) + + if response.success? + flash[:notice] = "Nueva planificación creada!" + else + flash[:alert] = "Algo ha ido mal!" + end + + redirect_to plans_path + end def current + @plan = Plan::FindCurrent.call( + account_id: current_account.id + ).value + end + + def destroy + Plan::Remove.call( + account_id: current_account.id, + plan_id: @plan.id + ) + + redirect_to plans_path + end + + private + + def load_plan + @plan = Plan::Find.call( + account_id: current_account.id, + plan_id: params[:id] + ).value! + end + + def input_data_for_create + params + .require(:plan_create_form) + .permit(:name) + .merge(account_id: current_account.id) + end + + def input_data_for_update + params + .require(:plan_update_form) + .permit(:name) + .merge(account_id: current_account.id, plan_id: params[:id]) end end diff --git a/app/packages/planning/models/picto.rb b/app/packages/planning/models/picto.rb index 579dab2..204304b 100644 --- a/app/packages/planning/models/picto.rb +++ b/app/packages/planning/models/picto.rb @@ -1,9 +1,14 @@ # frozen_string_literal: true class Picto < ApplicationRecord - has_one_attached :image + has_one_attached :image do |attachable| + attachable.variant :thumb, resize_to_limit: [160, 160] + attachable.variant :mini_thumb, resize_to_limit: [100, 100] + end def to_struct - CustomStruct.new(attributes.merge(enabled?: enabled)) + CustomStruct.new( + attributes.merge(enabled?: enabled, image:) + ) end end diff --git a/app/packages/planning/operations/event/find.rb b/app/packages/planning/operations/event/find.rb new file mode 100644 index 0000000..9fe22f1 --- /dev/null +++ b/app/packages/planning/operations/event/find.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +class Event::Find < CommandHandler::Command + class Form + include CommandHandler::Form + + attribute :plan_id, :integer + attribute :event_id, :integer + end + + delegate(*Form.new.attributes.keys, to: :form) + + def call + if (event = Event.find_by(plan_id:, id: event_id)) + Response.success(event.to_struct) + else + Response.failure( + Errors::RecordNotFoundError + .build(form:) + ) + end + end +end diff --git a/app/packages/planning/operations/event/find_all.rb b/app/packages/planning/operations/event/find_all.rb new file mode 100644 index 0000000..86e555e --- /dev/null +++ b/app/packages/planning/operations/event/find_all.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +class Event::FindAll < CommandHandler::Command + class Form + include CommandHandler::Form + + attribute :plan_id, :integer + + validates :plan_id, presence: true + end + + delegate(*Form.new.attributes.keys, to: :form) + + def execute + Response.success( + Event + .where(plan_id:) + .order(:day_of_the_week) + ) + end +end diff --git a/app/packages/planning/operations/event/remove.rb b/app/packages/planning/operations/event/remove.rb new file mode 100644 index 0000000..6a5f383 --- /dev/null +++ b/app/packages/planning/operations/event/remove.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +class Event::Remove < CommandHandler::Command + class Form + include CommandHandler::Form + + attribute :plan_id, :integer + attribute :event_id, :integer + + validates :plan_id, presence: true + validates :event_id, presence: true + end + + delegate :event_id, :plan_id, to: :form + + def execute + Event::Find + .call(plan_id:, event_id:) + .and_then do |event| + Response.success( + Event + .destroy(event.id) + .to_struct + ) + end + end +end diff --git a/app/packages/planning/operations/event/update.rb b/app/packages/planning/operations/event/update.rb new file mode 100644 index 0000000..d45b43b --- /dev/null +++ b/app/packages/planning/operations/event/update.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +class Event::Update < CommandHandler::Command + class Form + include CommandHandler::Form + + attribute :plan_id, :integer + attribute :event_id, :integer + attribute :picto_id, :integer + attribute :title, :string + attribute :day_of_the_week, :integer + end + + delegate(*Form.new.attributes.keys, to: :form) + + def call + Event::Find + .call(plan_id:, event_id:) + .and_then do + Event + .find_by(id: event_id) + .update_with_response(picto_id:, title:, day_of_the_week:) + .and_then do |event| + Response.success(event.to_struct) + end + end + end +end diff --git a/app/packages/planning/operations/picto/find_all.rb b/app/packages/planning/operations/picto/find_all.rb new file mode 100644 index 0000000..68930eb --- /dev/null +++ b/app/packages/planning/operations/picto/find_all.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +class Picto::FindAll < CommandHandler::Command + class Form + include CommandHandler::Form + + attribute :keyword, :string + attribute :enabled, :boolean, default: false + attribute :page, :integer + attribute :per_page, :integer, default: 25 + end + + delegate(*Form.new.attributes.keys, to: :form) + + def call + pictos = find_all + + Response.success( + PaginatedCollection.new( + pictos.map(&:to_struct), + pictos.current_page, + pictos.prev_page, + pictos.next_page, + pictos.total_pages, + per_page + ) + ) + end + + private + + def find_all + pictos = Picto.all + pictos = pictos.where("keyword ILIKE ?", "%#{keyword}%") if keyword.present? + + pictos + .where(enabled:) + .order(:keyword) + .page(page) + .per(per_page) + end +end diff --git a/app/packages/planning/operations/plan/find_all.rb b/app/packages/planning/operations/plan/find_all.rb new file mode 100644 index 0000000..9846dc2 --- /dev/null +++ b/app/packages/planning/operations/plan/find_all.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +class Plan::FindAll < CommandHandler::Command + class Form + include CommandHandler::Form + + attribute :account_id, :integer + + validates :account_id, presence: true + end + + delegate(*Form.new.attributes.keys, to: :form) + + def execute + Response.success( + Plan + .where(account_id:) + .map(&:to_struct) + ) + end +end diff --git a/app/packages/planning/operations/plan/find_current.rb b/app/packages/planning/operations/plan/find_current.rb new file mode 100644 index 0000000..c60f621 --- /dev/null +++ b/app/packages/planning/operations/plan/find_current.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +class Plan::FindCurrent < CommandHandler::Command + class Form + include CommandHandler::Form + + attribute :account_id, :integer + + validates :account_id, presence: true + end + + delegate :account_id, :plan_id, to: :form + + def execute + if (plan = Plan.find_by(account_id:, active: true)) + Response.success(plan.to_struct) + else + Response.failure( + Errors::RecordNotFoundError + .build(form:) + ) + end + end +end diff --git a/app/packages/planning/views/pictos/index.html.erb b/app/packages/planning/views/pictos/index.html.erb new file mode 100644 index 0000000..b921d67 --- /dev/null +++ b/app/packages/planning/views/pictos/index.html.erb @@ -0,0 +1,37 @@ +<%= form_tag pictos_path, method: :get, class: "mb-4 pl-2" do %> + +

+
+ +
+ + <%= text_field_tag :q, params[:q], placeholder: "Buscar por keyword...", class: "block w-full p-4 ps-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" %> + +
+
+ <%= check_box_tag :only_disabled, checked: params[:only_disabled], class: "w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600" %> + <%= label_tag :only_disabled, "No disponibles", class: "ms-2 text-sm font-medium text-gray-900 dark:text-gray-300" %> +
+<% end %> + +
+ <% @pictos.each do |picto| %> +
+ <%= image_tag picto.image.variant(:thumb), class: "h-auto max-w-full rounded-lg w-40 mx-auto" %> + +
+ <% end %> +
+ +<%= paginate @pictos %> diff --git a/app/packages/planning/views/plans/_form.html.erb b/app/packages/planning/views/plans/_form.html.erb new file mode 100644 index 0000000..0fa2db6 --- /dev/null +++ b/app/packages/planning/views/plans/_form.html.erb @@ -0,0 +1,4 @@ +
+ <%= f.label :name, I18n.t("plans.name"), class: label_classes %> + <%= f.text_field :name, autofocus: true, class: input_classes %> +
diff --git a/app/packages/planning/views/plans/current.html.erb b/app/packages/planning/views/plans/current.html.erb index 3e42813..4953f0a 100644 --- a/app/packages/planning/views/plans/current.html.erb +++ b/app/packages/planning/views/plans/current.html.erb @@ -1,4 +1,26 @@ -<% if @plan.nil? %> +<% if @plan.present? %> +
+ <% days_of_week.each do |day_of_week| %> +
p-2"> +
+
+ <% if day_of_week.today? %> + <%= image_tag "hoy.png"%> + <% end %> +
+
+ +

<%= day_of_week.title %>

+ + <% Event.where(plan_id: @plan.id, day_of_the_week: day_of_week.id).each do |event| %> +
+ <%= image_tag event.picto.image.variant(:mini_thumb) %> +
+ <% end %> +
+ <% end %> +
+<% else %>
No hay planifación activa

Antes de nada hay que crear una planificación.

diff --git a/app/packages/planning/views/plans/edit.html.erb b/app/packages/planning/views/plans/edit.html.erb new file mode 100644 index 0000000..86d2a22 --- /dev/null +++ b/app/packages/planning/views/plans/edit.html.erb @@ -0,0 +1,7 @@ +<%= form_for @plan_form, url: plan_path(@plan.id), method: :put, html: { class: "max-w-sm mx-auto mt-20" } do |f| %> +

Editar planificación

+ + <%= render "form", f: f %> + + <%= f.submit "Editar", class: submit_classes %> +<% end %> diff --git a/app/packages/planning/views/plans/events/_form.html.erb b/app/packages/planning/views/plans/events/_form.html.erb new file mode 100644 index 0000000..fcfd76a --- /dev/null +++ b/app/packages/planning/views/plans/events/_form.html.erb @@ -0,0 +1,14 @@ +
+ <%= f.label :day_of_the_week, "Día de la semana", class: label_classes %> + <%= f.collection_select :day_of_the_week, days_of_week, :id, :title, { include_blank: true }, class: input_classes %> +
+ +
+ <%= f.label :picto_id, "Picto", class: label_classes %> + <%= f.collection_select :picto_id, Picto::FindAll.call(enabled: true).value!, :id, :keyword, { include_blank: true }, class: input_classes %> +
+ +
+ <%= f.label :title, "Título", class: label_classes %> + <%= f.text_field :title, class: input_classes %> +
diff --git a/app/packages/planning/views/plans/events/edit.html.erb b/app/packages/planning/views/plans/events/edit.html.erb new file mode 100644 index 0000000..c6f0a6c --- /dev/null +++ b/app/packages/planning/views/plans/events/edit.html.erb @@ -0,0 +1,7 @@ +<%= form_for @event_form, url: plan_event_path(@plan.id, @event.id), method: :put, html: { class: "max-w-sm mx-auto mt-20" } do |f| %> +

Editar evento

+ + <%= render "form", f: f %> + + <%= f.submit "Editar", class: submit_classes %> +<% end %> diff --git a/app/packages/planning/views/plans/events/index.html.erb b/app/packages/planning/views/plans/events/index.html.erb new file mode 100644 index 0000000..477ce8f --- /dev/null +++ b/app/packages/planning/views/plans/events/index.html.erb @@ -0,0 +1,43 @@ +<% if @events.any? %> +
+ + + + + + + + + + <% @events.each do |event| %> + + + + + + + <% end %> + +
+ Día de la semana + + Nombre + + Acciones +
+ <%= day_to_name(event.day_of_the_week) %> + + <%= event.title %> + + <%= link_to "Editar", edit_plan_event_path(@plan.id, event.id), + class: "font-medium text-blue-600 dark:text-blue-500 hover:underline" %> + - + <%= link_to "Eliminar", plan_event_path(@plan.id, event.id), data: { "turbo-method": :delete }, + class: "font-medium text-blue-600 dark:text-blue-500 hover:underline" %> +
+
+ + <%= link_to "Crea evento", new_plan_event_path(@plan.id), class: submit_classes %> +<% else %> + Sin eventos todavía. <%= link_to "Crea el primero", new_plan_event_path(@plan.id) %>. +<% end %> diff --git a/app/packages/planning/views/plans/events/new.html.erb b/app/packages/planning/views/plans/events/new.html.erb new file mode 100644 index 0000000..c084b19 --- /dev/null +++ b/app/packages/planning/views/plans/events/new.html.erb @@ -0,0 +1,7 @@ +<%= form_for @event_form, url: plan_events_path(@plan.id), html: { class: "max-w-sm mx-auto mt-20" } do |f| %> +

Nuevo evento

+ + <%= render "form", f: f %> + + <%= f.submit "Crear", class: submit_classes %> +<% end %> diff --git a/app/packages/planning/views/plans/index.html.erb b/app/packages/planning/views/plans/index.html.erb new file mode 100644 index 0000000..c4ed9ca --- /dev/null +++ b/app/packages/planning/views/plans/index.html.erb @@ -0,0 +1,44 @@ +<% if @plans.any? %> +
+ + + + + + + + + <% @plans.each do |plan| %> + + + + + <% end %> + +
+ Nombre + + Acciones +
+ <%= plan.name %> + + <%= link_to "Editar", edit_plan_path(plan.id), + class: "font-medium text-blue-600 dark:text-blue-500 hover:underline" %> + - + <%= link_to "Eliminar", plan_path(plan.id), data: { "turbo-method": :delete }, + class: "font-medium text-blue-600 dark:text-blue-500 hover:underline" %> + - + <%= link_to "Gestionar", plan_events_path(plan.id), + class: "font-medium text-blue-600 dark:text-blue-500 hover:underline" %> + <% unless plan.active? %> + - + <%= link_to "Activar", activate_plan_path(plan.id), data: { "turbo-method": :put }, + class: "font-medium text-blue-600 dark:text-blue-500 hover:underline" %> + <% end %> +
+
+ + <%= link_to "Crea planificación", new_plan_path, class: submit_classes %> +<% else %> + Sin planificaciones aún. <%= link_to "Crea la primera", new_plan_path %>. +<% end %> diff --git a/app/packages/planning/views/plans/new.html.erb b/app/packages/planning/views/plans/new.html.erb new file mode 100644 index 0000000..3f9ba45 --- /dev/null +++ b/app/packages/planning/views/plans/new.html.erb @@ -0,0 +1,7 @@ +<%= form_for @plan_form, url: plans_path, html: { class: "max-w-sm mx-auto mt-20" } do |f| %> +

Nueva planificación

+ + <%= render "form", f: f %> + + <%= f.submit "Crear", class: submit_classes %> +<% end %> diff --git a/app/packages/rails/helpers/application_helper.rb b/app/packages/rails/helpers/application_helper.rb index ce8582e..2564c78 100644 --- a/app/packages/rails/helpers/application_helper.rb +++ b/app/packages/rails/helpers/application_helper.rb @@ -1,6 +1,20 @@ # frozen_string_literal: true module ApplicationHelper + def day_to_name(index) + days_of_week.find { |day_of_week| day_of_week.id == index }.title + end + + def days_of_week + @days_of_week = [1, 2, 3, 4, 5, 6, 0].map do |day_of_week| + CustomStruct.new( + id: day_of_week, + title: I18n.t("date.day_names")[day_of_week], + today?: Date.today.wday == day_of_week + ) + end + end + def input_classes "bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 " \ "focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 " \ @@ -12,8 +26,6 @@ def label_classes end def submit_classes - "text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 " \ - "font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center dark:bg-blue-600 " \ - "dark:hover:bg-blue-700 dark:focus:ring-blue-800" + "bg-blue-700 hover:bg-blue-800 text-white font-bold py-2 px-4 rounded" end end diff --git a/app/views/application/_header.html.erb b/app/views/application/_header.html.erb index 2c81c8a..c4c2c4f 100644 --- a/app/views/application/_header.html.erb +++ b/app/views/application/_header.html.erb @@ -27,7 +27,7 @@ <%= link_to "Planificaciones", plans_path, class: "block py-2 px-3 text-gray-900 rounded bg-gray-50 hover:bg-gray-200 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0 dark:text-white md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent" %>
  • - <%= link_to "Pictos", plans_path, class: "block py-2 px-3 text-gray-900 rounded bg-gray-50 hover:bg-gray-200 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0 dark:text-white md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent" %> + <%= link_to "Pictos", pictos_path, class: "block py-2 px-3 text-gray-900 rounded bg-gray-50 hover:bg-gray-200 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0 dark:text-white md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent" %>
  • diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 53ba189..0ab4b2a 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -3,6 +3,7 @@ PictoPlan + <%= csrf_meta_tags %> <%= csp_meta_tag %> diff --git a/config/application.rb b/config/application.rb index 9b5eda4..b895723 100644 --- a/config/application.rb +++ b/config/application.rb @@ -20,6 +20,8 @@ class Application < Rails::Application config.paths.add "app/packages", glob: "*/{*,*/concerns}", eager_load: true + config.i18n.default_locale = :es + # Configuration for the application, engines, and railties goes here. # # These settings can be overridden in specific environments using the files diff --git a/config/locales/devise.es.yml b/config/locales/devise.es.yml new file mode 100644 index 0000000..4a95b68 --- /dev/null +++ b/config/locales/devise.es.yml @@ -0,0 +1,16 @@ +es: + devise: + shared: + login: Acceder + signup: Regístrate + forgot_password?: ¿Olvidaste la contraseña? + sessions: + login: Acceder + password: Contraseña + remember_me: Recuérdame + registrations: + password: Contraseña + password_confirmation: Confirma contraseña + signup: Registrar + password: + send_me_instructions: Mándame las intrucciones para cambiar la contraseña diff --git a/config/locales/es.yml b/config/locales/es.yml new file mode 100644 index 0000000..9b1c42b --- /dev/null +++ b/config/locales/es.yml @@ -0,0 +1,5 @@ +es: + date: + day_names: [Domingo, Lunes, Martes, Miércoles, Jueves, Viernes, Sábado] + plans: + name: Nombre diff --git a/config/routes.rb b/config/routes.rb index b246f85..737e411 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -8,7 +8,17 @@ } get "/plans/current", to: "plans#current", as: :current_plan - resources :plans + + resources :plans do + put "activate", on: :member + + resources :events, controller: "plans/events" + end + + resources :pictos do + get "enable", on: :member + get "disable", on: :member + end get "up" => "rails/health#show", as: :rails_health_check diff --git a/lib/paginated_collection.rb b/lib/paginated_collection.rb new file mode 100644 index 0000000..b0f5c0c --- /dev/null +++ b/lib/paginated_collection.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +PaginatedCollection = ::Struct.new( + :collection, :current_page, :prev_page, :next_page, :total_pages, :total_count, :limit_value +) do + include Enumerable + + delegate :length, to: :collection + + def each(&block) + collection.each(&block) + end +end