From 8da2961b1b9319d06abff63d58f7b6e2f536e03a Mon Sep 17 00:00:00 2001 From: emielvdveen Date: Wed, 29 Nov 2023 15:38:16 +0100 Subject: [PATCH 1/5] Added title, subtitle, logo, cover to assignment settings CMS --- core/assets/js/app.js | 4 +- core/assets/js/elements.js | 27 +++ core/assets/js/image_catalog_picker.js | 57 +++++ .../assets/static/images/logo_placeholder.svg | 12 + core/frameworks/pixel/components/form.ex | 3 +- core/frameworks/pixel/components/grid.ex | 2 +- core/frameworks/pixel/components/image.ex | 13 +- core/lib/core_web/ui/dialog/dialog.ex | 13 + core/lib/core_web/ui/image_catalog_picker.ex | 224 ++++++++++-------- .../gettext/en/LC_MESSAGES/eyra-assignment.po | 36 +++ core/priv/gettext/en/LC_MESSAGES/eyra-ui.po | 4 + core/priv/gettext/eyra-assignment.pot | 36 +++ core/priv/gettext/eyra-ui.pot | 4 + .../gettext/nl/LC_MESSAGES/eyra-assignment.po | 36 +++ core/priv/gettext/nl/LC_MESSAGES/eyra-ui.po | 4 + ...20231127111416_add_assignment_branding.exs | 21 ++ core/systems/assignment/assignment_form.ex | 14 +- .../assignment/content_page_builder.ex | 7 +- core/systems/assignment/info_form.ex | 208 ++++++++-------- core/systems/assignment/info_model.ex | 17 +- core/systems/assignment/settings_view.ex | 34 ++- core/systems/project/form.ex | 13 +- .../core_web/image_catalog_picker_test.exs | 28 ++- 23 files changed, 564 insertions(+), 253 deletions(-) create mode 100644 core/assets/js/elements.js create mode 100644 core/assets/js/image_catalog_picker.js create mode 100644 core/assets/static/images/logo_placeholder.svg create mode 100644 core/priv/repo/migrations/20231127111416_add_assignment_branding.exs diff --git a/core/assets/js/app.js b/core/assets/js/app.js index b690b919b..67213d5d3 100644 --- a/core/assets/js/app.js +++ b/core/assets/js/app.js @@ -32,6 +32,7 @@ import { Tabbar, TabbarItem, TabbarFooterItem } from "./tabbar"; import { Clipboard } from "./clipboard"; import { FeldsparApp } from "./feldspar_app"; import { Wysiwyg } from "./wysiwyg"; +import { ImageCatalogPicker } from "./image_catalog_picker"; window.registerAPNSDeviceToken = registerAPNSDeviceToken; @@ -104,7 +105,8 @@ let Hooks = { TabbarFooterItem, NativeWrapper, FeldsparApp, - Wysiwyg + Wysiwyg, + ImageCatalogPicker, }; let liveSocket = new LiveSocket("/live", Socket, { diff --git a/core/assets/js/elements.js b/core/assets/js/elements.js new file mode 100644 index 000000000..87b4d64ee --- /dev/null +++ b/core/assets/js/elements.js @@ -0,0 +1,27 @@ +export function activateElement(element, activate) { + console.log("Activate element"); + if (!element) { + return console.warn("Unknown element"); + } + + var idle_classes = customClasses(element, "idle"); + var active_classes = customClasses(element, "active"); + + if (activate) { + updateClassList(element, idle_classes, "remove"); + updateClassList(element, active_classes, "add"); + } else { + updateClassList(element, active_classes, "remove"); + updateClassList(element, idle_classes, "add"); + } +} + +export function customClasses(element, name) { + return element.getAttribute(name + "-class").split(" "); +} + +export function updateClassList(element, classes, type) { + classes.forEach((clazz) => { + element.classList[type](clazz); + }); +} diff --git a/core/assets/js/image_catalog_picker.js b/core/assets/js/image_catalog_picker.js new file mode 100644 index 000000000..7085fb043 --- /dev/null +++ b/core/assets/js/image_catalog_picker.js @@ -0,0 +1,57 @@ +import { activateElement } from "./elements"; + +export const ImageCatalogPicker = { + mounted() { + console.log("[ImageCatalogPicker] Mounted"); + this.images = this.el.dataset.images; + this.imageContainer = this.el.querySelector(".image-container"); + this.pages = Array.from(this.el.querySelectorAll('[id^="page-"]')); + this.active_page = "1"; + this.refresh(); + }, + updated() { + console.log("[ImageCatalogPicker] Updated"); + this.images = this.el.dataset.images; + this.imageContainer = this.el.querySelector(".image-container"); + this.pages = Array.from(this.el.querySelectorAll('[id^="page-"]')); + this.refresh(); + }, + refresh() { + console.log("[ImageCatalogPicker] Refresh", this.imageContainer); + this.renderImages(); + this.renderPages(); + this.startListen(); + }, + renderImages() { + console.log("[ImageCatalogPicker] Render Images [", this.images, "]"); + if (this.images != undefined) { + for (var i = 0; i < this.images.length; i++) { + this.renderImage(i, i, "url", "srcset", "target"); + } + } else { + console.log("[ImageCatalogPicker] No Images"); + } + }, + renderImage(id, index, url, srcset, target) { + console.log("renderImage", id); + const div = document.createElement("div"); + this.el.appendChild(div); + }, + startListen() { + console.log(this.pages); + this.pages.forEach((page) => { + page.addEventListener("click", (_event) => { + if (this.active_page != page.dataset.page) { + this.active_page = page.dataset.page; + this.refresh(); + } + }); + }); + }, + renderPages() { + this.pages.forEach((page) => { + console.log("PAGE", page.dataset.page); + activateElement(page, page.dataset.page == this.active_page); + }); + }, +}; diff --git a/core/assets/static/images/logo_placeholder.svg b/core/assets/static/images/logo_placeholder.svg new file mode 100644 index 000000000..c9b74b8f2 --- /dev/null +++ b/core/assets/static/images/logo_placeholder.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/core/frameworks/pixel/components/form.ex b/core/frameworks/pixel/components/form.ex index 9c11fd777..90cc61a8c 100644 --- a/core/frameworks/pixel/components/form.ex +++ b/core/frameworks/pixel/components/form.ex @@ -461,6 +461,7 @@ defmodule Frameworks.Pixel.Form do attr(:uploads, :any, required: true) attr(:primary_button_text, :string, required: true) attr(:secondary_button_text, :string, required: true) + attr(:placeholder, :string, default: "profile_photo_default") def photo_input(assigns) do ~H""" @@ -470,7 +471,7 @@ defmodule Frameworks.Pixel.Form do
<.image_preview image_url={@photo_url} - placeholder={@static_path.("/images/profile_photo_default.svg")} + placeholder={"/images/#{@placeholder}.svg"} shape="w-image-preview-circle sm:w-image-preview-circle-sm h-image-preview-circle sm:h-image-preview-circle-sm rounded-full" /> <.spacing value="S" direction="l" /> diff --git a/core/frameworks/pixel/components/grid.ex b/core/frameworks/pixel/components/grid.ex index 404ce6ff8..0b5314784 100644 --- a/core/frameworks/pixel/components/grid.ex +++ b/core/frameworks/pixel/components/grid.ex @@ -27,7 +27,7 @@ defmodule Frameworks.Pixel.Grid do def image(assigns) do ~H""" -
+
<%= render_slot(@inner_block) %>
""" diff --git a/core/frameworks/pixel/components/image.ex b/core/frameworks/pixel/components/image.ex index 23e959a11..de58f54e8 100644 --- a/core/frameworks/pixel/components/image.ex +++ b/core/frameworks/pixel/components/image.ex @@ -62,6 +62,7 @@ defmodule Frameworks.Pixel.Image do attr(:srcset, :string, required: true) attr(:index, :string, required: true) attr(:target, :string, default: "") + attr(:selected, :boolean, default: false) @doc """ An image that can be used in an image grid. @@ -70,25 +71,21 @@ defmodule Frameworks.Pixel.Image do ~H"""
- +
""" diff --git a/core/lib/core_web/ui/dialog/dialog.ex b/core/lib/core_web/ui/dialog/dialog.ex index 24d4991a7..162339545 100644 --- a/core/lib/core_web/ui/dialog/dialog.ex +++ b/core/lib/core_web/ui/dialog/dialog.ex @@ -32,4 +32,17 @@ defmodule CoreWeb.UI.Dialog do
""" end + + def form_dialog_buttons(target) do + [ + %{ + action: %{type: :send, target: target, event: "submit"}, + face: %{type: :primary, label: dgettext("eyra-ui", "submit.button")} + }, + %{ + action: %{type: :send, target: target, event: "cancel"}, + face: %{type: :label, label: dgettext("eyra-ui", "cancel.button")} + } + ] + end end diff --git a/core/lib/core_web/ui/image_catalog_picker.ex b/core/lib/core_web/ui/image_catalog_picker.ex index 2173d7688..d50a51611 100644 --- a/core/lib/core_web/ui/image_catalog_picker.ex +++ b/core/lib/core_web/ui/image_catalog_picker.ex @@ -1,6 +1,8 @@ defmodule CoreWeb.UI.ImageCatalogPicker do - use CoreWeb, :live_component + use CoreWeb, :live_component_fabric + use Fabric.LiveComponent + import CoreWeb.UI.Dialog alias Frameworks.Pixel.Text alias Frameworks.Pixel.Button alias Frameworks.Pixel.Grid @@ -58,28 +60,54 @@ defmodule CoreWeb.UI.ImageCatalogPicker do %{ id: id, static_path: static_path, - image_catalog: image_catalog + image_catalog: image_catalog, + initial_query: initial_query } = props, socket ) do { :ok, socket - |> assign(id: id) - |> assign(static_path: static_path) - |> assign(image_catalog: image_catalog) + |> assign( + id: id, + static_path: static_path, + image_catalog: image_catalog, + initial_query: initial_query, + selected_page: 1, + selected_image: nil + ) |> update_defaults(props, @defaults) - |> update_close_button() + |> update_title() + |> update_buttons() + |> initial_search() } end - defp update_close_button(%{assigns: %{myself: myself}} = socket) do - close_button = %{ - action: %{type: :send, event: "close", target: myself}, - face: %{type: :icon, icon: :close} - } + defp initial_search(%{assigns: %{initial_query: nil}} = socket) do + socket + end + + defp initial_search(%{assigns: %{initial_query: ""}} = socket) do + socket + end + + defp initial_search( + %{assigns: %{initial_query: initial_query, image_catalog: image_catalog}} = socket + ) do + {:noreply, socket} = + socket + |> assign(selected_page: 1) + |> search(initial_query, image_catalog, 1) - socket |> assign(close_button: close_button) + socket + end + + defp update_title(socket) do + socket |> assign(:title, dgettext("eyra-imagecatalog", "search.image.title")) + end + + defp update_buttons(%{assigns: %{myself: myself}} = socket) do + assign(socket, buttons: form_dialog_buttons(myself)) end @impl true @@ -88,7 +116,9 @@ defmodule CoreWeb.UI.ImageCatalogPicker do %{"q" => query}, %{assigns: %{image_catalog: image_catalog}} = socket ) do - search(socket, query, image_catalog, 1) + socket + |> assign(selected_page: 1) + |> search(query, image_catalog, 1) end @impl true @@ -97,19 +127,29 @@ defmodule CoreWeb.UI.ImageCatalogPicker do %{"page" => page}, %{assigns: %{query: query, image_catalog: image_catalog}} = socket ) do - search(socket, query, image_catalog, String.to_integer(page)) + socket + |> assign(selected_page: String.to_integer(page)) + |> search(query, image_catalog, String.to_integer(page)) end @impl true - def handle_event("select_image", %{"image" => image_id}, %{assigns: %{id: id}} = socket) do - send(self(), {id, image_id}) + def handle_event("submit", _payload, %{assigns: %{selected_image: nil}} = socket) do {:noreply, socket} end @impl true - def handle_event("close", _, %{assigns: %{id: id}} = socket) do - send(self(), {id, :close}) - {:noreply, socket} + def handle_event("submit", _payload, %{assigns: %{selected_image: selected_image}} = socket) do + {:noreply, socket |> send_event(:parent, "finish", %{image_id: selected_image})} + end + + @impl true + def handle_event("cancel", _payload, socket) do + {:noreply, socket |> send_event(:parent, "finish")} + end + + @impl true + def handle_event("select_image", %{"image" => image_id}, socket) do + {:noreply, socket |> assign(selected_image: image_id)} end defp search( @@ -134,97 +174,79 @@ defmodule CoreWeb.UI.ImageCatalogPicker do @impl true def render(assigns) do ~H""" -
-
-
-
- <%= dgettext("eyra-imagecatalog", "search.image.title") %> +
+ <.dialog {%{title: @title, buttons: @buttons}}> + <.form id="image_catalog_picker_form" :let={_form} for={%{}} phx-submit="search" phx-target={@myself} > +
+ + <.spacing value="XS" direction="l" /> +
-
- -
-
- <.form id="image_catalog_picker_form" :let={_form} for={%{}} phx-submit="search" phx-target={@myself} > -
- - <.spacing value="XS" direction="l" /> - -
- - - <%= if @search_results do %> - <%= if Enum.empty?(@search_results) do %> - <%= if @query != "" do %> -
- <.spacing value="S" /> - <%= dgettext("eyra-imagecatalog", "no.results.found.message") %> -
- <% end %> - <% else %> + + + <%= if @search_results do %> + <%= if Enum.empty?(@search_results) do %> + <%= if @query != "" do %>
<.spacing value="S" /> - {dngettext( - "eyra-imagecatalog", - "images.found.message", - "images.found.message.%{count}", - @meta.image_count - )} - <.spacing value="S" /> - - <%= for {image, index} <- Enum.with_index(@search_results) do %> -
- -
- <% end %> -
- <.spacing value="S" /> -
-
- {dngettext( - "eyra-imagecatalog", - "page.info.message", - "page.info.message.%{count}", - @meta.image_count, - begin: @meta.begin, - end: @meta.end - )} + <%= dgettext("eyra-imagecatalog", "no.results.found.message") %> +
+ <% end %> + <% else %> +
+ <.spacing value="S" /> + <%= dngettext( + "eyra-imagecatalog", + "images.found.message", + "images.found.message.%{count}", + @meta.image_count + ) %> + <.spacing value="S" /> + + <%= for {image, index} <- Enum.with_index(@search_results) do %> +
+
-
-
- <%= for page <- 1..Enum.min([page_count(@viewport, @breakpoint), @meta.page_count]) do %> -
-
-
- {page} -
-
+ <% end %> + + <.spacing value="S" /> +
+
+ <%= dngettext( + "eyra-imagecatalog", + "page.info.message", + "page.info.message.%{count}", + @meta.image_count, + begin: @meta.begin, + end: @meta.end + ) %> +
+
+
+ <%= for page <- 1..Enum.min([page_count(@viewport, @breakpoint), @meta.page_count]) do %> +
+
+
<%= page %>
- <% end %> -
+
+ <% end %>
- <% end %> +
<% end %> -
-
+ <% end %> +
""" end diff --git a/core/priv/gettext/en/LC_MESSAGES/eyra-assignment.po b/core/priv/gettext/en/LC_MESSAGES/eyra-assignment.po index ffe214ff5..d2e04fbb9 100644 --- a/core/priv/gettext/en/LC_MESSAGES/eyra-assignment.po +++ b/core/priv/gettext/en/LC_MESSAGES/eyra-assignment.po @@ -181,3 +181,39 @@ msgstr "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod #, elixir-autogen, elixir-format, fuzzy msgid "settings.consent.title" msgstr "Consent" + +#, elixir-autogen, elixir-format +msgid "settings.subtitle.label" +msgstr "Subtitle" + +#, elixir-autogen, elixir-format +msgid "settings.title.label" +msgstr "Title" + +#, elixir-autogen, elixir-format +msgid "settings.image.title" +msgstr "Cover" + +#, elixir-autogen, elixir-format +msgid "search.different.image.button" +msgstr "Change image" + +#, elixir-autogen, elixir-format +msgid "choose.logo.file" +msgstr "Select image" + +#, elixir-autogen, elixir-format +msgid "choose.other.logo.file" +msgstr "Change image" + +#, elixir-autogen, elixir-format +msgid "settings.logo.title" +msgstr "Logo" + +#, elixir-autogen, elixir-format, fuzzy +msgid "settings.branding.text" +msgstr "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat." + +#, elixir-autogen, elixir-format, fuzzy +msgid "settings.branding.title" +msgstr "Branding" diff --git a/core/priv/gettext/en/LC_MESSAGES/eyra-ui.po b/core/priv/gettext/en/LC_MESSAGES/eyra-ui.po index 67f0d60b4..c360011d9 100644 --- a/core/priv/gettext/en/LC_MESSAGES/eyra-ui.po +++ b/core/priv/gettext/en/LC_MESSAGES/eyra-ui.po @@ -257,3 +257,7 @@ msgstr "Copy" #, elixir-autogen, elixir-format, fuzzy msgid "submit.button" msgstr "Save" + +#, elixir-autogen, elixir-format, fuzzy +msgid "save.button" +msgstr "Save" diff --git a/core/priv/gettext/eyra-assignment.pot b/core/priv/gettext/eyra-assignment.pot index 66a4d7e74..cb976c122 100644 --- a/core/priv/gettext/eyra-assignment.pot +++ b/core/priv/gettext/eyra-assignment.pot @@ -181,3 +181,39 @@ msgstr "" #, elixir-autogen, elixir-format msgid "settings.consent.title" msgstr "" + +#, elixir-autogen, elixir-format +msgid "settings.subtitle.label" +msgstr "" + +#, elixir-autogen, elixir-format +msgid "settings.title.label" +msgstr "" + +#, elixir-autogen, elixir-format +msgid "settings.image.title" +msgstr "" + +#, elixir-autogen, elixir-format +msgid "search.different.image.button" +msgstr "" + +#, elixir-autogen, elixir-format +msgid "choose.logo.file" +msgstr "" + +#, elixir-autogen, elixir-format +msgid "choose.other.logo.file" +msgstr "" + +#, elixir-autogen, elixir-format +msgid "settings.logo.title" +msgstr "" + +#, elixir-autogen, elixir-format +msgid "settings.branding.text" +msgstr "" + +#, elixir-autogen, elixir-format +msgid "settings.branding.title" +msgstr "" diff --git a/core/priv/gettext/eyra-ui.pot b/core/priv/gettext/eyra-ui.pot index 1223c014d..35fd6dbf6 100644 --- a/core/priv/gettext/eyra-ui.pot +++ b/core/priv/gettext/eyra-ui.pot @@ -257,3 +257,7 @@ msgstr "" #, elixir-autogen, elixir-format msgid "submit.button" msgstr "" + +#, elixir-autogen, elixir-format +msgid "save.button" +msgstr "" diff --git a/core/priv/gettext/nl/LC_MESSAGES/eyra-assignment.po b/core/priv/gettext/nl/LC_MESSAGES/eyra-assignment.po index 06cd04327..8b53521e9 100644 --- a/core/priv/gettext/nl/LC_MESSAGES/eyra-assignment.po +++ b/core/priv/gettext/nl/LC_MESSAGES/eyra-assignment.po @@ -181,3 +181,39 @@ msgstr "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod #, elixir-autogen, elixir-format, fuzzy msgid "settings.consent.title" msgstr "Toestemming" + +#, elixir-autogen, elixir-format +msgid "settings.subtitle.label" +msgstr "Ondertitel" + +#, elixir-autogen, elixir-format +msgid "settings.title.label" +msgstr "Titel" + +#, elixir-autogen, elixir-format +msgid "settings.image.title" +msgstr "Omslagafbeelding" + +#, elixir-autogen, elixir-format +msgid "search.different.image.button" +msgstr "Verander afbeelding" + +#, elixir-autogen, elixir-format +msgid "choose.logo.file" +msgstr "Kies afbeelding" + +#, elixir-autogen, elixir-format +msgid "choose.other.logo.file" +msgstr "Kies andere afbeelding" + +#, elixir-autogen, elixir-format +msgid "settings.logo.title" +msgstr "Logo" + +#, elixir-autogen, elixir-format, fuzzy +msgid "settings.branding.text" +msgstr "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat." + +#, elixir-autogen, elixir-format, fuzzy +msgid "settings.branding.title" +msgstr "Branding" diff --git a/core/priv/gettext/nl/LC_MESSAGES/eyra-ui.po b/core/priv/gettext/nl/LC_MESSAGES/eyra-ui.po index 2928996d8..b0c7950f2 100644 --- a/core/priv/gettext/nl/LC_MESSAGES/eyra-ui.po +++ b/core/priv/gettext/nl/LC_MESSAGES/eyra-ui.po @@ -257,3 +257,7 @@ msgstr "Kopieer" #, elixir-autogen, elixir-format, fuzzy msgid "submit.button" msgstr "Opslaan" + +#, elixir-autogen, elixir-format, fuzzy +msgid "save.button" +msgstr "Opslaan" diff --git a/core/priv/repo/migrations/20231127111416_add_assignment_branding.exs b/core/priv/repo/migrations/20231127111416_add_assignment_branding.exs new file mode 100644 index 000000000..ee8d5c3c2 --- /dev/null +++ b/core/priv/repo/migrations/20231127111416_add_assignment_branding.exs @@ -0,0 +1,21 @@ +defmodule Core.Repo.Migrations.AddAssignmentBranding do + use Ecto.Migration + + def up do + alter table(:assignment_info) do + add(:title, :string) + add(:subtitle, :string) + add(:image_id, :text) + add(:logo_url, :string) + end + end + + def down do + alter table(:assignment_info) do + remove(:title) + remove(:subtitle) + remove(:image_id) + remove(:logo_url) + end + end +end diff --git a/core/systems/assignment/assignment_form.ex b/core/systems/assignment/assignment_form.ex index a613ee097..7adbabf57 100644 --- a/core/systems/assignment/assignment_form.ex +++ b/core/systems/assignment/assignment_form.ex @@ -46,13 +46,13 @@ defmodule Systems.Assignment.AssignmentForm do callback_url = uri_origin <> callback_path [ - %{ - live_component: Assignment.InfoForm, - props: %{ - id: :info_form, - entity: info - } - }, + # %{ + # live_component: Assignment.InfoForm, + # props: %{ + # id: :info_form, + # entity: info + # } + # }, %{ live_component: tool_form, props: %{ diff --git a/core/systems/assignment/content_page_builder.ex b/core/systems/assignment/content_page_builder.ex index 3ded782c1..ed6fe8151 100644 --- a/core/systems/assignment/content_page_builder.ex +++ b/core/systems/assignment/content_page_builder.ex @@ -166,14 +166,17 @@ defmodule Systems.Assignment.ContentPageBuilder do :config, assignment, show_errors, - %{fabric: fabric, uri_origin: uri_origin} = _assigns + %{fabric: fabric, uri_origin: uri_origin, viewport: viewport, breakpoint: breakpoint} = + _assigns ) do ready? = false child = Fabric.prepare_child(fabric, :settings_form, Assignment.SettingsView, %{ entity: assignment, - uri_origin: uri_origin + uri_origin: uri_origin, + viewport: viewport, + breakpoint: breakpoint }) %{ diff --git a/core/systems/assignment/info_form.ex b/core/systems/assignment/info_form.ex index e3a6e726d..58accfec1 100644 --- a/core/systems/assignment/info_form.ex +++ b/core/systems/assignment/info_form.ex @@ -1,83 +1,116 @@ defmodule Systems.Assignment.InfoForm do - use CoreWeb.LiveForm - use Frameworks.Pixel.Form.CheckboxHelpers + use CoreWeb.LiveForm, :fabric + use Fabric.LiveComponent + use CoreWeb.FileUploader, ~w(.png .jpg .jpeg .svg) - alias Core.Enums.Devices - - # import Frameworks.Pixel.Form - # alias Frameworks.Pixel.Selector + import Core.ImageCatalog, only: [image_catalog: 0] + import Frameworks.Pixel.Form alias Frameworks.Pixel.Text + alias Core.ImageHelpers + alias Frameworks.Pixel.Image + alias CoreWeb.UI.ImageCatalogPicker - alias Systems.{ - Assignment - } + alias Systems.Assignment - # Handle selector update + @impl true + def process_file( + %{assigns: %{entity: entity}} = socket, + {local_relative_path, _local_full_path, _remote_file} + ) do + save(socket, entity, :auto_save, %{logo_url: local_relative_path}) + end @impl true def update( - %{active_item_id: active_item_id, selector_id: :language}, - %{assigns: %{entity: entity}} = socket + %{id: id, entity: entity, viewport: viewport, breakpoint: breakpoint}, + socket ) do - language = - case active_item_id do - nil -> nil - item when is_atom(item) -> Atom.to_string(item) - _ -> active_item_id - end + changeset = Assignment.InfoModel.changeset(entity, :create, %{}) { :ok, socket - |> save(entity, :auto_save, %{language: language}) + |> assign( + id: id, + entity: entity, + changeset: changeset, + viewport: viewport, + breakpoint: breakpoint + ) + |> update_image_info() + |> update_image_picker_button() + |> init_file_uploader(:photo) } end @impl true - def update( - %{active_item_ids: active_item_ids, selector_id: selector_id}, - %{assigns: %{entity: entity}} = socket - ) do + def compose(:image_picker, %{ + entity: %{title: title}, + viewport: viewport, + breakpoint: breakpoint + }) do + %{ + module: ImageCatalogPicker, + params: %{ + viewport: viewport, + breakpoint: breakpoint, + static_path: &CoreWeb.Endpoint.static_path/1, + initial_query: title, + image_catalog: image_catalog() + } + } + end + + defp update_image_info(%{assigns: %{entity: %{image_id: image_id}}} = socket) do + image_info = ImageHelpers.get_image_info(image_id, 400, 300) + socket |> assign(image_info: image_info) + end + + defp update_image_picker_button(%{assigns: %{myself: myself}} = socket) do + image_picker_button = %{ + action: %{type: :send, event: "open_image_picker", target: myself}, + face: %{ + type: :secondary, + text_color: "text-primary", + label: dgettext("eyra-assignment", "search.different.image.button") + } + } + + socket |> assign(image_picker_button: image_picker_button) + end + + # Handle Events + + @impl true + def handle_event("open_image_picker", _, socket) do { - :ok, + :noreply, socket - |> save(entity, :auto_save, %{selector_id => active_item_ids}) + |> compose_child(:image_picker) + |> show_popup(:image_picker) } end - # Handle initial update @impl true - def update( - %{id: id, entity: entity}, - socket + def handle_event( + "finish", + %{image_id: _image_id} = attrs, + %{assigns: %{entity: entity}} = socket ) do - changeset = Assignment.InfoModel.changeset(entity, :create, %{}) - { - :ok, + :noreply, socket - |> assign( - id: id, - entity: entity, - changeset: changeset - ) - |> update_device_labels() - |> update_language_labels() - |> validate_for_publish() + |> save(entity, :auto_save, attrs) + |> update_image_info() + |> hide_popup(:image_picker) } end - defp update_device_labels(%{assigns: %{entity: %{devices: devices}}} = socket) do - device_labels = Devices.labels(devices) - socket |> assign(device_labels: device_labels) - end - - defp update_language_labels(%{assigns: %{entity: %{language: language}}} = socket) do - language_labels = Assignment.OnlineStudyLanguages.labels(language) - socket |> assign(language_labels: language_labels) + @impl true + def handle_event("finish", _, socket) do + {:noreply, socket |> hide_popup(:image_picker)} end - # Handle Events @impl true def handle_event("save", %{"info_model" => attrs}, %{assigns: %{entity: entity}} = socket) do { @@ -94,70 +127,37 @@ defmodule Systems.Assignment.InfoForm do socket |> save(changeset) - |> update_device_labels() - |> update_language_labels() - |> validate_for_publish() - end - - # Validate - - def validate_for_publish(%{assigns: %{id: id, entity: entity}} = socket) do - changeset = - Assignment.InfoModel.operational_changeset(entity, %{}) - |> Map.put(:action, :validate_for_publish) - - send(self(), %{id: id, ready?: changeset.valid?}) - - socket - |> assign(changeset: changeset) end @impl true def render(assigns) do ~H"""
- - - <%= dgettext("eyra-assignment", "form.title") %> - - <%!-- <.form id={@id} :let={form} for={@changeset} phx-change="save" phx-target={@myself} > - <.number_input - form={form} - field={:duration} - label_text={dgettext("eyra-assignment", "duration.label")} - /> - <.spacing value="M" /> - - <.number_input - form={form} - field={:subject_count} - label_text={dgettext("eyra-assignment", "config.nrofsubjects.label")} - /> + <.form id={@id} :let={form} for={@changeset} phx-change="save" phx-target={@myself} > + <%= dgettext("eyra-assignment", "settings.branding.title") %> + <%= dgettext("eyra-assignment", "settings.branding.text") %> <.spacing value="M" /> - - <%= dgettext("eyra-assignment", "language.title") %> - <%= dgettext("eyra-assignment", "languages.label") %> + <.text_input form={form} field={:title} label_text={dgettext("eyra-assignment", "settings.title.label")} /> + <.text_input form={form} field={:subtitle} label_text={dgettext("eyra-assignment", "settings.subtitle.label")} /> <.spacing value="S" /> - <.live_component - module={Selector} - id={:language} - items={@language_labels} - type={:radio} - parent={%{type: __MODULE__, id: @id}} + <%= dgettext("eyra-assignment", "settings.logo.title") %> + <.spacing value="XS" /> + <.photo_input + static_path={&CoreWeb.Endpoint.static_path/1} + photo_url={@entity.logo_url} + uploads={@uploads} + primary_button_text={dgettext("eyra-assignment", "choose.logo.file")} + secondary_button_text={dgettext("eyra-assignment", "choose.other.logo.file")} + placeholder="logo_placeholder" /> - <.spacing value="XL" /> - - <%= dgettext("eyra-assignment", "devices.title") %> - <%= dgettext("eyra-assignment", "devices.label") %> - <.spacing value="S" /> - <.live_component - module={Selector} - id={:devices} - type={:label} - items={@device_labels} - parent={%{type: __MODULE__, id: @id}} /> - --%> - + <.spacing value="L" /> + <%= dgettext("eyra-assignment", "settings.image.title") %> + <.spacing value="XS" /> +
+ + +
+
""" end diff --git a/core/systems/assignment/info_model.ex b/core/systems/assignment/info_model.ex index f7329db04..61d7b61ed 100644 --- a/core/systems/assignment/info_model.ex +++ b/core/systems/assignment/info_model.ex @@ -11,6 +11,11 @@ defmodule Systems.Assignment.InfoModel do } schema "assignment_info" do + field(:title, :string) + field(:subtitle, :string) + field(:image_id, :string) + field(:logo_url, :string) + field(:subject_count, :integer) field(:duration, :string) field(:language, :string) @@ -23,8 +28,8 @@ defmodule Systems.Assignment.InfoModel do timestamps() end - @operational_fields ~w(subject_count duration ethical_code ethical_approval devices)a - @fields @operational_fields ++ ~w(language)a + @operational_fields ~w(title subtitle subject_count duration ethical_code ethical_approval devices)a + @fields @operational_fields ++ ~w(image_id logo_url language)a @required_fields ~w()a @@ -43,14 +48,14 @@ defmodule Systems.Assignment.InfoModel do end end - def changeset(tool, :auto_save, params) do - tool + def changeset(info, :auto_save, params) do + info |> cast(params, @fields) |> validate_required(@required_fields) end - def changeset(tool, _, params) do - tool + def changeset(info, _, params) do + info |> cast(params, @fields) end diff --git a/core/systems/assignment/settings_view.ex b/core/systems/assignment/settings_view.ex index 9a6cf0b78..1cc27325b 100644 --- a/core/systems/assignment/settings_view.ex +++ b/core/systems/assignment/settings_view.ex @@ -7,21 +7,45 @@ defmodule Systems.Assignment.SettingsView do } @impl true - def update(%{id: id, entity: assignment, uri_origin: uri_origin}, socket) do + def update( + %{ + id: id, + entity: assignment, + uri_origin: uri_origin, + viewport: viewport, + breakpoint: breakpoint + }, + socket + ) do { :ok, socket |> assign( id: id, entity: assignment, - uri_origin: uri_origin + uri_origin: uri_origin, + viewport: viewport, + breakpoint: breakpoint ) + |> compose_child(:info) |> compose_child(:consent) |> compose_child(:panel_connector) |> compose_child(:storage_connector) } end + @impl true + def compose(:info, %{entity: %{info: info}, viewport: viewport, breakpoint: breakpoint}) do + %{ + module: Assignment.InfoForm, + params: %{ + entity: info, + viewport: viewport, + breakpoint: breakpoint + } + } + end + @impl true def compose(:consent, %{entity: assignment}) do %{ @@ -72,6 +96,12 @@ defmodule Systems.Assignment.SettingsView do <%= dgettext("eyra-assignment", "settings.title") %> <.spacing value="L" /> + <.child id={:info} fabric={@fabric} > + <:footer> + <.spacing value="L" /> + + + <.child id={:consent} fabric={@fabric} > <:header> <%= dgettext("eyra-assignment", "settings.consent.title") %> diff --git a/core/systems/project/form.ex b/core/systems/project/form.ex index 7f4036b42..fa3cacd15 100644 --- a/core/systems/project/form.ex +++ b/core/systems/project/form.ex @@ -40,18 +40,7 @@ defmodule Systems.Project.Form do end defp update_buttons(%{assigns: %{myself: myself}} = socket) do - buttons = [ - %{ - action: %{type: :send, target: myself, event: "submit"}, - face: %{type: :primary, label: dgettext("eyra-ui", "submit.button")} - }, - %{ - action: %{type: :send, target: myself, event: "cancel"}, - face: %{type: :label, label: dgettext("eyra-ui", "cancel.button")} - } - ] - - assign(socket, buttons: buttons) + assign(socket, buttons: form_dialog_buttons(myself)) end # Handle Events diff --git a/core/test/core_web/image_catalog_picker_test.exs b/core/test/core_web/image_catalog_picker_test.exs index 7d015d3c8..4466be815 100644 --- a/core/test/core_web/image_catalog_picker_test.exs +++ b/core/test/core_web/image_catalog_picker_test.exs @@ -1,22 +1,34 @@ defmodule CoreWeb.UI.ImageCatalogPicker.Test.View do - use Phoenix.LiveView + use Fabric.LiveView, CoreWeb.Layouts alias CoreWeb.UI.ImageCatalogPicker @impl true def mount(_params, _session, socket) do - {:ok, socket} + { + :ok, + socket |> compose_child(:image_picker) + } + end + + @impl true + def compose(:image_picker, _) do + %{ + module: ImageCatalogPicker, + params: %{ + viewport: nil, + breakpoint: nil, + static_path: &CoreWeb.Endpoint.static_path/1, + image_catalog: Core.ImageCatalog.Local, + initial_query: "" + } + } end @impl true def render(assigns) do ~H"""
- <.live_component - module={ImageCatalogPicker} - id="picker" - image_catalog={Core.ImageCatalog.Local} - static_path={&CoreWeb.Endpoint.static_path/1} - /> + <.child id={:image_picker} fabric={@fabric} />
""" end From dbcf8868a29668603d129cb696f6a46015784b1a Mon Sep 17 00:00:00 2001 From: emielvdveen Date: Wed, 29 Nov 2023 19:17:36 +0100 Subject: [PATCH 2/5] Added branding to crew page --- core/frameworks/pixel/components/hero.ex | 42 +++++++++++++----- .../controllers/layouts/stripped/component.ex | 2 + core/systems/assignment/_public.ex | 9 ++++ core/systems/assignment/_switch.ex | 4 +- core/systems/assignment/crew_page.ex | 44 ++++++++++++++++++- core/systems/assignment/crew_page_builder.ex | 3 +- core/systems/assignment/crew_work_view.ex | 2 +- core/systems/assignment/start_view.ex | 2 +- 8 files changed, 90 insertions(+), 18 deletions(-) diff --git a/core/frameworks/pixel/components/hero.ex b/core/frameworks/pixel/components/hero.ex index 6203ac30d..d15e76f5a 100644 --- a/core/frameworks/pixel/components/hero.ex +++ b/core/frameworks/pixel/components/hero.ex @@ -7,6 +7,8 @@ defmodule Frameworks.Pixel.Hero do alias Frameworks.Pixel.Icon alias Frameworks.Pixel.Image + import Frameworks.Pixel.ImagePreview + attr(:title, :string, required: true) attr(:illustration, :string, default: "/images/illustration.svg") attr(:text_color, :string, default: "text-white") @@ -65,24 +67,42 @@ defmodule Frameworks.Pixel.Hero do attr(:title, :string, required: true) attr(:subtitle, :string, required: true) attr(:image_info, :any, required: true) + attr(:logo_url, :string, default: nil) attr(:text_color, :string, default: "text-white") slot(:call_to_action) def image(assigns) do ~H""" -
-
+
+
<%= if @image_info do %> - + <% end %> -
-
- <%= @title %> - <.spacing value="S" /> - <%= @subtitle %> - <.spacing value="S" /> -
- <%= render_slot(@call_to_action) %> +
+
+
+
+
+ <%= if @logo_url do %> +
+ <.image_preview + image_url={@logo_url} + placeholder={"/images/logo_placeholder.svg"} + shape="w-[96px] h-[96px] rounded-full" + /> +
+ <% end %> +
+
+ <%= @title %> + <%= @subtitle %> +
+
+
+
+ <%= render_slot(@call_to_action) %> +
+
diff --git a/core/lib/core_web/controllers/layouts/stripped/component.ex b/core/lib/core_web/controllers/layouts/stripped/component.ex index 559a1b797..d1c65fd94 100644 --- a/core/lib/core_web/controllers/layouts/stripped/component.ex +++ b/core/lib/core_web/controllers/layouts/stripped/component.ex @@ -49,6 +49,7 @@ defmodule CoreWeb.Layouts.Stripped.Component do attr(:menus, :map, required: true) attr(:footer?, :boolean, default: true) + slot(:header) slot(:inner_block, required: true) def stripped(assigns) do @@ -66,6 +67,7 @@ defmodule CoreWeb.Layouts.Stripped.Component do
+ <%= render_slot(@header) %> <%= if @title do %>
diff --git a/core/systems/assignment/_public.ex b/core/systems/assignment/_public.ex index 1bbde7c3f..5c7d8115a 100644 --- a/core/systems/assignment/_public.ex +++ b/core/systems/assignment/_public.ex @@ -627,3 +627,12 @@ defimpl Core.Persister, for: Systems.Assignment.Model do end end end + +defimpl Core.Persister, for: Systems.Assignment.InfoModel do + def save(_info, changeset) do + case Frameworks.Utility.EctoHelper.update_and_dispatch(changeset, :assignment_info) do + {:ok, %{assignment_info: assignment_info}} -> {:ok, assignment_info} + _ -> {:error, changeset} + end + end +end diff --git a/core/systems/assignment/_switch.ex b/core/systems/assignment/_switch.ex index b5881f421..32466a81b 100644 --- a/core/systems/assignment/_switch.ex +++ b/core/systems/assignment/_switch.ex @@ -26,9 +26,9 @@ defmodule Systems.Assignment.Switch do end @impl true - def intercept({:assignment_info, _} = signal, %{info: info} = message) do + def intercept({:assignment_info, _} = signal, %{assignment_info: info} = message) do if assignment = Assignment.Public.get_by(info, Assignment.Model.preload_graph(:down)) do - handle( + dispatch!( {:assignment, signal}, Map.merge(message, %{assignment: assignment}) ) diff --git a/core/systems/assignment/crew_page.ex b/core/systems/assignment/crew_page.ex index 365ce2156..7de924490 100644 --- a/core/systems/assignment/crew_page.ex +++ b/core/systems/assignment/crew_page.ex @@ -4,11 +4,14 @@ defmodule Systems.Assignment.CrewPage do use Systems.Observatory.Public use CoreWeb.LiveRemoteIp + use CoreWeb.UI.Responsive.Viewport use CoreWeb.Layouts.Stripped.Component, :projects require Logger alias CoreWeb.UI.Timestamp + alias Core.ImageHelpers + alias Frameworks.Pixel.Hero alias Systems.{ Assignment, @@ -30,7 +33,8 @@ defmodule Systems.Assignment.CrewPage do socket |> assign( id: id, - model: model + model: model, + image_info: nil ) |> update_panel_info(session) |> observe_view_model() @@ -41,9 +45,34 @@ defmodule Systems.Assignment.CrewPage do def handle_view_model_updated(socket) do socket |> update_flow() + |> update_image_info() |> update_menus() end + @impl true + def handle_resize(socket) do + socket + |> update_image_info() + |> update_menus() + end + + defp update_image_info(%{assigns: %{vm: %{info: %{image_id: nil}}}} = socket) do + socket + |> assign(image_info: nil) + end + + defp update_image_info( + %{assigns: %{viewport: %{"width" => viewport_width}, vm: %{info: %{image_id: image_id}}}} = + socket + ) do + image_width = viewport_width + image_height = 360 + image_info = ImageHelpers.get_image_info(image_id, image_width, image_height) + + socket + |> assign(image_info: image_info) + end + defp update_panel_info(socket, %{"panel_info" => panel_info}) do assign(socket, panel_info: panel_info) end @@ -100,7 +129,18 @@ defmodule Systems.Assignment.CrewPage do def render(assigns) do ~H""" <.stripped menus={@menus} footer?={false}> - <.flow fabric={@fabric} /> + <:header> +
+ <%= if @image_info do %> + + <% end %> +
+ +
+
+ <.flow fabric={@fabric} /> +
+
""" end diff --git a/core/systems/assignment/crew_page_builder.ex b/core/systems/assignment/crew_page_builder.ex index 1206d2daf..d681b6370 100644 --- a/core/systems/assignment/crew_page_builder.ex +++ b/core/systems/assignment/crew_page_builder.ex @@ -8,7 +8,8 @@ defmodule Systems.Assignment.CrewPageBuilder do def view_model(assignment, assigns) do %{ - flow: flow(assignment, assigns) + flow: flow(assignment, assigns), + info: assignment.info } end diff --git a/core/systems/assignment/crew_work_view.ex b/core/systems/assignment/crew_work_view.ex index a78921fab..62f7590dc 100644 --- a/core/systems/assignment/crew_work_view.ex +++ b/core/systems/assignment/crew_work_view.ex @@ -200,7 +200,7 @@ defmodule Systems.Assignment.CrewWorkView do
<% end %> -
+
<.child id={:start_view} fabric={@fabric} />
<% end %> diff --git a/core/systems/assignment/start_view.ex b/core/systems/assignment/start_view.ex index 65dd6ae82..56036cbb1 100644 --- a/core/systems/assignment/start_view.ex +++ b/core/systems/assignment/start_view.ex @@ -70,7 +70,7 @@ defmodule Systems.Assignment.StartView do @impl true def render(assigns) do ~H""" -
+
From 3d1098a1e591368789970de7aaa5be56aba738f8 Mon Sep 17 00:00:00 2001 From: emielvdveen Date: Wed, 29 Nov 2023 21:49:32 +0100 Subject: [PATCH 3/5] Improved user experience with image picker (restoring state) --- core/assets/js/app.js | 2 - core/assets/js/image_catalog_picker.js | 57 ------------------ core/lib/core_web/ui/image_catalog_picker.ex | 59 +++++++++++++++---- core/systems/assignment/crew_page.ex | 5 -- core/systems/assignment/info_form.ex | 20 +++++-- .../core_web/image_catalog_picker_test.exs | 3 +- 6 files changed, 66 insertions(+), 80 deletions(-) delete mode 100644 core/assets/js/image_catalog_picker.js diff --git a/core/assets/js/app.js b/core/assets/js/app.js index 67213d5d3..d42ff303e 100644 --- a/core/assets/js/app.js +++ b/core/assets/js/app.js @@ -32,7 +32,6 @@ import { Tabbar, TabbarItem, TabbarFooterItem } from "./tabbar"; import { Clipboard } from "./clipboard"; import { FeldsparApp } from "./feldspar_app"; import { Wysiwyg } from "./wysiwyg"; -import { ImageCatalogPicker } from "./image_catalog_picker"; window.registerAPNSDeviceToken = registerAPNSDeviceToken; @@ -106,7 +105,6 @@ let Hooks = { NativeWrapper, FeldsparApp, Wysiwyg, - ImageCatalogPicker, }; let liveSocket = new LiveSocket("/live", Socket, { diff --git a/core/assets/js/image_catalog_picker.js b/core/assets/js/image_catalog_picker.js deleted file mode 100644 index 7085fb043..000000000 --- a/core/assets/js/image_catalog_picker.js +++ /dev/null @@ -1,57 +0,0 @@ -import { activateElement } from "./elements"; - -export const ImageCatalogPicker = { - mounted() { - console.log("[ImageCatalogPicker] Mounted"); - this.images = this.el.dataset.images; - this.imageContainer = this.el.querySelector(".image-container"); - this.pages = Array.from(this.el.querySelectorAll('[id^="page-"]')); - this.active_page = "1"; - this.refresh(); - }, - updated() { - console.log("[ImageCatalogPicker] Updated"); - this.images = this.el.dataset.images; - this.imageContainer = this.el.querySelector(".image-container"); - this.pages = Array.from(this.el.querySelectorAll('[id^="page-"]')); - this.refresh(); - }, - refresh() { - console.log("[ImageCatalogPicker] Refresh", this.imageContainer); - this.renderImages(); - this.renderPages(); - this.startListen(); - }, - renderImages() { - console.log("[ImageCatalogPicker] Render Images [", this.images, "]"); - if (this.images != undefined) { - for (var i = 0; i < this.images.length; i++) { - this.renderImage(i, i, "url", "srcset", "target"); - } - } else { - console.log("[ImageCatalogPicker] No Images"); - } - }, - renderImage(id, index, url, srcset, target) { - console.log("renderImage", id); - const div = document.createElement("div"); - this.el.appendChild(div); - }, - startListen() { - console.log(this.pages); - this.pages.forEach((page) => { - page.addEventListener("click", (_event) => { - if (this.active_page != page.dataset.page) { - this.active_page = page.dataset.page; - this.refresh(); - } - }); - }); - }, - renderPages() { - this.pages.forEach((page) => { - console.log("PAGE", page.dataset.page); - activateElement(page, page.dataset.page == this.active_page); - }); - }, -}; diff --git a/core/lib/core_web/ui/image_catalog_picker.ex b/core/lib/core_web/ui/image_catalog_picker.ex index d50a51611..8080cf9a3 100644 --- a/core/lib/core_web/ui/image_catalog_picker.ex +++ b/core/lib/core_web/ui/image_catalog_picker.ex @@ -61,28 +61,49 @@ defmodule CoreWeb.UI.ImageCatalogPicker do id: id, static_path: static_path, image_catalog: image_catalog, - initial_query: initial_query + state: state } = props, socket ) do { :ok, socket + |> update_defaults(props, @defaults) + |> update_state(state) |> assign( id: id, static_path: static_path, - image_catalog: image_catalog, - initial_query: initial_query, - selected_page: 1, - selected_image: nil + image_catalog: image_catalog ) - |> update_defaults(props, @defaults) |> update_title() |> update_buttons() |> initial_search() } end + def update_state(%{} = socket, nil) do + socket + |> assign( + query: nil, + selected_page: 1, + selected_image: nil + ) + end + + def update_state(%{} = socket, %{ + query: query, + selected_page: selected_page, + selected_image: selected_image + }) do + socket + |> assign( + initial_query: query, + query: query, + selected_page: selected_page, + selected_image: selected_image + ) + end + defp initial_search(%{assigns: %{initial_query: nil}} = socket) do socket end @@ -92,12 +113,18 @@ defmodule CoreWeb.UI.ImageCatalogPicker do end defp initial_search( - %{assigns: %{initial_query: initial_query, image_catalog: image_catalog}} = socket + %{ + assigns: %{ + initial_query: initial_query, + image_catalog: image_catalog, + selected_page: selected_page + } + } = socket ) do {:noreply, socket} = socket - |> assign(selected_page: 1) - |> search(initial_query, image_catalog, 1) + |> assign(selected_page: selected_page) + |> search(initial_query, image_catalog, selected_page) socket end @@ -138,8 +165,18 @@ defmodule CoreWeb.UI.ImageCatalogPicker do end @impl true - def handle_event("submit", _payload, %{assigns: %{selected_image: selected_image}} = socket) do - {:noreply, socket |> send_event(:parent, "finish", %{image_id: selected_image})} + def handle_event( + "submit", + _payload, + %{assigns: %{query: query, selected_page: selected_page, selected_image: selected_image}} = + socket + ) do + {:noreply, + socket + |> send_event(:parent, "finish", %{ + image_id: selected_image, + state: %{query: query, selected_page: selected_page, selected_image: selected_image} + })} end @impl true diff --git a/core/systems/assignment/crew_page.ex b/core/systems/assignment/crew_page.ex index 7de924490..898cca247 100644 --- a/core/systems/assignment/crew_page.ex +++ b/core/systems/assignment/crew_page.ex @@ -56,11 +56,6 @@ defmodule Systems.Assignment.CrewPage do |> update_menus() end - defp update_image_info(%{assigns: %{vm: %{info: %{image_id: nil}}}} = socket) do - socket - |> assign(image_info: nil) - end - defp update_image_info( %{assigns: %{viewport: %{"width" => viewport_width}, vm: %{info: %{image_id: image_id}}}} = socket diff --git a/core/systems/assignment/info_form.ex b/core/systems/assignment/info_form.ex index 58accfec1..e207685bf 100644 --- a/core/systems/assignment/info_form.ex +++ b/core/systems/assignment/info_form.ex @@ -37,6 +37,7 @@ defmodule Systems.Assignment.InfoForm do viewport: viewport, breakpoint: breakpoint ) + |> update_image_picker_state() |> update_image_info() |> update_image_picker_button() |> init_file_uploader(:photo) @@ -47,7 +48,8 @@ defmodule Systems.Assignment.InfoForm do def compose(:image_picker, %{ entity: %{title: title}, viewport: viewport, - breakpoint: breakpoint + breakpoint: breakpoint, + image_picker_state: state }) do %{ module: ImageCatalogPicker, @@ -56,11 +58,20 @@ defmodule Systems.Assignment.InfoForm do breakpoint: breakpoint, static_path: &CoreWeb.Endpoint.static_path/1, initial_query: title, - image_catalog: image_catalog() + image_catalog: image_catalog(), + state: state } } end + defp update_image_picker_state(%{assigns: %{image_picker_state: %{}}} = socket) do + socket + end + + defp update_image_picker_state(socket) do + socket |> assign(image_picker_state: nil) + end + defp update_image_info(%{assigns: %{entity: %{image_id: image_id}}} = socket) do image_info = ImageHelpers.get_image_info(image_id, 400, 300) socket |> assign(image_info: image_info) @@ -94,13 +105,14 @@ defmodule Systems.Assignment.InfoForm do @impl true def handle_event( "finish", - %{image_id: _image_id} = attrs, + %{image_id: image_id, state: state}, %{assigns: %{entity: entity}} = socket ) do { :noreply, socket - |> save(entity, :auto_save, attrs) + |> assign(image_picker_state: state) + |> save(entity, :auto_save, %{image_id: image_id}) |> update_image_info() |> hide_popup(:image_picker) } diff --git a/core/test/core_web/image_catalog_picker_test.exs b/core/test/core_web/image_catalog_picker_test.exs index 4466be815..8ad722acb 100644 --- a/core/test/core_web/image_catalog_picker_test.exs +++ b/core/test/core_web/image_catalog_picker_test.exs @@ -19,7 +19,8 @@ defmodule CoreWeb.UI.ImageCatalogPicker.Test.View do breakpoint: nil, static_path: &CoreWeb.Endpoint.static_path/1, image_catalog: Core.ImageCatalog.Local, - initial_query: "" + initial_query: "", + state: nil } } end From 8bc361d36087c7adbf0488067fc37f4b97927ed8 Mon Sep 17 00:00:00 2001 From: emielvdveen Date: Wed, 29 Nov 2023 22:41:31 +0100 Subject: [PATCH 4/5] Fixed image selection border from ring to outline (ring does not work on prod) --- core/frameworks/pixel/components/image.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/frameworks/pixel/components/image.ex b/core/frameworks/pixel/components/image.ex index de58f54e8..248d4c6d6 100644 --- a/core/frameworks/pixel/components/image.ex +++ b/core/frameworks/pixel/components/image.ex @@ -71,7 +71,7 @@ defmodule Frameworks.Pixel.Image do ~H"""
Date: Thu, 30 Nov 2023 11:41:00 +0100 Subject: [PATCH 5/5] Applied branding on assignment card --- core/systems/project/card_view.ex | 31 +++++++++++++++++++++++++----- core/systems/project/item_model.ex | 12 ++++++++++-- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/core/systems/project/card_view.ex b/core/systems/project/card_view.ex index 498a9df2b..4bd1c1596 100644 --- a/core/systems/project/card_view.ex +++ b/core/systems/project/card_view.ex @@ -4,6 +4,7 @@ defmodule Systems.Project.CardView do import Frameworks.Pixel.Tag import Frameworks.Pixel.ClickableCard alias Frameworks.Pixel.Card + alias Frameworks.Pixel.Image attr(:card, :map, required: true) @@ -57,6 +58,8 @@ defmodule Systems.Project.CardView do attr(:title, :string, required: true) attr(:label, :map, required: true) attr(:tags, :list, default: []) + attr(:image_info, :map, default: nil) + attr(:icon_url, :string, default: nil) attr(:bg_color, :string, default: "grey1") attr(:text_color, :string, default: "text-white") @@ -77,12 +80,30 @@ defmodule Systems.Project.CardView do right_actions={@right_actions} > <:top> - <%= if @label do %> -
- <.spacing value="S" /> - +
+ <%= if @label do %> +
+ +
+ <% end %> + + <%= if @icon_url do %> +
+ +
+ <% end %> + + <%= if @image_info do %> +
+ +
+ <% end %>
- <% end %> <:title> diff --git a/core/systems/project/item_model.ex b/core/systems/project/item_model.ex index f3013eff9..4f784d745 100644 --- a/core/systems/project/item_model.ex +++ b/core/systems/project/item_model.ex @@ -5,6 +5,8 @@ defmodule Systems.Project.ItemModel do import Ecto.Changeset import CoreWeb.Gettext + alias Core.ImageHelpers + alias Systems.{ Project, Assignment, @@ -87,14 +89,18 @@ defmodule Systems.Project.ItemModel do assignment: %{ id: assignment_id, + status: status, info: %{ - subject_count: subject_count + subject_count: subject_count, + image_id: image_id, + logo_url: logo_url } } = assignment }, {Project.NodePage, :item_card}, _user ) do + image_info = ImageHelpers.get_image_info(image_id, 120, 115) tags = get_card_tags(assignment) path = ~p"/assignment/#{assignment_id}/content" @@ -112,7 +118,9 @@ defmodule Systems.Project.ItemModel do type: :secondary, id: id, path: path, - label: get_label(:concept), + image_info: image_info, + icon_url: logo_url, + label: get_label(status), title: name, tags: tags, info: ["#{subject_count} participants | 0 donations"],