From 2839a7ee07f8e1dff904a41f3fddf65b0e3de3ac Mon Sep 17 00:00:00 2001 From: Zack Siri Date: Mon, 26 Feb 2024 19:14:25 +0700 Subject: [PATCH] Can now create new space --- lib/polar/accounts.ex | 8 ++ lib/polar/accounts/space.ex | 4 +- lib/polar/accounts/space/manager.ex | 4 + .../components/layouts/app.html.heex | 18 ++- lib/polar_web/live/dashboard/data_loader.ex | 16 +++ .../live/dashboard/space/new_live.ex | 102 +++++++++++++++++ lib/polar_web/live/dashboard/space_live.ex | 41 +++++++ lib/polar_web/live/dashboard_live.ex | 106 ++++++++++++++++++ lib/polar_web/live/user_settings_live.ex | 2 +- lib/polar_web/router.ex | 5 + ...0226104718_remove_cdn_host_from_spaces.exs | 9 ++ 11 files changed, 309 insertions(+), 6 deletions(-) create mode 100644 lib/polar_web/live/dashboard/data_loader.ex create mode 100644 lib/polar_web/live/dashboard/space/new_live.ex create mode 100644 lib/polar_web/live/dashboard/space_live.ex create mode 100644 lib/polar_web/live/dashboard_live.ex create mode 100644 priv/repo/migrations/20240226104718_remove_cdn_host_from_spaces.exs diff --git a/lib/polar/accounts.ex b/lib/polar/accounts.ex index f216f40..39d0ae5 100644 --- a/lib/polar/accounts.ex +++ b/lib/polar/accounts.ex @@ -12,6 +12,14 @@ defmodule Polar.Accounts do to: Space.Manager, as: :create + defdelegate change_space(space), + to: Space.Manager, + as: :change + + defdelegate change_space(space, attrs), + to: Space.Manager, + as: :change + defdelegate get_space_credential(query), to: Space.Manager, as: :get_credential diff --git a/lib/polar/accounts/space.ex b/lib/polar/accounts/space.ex index d3accb4..fabd232 100644 --- a/lib/polar/accounts/space.ex +++ b/lib/polar/accounts/space.ex @@ -6,7 +6,6 @@ defmodule Polar.Accounts.Space do schema "spaces" do field :name, :string - field :cdn_host, :string belongs_to :owner, User @@ -16,7 +15,8 @@ defmodule Polar.Accounts.Space do @doc false def changeset(space, attrs) do space - |> cast(attrs, [:name, :cdn_host]) + |> cast(attrs, [:name]) |> validate_required([:name]) + |> unique_constraint(:name, name: :spaces_owner_id_name_index) end end diff --git a/lib/polar/accounts/space/manager.ex b/lib/polar/accounts/space/manager.ex index a576c8a..8a3656e 100644 --- a/lib/polar/accounts/space/manager.ex +++ b/lib/polar/accounts/space/manager.ex @@ -11,6 +11,10 @@ defmodule Polar.Accounts.Space.Manager do |> Repo.insert() end + def change(%Space{} = space, attrs \\ %{}) do + Space.changeset(space, attrs) + end + def get_credential(token: token) do Space.Credential.scope(:active, Space.Credential) |> Repo.get_by(token: token) diff --git a/lib/polar_web/components/layouts/app.html.heex b/lib/polar_web/components/layouts/app.html.heex index d3dde72..5ed7301 100644 --- a/lib/polar_web/components/layouts/app.html.heex +++ b/lib/polar_web/components/layouts/app.html.heex @@ -21,6 +21,18 @@ > <%= gettext("Home") %> + <.link + navigate={~p"/dashboard"} + class={ + if assigns[:current_path] == ~p"/dashboard", + do: "bg-slate-900 text-white rounded-md px-3 py-2 text-sm font-medium", + else: + "rounded-md px-3 py-2 text-sm font-medium text-slate-300 hover:bg-slate-900 hover:text-white" + } + aria-current="page" + > + <%= gettext("Dashboard") %> + @@ -28,7 +40,7 @@
<%= if @current_user do %> <.link - href={~p"/users/settings"} + navigate={~p"/users/settings"} class={ if assigns[:current_path] == ~p"/users/settings", do: "bg-slate-900 text-white rounded-md px-3 py-2 text-sm font-medium", @@ -47,13 +59,13 @@ <% else %> <.link - href={~p"/users/log_in"} + navigate={~p"/users/log_in"} class="text-slate-300 rounded-md px-3 py-2 text-sm font-medium hover:bg-slate-900 hover:text-white" > <%= gettext("Sign In") %> <.link - href={~p"/users/register"} + navigate={~p"/users/register"} class="text-slate-300 rounded-md px-3 py-2 text-sm font-medium hover:bg-slate-900 hover:text-white" > <%= gettext("Register") %> diff --git a/lib/polar_web/live/dashboard/data_loader.ex b/lib/polar_web/live/dashboard/data_loader.ex new file mode 100644 index 0000000..399398b --- /dev/null +++ b/lib/polar_web/live/dashboard/data_loader.ex @@ -0,0 +1,16 @@ +defmodule PolarWeb.Dashboard.DataLoader do + alias Polar.Repo + alias Polar.Accounts.Space + + import Ecto.Query, only: [from: 2] + + def load_spaces(user) do + from(s in Space, + where: s.owner_id == ^user.id, + limit: 5, + order_by: [desc: :updated_at] + ) + |> Repo.all() + |> Repo.preload([:owner]) + end +end diff --git a/lib/polar_web/live/dashboard/space/new_live.ex b/lib/polar_web/live/dashboard/space/new_live.ex new file mode 100644 index 0000000..7d7ec25 --- /dev/null +++ b/lib/polar_web/live/dashboard/space/new_live.ex @@ -0,0 +1,102 @@ +defmodule PolarWeb.Dashboard.Space.NewLive do + use PolarWeb, :live_view + + alias Polar.Accounts + alias Polar.Accounts.Space + + def render(assigns) do + ~H""" +
+
+
+

+ <%= gettext("Create a space") %> +

+

+ <%= gettext( + "Spaces encapsulate all your tokens, it can represent an organization or just a workspace." + ) %> +

+
+ + <.simple_form + for={@space_form} + id="new-space-form" + phx-submit="save" + phx-change="validate" + class="bg-white shadow-sm ring-1 ring-slate-900/5 sm:rounded-xl md:col-span-2" + > +
+
+
+ <.input field={@space_form[:name]} label={gettext("Name")} required /> +
+
+
+ <:actions> +
+ <.link navigate={~p"/dashboard"} class="text-sm font-semibold leading-6 text-gray-900"> + Cancel + + <.button + type="submit" + class="rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" + > + <%= gettext("Save") %> + +
+ + +
+
+ """ + end + + def mount(_params, _session, socket) do + space_form = to_form(Accounts.change_space(%Space{})) + + socket = + socket + |> assign(:space_form, space_form) + |> assign(:page_title, gettext("New space")) + |> assign(:current_path, ~p"/dashboard") + + {:ok, socket} + end + + def handle_event("validate", %{"space" => space_params} = params, %{assigns: assigns} = socket) do + space_form = + %Space{owner_id: assigns.current_user.id} + |> Accounts.change_space(space_params) + |> Map.put(:action, :validate) + |> to_form() + + socket = + socket + |> assign(:space_form, space_form) + + {:noreply, socket} + end + + def handle_event("save", %{"space" => space_params}, %{assigns: assigns} = socket) do + case Accounts.create_space(assigns.current_user, space_params) do + {:ok, space} -> + socket = + socket + |> put_flash(:info, gettext("Space successfully created!")) + |> push_navigate(to: ~p"/dashboard") + + {:noreply, socket} + + {:error, %Ecto.Changeset{} = changeset} -> + space_form = to_form(changeset) + + socket = + socket + |> assign(:check_errors, true) + |> assign(:space_form, space_form) + + {:noreply, socket} + end + end +end diff --git a/lib/polar_web/live/dashboard/space_live.ex b/lib/polar_web/live/dashboard/space_live.ex new file mode 100644 index 0000000..d167700 --- /dev/null +++ b/lib/polar_web/live/dashboard/space_live.ex @@ -0,0 +1,41 @@ +defmodule PolarWeb.Dashboard.SpaceLive do + use PolarWeb, :live_view + + alias Polar.Repo + alias Polar.Accounts.Space + + def render(assigns) do + ~H""" +
+
+
+
+

+ <%= gettext("Credentials") %> +

+
+
+
+
+ """ + end + + def mount(%{"id" => id}, _session, %{assigns: assigns} = socket) do + space = Repo.get_by(Space, owner_id: assigns.current_user.id, id: id) + + if space do + socket = + socket + |> assign(:page_title, space.name) + + {:ok, socket} + else + socket = + socket + |> put_flash(:error, gettext("Space not found")) + |> push_navigate(to: ~p"/dashboard") + + {:ok, socket} + end + end +end diff --git a/lib/polar_web/live/dashboard_live.ex b/lib/polar_web/live/dashboard_live.ex new file mode 100644 index 0000000..bc7ed85 --- /dev/null +++ b/lib/polar_web/live/dashboard_live.ex @@ -0,0 +1,106 @@ +defmodule PolarWeb.DashboardLive do + use PolarWeb, :live_view + + import PolarWeb.Dashboard.DataLoader + + def render(assigns) do + ~H""" +
+
+
+
+

+ <%= gettext("Your spaces") %> +

+
+
0} class="ml-4 mt-2 flex-shrink-0"> + <.link + navigate={~p"/dashboard/spaces/new"} + class="relative inline-flex items-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" + > + <.icon name="hero-plus-solid" class="-ml-0.5 mr-1.5 h-5 w-5 text-white" /> + <%= gettext("Create new space") %> + +
+
+
+
+
+ +

<%= gettext("No spaces") %>

+

+ <%= gettext("Get started by creating a new space.") %> +

+
+ <.link + navigate={~p"/dashboard/spaces/new"} + class="inline-flex items-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" + > + <.icon name="hero-plus-solid" class="-ml-0.5 mr-1.5 h-5 w-5 text-white" /> + <%= gettext("Create new space") %> + +
+
+
+
    +
  • +
    +
    +

    <%= space.name %>

    +
    +
    +

    + <%= gettext("Created on") %> + +

    + + + +

    <%= gettext("Owned by") %> <%= space.owner.email %>

    +
    +
    +
    + <.link + navigate={~p"/dashboard/spaces/#{space.id}"} + class="hidden rounded-md bg-white px-2.5 py-1.5 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50 sm:block" + > + <%= gettext("View space") %> + +
    +
  • +
+
+ """ + end + + def mount(_params, _session, %{assigns: assigns} = socket) do + spaces = load_spaces(assigns.current_user) + + socket = + socket + |> assign(:current_path, ~p"/dashboard") + |> assign(:page_title, gettext("Dashboard")) + |> assign(:spaces, spaces) + + {:ok, socket} + end +end diff --git a/lib/polar_web/live/user_settings_live.ex b/lib/polar_web/live/user_settings_live.ex index e9ddc49..ff2e23a 100644 --- a/lib/polar_web/live/user_settings_live.ex +++ b/lib/polar_web/live/user_settings_live.ex @@ -5,7 +5,7 @@ defmodule PolarWeb.UserSettingsLive do def render(assigns) do ~H""" -
+
<.header class="px-4 sm:px-0">

diff --git a/lib/polar_web/router.ex b/lib/polar_web/router.ex index c211313..6c593db 100644 --- a/lib/polar_web/router.ex +++ b/lib/polar_web/router.ex @@ -49,6 +49,11 @@ defmodule PolarWeb.Router do live_session :require_authenticated_user, on_mount: [{PolarWeb.UserAuth, :ensure_authenticated}] do + live "/dashboard", DashboardLive, :show + + live "/dashboard/spaces/new", Dashboard.Space.NewLive, :new + live "/dashboard/spaces/:id", Dashboard.SpaceLive, :show + live "/users/settings", UserSettingsLive, :edit live "/users/settings/confirm_email/:token", UserSettingsLive, :confirm_email end diff --git a/priv/repo/migrations/20240226104718_remove_cdn_host_from_spaces.exs b/priv/repo/migrations/20240226104718_remove_cdn_host_from_spaces.exs new file mode 100644 index 0000000..bbeed16 --- /dev/null +++ b/priv/repo/migrations/20240226104718_remove_cdn_host_from_spaces.exs @@ -0,0 +1,9 @@ +defmodule Polar.Repo.Migrations.RemoveCDNHostFromSpaces do + use Ecto.Migration + + def change do + alter table(:spaces) do + remove :cdn_host + end + end +end