towerops/lib/towerops_web/components/consent_prompt.ex
Graham McIntire 5a7cdc7138 refactor: apply custom color palette across entire codebase
- Replace gray->cool-steel, blue/indigo->cerulean, red->sweet-salmon, yellow/amber->wheat
- Dark sidebar: sidebar/footer use cool-steel-800 bg, text lightened for contrast
- ~11,600 color replacements across ~99 files
- Update tests for new color class names
2026-06-23 10:58:48 -05:00

123 lines
5.5 KiB
Elixir

defmodule ToweropsWeb.Components.ConsentPrompt do
@moduledoc """
LiveView component for prompting users to re-consent when policies are updated.
This component displays a modal that users cannot dismiss until they accept
the updated privacy policy and/or terms of service.
"""
use Phoenix.Component
use Gettext, backend: ToweropsWeb.Gettext
import ToweropsWeb.CoreComponents
attr :user_id, :string, required: true
attr :policies, :list, required: true
def consent_modal(assigns) do
~H"""
<%= if @policies != [] do %>
<div
id="consent-modal"
class="fixed inset-0 z-50 overflow-y-auto"
aria-labelledby="consent-modal-title"
role="dialog"
aria-modal="true"
>
<div class="flex min-h-screen items-center justify-center p-4">
<!-- Backdrop -->
<div class="fixed inset-0 bg-cool-steel-500 dark:bg-cool-steel-900 bg-opacity-75 dark:bg-opacity-80 transition-opacity">
</div>
<!-- Modal panel -->
<div class="relative transform overflow-hidden rounded-lg bg-white dark:bg-cool-steel-800 px-4 pb-4 pt-5 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg sm:p-6">
<div class="sm:flex sm:items-start">
<div class="mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-cerulean-100 dark:bg-cerulean-900 sm:mx-0 sm:h-10 sm:w-10">
<.icon
name="hero-information-circle"
class="h-6 w-6 text-cerulean-600 dark:text-cerulean-400"
/>
</div>
<div class="mt-3 text-center sm:ml-4 sm:mt-0 sm:text-left w-full">
<h3
class="text-lg font-semibold leading-6 text-cool-steel-900 dark:text-white"
id="consent-modal-title"
>
{gettext("Updated Policies - Action Required")}
</h3>
<div class="mt-4 space-y-4">
<p class="text-sm text-cool-steel-600 dark:text-cool-steel-400">
{gettext(
"We've updated our policies. Please review and accept the changes to continue using Towerops."
)}
</p>
<div class="space-y-3">
<%= for policy_type <- @policies do %>
<div class="flex items-start">
<div class="flex items-center h-5">
<input
type="checkbox"
id={"consent-#{policy_type}"}
name={"consent[#{policy_type}]"}
phx-click="toggle_consent"
phx-value-policy={policy_type}
required
class="h-4 w-4 rounded border-zinc-300 text-cerulean-600 focus:ring-cerulean-500 dark:border-zinc-600 dark:bg-zinc-800 dark:checked:bg-cerulean-500 dark:checked:border-cerulean-500"
/>
</div>
<div class="ml-3 text-sm">
<label
for={"consent-#{policy_type}"}
class="text-cool-steel-700 dark:text-cool-steel-300"
>
{gettext("I agree to the updated")}
<.link
href={policy_link(policy_type)}
target="_blank"
class="font-medium text-cerulean-600 hover:text-cerulean-700 dark:text-cerulean-400 dark:hover:text-cerulean-300"
>
{policy_name(policy_type)}
</.link>
<span class="text-sweet-salmon-600 dark:text-sweet-salmon-400">*</span>
</label>
</div>
</div>
<% end %>
</div>
<div class="mt-4 pt-4 border-t border-cool-steel-200 dark:border-cool-steel-700">
<p class="text-xs text-cool-steel-500 dark:text-cool-steel-400">
{gettext(
"By accepting, you acknowledge that you have read and agree to the updated policies. You can review your consent history at any time from your account settings."
)}
</p>
</div>
</div>
</div>
</div>
<div class="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse">
<button
type="button"
phx-click="accept_updated_policies"
phx-value-user-id={@user_id}
class="inline-flex w-full justify-center rounded-md bg-cerulean-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-cerulean-500 sm:ml-3 sm:w-auto disabled:opacity-50 disabled:cursor-not-allowed"
id="accept-policies-button"
>
{gettext("Accept and Continue")}
</button>
</div>
</div>
</div>
</div>
<% end %>
"""
end
defp policy_name("privacy_policy"), do: gettext("Privacy Policy")
defp policy_name("terms_of_service"), do: gettext("Terms of Service")
defp policy_name(_), do: gettext("Policy")
defp policy_link("privacy_policy"), do: "/privacy"
defp policy_link("terms_of_service"), do: "/terms"
defp policy_link(_), do: "/"
end