Skip to content
Merged
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
140 changes: 140 additions & 0 deletions lib/ares/companies.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
defmodule Ares.Companies do
@moduledoc """
The Companies context.
"""

import Ecto.Query, warn: false
alias Ares.Repo

alias Ares.Companies.Company

@doc """
Returns the list of companies.

## Examples

iex> list_companies()
[%Company{}, ...]

"""
def list_companies do
Repo.all(Company)
end

@doc """
Gets a single company.

Raises `Ecto.NoResultsError` if the Company does not exist.

## Examples

iex> get_company!(123)
%Company{}

iex> get_company!(456)
** (Ecto.NoResultsError)

"""
def get_company!(id), do: Repo.get!(Company, id)

@doc """
Creates a company.

## Examples

iex> create_company(%{field: value})
{:ok, %Company{}}

iex> create_company(%{field: bad_value})
{:error, %Ecto.Changeset{}}

"""
def create_company(attrs) do
%Company{}
|> Company.changeset(attrs)
|> Repo.insert()
end

@doc """
Updates a company.

## Examples

iex> update_company(company, %{field: new_value})
{:ok, %Company{}}

iex> update_company(company, %{field: bad_value})
{:error, %Ecto.Changeset{}}

"""
def update_company(%Company{} = company, attrs) do
company
|> Company.changeset(attrs)
|> Repo.update()
end

@doc """
Updates a company logo.

## Examples

iex> update_company_logo(company, %{logo: image})
{:ok, %Company{}}

iex> update_company_logo(company, %{logo: bad_image})
{:error, %Ecto.Changeset{}}

"""
def update_company_logo(%Company{} = company, attrs) do
company
|> Company.image_changeset(attrs)
|> Repo.update()
end

@doc """
Creates or updates a company.

## Examples

iex> create_or_update_company(%Company{}, %{field: value})
{:ok, %Company{}}

iex> create_or_update_company(%Company{}, %{field: bad_value})
{:error, %Ecto.Changeset{}}

"""
def create_or_update_company(%Company{} = company, attrs) do
company
|> Company.changeset(attrs)
|> Repo.insert_or_update()
end

@doc """
Deletes a company.

## Examples

iex> delete_company(company)
{:ok, %Company{}}

iex> delete_company(company)
{:error, %Ecto.Changeset{}}

"""
def delete_company(%Company{} = company) do
Repo.delete(company)
end

@doc """
Returns an `%Ecto.Changeset{}` for tracking company changes.

## Examples

iex> change_company(company)
%Ecto.Changeset{data: %Company{}}

"""
def change_company(%Company{} = company, attrs \\ %{}) do
Company.changeset(company, attrs)
end
end
35 changes: 35 additions & 0 deletions lib/ares/companies/company.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
defmodule Ares.Companies.Company do
@moduledoc """
Represents companies sponsoring the event.
"""
use Ecto.Schema
use Waffle.Ecto.Schema
import Ecto.Changeset

@required_fields ~w(name)a
@optional_fields ~w(url type)a

@primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id
schema "companies" do
field :name, :string
field :url, :string
field :logo, Ares.Uploaders.Company.Type
field :type, Ecto.Enum, values: [:sponsor, :partner], default: :sponsor

timestamps(type: :utc_datetime)
end

@doc false
def changeset(company, attrs) do
company
|> cast(attrs, @required_fields ++ @optional_fields)
|> validate_required(@required_fields)
end

@doc false
def image_changeset(company, attrs) do
company
|> cast_attachments(attrs, [:logo])
end
end
28 changes: 28 additions & 0 deletions lib/ares/uploaders/company.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
defmodule Ares.Uploaders.Company do
@moduledoc """
Company image uploader.
"""
use Ares.Uploader

alias Ares.Companies.Company

@versions [:original]
@extension_whitelist ~w(.svg .png)

def validate({file, _}) do
file_extension = file.file_name |> Path.extname() |> String.downcase()
Enum.member?(extension_whitelist(), file_extension)
end

def storage_dir(_, {_file, %Company{} = company}) do
"uploads/companies/company/#{company.id}"
end

def filename(version, _) do
version
end

def extension_whitelist do
@extension_whitelist
end
end
80 changes: 80 additions & 0 deletions lib/ares_web/components/image_uploader.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
defmodule AresWeb.Components.ImageUploader do
@moduledoc """
Image uploader component.
"""
use AresWeb, :html

attr :upload, :any, required: true
attr :class, :string, default: ""
attr :image_class, :string, default: ""
attr :image, :string, default: nil
attr :icon, :string, default: "hero-photo"
attr :preview_disabled, :boolean, default: false
attr :rounded, :boolean, default: false

slot :placeholder, required: false, doc: "Slot for the placeholder content."

def image_uploader(assigns) do
~H"""
<.live_file_input upload={@upload} class="hidden" />
<section
phx-drop-target={@upload.ref}
class={[
"transition-colors hover:cursor-pointer hover:bg-lightShade/30 dark:hover:bg-darkShade/20 border-2 border-dashed border-lightShade dark:border-darkShade",
@rounded && "rounded-full overflow-hidden",
not @rounded && "rounded-xl",
@class
]}
onclick={"document.getElementById('#{@upload.ref}').click()"}
>
<%= if @upload.entries == [] do %>
<article class="h-full">
<figure class="h-full flex items-center justify-center">
<%= if @image do %>
<img class={[@rounded && "p-0", not @rounded && "p-4", @image_class]} src={@image} />
<% else %>
<%= if @placeholder do %>
{render_slot(@placeholder)}
<% else %>
<div class="select-none flex flex-col gap-2 items-center text-lightMuted dark:text-darkMuted">
<.icon name={@icon} class="w-12 h-12" />
<p class="px-4 text-center">{gettext("Upload a file or drag and drop.")}</p>
</div>
<% end %>
<% end %>
</figure>
</article>
<% end %>
<%= if !@preview_disabled do %>
<%= for entry <- @upload.entries do %>
<article class="h-full">
<figure class="h-full flex items-center justify-center">
<%= if image_file?(entry) do %>
<.live_img_preview
class={[@rounded && "p-0", not @rounded && "p-4", @image_class]}
entry={entry}
/>
<% else %>
<div class="select-none flex flex-col gap-2 items-center text-lightMuted dark:text-darkMuted">
<.icon name="hero-document" class="w-12 h-12" />
<p class="px-4 text-center">{entry.client_name}</p>
</div>
<% end %>
</figure>
<%= for err <- upload_errors(@upload, entry) do %>
<p class="alert alert-danger">{Phoenix.Naming.humanize(err)}</p>
<% end %>
</article>
<% end %>
<% end %>
<%= for err <- upload_errors(@upload) do %>
<p class="alert alert-danger">{Phoenix.Naming.humanize(err)}</p>
<% end %>
</section>
"""
end

defp image_file?(entry) do
entry.client_type in ["image/jpeg", "image/png", "image/gif"]
end
end
16 changes: 16 additions & 0 deletions lib/ares_web/components/sidebar.ex
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ defmodule AresWeb.Components.Sidebar do
Event Settings
</.link>
</li>
<li class="w-full">
<.link
class="block w-full text-left py-3 px-6 hover:bg-white/10 hover:text-white transition-colors duration-150 rounded"
navigate="/backoffice/companies"
>
Companies
</.link>
</li>
</ul>
</nav>
<button
Expand Down Expand Up @@ -114,6 +122,14 @@ defmodule AresWeb.Components.Sidebar do
Event Settings
</.link>
</li>
<li class="w-full">
<.link
class="block w-full text-left py-3 px-6 hover:bg-white/10 hover:text-white transition-colors duration-150 rounded"
navigate="/backoffice/companies"
>
Companies
</.link>
</li>
</ul>
</nav>
</div>
Expand Down
8 changes: 8 additions & 0 deletions lib/ares_web/endpoint.ex
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ defmodule AresWeb.Endpoint do
gzip: not code_reloading?,
only: AresWeb.static_paths()

# Serve uploads from the "uploads" directory in development
if Mix.env() == :dev do
plug Plug.Static,
at: "/uploads",
from: Path.expand("./priv/uploads"),
gzip: false
end

# Code reloading can be explicitly enabled under the
# :code_reloader configuration of your endpoint.
if code_reloading? do
Expand Down
Loading