Compare commits
17 Commits
2f21ccd9de
...
fd5bcbfc05
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd5bcbfc05 | ||
|
|
5339fdb2b0 | ||
|
|
5ca34c2b6f | ||
|
|
bbf526d6a8 | ||
|
|
c72c09b1b2 | ||
|
|
90c3b06cfc | ||
|
|
d331da9e17 | ||
|
|
aa0c43aeb1 | ||
|
|
075ae78df2 | ||
|
|
1a4a7f0d0c | ||
|
|
f90c8621b9 | ||
|
|
2456c6d14b | ||
|
|
eccaca068d | ||
|
|
0c2f304b2f | ||
|
|
90007d40e7 | ||
|
|
2284a437fa | ||
|
|
117ccf5e16 |
@ -1,6 +1,7 @@
|
||||
defmodule Friends.Event do
|
||||
use Ecto.Schema
|
||||
alias Friends.{Relationship,Event}
|
||||
import Ecto.Query
|
||||
alias Friends.{Relationship, Event}
|
||||
alias Places.Place
|
||||
|
||||
@repo Friends.Repo
|
||||
@ -16,33 +17,157 @@ defmodule Friends.Event do
|
||||
belongs_to(:relationship, Relationship)
|
||||
end
|
||||
|
||||
def changeset(event, params \\ %{}) do
|
||||
event
|
||||
|> Ecto.Changeset.cast(params, [
|
||||
:name,
|
||||
:date,
|
||||
:story,
|
||||
:defining,
|
||||
:solo,
|
||||
:place_id,
|
||||
:relationship_id
|
||||
])
|
||||
|> Ecto.Changeset.validate_required([:name, :date, :solo, :relationship_id],
|
||||
message: "This field is required."
|
||||
)
|
||||
|> validate_date_in_past()
|
||||
|> validate_unique_event()
|
||||
end
|
||||
|
||||
defp validate_unique_event(changeset) do
|
||||
changeset
|
||||
end
|
||||
|
||||
defp validate_date_in_past(%{changes: %{date: date}} = changeset) do
|
||||
today = DateTime.utc_now() |> DateTime.to_date()
|
||||
|
||||
case date |> Date.diff(today) do
|
||||
age when age < 0 ->
|
||||
changeset |> Ecto.Changeset.add_error(:born, "Please enter a date in the past.")
|
||||
|
||||
_ ->
|
||||
changeset
|
||||
end
|
||||
end
|
||||
|
||||
defp validate_date_in_past(changeset), do: changeset
|
||||
|
||||
def new(params \\ %{}) do
|
||||
%Event{id: nil}
|
||||
|> struct(params)
|
||||
end
|
||||
|
||||
def get_by_id(id) do
|
||||
@repo.one(
|
||||
from(e in Event,
|
||||
where: e.id == ^id,
|
||||
preload: [:relationship, :place]
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
def get(%{relationship_id: rel, date: date, name: name}) do
|
||||
@repo.one(
|
||||
from(e in Event,
|
||||
where: e.relationship_id == ^rel and e.date == ^date and e.name == ^name,
|
||||
preload: [:relationship, :place]
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
def get_or_create(params) do
|
||||
case get(params) do
|
||||
nil -> create(params) |> commit()
|
||||
event -> event
|
||||
end
|
||||
end
|
||||
|
||||
def create(params \\ %{id: nil}) do
|
||||
Event.new(params)
|
||||
|> Event.changeset()
|
||||
|> Map.put(:action, :insert)
|
||||
end
|
||||
|
||||
def update(params) do
|
||||
Event.get_by_id(params.id |> String.to_integer())
|
||||
|> Event.changeset(params)
|
||||
|> Map.put(:action, :update)
|
||||
end
|
||||
|
||||
def commit(changeset) do
|
||||
changeset
|
||||
|> @repo.commit!
|
||||
|> load_preloads
|
||||
end
|
||||
|
||||
def load_preloads(
|
||||
%Event{
|
||||
place: %Ecto.Association.NotLoaded{},
|
||||
relationship: %Ecto.Association.NotLoaded{}
|
||||
} = model
|
||||
) do
|
||||
model
|
||||
|> @repo.preload([:place, :relationship])
|
||||
end
|
||||
|
||||
def load_preloads(event), do: event
|
||||
|
||||
def create_or_update(params) do
|
||||
case params.id do
|
||||
"new" ->
|
||||
params
|
||||
|> create()
|
||||
|> commit()
|
||||
|
||||
_number ->
|
||||
params
|
||||
|> update()
|
||||
|> commit()
|
||||
end
|
||||
end
|
||||
|
||||
def meet(friend1, friend2, opts \\ nil) do
|
||||
relationship = Relationship.get_or_new(friend1, friend2)
|
||||
opts = opts ++ [if opts[:place] do
|
||||
|
||||
opts =
|
||||
opts ++
|
||||
[
|
||||
if opts[:place] do
|
||||
{
|
||||
:place_id,
|
||||
Places.Place.get_or_new(opts[:place]).id
|
||||
}
|
||||
end]
|
||||
{:ok, event} = %Event{
|
||||
end
|
||||
]
|
||||
|
||||
{:ok, event} =
|
||||
%Event{
|
||||
story: opts[:story],
|
||||
date: opts[:date],
|
||||
place_id: opts[:place_id],
|
||||
relationship_id: relationship.id
|
||||
} |> @repo.insert
|
||||
}
|
||||
|> @repo.insert
|
||||
|
||||
event
|
||||
end
|
||||
|
||||
def person(event) do
|
||||
Friends.Friend.get_by_id(event.relationship.friend_id)
|
||||
end
|
||||
|
||||
def people(event) do
|
||||
event.relationship |> Relationship.members
|
||||
if event.solo, do: event.person, else: event.relationship |> Relationship.members()
|
||||
end
|
||||
|
||||
def age(event) do
|
||||
years = Date.diff(Date.utc_today, event.date)
|
||||
years =
|
||||
Date.diff(Date.utc_today(), event.date)
|
||||
|> div(365)
|
||||
|
||||
if years == 0 do
|
||||
months = Date.diff(Date.utc_today, event.date)
|
||||
|> rem(365) |> div(12)
|
||||
months = Date.diff(Date.utc_today(), event.date) |> rem(365) |> div(12)
|
||||
{months, :month}
|
||||
else
|
||||
{years, :year}
|
||||
@ -52,5 +177,4 @@ defmodule Friends.Event do
|
||||
def print_age(age) do
|
||||
Friends.Helpers.pluralize(age |> elem(0), age |> elem(1))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
defmodule Friends.Friend do
|
||||
use Ecto.Schema
|
||||
|
||||
alias Friends.{Relationship, Friend}
|
||||
alias Friends.{Relationship, Friend, Event}
|
||||
import Helpers
|
||||
import Ecto.Query
|
||||
|
||||
@ -46,7 +46,9 @@ defmodule Friends.Friend do
|
||||
:user_id,
|
||||
:address_id
|
||||
])
|
||||
|> Ecto.Changeset.validate_required([:name, :email, :phone, :born], message: "This field is required.")
|
||||
|> Ecto.Changeset.validate_required([:name, :email, :phone, :born],
|
||||
message: "This field is required."
|
||||
)
|
||||
|> Ecto.Changeset.validate_format(:name, ~r/\w+\ \w+/, message: "Please enter your full name.")
|
||||
|> Ecto.Changeset.validate_format(
|
||||
:email,
|
||||
@ -64,15 +66,20 @@ defmodule Friends.Friend do
|
||||
end
|
||||
|
||||
defp validate_birthdate(%{changes: %{born: born}} = changeset) do
|
||||
today = DateTime.utc_now |> DateTime.to_date
|
||||
today = DateTime.utc_now() |> DateTime.to_date()
|
||||
|
||||
case born |> Date.diff(today) |> div(-365) do
|
||||
age when age < 0 ->
|
||||
changeset |> Ecto.Changeset.add_error(:born, "Please enter a date in the past.")
|
||||
|
||||
age when age > 90 ->
|
||||
changeset |> Ecto.Changeset.add_error(:born, "Are you sure you're #{age} years old?")
|
||||
_ -> changeset
|
||||
|
||||
_ ->
|
||||
changeset
|
||||
end
|
||||
end
|
||||
|
||||
defp validate_birthdate(changeset), do: changeset
|
||||
|
||||
def all() do
|
||||
@ -152,7 +159,8 @@ defmodule Friends.Friend do
|
||||
"new" ->
|
||||
params
|
||||
|> create()
|
||||
|> generate_slug
|
||||
|> generate_slug()
|
||||
|> create_birth_event()
|
||||
|> commit()
|
||||
|
||||
_number ->
|
||||
@ -162,17 +170,17 @@ defmodule Friends.Friend do
|
||||
end
|
||||
end
|
||||
|
||||
def get_relationships(friend) do
|
||||
def get_relationships(friend, include_self \\ false) do
|
||||
friend
|
||||
|> relations
|
||||
|> relations(include_self)
|
||||
|> Enum.map(&relation(friend, &1))
|
||||
end
|
||||
|
||||
def get_events(friend) do
|
||||
friend
|
||||
|> get_relationships
|
||||
|> Enum.map(& &1.events)
|
||||
|> List.flatten()
|
||||
|> get_relationships(:all)
|
||||
|> Enum.flat_map(& &1.events)
|
||||
|> Enum.dedup()
|
||||
end
|
||||
|
||||
def age(friend) do
|
||||
@ -250,4 +258,16 @@ defmodule Friends.Friend do
|
||||
{nil, nil}
|
||||
end
|
||||
end
|
||||
|
||||
def create_birth_event(%Friend{id: id} = friend) do
|
||||
solo_relationship = Relationship.get_or_new(friend, friend)
|
||||
|
||||
Event.get_or_create(%{
|
||||
name: "Born",
|
||||
date: friend.born,
|
||||
solo: true,
|
||||
defining: true,
|
||||
relationship_id: solo_relationship.id
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
@ -26,8 +26,17 @@ defmodule Friends.Places.Place do
|
||||
end
|
||||
|
||||
def get_or_create(place) do
|
||||
case @repo.one(
|
||||
from(
|
||||
p in Friends.Places.Place,
|
||||
where: p.name == ^place.name
|
||||
)
|
||||
) do
|
||||
nil ->
|
||||
place
|
||||
|> Friends.Places.Place.validate()
|
||||
|> Friends.Repo.insert!()
|
||||
|> @repo.insert!()
|
||||
found -> found
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
defmodule Friends.Relationship do
|
||||
use Ecto.Schema
|
||||
import Ecto.Query
|
||||
alias Friends.{Relationship,Friend}
|
||||
alias Friends.{Relationship, Friend}
|
||||
|
||||
@repo Friends.Repo
|
||||
@default_type 3
|
||||
|
||||
schema "relationships" do
|
||||
field(:friend_id, :id)
|
||||
@ -22,6 +23,7 @@ defmodule Friends.Relationship do
|
||||
def types do
|
||||
# Tuple: name of the type, associated color, and what that person "is" to the other
|
||||
{
|
||||
{:self, :hidden, :self},
|
||||
{:acquaintances, :info, nil},
|
||||
{:family, :primary, :relative},
|
||||
{:friends, :secondary, :friend},
|
||||
@ -68,34 +70,39 @@ defmodule Friends.Relationship do
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
def all() do
|
||||
preloads = []
|
||||
@repo.all(from(r in Friends.Relationship, preload: ^preloads))
|
||||
@repo.all(from(r in Friends.Relationship, where: r.type != 0, preload: ^preloads))
|
||||
end
|
||||
|
||||
def new(friend1, friend2, type \\ 2) do
|
||||
def new(friend1, friend2, type \\ @default_type) do
|
||||
id1 = friend1.id
|
||||
id2 = friend2.id
|
||||
{:ok, relationship} = @repo.insert(
|
||||
%Relationship{
|
||||
|
||||
rel_type = if id1 == id2, do: 0, else: type
|
||||
|
||||
relationship =
|
||||
@repo.insert(%Relationship{
|
||||
friend_id: id1,
|
||||
relation_id: id2,
|
||||
type: type
|
||||
}
|
||||
)
|
||||
type: rel_type
|
||||
})
|
||||
|
||||
relationship
|
||||
end
|
||||
|
||||
def get(friend1, friend2) do
|
||||
id1 = friend1.id
|
||||
id2 = friend2.id
|
||||
rel = @repo.one(
|
||||
|
||||
rel =
|
||||
@repo.one(
|
||||
from(r in Relationship,
|
||||
where: r.friend_id == ^id1 and r.relation_id == ^id2,
|
||||
preload: [:events]
|
||||
)
|
||||
)
|
||||
|
||||
if rel == nil do
|
||||
@repo.one(
|
||||
from(r in Relationship,
|
||||
@ -108,16 +115,16 @@ defmodule Friends.Relationship do
|
||||
end
|
||||
end
|
||||
|
||||
def get_or_new(a,b) do
|
||||
def get_or_create(a, b) do
|
||||
case get(a, b) do
|
||||
nil -> new(a,b)
|
||||
nil -> new(a, b)
|
||||
relationship -> relationship
|
||||
end
|
||||
end
|
||||
|
||||
def get_by_slugs([slug1, slug2]) do
|
||||
friend1 = slug1 |> Friend.get_by_slug
|
||||
friend2 = slug2 |> Friend.get_by_slug
|
||||
friend1 = slug1 |> Friend.get_by_slug()
|
||||
friend2 = slug2 |> Friend.get_by_slug()
|
||||
get(friend1, friend2)
|
||||
end
|
||||
|
||||
@ -131,22 +138,33 @@ defmodule Friends.Relationship do
|
||||
|
||||
def age(relationship) do
|
||||
relationship.events
|
||||
|> Enum.map(fn(event) ->
|
||||
Date.diff(Date.utc_today, event.date)
|
||||
end) |> Enum.sort |> List.last |> div(365)
|
||||
|> Enum.map(fn event ->
|
||||
Date.diff(Date.utc_today(), event.date)
|
||||
end)
|
||||
|> Enum.sort()
|
||||
|> List.last()
|
||||
|> div(365)
|
||||
end
|
||||
|
||||
def load_events(%Relationship{
|
||||
events: %Ecto.Association.NotLoaded{}} = model) do
|
||||
def load_events(
|
||||
%Relationship{
|
||||
events: %Ecto.Association.NotLoaded{}
|
||||
} = model
|
||||
) do
|
||||
model
|
||||
|> @repo.preload([:events])
|
||||
end
|
||||
|
||||
def load_events(%Relationship{} = r), do: r
|
||||
def load_preloads(%Relationship{
|
||||
events: %Ecto.Association.NotLoaded{}} = model) do
|
||||
|
||||
def load_preloads(
|
||||
%Relationship{
|
||||
events: %Ecto.Association.NotLoaded{}
|
||||
} = model
|
||||
) do
|
||||
model
|
||||
|> @repo.preload([:events])
|
||||
end
|
||||
def load_preloads(%Relationship{} = r), do: r
|
||||
|
||||
def load_preloads(%Relationship{} = r), do: r
|
||||
end
|
||||
|
||||
@ -2,6 +2,7 @@ defmodule FriendsWeb.FriendsLive.Components do
|
||||
use FriendsWeb, :live_component
|
||||
use Phoenix.HTML
|
||||
import Helpers
|
||||
import FriendsWeb.LiveHelpers
|
||||
alias Friends.Friend
|
||||
alias FriendsWeb.Components.{Autocomplete, Map}
|
||||
alias Phoenix.LiveView.JS
|
||||
@ -89,12 +90,13 @@ defmodule FriendsWeb.FriendsLive.Components do
|
||||
<%= for event <- @friend |> Friends.Friend.get_events do %>
|
||||
<ul>
|
||||
<li>
|
||||
<%= event.name %>
|
||||
<b><%= event.name %></b> |
|
||||
<span><%= event.date |> format_date %></span>
|
||||
</li>
|
||||
</ul>
|
||||
<% end %>
|
||||
<%= if @friend |> Friends.Friend.get_events |> Enum.empty? do %>
|
||||
<div class="italic">None yet.</div>
|
||||
<div class="italic">No events on record yet.</div>
|
||||
<% end %>
|
||||
</div>
|
||||
"""
|
||||
@ -102,7 +104,7 @@ defmodule FriendsWeb.FriendsLive.Components do
|
||||
|
||||
def show_page(:relationships, assigns) do
|
||||
~H"""
|
||||
<div id="relationships" class="flex md:flex-row flex-col gap-8">
|
||||
<div id="relationships" class="flex md:flex-row flex-col gap-8 p-8">
|
||||
<%= for relation <- @friend |> relations do %>
|
||||
<% relationship = relation(@friend, relation) %>
|
||||
<div id={"relation-#{relation.id}"} class="card card-compact w-96 bg-base-100 shadow-xl">
|
||||
@ -119,7 +121,7 @@ defmodule FriendsWeb.FriendsLive.Components do
|
||||
</div>
|
||||
<% end %>
|
||||
<%= if @friend |> relations |> Enum.empty? do %>
|
||||
<div class="italic p-4">No relationships on record yet.</div>
|
||||
<div class="italic">No relationships on record yet.</div>
|
||||
<% end %>
|
||||
</div>
|
||||
"""
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
defmodule FriendsWeb.FriendsLive.Friend do
|
||||
use FriendsWeb, :live_view
|
||||
|
||||
alias FriendsWeb.FriendsLive.Components
|
||||
alias FriendsWeb.Router.Helpers, as: Routes
|
||||
alias Friends.Friend
|
||||
|
||||
|
||||
@ -22,7 +22,8 @@ defmodule FriendsWeb.FriendsLive.Show do
|
||||
|> assign(:latlon, latlon |> Poison.encode!())
|
||||
|> title(friend.name <> " - " <> (live_action |> titlecase))
|
||||
|> assign(:changeset, %Friend{} |> Friend.changeset())
|
||||
|> assign(:action, editable)}
|
||||
|> assign(:editable, editable)
|
||||
|> assign(:action, :moot)}
|
||||
else
|
||||
{:ok, socket |> redirect(to: Routes.friends_show_path(socket, :overview, friend.slug))}
|
||||
end
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
|
||||
<%= if @editable do %>
|
||||
<div class="form-control flex flex-row mb-4">
|
||||
<.link navigate={Routes.friends_edit_path(FriendsWeb.Endpoint, :overview, @friend.slug)} class="btn btn-block md:btn-wide text-white">edit</.link>
|
||||
<.link navigate={Routes.friends_edit_path(FriendsWeb.Endpoint, @live_action, @friend.slug)} class="btn btn-block md:btn-wide text-white"><%=@live_action |> get_edit_text%></.link>
|
||||
</div>
|
||||
<% end %>
|
||||
</article>
|
||||
|
||||
@ -16,23 +16,44 @@ defmodule FriendsWeb.LiveHelpers do
|
||||
display_phone(phone)
|
||||
end
|
||||
end
|
||||
|
||||
def display_phone(phone) do
|
||||
"""
|
||||
TODO: Actually implement this
|
||||
"""
|
||||
|
||||
has_plus = phone |> String.starts_with?("+")
|
||||
case phone |> String.length do
|
||||
|
||||
case phone |> String.length() do
|
||||
10 ->
|
||||
country = "+1 "
|
||||
[area, first, sec1, sec2] = phone |> to_charlist |> Enum.chunk_every(3) |> Enum.map(&(&1 |> to_string))
|
||||
|
||||
[area, first, sec1, sec2] =
|
||||
phone |> to_charlist |> Enum.chunk_every(3) |> Enum.map(&(&1 |> to_string))
|
||||
|
||||
"#{country}(#{area}) #{first}-#{sec1}#{sec2}"
|
||||
IO.inspect "#{country}(#{area}) #{first}-#{sec1}#{sec2}"
|
||||
|
||||
11 when has_plus ->
|
||||
phone
|
||||
|
||||
12 when has_plus ->
|
||||
phone
|
||||
end
|
||||
end
|
||||
|
||||
def get_edit_text(live_action) do
|
||||
case live_action do
|
||||
:timeline -> "add a moment"
|
||||
:relationships -> "add a relationship"
|
||||
_ -> "edit"
|
||||
end
|
||||
end
|
||||
|
||||
def format_date(date) do
|
||||
date
|
||||
|> Calendar.strftime("%b %d, %Y")
|
||||
end
|
||||
|
||||
def assign_current_user(socket, user_token) do
|
||||
user =
|
||||
case user_token do
|
||||
|
||||
@ -74,16 +74,20 @@ defmodule Helpers do
|
||||
birthday(friend) |> Date.diff(Date.utc_today())
|
||||
end
|
||||
|
||||
def relations(friend) do
|
||||
def relations(friend, include_self \\ false) do
|
||||
list =
|
||||
[friend.relationships, friend.reverse_relationships]
|
||||
|> List.flatten()
|
||||
|> Enum.dedup()
|
||||
|
||||
if include_self, do: list, else: list |> Enum.filter(&(&1.id != friend.id))
|
||||
end
|
||||
|
||||
def relation(friend, friend2) do
|
||||
Friends.Relationship.get(friend, friend2)
|
||||
end
|
||||
|
||||
def events(relationship) do
|
||||
def events(%Friends.Relationship{} = relationship) do
|
||||
relationship.events
|
||||
end
|
||||
end
|
||||
|
||||
Loading…
Reference in New Issue
Block a user