Skip to content

Commit

Permalink
Merge branch 'main' into feat/responsive-landing
Browse files Browse the repository at this point in the history
  • Loading branch information
douglastofoli authored Aug 30, 2024
2 parents a011e2c + 946df29 commit bc9d36d
Show file tree
Hide file tree
Showing 27 changed files with 919 additions and 214 deletions.
10 changes: 1 addition & 9 deletions assets/css/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,6 @@ body {
position: relative;
}

footer {
@apply border-black-10;
border-top-width: 1px;

img {
z-index: -99;
}
}

.grid {
display: grid;
grid-template-rows: $navbar-height 1fr $footer-height;
Expand Down Expand Up @@ -104,6 +95,7 @@ nav {

main {
grid-area: content;
margin-bottom: 100px;
}

footer {
Expand Down
2 changes: 1 addition & 1 deletion assets/css/navbar.scss
Original file line number Diff line number Diff line change
Expand Up @@ -192,4 +192,4 @@
width: 12.25rem;
height: 3.8rem;
}
}
}
3 changes: 2 additions & 1 deletion config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ config :flop, repo: Pescarte.Database.Repo.Replica

config :pescarte, fetch_pesagro_cotacoes: !!System.get_env("FETCH_PESAGRO_COTACOES")

config :pescarte, PescarteWeb, receiver_email: "[email protected]"
config :pescarte, PescarteWeb, sender_email: "[email protected]"
config :pescarte, PescarteWeb, receiver_email: "[email protected]"

config :pescarte,
ecto_repos: [Pescarte.Database.Repo],
Expand Down
76 changes: 76 additions & 0 deletions lib/pescarte/blog/entity/tag.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
defmodule Pescarte.Blog.Entity.Tag do
@moduledoc """
A entidade `Tag` fornece um CRUD básico para a mesma e é responsável por categorizar os posts do contexto Blog, para filtragem e pesquisa.
"""

use Pescarte, :model

alias Pescarte.Database.Types.PublicId

@type t :: %Tag{nome: binary, id: binary}

@required_fields ~w(nome)a

@primary_key {:id, PublicId, autogenerate: true}
schema "blog_tag" do
field :nome, :string

timestamps()
end

@spec changeset(Tag.t(), map) :: changeset
def changeset(%Tag{} = tag, attrs) do
tag
|> cast(attrs, @required_fields)
|> validate_required(@required_fields)
|> unique_constraint(:nome)
end

@spec list_tags() :: {:ok, list(Tag.t())} | {:error, term()}
def list_tags do
Repo.replica().all(Tag)
end

@spec fetch_tag_by_id(String.t()) :: {:ok, Tag.t()} | {:error, term()}
def fetch_tag_by_id(id) do
Pescarte.Database.fetch(Tag, id)
end

@spec fetch_tag_by_name(String.t()) :: {:ok, Tag.t()} | {:error, term()}
def fetch_tag_by_name(nome) do
Pescarte.Database.fetch_by(Tag, nome: nome)
end

@spec create_tag(map()) :: {:ok, Tag.t()} | {:error, changeset}
def create_tag(attrs) do
%Tag{}
|> changeset(attrs)
|> Repo.insert()
end

@spec update_tag(String.t(), map()) :: {:ok, Tag.t()} | {:error, :not_found}
def update_tag(id, attrs) do
query = from(t in Tag, where: t.id == ^id, select: t)

attrs_with_updated_date = Map.put(attrs, :updated_at, NaiveDateTime.utc_now())

query
|> Repo.update_all(set: Map.to_list(attrs_with_updated_date))
|> case do
{1, [updated_tag]} -> {:ok, updated_tag}
{_, _} -> {:error, :not_found}
end
end

@spec delete_tag(String.t()) :: :ok | {:error, :not_found}
def delete_tag(id) do
query = from(t in Tag, where: t.id == ^id)

query
|> Repo.delete_all()
|> case do
{1, _} -> :ok
{_, _} -> {:error, :not_found}
end
end
end
92 changes: 92 additions & 0 deletions lib/pescarte/blog/post.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
defmodule Pescarte.Blog.Post do
@moduledoc """
Módulo que define o schema e o changeset para os posts.
"""
alias Pescarte.Database
alias Pescarte.Database.Repo
alias Pescarte.Database.Types.PublicId
alias Pescarte.Identidades.Models.Usuario
use Pescarte, :model

@type t :: %Post{
id: String.t(),
titulo: String.t(),
conteudo: String.t(),
link_imagem_capa: String.t(),
published_at: NaiveDateTime.t(),
inserted_at: NaiveDateTime.t(),
updated_at: NaiveDateTime.t(),
usuario: Usuario.t(),
usuario_id: String.t()
}

@required_params [:titulo, :conteudo, :link_imagem_capa, :published_at]

@primary_key {:id, PublicId, autogenerate: true}
schema "posts" do
field :titulo, :string
field :conteudo, :binary
field :link_imagem_capa, :string
field :published_at, :naive_datetime

belongs_to :usuario, Usuario

# comentado enquanto o PR das tags não é aprovado
# many_to_many :tags, Tag, through: [:post_tags, :tag]

timestamps()
end

def changeset(post \\ %Post{}, params) do
post
|> cast(params, @required_params)
|> validate_required(@required_params)
|> unique_constraint(:titulo)
end

@spec get_posts :: list(Post.t()) | Ecto.QueryError
def get_posts do
Repo.Replica.all(Post)
end

@spec get_post(String.t()) :: {:ok, Post.t()} | {:error, :not_found}
def get_post(id) do
Database.fetch(Post, id)
end

@spec create_post(Post.t()) :: {:ok, Post.t()} | {:error, Ecto.Changeset.t()}
def create_post(params) do
%Post{}
|> Post.changeset(params)
|> Repo.insert()
end

@spec delete_post(String.t()) :: {:ok, Post.t()} | {:error, :not_found}
def delete_post(id) do
query = from(p in Post, where: p.id == ^id, select: p)

query
|> Repo.delete_all()
|> case do
{1, [deleted_post]} -> {:ok, deleted_post}
{0, nil} -> {:error, :not_found}
end
end

@spec update_post(String.t(), Post.t()) :: {:ok, Post.t()} | {:error, :not_found}
def update_post(id, params) do
query = from(p in Post, where: p.id == ^id, select: p)

params_with_updated_at =
params
|> Map.put(:updated_at, NaiveDateTime.utc_now())
|> Map.to_list()

query
|> Repo.update_all(set: params_with_updated_at)
|> case do
{1, [updated_post]} -> {:ok, updated_post}
{0, _} -> {:error, :not_found}
end
end
end
3 changes: 3 additions & 0 deletions lib/pescarte/identidades/models/usuario.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ defmodule Pescarte.Identidades.Models.Usuario do

import Brcpfcnpj.Changeset, only: [validate_cpf: 3]

alias Pescarte.Blog.Post
alias Pescarte.Database.Types.PublicId
alias Pescarte.Identidades.Models.Contato
alias Pescarte.ModuloPesquisa.Models.Pesquisador
Expand Down Expand Up @@ -44,6 +45,8 @@ defmodule Pescarte.Identidades.Models.Usuario do

belongs_to :contato, Contato, type: :string

has_many :posts, Post

timestamps()
end

Expand Down
21 changes: 19 additions & 2 deletions lib/pescarte_web/controllers/agenda_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,22 @@ defmodule PescarteWeb.AgendaController do
alias NimbleCSV.RFC4180, as: CSV

def show(conn, _params) do
current_month =
"appointments_data"
|> Pescarte.get_static_file_path("agenda_setembro.csv")
|> File.stream!()
|> CSV.parse_stream(skip_headers: false)
|> Enum.take(1)
|> List.first()

table_data =
"appointments_data"
|> Pescarte.get_static_file_path("agenda_setembro.csv")
|> File.stream!()
|> CSV.parse_stream()
|> Stream.drop(1)
|> Stream.map(&convert_to_map/1)
|> Enum.filter(& &1)
|> Enum.filter(&valid_row?/1)
|> then(fn rows ->
total_rows = Enum.count(rows)

Expand All @@ -22,7 +31,11 @@ defmodule PescarteWeb.AgendaController do

current_path = conn.request_path

render(conn, :show, mapa: table_data, current_path: current_path)
render(conn, :show,
mapa: table_data,
current_month: current_month,
current_path: current_path
)
end

defp convert_to_map([data, horario, atividade, local]) do
Expand All @@ -33,4 +46,8 @@ defmodule PescarteWeb.AgendaController do
local: local
}
end

defp valid_row?(row) do
Enum.all?(row, &(&1 != ""))
end
end
68 changes: 42 additions & 26 deletions lib/pescarte_web/controllers/contact_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ defmodule PescarteWeb.ContactController do
require Logger
alias PescarteWeb.ContactForm

@sender_email Application.compile_env!(:pescarte, [PescarteWeb, :sender_email])
@receiver_email Application.compile_env!(:pescarte, [PescarteWeb, :receiver_email])

def show(conn, _params) do
Expand All @@ -16,45 +17,60 @@ defmodule PescarteWeb.ContactController do
{:ok, contact_form} ->
client = Resend.client()

email_data = %{
from: contact_form.sender_email,
to: @receiver_email,
subject: contact_form.sender_option,
html: """
<p><strong>Nome:</strong> #{contact_form.sender_name}</p>
<p><strong>Assunto:</strong> #{contact_form.sender_option}</p>
<p><strong>Mensagem:</strong> #{contact_form.sender_message}</p>
"""
}

case Resend.Emails.send(client, email_data) do
{:ok, email_response} ->
Logger.info("""
[#{__MODULE__}] ==> Sent email from contact form:
RESPONSE: #{inspect(email_response, pretty: true)}
LOG_UUID: #{Ecto.UUID.generate()}
""")

conn
|> put_flash(:info, "Email enviado com sucesso!")
|> redirect(~p"/")

with {:ok, _} <- send_email_to_pescarte(client, contact_form),
{:ok, _} <- send_confirmation_email(client, contact_form) do
conn
|> put_flash(:info, "Email enviado com sucesso!")
|> redirect(to: ~p"/")
else
{:error, reason} ->
Logger.error("""
[#{__MODULE__}] ==> Error sending email from contact form:
[#{__MODULE__}] ==> Error sending email:
REASON: #{inspect(reason, pretty: true)}
LOG_UUID: #{Ecto.UUID.generate()}
""")

conn
|> put_flash(:error, "Erro ao enviar email.")
|> redirect(~p"/")
|> redirect(to: ~p"/")
end

{:error, _changeset} ->
conn
|> put_flash(:error, "Erro na validação do formulário.")
|> redirect(~p"/")
|> redirect(to: ~p"/")
end
end

defp send_email_to_pescarte(client, contact_form) do
email_data_to_pescarte = %{
from: @sender_email,
to: @receiver_email,
subject: contact_form.form_sender_option,
html: """
<p><strong>Nome:</strong> #{contact_form.form_sender_name}</p>
<p><strong>Assunto:</strong> #{contact_form.form_sender_option}</p>
<p><strong>Mensagem:</strong> #{contact_form.form_sender_message}</p>
"""
}

Resend.Emails.send(client, email_data_to_pescarte)
end

defp send_confirmation_email(client, contact_form) do
email_data_to_form_sender = %{
from: @sender_email,
to: contact_form.form_sender_email,
subject: "Confirmação de recebimento do formulário",
html: """
<p>Olá, #{contact_form.form_sender_name},</p>
<p>Recebemos seu formulário com o assunto: <strong>#{contact_form.form_sender_option}</strong>.</p>
<p>Em breve retornaremos sua mensagem.</p>
<p>Atenciosamente,</p>
<p>Equipe Pescarte</p>
"""
}

Resend.Emails.send(client, email_data_to_form_sender)
end
end
4 changes: 2 additions & 2 deletions lib/pescarte_web/design_system.ex
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,8 @@ defmodule PescarteWeb.DesignSystem do
"""
def footer(assigns) do
~H"""
<footer class="flex justify-center items-center">
<img src={~p"/images/footer_logos.png"} />
<footer class="fixed bottom-0 z-10 w-full">
<img src={~p"/images/footer_logos_reduced_height.png"} />
</footer>
"""
end
Expand Down
1 change: 1 addition & 0 deletions lib/pescarte_web/design_system/get_in_touch.ex
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ defmodule PescarteWeb.DesignSystem.GetInTouch do
</div>
</div>
</div>
<div class="fale-conosco-wrapper">
<.text size="h4" color="text-white-100">
Mas, se preferir, entre em contato diretamente.
Expand Down
9 changes: 3 additions & 6 deletions lib/pescarte_web/layouts/app.html.heex
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
<PescarteWeb.DesignSystem.Navbar.render current_path={@current_path} />

<main class="w-full h-full">
<.flash_group flash={@flash} />
<%= @inner_content %>
<PescarteWeb.DesignSystem.Navbar.render current_path="{@current_path}" />
<main class="w-full h-full z-0">
<.flash_group flash={@flash} /> <%= @inner_content %>
</main>

<.footer />
Loading

0 comments on commit bc9d36d

Please sign in to comment.