chore: init commit
in worker.../repo/GITFOLDER.zip is the .git folder.
This commit is contained in:
@@ -0,0 +1,250 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# rubocop:disable Metrics/ModuleLength
|
||||
module AdminHelper
|
||||
# Renders a table for index pages with sortable columns
|
||||
# @param collection [ActiveRecord::Relation] The records to display
|
||||
# @param columns [Array<Hash>] Column definitions with :attribute, :label, :sortable keys
|
||||
# @param options [Hash] Additional options for the table
|
||||
def admin_table(collection, columns: [], **options)
|
||||
title = options.delete(:title)
|
||||
actions = options.delete(:actions)
|
||||
render "admin/shared/table",
|
||||
collection: collection,
|
||||
columns: columns,
|
||||
options: options,
|
||||
title: title,
|
||||
actions: actions
|
||||
end
|
||||
|
||||
# Renders attribute rows for show pages
|
||||
# @param resource [ActiveRecord::Base] The record to display
|
||||
# @param attributes [Array<Symbol>] Attributes to display
|
||||
def admin_show_attributes(resource, attributes: [])
|
||||
render "admin/shared/show_attributes", resource: resource, attributes: attributes
|
||||
end
|
||||
|
||||
# Renders breadcrumbs for navigation
|
||||
# @param breadcrumbs [Array<Hash>] Breadcrumb items with :label and :path keys
|
||||
def admin_breadcrumbs(breadcrumbs = [])
|
||||
render "admin/shared/breadcrumbs", breadcrumbs: breadcrumbs
|
||||
end
|
||||
|
||||
# Renders action buttons (Edit, Delete, Custom)
|
||||
# @param resource [ActiveRecord::Base] The record for actions
|
||||
# @param actions [Array<Symbol>] Actions to include (:edit, :delete, :custom)
|
||||
# @param custom_actions [Array<Hash>] Custom action definitions
|
||||
def admin_actions(resource, actions: %i[edit delete], custom_actions: [])
|
||||
render "admin/shared/actions", resource: resource, actions: actions, custom_actions: custom_actions
|
||||
end
|
||||
|
||||
# Formats an attribute value for display
|
||||
# @param resource [ActiveRecord::Base] The record
|
||||
# @param attribute [Symbol] The attribute name
|
||||
# @return [String] Formatted value
|
||||
def format_attribute(resource, attribute)
|
||||
value = resource.send(attribute)
|
||||
|
||||
case value
|
||||
when TrueClass, FalseClass
|
||||
boolean_badge(value)
|
||||
when Time, DateTime, Date
|
||||
value.strftime("%B %d, %Y")
|
||||
when ActiveRecord::Base
|
||||
format_association(value)
|
||||
when nil
|
||||
content_tag(:span, "—", class: "text-gray-400")
|
||||
else
|
||||
value.to_s
|
||||
end
|
||||
end
|
||||
|
||||
# Renders a boolean badge
|
||||
# @param value [Boolean] The boolean value
|
||||
# @return [String] HTML badge
|
||||
def boolean_badge(value)
|
||||
if value
|
||||
content_tag(
|
||||
:span, "Yes",
|
||||
class: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800"
|
||||
)
|
||||
else
|
||||
content_tag(
|
||||
:span, "No",
|
||||
class: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-gray-100 text-gray-800"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# Generates a sort link for table headers
|
||||
# @param column [Symbol] The column name
|
||||
# @param label [String] The display label
|
||||
# @return [String] HTML link
|
||||
def sort_link(column, label)
|
||||
direction = params[:sort] == column.to_s && params[:direction] == "asc" ? "desc" : "asc"
|
||||
icon = sort_icon(column)
|
||||
|
||||
# Build URL with query parameters
|
||||
url = url_for(sort: column, direction: direction, only_path: true)
|
||||
|
||||
link_to url, class: "group inline-flex items-center" do
|
||||
safe_join(
|
||||
[
|
||||
label,
|
||||
content_tag(
|
||||
:span, icon,
|
||||
class: "ml-2 flex-none rounded text-gray-900 group-hover:text-gray-900"
|
||||
)
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the sort icon for a column
|
||||
# @param column [Symbol] The column name
|
||||
# @return [String] Icon HTML
|
||||
def sort_icon(column)
|
||||
if params[:sort] == column.to_s
|
||||
params[:direction] == "asc" ? "↑" : "↓"
|
||||
else
|
||||
"⇅"
|
||||
end
|
||||
end
|
||||
|
||||
# Renders search and filter form
|
||||
# @param filters [Array<Hash>] Filter definitions with :name, :label, :options keys
|
||||
# @param search_placeholder [String] Placeholder text for search field
|
||||
def admin_search_filter(filters: [], search_placeholder: "Search...")
|
||||
render "admin/shared/search_filter", filters: filters, search_placeholder: search_placeholder
|
||||
end
|
||||
|
||||
# Determines the current discard filter state based on query parameters
|
||||
# @return [Symbol] :active, :discarded, or :all
|
||||
def current_discard_filter
|
||||
if params[:discarded].present?
|
||||
:discarded
|
||||
elsif params[:all].present?
|
||||
:all
|
||||
else
|
||||
:active
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the correct model for routing purposes
|
||||
# Handles STI (Single Table Inheritance) by returning the base class
|
||||
# @param record [ActiveRecord::Base] The record
|
||||
# @return [ActiveRecord::Base] The record or its base class for routing
|
||||
def route_model(record)
|
||||
if record.class.base_class == record.class
|
||||
record
|
||||
else
|
||||
record.becomes(record.class.base_class)
|
||||
end
|
||||
end
|
||||
|
||||
# Renders the archive/activate toggle button for a classroom
|
||||
# @param classroom [Classroom] The classroom record
|
||||
# @return [String] HTML button
|
||||
def classroom_archive_toggle_button(classroom)
|
||||
if classroom.archived?
|
||||
activate_button(classroom)
|
||||
else
|
||||
archive_button(classroom)
|
||||
end
|
||||
end
|
||||
|
||||
# Renders the discard/restore action button for a soft-deletable resource
|
||||
# @param resource [ActiveRecord::Base] The resource record (must respond_to :discarded?)
|
||||
# @return [String] HTML button or link
|
||||
def discard_restore_action(resource)
|
||||
if resource.discarded?
|
||||
restore_button(resource)
|
||||
else
|
||||
discard_link(resource)
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the appropriate show path for a user based on their type
|
||||
# @param user [User] The user record
|
||||
# @return [String] Path to the type-specific show page
|
||||
def user_show_path(user)
|
||||
case user.type
|
||||
when "Student"
|
||||
admin_student_path(user)
|
||||
when "Teacher"
|
||||
admin_teacher_path(user)
|
||||
else
|
||||
admin_user_path(user)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def format_association(value)
|
||||
# Use presenter if available, otherwise fall back to to_s
|
||||
presenter_class = "#{value.class.name}Presenter".safe_constantize
|
||||
display_value = if presenter_class
|
||||
presenter_class.new(value).display_name
|
||||
else
|
||||
value.to_s
|
||||
end
|
||||
|
||||
# Try to link to the resource, but fall back to text if route doesn't exist
|
||||
begin
|
||||
link_to display_value, [:admin, route_model(value)]
|
||||
rescue NoMethodError, ActionController::UrlGenerationError
|
||||
display_value
|
||||
end
|
||||
end
|
||||
|
||||
def restore_button(resource)
|
||||
resource_name = resource.class.name.underscore
|
||||
restore_path = send("restore_admin_#{resource_name}_path", resource)
|
||||
|
||||
button_to "Restore", restore_path,
|
||||
method: :patch,
|
||||
data: { turbo_confirm: "Are you sure you want to restore this #{resource_name.humanize.downcase}?" },
|
||||
class: "text-green-600 hover:text-green-800",
|
||||
form: { style: "display: inline;" }
|
||||
end
|
||||
|
||||
def discard_link(resource)
|
||||
resource_name = resource.class.name.underscore
|
||||
resource_path = send("admin_#{resource_name}_path", resource)
|
||||
|
||||
link_to "Archive", resource_path,
|
||||
data: { turbo_method: :delete, turbo_confirm: "Are you sure you want to archive this #{resource_name.humanize.downcase}?" }, # rubocop:disable Layout/LineLength
|
||||
class: "text-red-600 hover:text-red-800"
|
||||
end
|
||||
|
||||
def activate_button(classroom)
|
||||
button_class = "inline-flex items-center px-4 py-2 border border-green-300 shadow-sm " \
|
||||
"text-sm font-medium rounded-md text-green-700 bg-white hover:bg-green-50"
|
||||
link_to toggle_archive_admin_classroom_path(classroom),
|
||||
data: { turbo_method: :patch, turbo_confirm: "Are you sure you want to activate this classroom?" },
|
||||
class: button_class do
|
||||
safe_join(
|
||||
[
|
||||
content_tag(:i, "", class: "fas fa-check-circle -ml-1 mr-2 h-5 w-5 text-green-500"),
|
||||
"Activate"
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def archive_button(classroom)
|
||||
button_class = "inline-flex items-center px-4 py-2 border border-yellow-300 shadow-sm " \
|
||||
"text-sm font-medium rounded-md text-yellow-700 bg-white hover:bg-yellow-50"
|
||||
link_to toggle_archive_admin_classroom_path(classroom),
|
||||
data: { turbo_method: :patch, turbo_confirm: "Are you sure you want to archive this classroom?" },
|
||||
class: button_class do
|
||||
safe_join(
|
||||
[
|
||||
content_tag(:i, "", class: "fas fa-archive -ml-1 mr-2 h-5 w-5 text-yellow-500"),
|
||||
"Archive"
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
# rubocop:enable Metrics/ModuleLength
|
||||
Reference in New Issue
Block a user