diff --git a/lib/safira/activities.ex b/lib/safira/activities.ex index 7a4a6354a..25fe00cd5 100644 --- a/lib/safira/activities.ex +++ b/lib/safira/activities.ex @@ -68,7 +68,7 @@ defmodule Safira.Activities do def list_daily_activities(day) do Activity |> where([a], a.date == ^day) - |> order_by([a], a.time_start) + |> order_by([a], asc: a.time_start) |> preload([:speakers, :category]) |> Repo.all() end diff --git a/lib/safira/activities/speaker.ex b/lib/safira/activities/speaker.ex index 67bdb8e27..a3717bb14 100644 --- a/lib/safira/activities/speaker.ex +++ b/lib/safira/activities/speaker.ex @@ -80,11 +80,8 @@ defmodule Safira.Activities.Speaker.Socials do def validate_linkedin(changeset) do changeset - |> validate_format( - :linkedin, - ~r/^[a-zA-Z0-9]{3,100}$/, - message: "not a valid linkedin handle" - ) + |> validate_length(:linkedin, min: 3, max: 100, message: "not a valid linkedin handle") + |> validate_format(:linkedin, ~r/^\S+$/, message: "cannot contain spaces") end def validate_x(changeset) do diff --git a/lib/safira/event.ex b/lib/safira/event.ex index 7f3178f49..ecff09b63 100644 --- a/lib/safira/event.ex +++ b/lib/safira/event.ex @@ -33,6 +33,14 @@ defmodule Safira.Event do defp bool_to_string(true), do: "true" defp bool_to_string(false), do: "false" + @doc """ + Changes whether the registrations for the event are open + + ## Examples + + iex> change_registrations_open(true) + :ok + """ def change_registrations_open(registrations_open) do Constants.set( "registrations_open", @@ -40,6 +48,14 @@ defmodule Safira.Event do ) end + @doc """ + Returns the event's start time. + + ## Examples + + iex> get_event_start_time() + ~U[2025-02-11T08:00:00Z] + """ def get_event_start_time! do case Constants.get("start_time") do {:ok, start_time_str} -> @@ -54,6 +70,14 @@ defmodule Safira.Event do end end + @doc """ + Changes the event's start time. + + ## Examples + + iex> change_event_start_time(~U[2025-02-11T08:00:00Z]) + :ok + """ def change_event_start_time(start_time) do result = Constants.set("start_time", DateTime.to_iso8601(start_time)) broadcast_start_time_update("start_time", start_time) @@ -76,6 +100,14 @@ defmodule Safira.Event do Phoenix.PubSub.broadcast(@pubsub, "start_time", {config, value}) end + @doc """ + Returns whether the event has started. + + ## Examples + + iex> event_started?() + false + """ def event_started? do start_time = get_event_start_time!() DateTime.compare(start_time, DateTime.utc_now()) == :lt @@ -95,6 +127,14 @@ defmodule Safira.Event do ] end + @doc """ + Returns the active feature flags. + + ## Examples + + iex> get_active_feature_flags() + ["login_enabled", "schedule_enabled"] + """ def get_active_feature_flags! do feature_flag_keys() |> Constants.get_many!() @@ -102,16 +142,57 @@ defmodule Safira.Event do |> Enum.map(fn {k, _v} -> k end) end + @doc """ + Returns the feature flag. + + Raises `Ecto.NoResultsError` if the flag does not exist. + + ## Examples + + iex> get_feature_flag!("login_enabled") + true + """ def get_feature_flag!(flag) do with {:ok, value} <- Constants.get(flag), do: value == "true" end + @doc """ + Returns the feature flag. + + ## Examples + + iex> get_feature_flag("login_enabled") + true + """ + def get_feature_flag(flag) do + case Constants.get(flag) do + {:ok, value} -> value == "true" + _ -> false + end + end + + @doc """ + Returns the feature flags. + + ## Examples + + iex> get_feature_flags() + %{"login_enabled" => true, "schedule_enabled" => false} + """ def get_feature_flags do feature_flag_keys() |> Enum.map(fn k -> with {:ok, v} <- Constants.get(k), do: {k, v} end) |> Enum.into(%{}) end + @doc """ + Changes the feature flags. + + ## Examples + + iex> change_feature_flags([{"login_enabled", true}, {"schedule_enabled", false}]) + :ok + """ def change_feature_flags(flags) do flags |> Enum.each(fn {k, v} -> Constants.set(k, bool_to_string(v)) end) diff --git a/lib/safira_web/components/layouts/landing.html.heex b/lib/safira_web/components/layouts/landing.html.heex index a66518966..87892643b 100644 --- a/lib/safira_web/components/layouts/landing.html.heex +++ b/lib/safira_web/components/layouts/landing.html.heex @@ -9,5 +9,14 @@ <.flash_group flash={@flash} /> <%= @inner_content %> - <.footer /> + <.footer> + <:tip :if={ + Map.get(assigns, :current_page, nil) in [:home, :schedule, :speakers, :faqs] and + Safira.Event.get_feature_flag("challenges_enabled") + }> + Have you checked out the + <.link class="underline" navigate={~p"/challenges"}>challenges + yet? 🏆 + + diff --git a/lib/safira_web/controllers/error_html/404.html.heex b/lib/safira_web/controllers/error_html/404.html.heex index 066e52519..7adb511c0 100644 --- a/lib/safira_web/controllers/error_html/404.html.heex +++ b/lib/safira_web/controllers/error_html/404.html.heex @@ -1,11 +1,11 @@ - +
<.sparkles /> <.navbar pages={SafiraWeb.Config.landing_pages()} registrations_open?={Safira.Event.registrations_open?()} />
- + <.sparkles />
404
@@ -15,5 +15,9 @@
- <.footer /> - + <.footer> + <:tip> + Okay, let's get you back on track. <.link class="underline" navigate={~p"/"}>Go home? + + +
diff --git a/lib/safira_web/controllers/error_html/500.html.heex b/lib/safira_web/controllers/error_html/500.html.heex index 3cf14d766..950da0b8d 100644 --- a/lib/safira_web/controllers/error_html/500.html.heex +++ b/lib/safira_web/controllers/error_html/500.html.heex @@ -1,11 +1,11 @@ - +
<.sparkles /> <.navbar pages={SafiraWeb.Config.landing_pages()} registrations_open?={Safira.Event.registrations_open?()} />
- + <.sparkles />
500
@@ -15,5 +15,16 @@
- <.footer /> - + <.footer> + <:tip> + <.link + class="underline" + target="_blank" + href="https://github.com/cesium/safira/graphs/contributors" + > + Their + + fault. + + +
diff --git a/lib/safira_web/live/landing/challenges_live/index.ex b/lib/safira_web/live/landing/challenges_live/index.ex index 77c4823ec..f54cc6d1d 100644 --- a/lib/safira_web/live/landing/challenges_live/index.ex +++ b/lib/safira_web/live/landing/challenges_live/index.ex @@ -11,7 +11,7 @@ defmodule SafiraWeb.Landing.ChallengesLive.Index do @impl true def mount(_params, _session, socket) do - {:ok, socket} + {:ok, assign(socket, :current_page, :challenges)} end @impl true diff --git a/lib/safira_web/live/landing/components/footer.ex b/lib/safira_web/live/landing/components/footer.ex index 79c413843..29af4a17b 100644 --- a/lib/safira_web/live/landing/components/footer.ex +++ b/lib/safira_web/live/landing/components/footer.ex @@ -7,17 +7,18 @@ defmodule SafiraWeb.Landing.Components.Footer do alias Safira.Event + slot :tip, required: false + def footer(assigns) do ~H""" """ end diff --git a/lib/safira_web/live/landing/components/schedule.ex b/lib/safira_web/live/landing/components/schedule.ex index 870356095..87c8cc862 100644 --- a/lib/safira_web/live/landing/components/schedule.ex +++ b/lib/safira_web/live/landing/components/schedule.ex @@ -43,7 +43,6 @@ defmodule SafiraWeb.Landing.Components.Schedule do <.schedule_table date={fetch_current_date_from_params(assigns.params) || assigns.event_start_date} filters={fetch_filters_from_params(assigns.params)} - descriptions_enabled={assigns.descriptions_enabled} user_role={get_user_role(assigns.current_user)} enrolments={assigns.enrolments} myself={assigns.myself} @@ -69,7 +68,7 @@ defmodule SafiraWeb.Landing.Components.Schedule do ", else: "text-md m-1 items-center rounded-full border-2 px-12 py-2 text-center font-bold text-white shadow-sm - hover:border-accent hover:text-accent px-8 + hover:bg-white/20 px-8 transition-colors " } patch={filter_url(@url, @current_day, @filters, category.id)} @@ -93,7 +92,6 @@ defmodule SafiraWeb.Landing.Components.Schedule do <% else %> <.schedule_activity activity={activity} - descriptions_enabled={@descriptions_enabled} user_role={@user_role} enrolments={@enrolments} myself={@myself} @@ -108,10 +106,7 @@ defmodule SafiraWeb.Landing.Components.Schedule do defp schedule_activity(assigns) do ~H""" -
+

@@ -127,17 +122,17 @@ defmodule SafiraWeb.Landing.Components.Schedule do

-
    +
    • {el, i} end)} - class="list-none sm:float-left" + class="list-none xl:float-left" > <%= if index == length(@activity.speakers) - 1 and length(@activity.speakers) != 1 do %> -