Skip to content

Commit

Permalink
feat: partners pages (#442)
Browse files Browse the repository at this point in the history
  • Loading branch information
MarioRodrigues10 authored Jul 1, 2024
1 parent 9aea5da commit d99a0ea
Show file tree
Hide file tree
Showing 26 changed files with 572 additions and 211 deletions.
2 changes: 1 addition & 1 deletion lib/atomic/activities/activity.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ defmodule Atomic.Activities.Activity do
alias Atomic.Activities.{
ActivityEnrollment,
ActivitySpeaker,
Location,
Speaker
}

alias Atomic.Events.Event
alias Atomic.Feed.Post
alias Atomic.Location
alias Atomic.Organizations.Organization

@required_fields ~w(title description start finish minimum_entries maximum_entries organization_id enrolled)a
Expand Down
2 changes: 1 addition & 1 deletion lib/atomic/events/event.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ defmodule Atomic.Events.Event do
use Atomic.Schema

alias Atomic.Activities.Activity
alias Atomic.Activities.Location
alias Atomic.Events.EventEnrollment
alias Atomic.Events.EventOrganization
alias Atomic.Location

@required_fields ~w(name location_id)a
@optional_fields ~w(description event_organization_id)a
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
defmodule Atomic.Activities.Location do
defmodule Atomic.Location do
@moduledoc """
An activity location embedded struct schema.
A location embedded struct schema.
"""
use Atomic.Schema

Expand Down
2 changes: 1 addition & 1 deletion lib/atomic/organizations/organization.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Atomic.Organizations.Organization do
use Atomic.Schema

alias Atomic.Accounts.User
alias Atomic.Activities.Location
alias Atomic.Location
alias Atomic.Organizations.{Announcement, Board, Card, Department, Membership, Partner}
alias Atomic.Uploaders

Expand Down
15 changes: 11 additions & 4 deletions lib/atomic/organizations/partner.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ defmodule Atomic.Organizations.Partner do
"""
use Atomic.Schema

alias Atomic.Location
alias Atomic.Organizations.Organization
alias Atomic.Socials

@required_fields ~w(name organization_id)a
@optional_fields ~w(description state image)a
@states ~w(active inactive)a
@optional_fields ~w(description benefits archived image notes)a

@derive {
Flop.Schema,
Expand All @@ -24,17 +25,23 @@ defmodule Atomic.Organizations.Partner do
schema "partners" do
field :name, :string
field :description, :string
field :state, Ecto.Enum, values: @states, default: :active
field :benefits, :string
field :archived, :boolean, default: false
field :image, Uploaders.PartnerImage.Type

embeds_one :location, Location, on_replace: :update
embeds_one :socials, Socials, on_replace: :update
belongs_to :organization, Organization

field :notes, :string

timestamps()
end

def changeset(partner, attrs) do
partner
|> cast(attrs, @required_fields ++ @optional_fields)
|> cast_embed(:location, with: &Location.changeset/2)
|> cast_embed(:socials, with: &Socials.changeset/2)
|> cast_attachments(attrs, [:image])
|> validate_required(@required_fields)
|> unique_constraint(:name)
Expand Down
79 changes: 66 additions & 13 deletions lib/atomic/partnerships.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ defmodule Atomic.Partners do
use Atomic.Context

alias Atomic.Organizations.Partner
alias Atomic.Socials

@doc """
Returns the list of partners.
Expand All @@ -25,17 +26,10 @@ defmodule Atomic.Partners do
|> Flop.validate_and_run(flop, for: Partner)
end

@doc """
Returns the list of partners belonging to an organization.
## Examples
iex> list_partners_by_organization_id("99d7c9e5-4212-4f59-a097-28aaa33c2621")
[%Partner{}, ...]
"""
def list_partners_by_organization_id(id) do
Repo.all(from p in Partner, where: p.organization_id == ^id)
def list_partners(opts) when is_list(opts) do
Partner
|> apply_filters(opts)
|> Repo.all()
end

@doc """
Expand Down Expand Up @@ -66,10 +60,11 @@ defmodule Atomic.Partners do
{:error, %Ecto.Changeset{}}
"""
def create_partner(attrs \\ %{}, _after_save \\ &{:ok, &1}) do
def create_partner(attrs \\ %{}, after_save \\ &{:ok, &1}) do
%Partner{}
|> Partner.changeset(attrs)
|> Repo.insert()
|> after_save(after_save)
end

@doc """
Expand All @@ -84,10 +79,29 @@ defmodule Atomic.Partners do
{:error, %Ecto.Changeset{}}
"""
def update_partner(%Partner{} = partner, attrs, _after_save \\ &{:ok, &1}) do
def update_partner(%Partner{} = partner, attrs, after_save \\ &{:ok, &1}) do
partner
|> Partner.changeset(attrs)
|> Repo.update()
|> after_save(after_save)
end

@doc """
Updates a partner's picture.
## Examples
iex> update_partner_picture(partner, %{image: %Plug.Upload{}})
{:ok, %Partner{}}
iex> update_partner_picture(partner, %{image: %Plug.Upload{}})
{:error, %Ecto.Changeset{}}
"""
def update_partner_picture(%Partner{} = partner, attrs, _after_save \\ &{:ok, &1}) do
partner
|> Partner.image_changeset(attrs)
|> Repo.update()
end

@doc """
Expand All @@ -106,6 +120,41 @@ defmodule Atomic.Partners do
Repo.delete(partner)
end

@doc """
Archives a partner.
## Examples
iex> archive_partner(partner)
{:ok, %Partner{}}
iex> archive_partner(partner)
{:error, %Ecto.Changeset{}}
"""
def archive_partner(%Partner{} = partner) do
partner
|> Partner.changeset(%{archived: true})
|> Repo.update()
end

@doc """
Unarchives a partner.
## Examples
iex> unarchive_partner(partner)
{:ok, %Partner{}}
iex> unarchive_partner(partner)
{:error, %Ecto.Changeset{}}
"""
def unarchive_partner(%Partner{} = partner) do
partner
|> Partner.changeset(%{archived: false})
|> Repo.update()
end

@doc """
Returns an `%Ecto.Changeset{}` for tracking partner changes.
Expand All @@ -118,4 +167,8 @@ defmodule Atomic.Partners do
def change_partner(%Partner{} = partner, attrs \\ %{}) do
Partner.changeset(partner, attrs)
end

def change_partner_socials(%Socials{} = socials, attrs \\ %{}) do
Socials.changeset(socials, attrs)
end
end
25 changes: 25 additions & 0 deletions lib/atomic/socials/socials.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
defmodule Atomic.Socials do
@moduledoc """
A socials embedded struct schema.
"""
use Atomic.Schema

@optional_fields ~w(instagram facebook x youtube tiktok website)a

@derive Jason.Encoder
@primary_key false
embedded_schema do
field :instagram, :string
field :facebook, :string
field :x, :string
field :youtube, :string
field :tiktok, :string
field :website, :string
end

def changeset(socials, attrs) do
socials
|> cast(attrs, @optional_fields)
|> validate_format(:website, ~r{^https?://}, message: "must start with http:// or https://")
end
end
3 changes: 2 additions & 1 deletion lib/atomic/uploaders/partner_image.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ defmodule Atomic.Uploaders.PartnerImage do
Uploader for partner images.
"""
use Atomic.Uploader

alias Atomic.Organizations.Partner

def storage_dir(_version, {_file, %Partner{} = scope}) do
"uploads/partners/#{scope.id}"
"uploads/atomic/partners/#{scope.id}"
end
end
110 changes: 108 additions & 2 deletions lib/atomic_web/live/partner_live/edit.ex
Original file line number Diff line number Diff line change
@@ -1,21 +1,127 @@
defmodule AtomicWeb.PartnerLive.Edit do
use AtomicWeb, :live_view

alias Atomic.Organizations.Partner
alias Atomic.Partners
alias Phoenix.LiveView.JS

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

@impl true
def handle_params(%{"id" => partner_id} = _params, _, socket) do
def handle_params(
%{"id" => partner_id} = _params,
_,
%{:assigns => %{:live_action => :edit}} = socket
) do
partner = Partners.get_partner!(partner_id)

{:noreply,
socket
|> assign(:page_title, partner.name)
|> assign(:action, nil)
|> assign(:partner, partner)
|> assign(:current_page, :partner)}
|> assign(:current_page, :partners)}
end

@impl true
def handle_params(_params, _, %{:assigns => %{:live_action => :new}} = socket) do
{:noreply,
socket
|> assign(:page_title, "New Partner")
|> assign(:action, nil)
|> assign(:partner, %Partner{organization_id: socket.assigns.current_organization.id})
|> assign(:current_page, :partners)}
end

@impl true
def handle_event("set-action", %{"action" => action}, socket) do
{:noreply, assign(socket, :action, action |> String.to_atom())}
end

@impl true
def handle_event("clear-action", _params, socket) do
{:noreply, assign(socket, :action, nil)}
end

@impl true
def handle_event("confirm-action", _params, %{assigns: %{action: :delete}} = socket) do
partner = socket.assigns.partner
organization_id = partner.organization_id

case Partners.delete_partner(partner) do
{:ok, _partner} ->
{:noreply,
socket
|> put_flash(:success, "Partner deleted successfully")
|> push_redirect(to: Routes.partner_index_path(socket, :index, organization_id))}

{:error, _reason} ->
{:noreply, put_flash(socket, :error, "Failed to delete partner")}
end
end

@impl true
def handle_event("confirm-action", _params, %{assigns: %{action: :archive}} = socket) do
partner = socket.assigns.partner
organization_id = partner.organization_id

case Partners.archive_partner(partner) do
{:ok, _partner} ->
{:noreply,
socket
|> put_flash(:success, "Partner archived successfully")
|> push_redirect(to: Routes.partner_index_path(socket, :index, organization_id))}

{:error, _reason} ->
{:noreply, put_flash(socket, :error, "Failed to delete partner")}
end
end

def handle_event("confirm-action", _params, %{assigns: %{action: :unarchive}} = socket) do
partner = socket.assigns.partner
organization_id = partner.organization_id

case Partners.unarchive_partner(partner) do
{:ok, _partner} ->
{:noreply,
socket
|> put_flash(:success, "Partner archived successfully")
|> push_redirect(to: Routes.partner_index_path(socket, :index, organization_id))}

{:error, _reason} ->
{:noreply, put_flash(socket, :error, "Failed to delete partner")}
end
end

defp display_action_goal_confirm_title(action) do
case action do
:archive ->
gettext("Are you sure you want to archive this partner?")

:unarchive ->
gettext("Are you sure you want to unarchive this partner?")

:delete ->
gettext("Are you sure you want do delete this partner?")
end
end

defp display_action_goal_confirm_description(action, partner) do
case action do
:archive ->
gettext("You can always change you mind later and make it public again.")

:unarchive ->
gettext("This will make it so that any person can view this partner.")

:delete ->
gettext(
"This will permanently delete %{partner_name}, this action is not reversible.",
partner_name: partner.name
)
end
end
end
Loading

0 comments on commit d99a0ea

Please sign in to comment.