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
2 changes: 1 addition & 1 deletion lib/split_app_web/components/layouts/app.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
</div>
</nav>
<.flash_group flash={@flash} />
<div class="relative flex flex-grow">
<div class="relative flex flex-grow mt-10">
{@inner_content}
</div>
</main>
11 changes: 3 additions & 8 deletions lib/split_app_web/live/dashboard_live.ex
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ defmodule SplitAppWeb.DashboardLive do
def handle_info({SplitAppWeb.ExpenseLive.FormComponent, {:saved, _expense}}, socket) do
user = socket.assigns.current_user
recent_expenses = Expenses.list_expenses_by_user(user.id) |> Enum.take(5)

{:noreply,
socket
|> assign(:recent_expenses, recent_expenses)
Expand All @@ -86,7 +86,7 @@ defmodule SplitAppWeb.DashboardLive do
def handle_info({SplitAppWeb.GroupLive.FormComponent, {:saved, _group}}, socket) do
user = socket.assigns.current_user
groups = Groups.list_user_groups(user)

{:noreply,
socket
|> assign(:groups, groups)
Expand Down Expand Up @@ -331,12 +331,7 @@ defmodule SplitAppWeb.DashboardLive do
/>
</.modal>

<.modal
:if={@show_group_modal}
id="group-modal"
show
on_cancel={JS.push("close_group_modal")}
>
<.modal :if={@show_group_modal} id="group-modal" show on_cancel={JS.push("close_group_modal")}>
<.live_component
module={SplitAppWeb.GroupLive.FormComponent}
id={:new}
Expand Down
2 changes: 1 addition & 1 deletion lib/split_app_web/live/expense_live/index.ex
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ defmodule SplitAppWeb.ExpenseLive.Index do
def handle_info({SplitAppWeb.ExpenseLive.FormComponent, {:saved, _expense}}, socket) do
current_user = socket.assigns.current_user
expenses = if current_user, do: Expenses.list_expenses_by_user(current_user.id), else: []

{:noreply,
socket
|> stream(:expenses, expenses, reset: true)
Expand Down
5 changes: 5 additions & 0 deletions lib/split_app_web/live/group_live/index.ex
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ defmodule SplitAppWeb.GroupLive.Index do
{:noreply, put_flash(socket, type, message)}
end

@impl true
def handle_event("edit_group", %{"id" => id}, socket) do
{:noreply, push_patch(socket, to: ~p"/groups/#{id}/edit")}
end

@impl true
def handle_event("delete", %{"id" => id}, socket) do
user = socket.assigns.current_user
Expand Down
122 changes: 75 additions & 47 deletions lib/split_app_web/live/group_live/index.html.heex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div class="max-w-7xl mx-auto">
<div class="mx-auto max-w-6xl">
<.header class="mb-8">
Your Groups
<:subtitle>Manage your expense sharing groups</:subtitle>
Expand All @@ -11,62 +11,90 @@
</:actions>
</.header>

<div class="bg-white overflow-hidden shadow sm:rounded-md">
<ul role="list" class="divide-y divide-gray-200">
<li
:for={{_id, group} <- @streams.groups}
class="px-6 py-4 hover:bg-gray-50 cursor-pointer"
phx-click={JS.navigate(~p"/groups/#{group}")}
<div :if={@groups_count == 0} class="text-center py-12">
<div class="mx-auto h-12 w-12 text-gray-400">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
>
<div class="flex items-center justify-between">
<div class="min-w-0 flex-1">
<div class="flex items-center justify-between">
<p class="text-sm font-medium text-gray-900 truncate">
{group.name}
</p>
<div class="ml-4 flex-shrink-0">
<span class="text-sm text-gray-500">
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M15 19.128a9.38 9.38 0 0 0 2.625.372 9.337 9.337 0 0 0 4.121-.952 4.125 4.125 0 0 0-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.106A12.318 12.318 0 0 1 8.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0 1 11.964-3.07M12 6.375a3.375 3.375 0 1 1-6.75 0 3.375 3.375 0 0 1 6.75 0Zm8.25 2.25a2.625 2.625 0 1 1-5.25 0 2.625 2.625 0 0 1 5.25 0Z"
/>
</svg>
</div>
<h3 class="mt-2 text-lg font-semibold text-gray-900">No groups yet</h3>
<p class="mt-1 text-gray-500 mb-6">
Create your first group to start splitting expenses with friends.
</p>
<.link patch={~p"/groups/new"}>
<.button>New Group</.button>
</.link>
</div>

<div :if={@groups_count > 0} class="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
<div :for={{_id, group} <- @streams.groups} class="group cursor-pointer">
<.link navigate={~p"/groups/#{group}"} class="block">
<div class="relative rounded-lg border border-gray-300 bg-white px-6 py-6 shadow-sm hover:border-gray-400 hover:shadow-md transition-all">
<div>
<span class="inline-flex rounded-lg bg-indigo-50 p-3 text-indigo-600">
<.icon name="hero-user-group" class="h-6 w-6" />
</span>
</div>
<div class="mt-4">
<h3 class="text-base font-semibold leading-6 text-gray-900">
{group.name}
</h3>
<p class="mt-2 text-sm text-gray-500 line-clamp-2">
{if group.description && String.length(group.description) > 0,
do: group.description,
else: "No description provided"}
</p>
<div class="mt-4 flex items-center justify-between">
<div class="flex items-center text-sm text-gray-500">
<.icon name="hero-users" class="w-4 h-4 mr-1" />
<span>
{get_user_count(group)} {if get_user_count(group) == 1,
do: "member",
else: "members"}
</span>
</div>
</div>
<div class="mt-2 flex items-center justify-between">
<p class="text-sm text-gray-500 truncate">
{if group.description && String.length(group.description) > 0,
do: group.description,
else: "No description"}
</p>
<div class="ml-4 flex items-center space-x-4 text-sm text-gray-500">
<span>{format_date(group.inserted_at)}</span>
<.link
patch={~p"/groups/#{group}/edit"}
class="text-indigo-600 hover:text-indigo-900"
>
Edit
</.link>
<.link
phx-click={JS.push("delete", value: %{id: group.id})}
data-confirm="Are you sure you want to delete this group? This will remove all associated data."
class="text-red-600 hover:text-red-900"
>
Delete
</.link>
<div class="text-xs text-gray-400">
{format_date(group.inserted_at)}
</div>
</div>
</div>
<span
class="pointer-events-none absolute right-6 top-6 text-gray-300 group-hover:text-gray-400"
aria-hidden="true"
>
<.icon name="hero-chevron-right" class="h-5 w-5" />
</span>
<div class="absolute bottom-4 right-4 opacity-0 group-hover:opacity-100 transition-opacity">
<div class="flex items-center space-x-2">
<.link
patch={~p"/groups/#{group}/edit"}
class="p-1 text-indigo-600 hover:text-indigo-900 bg-white rounded shadow-sm border border-gray-200"
phx-click="edit_group"
phx-value-id={group.id}
>
<.icon name="hero-pencil" class="w-4 h-4" />
</.link>
<button
phx-click="delete"
phx-value-id={group.id}
data-confirm="Are you sure you want to delete this group? This will remove all associated data."
class="p-1 text-red-600 hover:text-red-900 bg-white rounded shadow-sm border border-gray-200"
>
<.icon name="hero-trash" class="w-4 h-4" />
</button>
</div>
</div>
</div>
</li>
</ul>

<div :if={@groups_count == 0} class="text-center py-12">
<h3 class="text-lg font-medium text-gray-900 mb-2">No groups yet</h3>
<p class="text-gray-500 mb-6">
Create your first group to start splitting expenses with friends.
</p>
<.link patch={~p"/groups/new"}>
<.button>New Group</.button>
</.link>
</div>
</div>
Expand Down
Loading