Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: block routes based on event start time #431

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
2 changes: 1 addition & 1 deletion .env.dev.sample
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ DB_HOST=localhost
DB_PORT=5432
DB_NAME=safira_dev
HOST_URL=http://localhost:4000
ASSET_HOST=http://localhost:4000
ASSET_HOST=http://localhost:4000
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,5 @@ safira-*.tar
npm-debug.log
/assets/node_modules/

.env.dev
.env.*
.env
3 changes: 2 additions & 1 deletion assets/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ import {Socket} from "phoenix"
import {LiveSocket} from "phoenix_live_view"
import topbar from "../vendor/topbar"
import live_select from "live_select"
import { QrScanner, Wheel, Confetti, Sorting } from "./hooks";
import { QrScanner, Wheel, Confetti, Countdown, Sorting } from "./hooks";

let Hooks = {
QrScanner: QrScanner,
Wheel: Wheel,
Confetti: Confetti,
Countdown: Countdown,
Sorting: Sorting,
...live_select
};
Expand Down
50 changes: 50 additions & 0 deletions assets/js/hooks/countdown.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
export const Countdown = {
mounted() {
let countdownInterval = null;

const startCountdown = (startTime) => {
if (countdownInterval) {
clearInterval(countdownInterval);
}

const textElement = document.getElementById("seconds-remaining");
if (!textElement) {
console.warn("Countdown element not found!");
return;
}

countdownInterval = setInterval(() => {
const now = Date.now();
const secondsLeft = Math.round((startTime - now) / 1000);

if (secondsLeft >= 0) {
textElement.textContent = formatTime(secondsLeft);
} else {
clearInterval(countdownInterval);
textElement.textContent = "00";
window.location.reload();
}
}, 100);
};

window.addEventListener("phx:highlight", (e) => {
const startTime = new Date(e.detail.start_time).getTime();
startCountdown(startTime);
});
}
};

function formatTime(totalSeconds) {
const dayToSeconds = 86400;
const days = Math.floor(totalSeconds / dayToSeconds);
const hours = Math.floor((totalSeconds % dayToSeconds) / 3600);
const minutes = Math.floor((totalSeconds % 3600) / 60);
const seconds = totalSeconds % 60;

const formattedTime = [
days > 0 ? `${days} days` : null,
`${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`
].filter(Boolean).join(", ");

return formattedTime;
}
3 changes: 2 additions & 1 deletion assets/js/hooks/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { QrScanner } from "./qr_reading.js";
export { Wheel } from "./wheel.js";
export { Confetti } from "./confetti.js";
export { Sorting } from "./sorting.js";
export { Sorting } from "./sorting.js";
export { Countdown } from "./countdown.js";
1 change: 1 addition & 0 deletions lib/safira/accounts/roles/permissions.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ defmodule Safira.Accounts.Roles.Permissions do
"purchases" => ["show", "redeem", "refund"],
"badges" => ["show", "edit", "delete", "give", "revoke", "give_without_restrictions"],
"minigames" => ["show", "edit", "simulate"],
"event" => ["show", "edit"],
"spotlights" => ["edit"],
"schedule" => ["edit"],
"statistics" => ["show"],
Expand Down
69 changes: 69 additions & 0 deletions lib/safira/event.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,75 @@ defmodule Safira.Event do
"""
alias Safira.Constants

@pubsub Safira.PubSub

@doc """
Returns whether the registrations for the event are open

## Examples

iex> registrations_open?()
false
"""
def registrations_open? do
case Constants.get("registrations_open") do
{:ok, registrations_open} ->
case String.downcase(registrations_open) do
"true" -> true
_ -> false
end

_ ->
false
end
end

def change_registrations_open(registrations_open) do
Constants.set(
"registrations_open",
if registrations_open do
"true"
else
"false"
end
)
end

def get_event_start_time! do
with {:ok, start_time_str} <- Constants.get("start_time") do
with {:ok, start_time, _} <- DateTime.from_iso8601(start_time_str) do
start_time
end
end
end

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)
result
end

@doc """
Subscribes the caller to the start time's updates.

## Examples

iex> subscribe_to_start_time_update("start_time")
:ok
"""
def subscribe_to_start_time_update(config) do
Phoenix.PubSub.subscribe(@pubsub, config)
end

defp broadcast_start_time_update(config, value) do
Phoenix.PubSub.broadcast(@pubsub, "start_time", {config, value})
end

def event_started? do
start_time = get_event_start_time!()
DateTime.compare(start_time, DateTime.utc_now()) == :lt
end

@doc """
Returns the event's start date.
If the date is not set, it will be set to today's date by default.
Expand Down
4 changes: 2 additions & 2 deletions lib/safira_web.ex
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ defmodule SafiraWeb do
layouts: [html: SafiraWeb.Layouts]

import Plug.Conn
import SafiraWeb.Gettext
use Gettext, backend: SafiraWeb.Gettext

unquote(verified_routes())
end
Expand Down Expand Up @@ -117,7 +117,7 @@ defmodule SafiraWeb do
# Core UI components and translation
import SafiraWeb.CoreComponents
import SafiraWeb.Components.Page
import SafiraWeb.Gettext
use Gettext, backend: SafiraWeb.Gettext

import SafiraWeb.Helpers

Expand Down
2 changes: 1 addition & 1 deletion lib/safira_web/components/core_components.ex
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ defmodule SafiraWeb.CoreComponents do
alias Phoenix.HTML.Form
alias Phoenix.LiveView.JS

import SafiraWeb.Gettext
use Gettext, backend: SafiraWeb.Gettext

@doc """
Renders a modal.
Expand Down
34 changes: 18 additions & 16 deletions lib/safira_web/components/layouts/app.html.heex
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
<div class="relative h-screen flex overflow-hidden">
<.sidebar
current_user={@current_user}
pages={SafiraWeb.Config.app_pages()}
current_page={Map.get(assigns, :current_page, nil)}
background="bg-primaryDark"
border="border-darkShade"
logo_padding="px-16 pt-8 pb-4"
logo_images={%{light: "/images/sei.svg", dark: "/images/sei.svg"}}
logo_url={~p"/app/"}
user_dropdown_name_color="text-light"
user_dropdown_handle_color="text-lightMuted"
user_dropdown_icon_color="text-lightShade"
link_class="px-3 group flex items-center py-2 text-sm font-medium rounded-md transition-colors"
link_active_class="bg-light text-primaryDark"
link_inactive_class="hover:bg-primary-500/10 text-light"
/>
<%= if Map.get(assigns, :event_started, true) do %>
<.sidebar
current_user={@current_user}
pages={SafiraWeb.Config.app_pages()}
current_page={Map.get(assigns, :current_page, nil)}
background="bg-primaryDark"
border="border-darkShade"
logo_padding="px-16 pt-8 pb-4"
logo_images={%{light: "/images/sei.svg", dark: "/images/sei.svg"}}
logo_url={~p"/app/"}
user_dropdown_name_color="text-light"
user_dropdown_handle_color="text-lightMuted"
user_dropdown_icon_color="text-lightShade"
link_class="px-3 group flex items-center py-2 text-sm font-medium rounded-md transition-colors"
link_active_class="bg-light text-primaryDark"
link_inactive_class="hover:bg-primary-500/10 text-light"
/>
<% end %>
<div class="flex flex-col flex-1 overflow-hidden">
<div class="bg-primaryDark flex justify-end lg:hidden px-4 sm:px-6 py-2">
<button
Expand Down
2 changes: 1 addition & 1 deletion lib/safira_web/components/table.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ defmodule SafiraWeb.Components.Table do
use Phoenix.Component

alias Plug.Conn.Query
import SafiraWeb.Gettext
use Gettext, backend: SafiraWeb.Gettext
import SafiraWeb.CoreComponents

attr :id, :string, required: true
Expand Down
2 changes: 1 addition & 1 deletion lib/safira_web/components/table_search.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule SafiraWeb.Components.TableSearch do
Reusable table search component.
"""
use Phoenix.Component
import SafiraWeb.Gettext
use Gettext, backend: SafiraWeb.Gettext

attr :id, :string, required: true
attr :params, :map, required: true
Expand Down
89 changes: 51 additions & 38 deletions lib/safira_web/config.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,45 +3,51 @@ defmodule SafiraWeb.Config do
Web configuration for the app.
"""

alias Safira.Event

def app_pages do
[
%{
key: :badgedex,
title: "Badgedex",
icon: "hero-check-badge",
url: "/app/badgedex"
},
%{
key: :wheel,
title: "Wheel",
icon: "hero-circle-stack",
url: "/app/wheel"
},
%{
key: :leaderboard,
title: "Leaderboard",
icon: "hero-trophy",
url: "/app/leaderboard"
},
%{
key: :store,
title: "Store",
icon: "hero-shopping-bag",
url: "/app/store"
},
%{
key: :vault,
title: "Vault",
icon: "hero-archive-box",
url: "/app/vault"
},
%{
key: :credential,
title: "Credential",
icon: "hero-ticket",
url: "/app/credential"
}
]
if Event.event_started?() do
[
%{
key: :badgedex,
title: "Badgedex",
icon: "hero-check-badge",
url: "/app/badgedex"
},
%{
key: :wheel,
title: "Wheel",
icon: "hero-circle-stack",
url: "/app/wheel"
},
%{
key: :leaderboard,
title: "Leaderboard",
icon: "hero-trophy",
url: "/app/leaderboard"
},
%{
key: :store,
title: "Store",
icon: "hero-shopping-bag",
url: "/app/store"
},
%{
key: :vault,
title: "Vault",
icon: "hero-archive-box",
url: "/app/vault"
},
%{
key: :credential,
title: "Credential",
icon: "hero-ticket",
url: "/app/credential"
}
]
else
[]
end
end

def backoffice_pages(user) do
Expand Down Expand Up @@ -131,6 +137,13 @@ defmodule SafiraWeb.Config do
icon: "hero-qr-code",
url: "/dashboard/scanner",
scope: %{"scanner" => ["show"]}
},
%{
key: :event,
title: "Event",
icon: "hero-cog-8-tooth",
url: "/dashboard/event",
scope: %{"event" => ["edit"]}
}
]
|> Enum.filter(fn page -> has_permission?(permissions, page.scope) end)
Expand Down
9 changes: 1 addition & 8 deletions lib/safira_web/controllers/error_html.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,5 @@ defmodule SafiraWeb.ErrorHTML do
# * lib/safira_web/controllers/error_html/404.html.heex
# * lib/safira_web/controllers/error_html/500.html.heex
#
# embed_templates "error_html/*"

# The default is to render a plain text page based on
# the template name. For example, "404.html" becomes
# "Not Found".
def render(template, _assigns) do
Phoenix.Controller.status_message_from_template(template)
end
embed_templates "error_html/*"
end
1 change: 1 addition & 0 deletions lib/safira_web/controllers/error_html/404.html.heex
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Not Found
1 change: 1 addition & 0 deletions lib/safira_web/controllers/error_html/500.html.heex
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Internal Server Error
4 changes: 2 additions & 2 deletions lib/safira_web/gettext.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ defmodule SafiraWeb.Gettext do
By using [Gettext](https://hexdocs.pm/gettext),
your module gains a set of macros for translations, for example:

import SafiraWeb.Gettext
use Gettext, backend: SafiraWeb.Gettext

# Simple translation
gettext("Here is the string to translate")
Expand All @@ -20,5 +20,5 @@ defmodule SafiraWeb.Gettext do

See the [Gettext Docs](https://hexdocs.pm/gettext) for detailed usage.
"""
use Gettext, otp_app: :safira
use Gettext.Backend, otp_app: :safira
end
Loading