Skip to content

Commit

Permalink
feat: created Cycle schema in Schools context
Browse files Browse the repository at this point in the history
adjusted files generated by `mix phx.gen.live`, supporting DB constraints
  • Loading branch information
endoooo committed Nov 11, 2023
1 parent 1bd3f0e commit fccb0c3
Show file tree
Hide file tree
Showing 13 changed files with 637 additions and 45 deletions.
96 changes: 96 additions & 0 deletions lib/lanttern/schools.ex
Original file line number Diff line number Diff line change
Expand Up @@ -715,4 +715,100 @@ defmodule Lanttern.Schools do

{:ok, response}
end

alias Lanttern.Schools.Cycle

@doc """
Returns the list of school_cycles.
## Examples
iex> list_school_cycles()
[%Cycle{}, ...]
"""
def list_school_cycles do
Repo.all(Cycle)
end

@doc """
Gets a single cycle.
Raises `Ecto.NoResultsError` if the Cycle does not exist.
## Examples
iex> get_cycle!(123)
%Cycle{}
iex> get_cycle!(456)
** (Ecto.NoResultsError)
"""
def get_cycle!(id), do: Repo.get!(Cycle, id)

@doc """
Creates a cycle.
## Examples
iex> create_cycle(%{field: value})
{:ok, %Cycle{}}
iex> create_cycle(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_cycle(attrs \\ %{}) do
%Cycle{}
|> Cycle.changeset(attrs)
|> Repo.insert()
end

@doc """
Updates a cycle.
## Examples
iex> update_cycle(cycle, %{field: new_value})
{:ok, %Cycle{}}
iex> update_cycle(cycle, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_cycle(%Cycle{} = cycle, attrs) do
cycle
|> Cycle.changeset(attrs)
|> Repo.update()
end

@doc """
Deletes a cycle.
## Examples
iex> delete_cycle(cycle)
{:ok, %Cycle{}}
iex> delete_cycle(cycle)
{:error, %Ecto.Changeset{}}
"""
def delete_cycle(%Cycle{} = cycle) do
Repo.delete(cycle)
end

@doc """
Returns an `%Ecto.Changeset{}` for tracking cycle changes.
## Examples
iex> change_cycle(cycle)
%Ecto.Changeset{data: %Cycle{}}
"""
def change_cycle(%Cycle{} = cycle, attrs \\ %{}) do
Cycle.changeset(cycle, attrs)
end
end
25 changes: 25 additions & 0 deletions lib/lanttern/schools/cycle.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
defmodule Lanttern.Schools.Cycle do
use Ecto.Schema
import Ecto.Changeset

schema "school_cycles" do
field :name, :string
field :start_at, :date
field :end_at, :date
belongs_to :school, Lanttern.Schools.School

timestamps()
end

@doc false
def changeset(cycle, attrs) do
cycle
|> cast(attrs, [:name, :start_at, :end_at, :school_id])
|> validate_required([:name, :start_at, :end_at, :school_id])
|> check_constraint(
:end_at,
name: :cycle_end_date_is_greater_than_start_date,
message: "End date should be greater than start date"
)
end
end
1 change: 1 addition & 0 deletions lib/lanttern_web/controllers/admin_html/home.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
<:item link={~p"/admin/import_students"}>Import students</:item>
<:item link={~p"/admin/teachers"}>Teachers</:item>
<:item link={~p"/admin/import_teachers"}>Import teachers</:item>
<:item link={~p"/admin/school_cycles"}>Cycles</:item>
</.link_list>
<.link_list title="Taxonomy">
<:item link={~p"/admin/subjects"}>Subjects</:item>
Expand Down
101 changes: 101 additions & 0 deletions lib/lanttern_web/live/admin/cycle_live/form_component.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
defmodule LantternWeb.Admin.CycleLive.FormComponent do
use LantternWeb, :live_component

alias Lanttern.Schools
import LantternWeb.SchoolsHelpers

@impl true
def render(assigns) do
~H"""
<div>
<.header>
<%= @title %>
<:subtitle>Use this form to manage cycle records in your database.</:subtitle>
</.header>
<.simple_form
for={@form}
id="cycle-form"
phx-target={@myself}
phx-change="validate"
phx-submit="save"
>
<.input
field={@form[:school_id]}
type="select"
label="School"
prompt="Select school"
options={@school_options}
/>
<.input field={@form[:name]} type="text" label="Name" />
<.input field={@form[:start_at]} type="date" label="Start at" />
<.input field={@form[:end_at]} type="date" label="End at" />
<:actions>
<.button phx-disable-with="Saving...">Save Cycle</.button>
</:actions>
</.simple_form>
</div>
"""
end

@impl true
def update(%{cycle: cycle} = assigns, socket) do
changeset = Schools.change_cycle(cycle)

{:ok,
socket
|> assign(assigns)
|> assign(:school_options, generate_school_options())
|> assign_form(changeset)}
end

@impl true
def handle_event("validate", %{"cycle" => cycle_params}, socket) do
changeset =
socket.assigns.cycle
|> Schools.change_cycle(cycle_params)
|> Map.put(:action, :validate)

{:noreply, assign_form(socket, changeset)}
end

def handle_event("save", %{"cycle" => cycle_params}, socket) do
save_cycle(socket, socket.assigns.action, cycle_params)
end

defp save_cycle(socket, :edit, cycle_params) do
case Schools.update_cycle(socket.assigns.cycle, cycle_params) do
{:ok, cycle} ->
notify_parent({:saved, cycle})

{:noreply,
socket
|> put_flash(:info, "Cycle updated successfully")
|> push_patch(to: socket.assigns.patch)}

{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign_form(socket, changeset)}
end
end

defp save_cycle(socket, :new, cycle_params) do
case Schools.create_cycle(cycle_params) do
{:ok, cycle} ->
notify_parent({:saved, cycle})

{:noreply,
socket
|> put_flash(:info, "Cycle created successfully")
|> push_patch(to: socket.assigns.patch)}

{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign_form(socket, changeset)}
end
end

defp assign_form(socket, %Ecto.Changeset{} = changeset) do
assign(socket, :form, to_form(changeset))
end

defp notify_parent(msg), do: send(self(), {__MODULE__, msg})
end
47 changes: 47 additions & 0 deletions lib/lanttern_web/live/admin/cycle_live/index.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
defmodule LantternWeb.Admin.CycleLive.Index do
use LantternWeb, {:live_view, layout: :admin}

alias Lanttern.Schools
alias Lanttern.Schools.Cycle

@impl true
def mount(_params, _session, socket) do
{:ok, stream(socket, :school_cycles, Schools.list_school_cycles())}
end

@impl true
def handle_params(params, _url, socket) do
{:noreply, apply_action(socket, socket.assigns.live_action, params)}
end

defp apply_action(socket, :edit, %{"id" => id}) do
socket
|> assign(:page_title, "Edit Cycle")
|> assign(:cycle, Schools.get_cycle!(id))
end

defp apply_action(socket, :new, _params) do
socket
|> assign(:page_title, "New Cycle")
|> assign(:cycle, %Cycle{})
end

defp apply_action(socket, :index, _params) do
socket
|> assign(:page_title, "Listing School cycles")
|> assign(:cycle, nil)
end

@impl true
def handle_info({LantternWeb.Admin.CycleLive.FormComponent, {:saved, cycle}}, socket) do
{:noreply, stream_insert(socket, :school_cycles, cycle)}
end

@impl true
def handle_event("delete", %{"id" => id}, socket) do
cycle = Schools.get_cycle!(id)
{:ok, _} = Schools.delete_cycle(cycle)

{:noreply, stream_delete(socket, :school_cycles, cycle)}
end
end
48 changes: 48 additions & 0 deletions lib/lanttern_web/live/admin/cycle_live/index.html.heex
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<.header>
Listing School cycles
<:actions>
<.link patch={~p"/admin/school_cycles/new"}>
<.button>New Cycle</.button>
</.link>
</:actions>
</.header>

<.table
id="school_cycles"
rows={@streams.school_cycles}
row_click={fn {_id, cycle} -> JS.navigate(~p"/admin/school_cycles/#{cycle}") end}
>
<:col :let={{_id, cycle}} label="Name"><%= cycle.name %></:col>
<:col :let={{_id, cycle}} label="Start at"><%= cycle.start_at %></:col>
<:col :let={{_id, cycle}} label="End at"><%= cycle.end_at %></:col>
<:action :let={{_id, cycle}}>
<div class="sr-only">
<.link navigate={~p"/admin/school_cycles/#{cycle}"}>Show</.link>
</div>
<.link patch={~p"/admin/school_cycles/#{cycle}/edit"}>Edit</.link>
</:action>
<:action :let={{id, cycle}}>
<.link
phx-click={JS.push("delete", value: %{id: cycle.id}) |> hide("##{id}")}
data-confirm="Are you sure?"
>
Delete
</.link>
</:action>
</.table>

<.modal
:if={@live_action in [:new, :edit]}
id="cycle-modal"
show
on_cancel={JS.patch(~p"/admin/school_cycles")}
>
<.live_component
module={LantternWeb.Admin.CycleLive.FormComponent}
id={@cycle.id || :new}
title={@page_title}
action={@live_action}
cycle={@cycle}
patch={~p"/admin/school_cycles"}
/>
</.modal>
21 changes: 21 additions & 0 deletions lib/lanttern_web/live/admin/cycle_live/show.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
defmodule LantternWeb.Admin.CycleLive.Show do
use LantternWeb, {:live_view, layout: :admin}

alias Lanttern.Schools

@impl true
def mount(_params, _session, socket) do
{:ok, socket}
end

@impl true
def handle_params(%{"id" => id}, _, socket) do
{:noreply,
socket
|> assign(:page_title, page_title(socket.assigns.live_action))
|> assign(:cycle, Schools.get_cycle!(id))}
end

defp page_title(:show), do: "Show Cycle"
defp page_title(:edit), do: "Edit Cycle"
end
33 changes: 33 additions & 0 deletions lib/lanttern_web/live/admin/cycle_live/show.html.heex
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<.header>
Cycle <%= @cycle.id %>
<:subtitle>This is a cycle record from your database.</:subtitle>
<:actions>
<.link patch={~p"/admin/school_cycles/#{@cycle}/show/edit"} phx-click={JS.push_focus()}>
<.button>Edit cycle</.button>
</.link>
</:actions>
</.header>

<.list>
<:item title="Name"><%= @cycle.name %></:item>
<:item title="Start at"><%= @cycle.start_at %></:item>
<:item title="End at"><%= @cycle.end_at %></:item>
</.list>

<.back navigate={~p"/admin/school_cycles"}>Back to school_cycles</.back>

<.modal
:if={@live_action == :edit}
id="cycle-modal"
show
on_cancel={JS.patch(~p"/admin/school_cycles/#{@cycle}")}
>
<.live_component
module={LantternWeb.Admin.CycleLive.FormComponent}
id={@cycle.id}
title={@page_title}
action={@live_action}
cycle={@cycle}
patch={~p"/admin/school_cycles/#{@cycle}"}
/>
</.modal>
Loading

0 comments on commit fccb0c3

Please sign in to comment.