Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/event planning crud v2 #5

Open
wants to merge 5 commits into
base: feature/event_planning
Choose a base branch
from
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
3 changes: 2 additions & 1 deletion event_planning/.formatter.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[
import_deps: [:ecto, :phoenix],
inputs: ["*.{ex,exs}", "priv/*/seeds.exs", "{config,lib,test}/**/*.{ex,exs}"],
plugins: [Phoenix.LiveView.HTMLFormatter],
inputs: ["*.{heex,ex,exs}", "priv/*/seeds.exs", "{config,lib,test}/**/*.{heex,ex,exs}"],
subdirectories: ["priv/*/migrations"]
]
18 changes: 18 additions & 0 deletions event_planning/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
// Based on Elixir formatter's style
"editor.insertSpaces": true,
// Note: While it is possible to override this in your VSCode configuration, the Elixir Formatter
// does not support a configurable tab size, so if you override this then you should not use the
// formatter.
"editor.tabSize": 2,
"files.trimTrailingWhitespace": true,
"files.insertFinalNewline": true,
"files.trimFinalNewlines": true,

// Provides smart completion for "do" and "fn ->" blocks. Does not run the Elixir formatter.
"editor.formatOnType": true,

// Misc
"editor.wordBasedSuggestions": false,
"editor.trimAutoWhitespace": false
}
5 changes: 5 additions & 0 deletions event_planning/assets/css/app.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
/* This file is for your main application CSS */
@import "./phoenix.css";


.bg-yellow{
background-color: #faebcc;
}

/* Alerts and form errors used by phx.new */
.alert {
padding: 15px;
Expand Down
3 changes: 2 additions & 1 deletion event_planning/config/prod.exs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import Config
# manifest is generated by the `mix phx.digest` task,
# which you should run after static files are built and
# before starting your production server.
config :event_planning, EventPlanningWeb.Endpoint, cache_static_manifest: "priv/static/cache_manifest.json"
config :event_planning, EventPlanningWeb.Endpoint,
cache_static_manifest: "priv/static/cache_manifest.json"

# Do not print debug messages in production
config :logger, level: :info
Expand Down
196 changes: 196 additions & 0 deletions event_planning/lib/event_planning/accounts.ex
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,202 @@ defmodule EventPlanning.Accounts do
Repo.all(Event)
end

defp my_shedule_query(date_start, date_end) do
result =
Repo.all(
from e in Event,
where:
(e.date_start >= ^date_start and
e.date_start < ^date_end) or
e.repeat != :disabled,
order_by: e.date_start
)

IO.inspect(date_start)
IO.inspect(date_end)

result
|> event_repeat()
|> Enum.filter(fn x ->
# Something difficult
cond do
NaiveDateTime.diff(x.date_start, date_start, :second) >= 0 and
NaiveDateTime.diff(date_end, x.date_start, :second) >= 0 ->
true

true ->
false
end
end)
|> event_collision()
|> Enum.sort_by(& &1.date_start, Date)
end

defp event_collision(events) do
events
|> Enum.map(fn x ->
color =
Enum.any?(events, fn y ->
if(
x.date_start <= y.date_end and y.date_start <= x.date_end and
x.id != y.id
) do
true
end
end)

Map.put(x, :color, color)
end)
end

defp event_dublicate(event, seconds_in_period) do
counter =
(NaiveDateTime.diff(event.repeat_date_end, event.date_start, :second) / seconds_in_period)
|> trunc

repeat =
for w <- 0..counter do
if w > 0 do
date_start = NaiveDateTime.add(event.date_start, seconds_in_period * w)
date_end = NaiveDateTime.add(event.date_end, seconds_in_period * w)

Map.put(event, :date_start, date_start)
|> Map.put(:date_end, date_end)
end
end

[event | repeat] |> Enum.filter(&(!is_nil(&1)))
end

defp event_repeat(events) do
map_week = %{
"monday" => 1,
"tuesday" => 2,
"wednesday" => 3,
"thursday" => 4,
"friday" => 5,
"saturday" => 6,
"sunday" => 7,
nil => nil
}

Enum.flat_map(events, fn x ->
case x.repeat do
:day ->
event_dublicate(x, 86400)

:week ->
event_dublicate(x, 86400)
|> Enum.filter(fn x2 ->
x |> IO.inspect()

cond do
x.date_start == x2.date_start ->
true

x.repeat_days_week == nil ->
Date.day_of_week(x.date_start) == Date.day_of_week(x2.date_start)

Enum.member?(
Enum.map(x.repeat_days_week, fn r -> map_week[r] end),
Date.day_of_week(x2.date_start)
) ->
true

true ->
false
end
end)

:month ->
event_dublicate(x, 86400 * 30)

:year ->
event_dublicate(x, 86400 * 365)

_ ->
[x]
end
end)
end

def my_shedule("week") do
start_date = DateTime.utc_now() |> Date.beginning_of_week()
{:ok, start_date_native} = start_date |> NaiveDateTime.new(~T[00:00:00])

{:ok, end_date_native} = start_date |> Date.add(7) |> NaiveDateTime.new(~T[00:00:00])

events = my_shedule_query(start_date_native, end_date_native)

{events, start_date, end_date_native |> NaiveDateTime.to_date() |> Date.add(-1)}
end

def my_shedule("month") do
start_date = DateTime.utc_now() |> Date.beginning_of_month()

{:ok, start_date_native} = start_date |> NaiveDateTime.new(~T[00:00:00])

{:ok, end_date_native} = start_date |> Date.end_of_month() |> NaiveDateTime.new(~T[00:00:00])

events = my_shedule_query(start_date_native, end_date_native)

{events, start_date, end_date_native |> NaiveDateTime.to_date()}
end

def my_shedule("year") do
today = Date.utc_today()
year = today.year
{:ok, start_date_native} = NaiveDateTime.new(year, 1, 1, 0, 0, 0)
{:ok, end_date_native} = NaiveDateTime.new(year + 1, 1, 1, 0, 0, 0)

events = my_shedule_query(start_date_native, end_date_native)

{events, start_date_native |> NaiveDateTime.to_date(),
end_date_native |> NaiveDateTime.to_date()}
end

def my_shedule(_) do
my_shedule("week")
end

def next_event() do
limit = 25
start_date = DateTime.utc_now() |> Date.beginning_of_month()

{:ok, start_date_native} = start_date |> NaiveDateTime.new(~T[00:00:00])

result =
Repo.all(
from e in Event,
where:
e.date_start >= ^start_date_native or
e.repeat != :disabled,
order_by: e.date_start,
limit: ^limit
)

events =
result
|> event_repeat()
|> Enum.filter(fn x ->
cond do
NaiveDateTime.diff(x.date_start, DateTime.utc_now(), :second) >= 0 ->
true

true ->
false
end
end)
|> event_collision()
|> Enum.sort_by(& &1.date_start, Date)
|> Enum.take(limit)
|> Enum.map(fn x ->
Map.put(x, :time_left, NaiveDateTime.diff(x.date_start, DateTime.utc_now()))
end)

{events, start_date, limit}
end

@doc """
Gets a single event.

Expand Down
31 changes: 25 additions & 6 deletions event_planning/lib/event_planning/accounts/event.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@ defmodule EventPlanning.Accounts.Event do
import Ecto.Changeset

schema "events" do
field :dEnd, :naive_datetime
field :dStart, :naive_datetime
field :description, :string
field :isActive, :boolean, default: false
field :name, :string
field :description, :string
field :date_start, :naive_datetime
field :date_end, :naive_datetime

field :repeat, Ecto.Enum, values: [disabled: 0, day: 1, week: 2, month: 3, year: 4]

field :repeat_days_week, {:array, :string}, default: nil

field :repeat_date_end, :naive_datetime

field :user_id, :id

timestamps()
Expand All @@ -16,7 +22,20 @@ defmodule EventPlanning.Accounts.Event do
@doc false
def changeset(event, attrs) do
event
|> cast(attrs, [:name, :description, :dStart, :dEnd, :isActive])
|> validate_required([:name, :description, :dStart, :dEnd, :isActive])
|> cast(attrs, [
:name,
:description,
:date_start,
:date_end,
:repeat,
:repeat_days_week,
:repeat_date_end,
:user_id
])
|> validate_required([
:date_start,
:date_end,
:repeat
])
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,56 @@ defmodule EventPlanningWeb.EventController do
render(conn, "index.html", events: events)
end

@spec my_schedule(Plug.Conn.t(), any) :: Plug.Conn.t()
def my_schedule(conn, %{"period" => period}) do
case period do
"week" ->
my_schedule_render(conn, period)

"month" ->
my_schedule_render(conn, period)

"year" ->
my_schedule_render(conn, period)

_ ->
my_schedule_render(conn)
end
end

def my_schedule(conn, _params) do
my_schedule_render(conn)
end

defp my_schedule_render(conn, period \\ "week") do
{events, start, end_date} = Accounts.my_shedule(period)

render(conn, "my_schedule.html",
events: events,
period: period,
start: start,
end_date: end_date
)
end

def next_event(conn, _params) do
{events, start, limit} = Accounts.next_event()

render(conn, "next_event.html",
events: events,
start: start,
limit: limit
)
end

@spec new(Plug.Conn.t(), any) :: Plug.Conn.t()
def new(conn, _params) do
changeset = Accounts.change_event(%Event{})
render(conn, "new.html", changeset: changeset)
end

def create(conn, %{"event" => event_params}) do
case Accounts.create_event(event_params) do
case Accounts.create_event(fix_end_datetime(event_params)) do
{:ok, event} ->
conn
|> put_flash(:info, "Event created successfully.")
Expand All @@ -42,7 +85,14 @@ defmodule EventPlanningWeb.EventController do
def update(conn, %{"id" => id, "event" => event_params}) do
event = Accounts.get_event!(id)

case Accounts.update_event(event, event_params) do
event_params =
Map.put(
event_params,
"repeat_days_week",
event_params["repeat_days_week"]
)

case Accounts.update_event(event, fix_end_datetime(event_params)) do
{:ok, event} ->
conn
|> put_flash(:info, "Event updated successfully.")
Expand All @@ -53,6 +103,20 @@ defmodule EventPlanningWeb.EventController do
end
end

defp fix_end_datetime(event_params) do
# for test renders errors when data is invalid
# my tests didn't pass so I added an if
if !event_params["date_start"] or !event_params["date_end"] do
event_params
else
Map.put(
event_params,
"date_end",
Map.merge(event_params["date_start"], event_params["date_end"])
)
end
end

def delete(conn, %{"id" => id}) do
event = Accounts.get_event!(id)
{:ok, _event} = Accounts.delete_event(event)
Expand Down
Loading