Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions app/controllers/content_modules_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
class ContentModulesController < AdminController
before_action :set_content_module, only: %i[edit update destroy]

def index
@programs = Program.order(:name)
@active_program = @programs.find { |p| p.id.to_s == params[:program_id] } || @programs.first
@modules_by_level = @active_program
.content_modules
.includes(:links)
.group_by(&:level)
end

def new
@content_module = ContentModule.new
end

def create
@content_module = ContentModule.new(content_module_params)

if @content_module.save
redirect_to content_modules_path, notice: "Module was successfully created."
else
render :new, status: :unprocessable_entity
end
end

def edit
end

def update
if @content_module.update(content_module_params)
redirect_to content_modules_path, notice: "Module was successfully updated."
else
render :edit, status: :unprocessable_entity
end
end

def destroy
@content_module.destroy!
redirect_to content_modules_path, notice: "Module was successfully deleted.", status: :see_other
rescue ActiveRecord::DeleteRestrictionError
redirect_to content_modules_path, alert: "Cannot delete a module that has been assigned to classrooms."
end

private
def set_content_module
@content_module = ContentModule.find(params.expect(:id))
end

def content_module_params
params.expect(content_module: [ :name, :program_id, :level, :position ])
end
end
47 changes: 47 additions & 0 deletions app/controllers/links_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
class LinksController < AdminController
before_action :set_content_module, only: %i[new create]
before_action :set_link, only: %i[edit update destroy]

def new
@link = @content_module.links.build
end

def create
@link = @content_module.links.build(link_params)

if @link.save
redirect_to edit_content_module_path(@content_module), notice: "Link was successfully created."
else
render :new, status: :unprocessable_entity
end
end

def edit
end

def update
if @link.update(link_params)
redirect_to edit_content_module_path(@link.content_module), notice: "Link was successfully updated."
else
render :edit, status: :unprocessable_entity
end
end

def destroy
@link.destroy!
redirect_to edit_content_module_path(@link.content_module), notice: "Link was successfully deleted.", status: :see_other
end

private
def set_content_module
@content_module = ContentModule.find(params.expect(:content_module_id))
end

def set_link
@link = Link.find(params.expect(:id))
end

def link_params
params.expect(link: [ :title, :url, :link_type, :position ])
end
end
6 changes: 6 additions & 0 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
module ApplicationHelper
def safe_external_url(url)
uri = URI.parse(url.to_s)
uri.scheme.in?(%w[http https]) ? url : "#"
rescue URI::InvalidURIError
"#"
end
end
10 changes: 10 additions & 0 deletions app/models/content_module.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class ContentModule < ApplicationRecord
belongs_to :program
has_many :links, dependent: :destroy

enum :level, { basic: "basic", moderate: "moderate", advanced: "advanced" }, validate: true

validates :name, :level, presence: true

default_scope { order(:position) }
end
10 changes: 10 additions & 0 deletions app/models/link.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class Link < ApplicationRecord
belongs_to :content_module

enum :link_type, { survey: "survey", game: "game" }, validate: true

validates :title, :url, :link_type, presence: true
validates :url, format: { with: /\Ahttps?:\/\/.+\z/i, message: "must start with http:// or https://" }, allow_blank: true

default_scope { order(:position) }
end
1 change: 1 addition & 0 deletions app/models/program.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
class Program < ApplicationRecord
has_many :classroom_programs, dependent: :destroy
has_many :classrooms, through: :classroom_programs
has_many :content_modules, dependent: :destroy
end
30 changes: 30 additions & 0 deletions app/views/content_modules/_form.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<%= form_with(model: content_module) do |form| %>
<div class="flex flex-col gap-2">
<% if content_module.errors.any? %>
<div style="color: red">
<h2><%= pluralize(content_module.errors.count, "error") %> prohibited this module from being saved:</h2>
<ul>
<% content_module.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>

<%= form.label :name, class: "label" %>
<%= form.text_field :name, class: "input w-full" %>

<%= form.label :program_id, "Program", class: "label" %>
<%= form.collection_select :program_id, Program.order(:name), :id, :name,
{ include_blank: "Select a program" }, class: "select w-full" %>

<%= form.label :level, class: "label" %>
<%= form.select :level, ContentModule.levels.keys.map { |l| [ l.humanize, l ] },
{ include_blank: "Select a level" }, class: "select w-full" %>

<%= form.label :position, class: "label" %>
<%= form.number_field :position, class: "input w-full" %>

<%= form.submit class: "btn btn-primary" %>
</div>
<% end %>
56 changes: 56 additions & 0 deletions app/views/content_modules/edit.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<% content_for :title, "Edit Module" %>

<nav class="breadcrumbs text-sm">
<ul>
<li><%= link_to "Content Modules", content_modules_path %></li>
<li>Edit Module</li>
</ul>
</nav>
<section class="py-10 flex justify-center">
<div class="flex flex-col gap-6 w-full max-w-lg">
<div class="card card-border bg-base-100 shadow-md">
<div class="card-body">
<h1 class="card-title">Edit Module</h1>
<%= render "form", content_module: @content_module %>
</div>
</div>

<div class="card card-border bg-base-100 shadow-md">
<div class="card-body">
<div class="flex justify-between items-center mb-2">
<h2 class="card-title text-lg">Links</h2>
<%= link_to "Add link", new_content_module_link_path(@content_module), class: "btn btn-sm btn-primary" %>
</div>
<% if @content_module.links.any? %>
<table class="table">
<thead>
<tr>
<th>Title</th>
<th>Type</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% @content_module.links.each do |link| %>
<tr>
<td><a href="<%= safe_external_url(link.url) %>" target="_blank" class="link inline-flex items-center gap-1"><%= link.title %> ↗</a></td>
<td><%= link.link_type.humanize %></td>
<td>
<div class="flex gap-2">
<%= link_to "Edit", edit_link_path(link), class: "btn btn-xs btn-primary" %>
<%= button_to "Delete", link_path(link), method: :delete,
data: { "turbo-confirm": "Delete this link?" },
class: "btn btn-xs btn-error" %>
</div>
</td>
</tr>
<% end %>
</tbody>
</table>
<% else %>
<p class="text-sm opacity-60">No links yet.</p>
<% end %>
</div>
</div>
</div>
</section>
57 changes: 57 additions & 0 deletions app/views/content_modules/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<% content_for :title, "Content Modules" %>

<p style="color: green"><%= notice %></p>
<p style="color: red"><%= alert %></p>

<header class="flex justify-between items-center mb-4">
<h1 class="text-2xl">Content Modules</h1>
<%= link_to "New module", new_content_module_path, class: "btn btn-primary" %>
</header>

<div role="tablist" class="tabs tabs-border mb-6">
<% @programs.each do |program| %>
<%= link_to content_modules_path(program_id: program.id),
role: "tab",
class: "tab #{"tab-active" if program == @active_program}" do %>
<%= program.name %>
<% end %>
<% end %>
</div>

<% ContentModule.levels.each_key do |level| %>
<% modules = @modules_by_level[level] || [] %>
<section class="mb-8">
<h2 class="text-lg font-semibold mb-2"><%= level.humanize %></h2>
<% if modules.any? %>
<div class="overflow-x-auto rounded-box border border-base-content/5 bg-base-100">
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Links</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% modules.each do |mod| %>
<tr>
<td><%= mod.name %></td>
<td><%= mod.links.size %></td>
<td>
<div class="flex gap-2">
<%= link_to "Edit", edit_content_module_path(mod), class: "btn btn-sm btn-primary" %>
<%= button_to "Delete", content_module_path(mod), method: :delete,
data: { "turbo-confirm": "Delete this module?" },
class: "btn btn-sm btn-error" %>
</div>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
<% else %>
<p class="text-sm opacity-60">No modules for this level yet.</p>
<% end %>
</section>
<% end %>
16 changes: 16 additions & 0 deletions app/views/content_modules/new.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<% content_for :title, "New Module" %>

<nav class="breadcrumbs text-sm">
<ul>
<li><%= link_to "Content Modules", content_modules_path %></li>
<li>New Module</li>
</ul>
</nav>
<section class="py-10 flex items-center justify-center">
<div class="card card-border bg-base-100 shadow-md w-96">
<div class="card-body">
<h1 class="card-title">New Module</h1>
<%= render "form", content_module: @content_module %>
</div>
</div>
</section>
3 changes: 3 additions & 0 deletions app/views/layouts/application.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
</head>

<body>
<% if controller.is_a?(AdminController) %>
<%= render "shared/admin_nav" %>
<% end %>
<main class="container mx-auto p-5">
<%= yield %>
</main>
Expand Down
29 changes: 29 additions & 0 deletions app/views/links/_form.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<%= form_with(model: link.persisted? ? link : [ link.content_module, link ]) do |form| %>
<div class="flex flex-col gap-2">
<% if link.errors.any? %>
<div style="color: red">
<h2><%= pluralize(link.errors.count, "error") %> prohibited this link from being saved:</h2>
<ul>
<% link.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>

<%= form.label :title, class: "label" %>
<%= form.text_field :title, class: "input w-full" %>

<%= form.label :url, "URL", class: "label" %>
<%= form.url_field :url, class: "input w-full" %>

<%= form.label :link_type, "Type", class: "label" %>
<%= form.select :link_type, Link.link_types.keys.map { |t| [ t.humanize, t ] },
{ include_blank: "Select a type" }, class: "select w-full" %>

<%= form.label :position, class: "label" %>
<%= form.number_field :position, class: "input w-full" %>

<%= form.submit class: "btn btn-primary" %>
</div>
<% end %>
17 changes: 17 additions & 0 deletions app/views/links/edit.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<% content_for :title, "Edit Link" %>

<nav class="breadcrumbs text-sm">
<ul>
<li><%= link_to "Content Modules", content_modules_path %></li>
<li><%= link_to @link.content_module.name, edit_content_module_path(@link.content_module) %></li>
<li>Edit Link</li>
</ul>
</nav>
<section class="py-10 flex items-center justify-center">
<div class="card card-border bg-base-100 shadow-md w-96">
<div class="card-body">
<h1 class="card-title">Edit Link</h1>
<%= render "form", link: @link %>
</div>
</div>
</section>
17 changes: 17 additions & 0 deletions app/views/links/new.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<% content_for :title, "New Link" %>

<nav class="breadcrumbs text-sm">
<ul>
<li><%= link_to "Content Modules", content_modules_path %></li>
<li><%= link_to @content_module.name, edit_content_module_path(@content_module) %></li>
<li>New Link</li>
</ul>
</nav>
<section class="py-10 flex items-center justify-center">
<div class="card card-border bg-base-100 shadow-md w-96">
<div class="card-body">
<h1 class="card-title">New Link</h1>
<%= render "form", link: @link %>
</div>
</div>
</section>
20 changes: 20 additions & 0 deletions app/views/shared/_admin_nav.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<nav class="navbar bg-base-200 border-b border-base-300 mb-6 px-4">
<div class="navbar-start">
<span class="font-semibold text-lg">Endsideout Admin</span>
</div>
<% if Current.user %>
<div class="navbar-end">
<ul class="menu menu-horizontal gap-1 p-0">
<li>
<%= link_to "Schools", schools_path,
class: "#{controller_path.start_with?("schools", "students", "classrooms") ? "active" : ""}" %>
</li>
<li>
<%= link_to "Content Modules", content_modules_path,
class: "#{controller_path.start_with?("content_modules", "links") ? "active" : ""}" %>
</li>
</ul>
<%= button_to "Log out", session_path, method: :delete, class: "btn btn-sm btn-ghost ml-2" %>
</div>
<% end %>
</nav>
Loading