- <.input
- field={@form[:vereinfacht_api_url]}
- type="text"
- label={gettext("API URL")}
- disabled={@vereinfacht_api_url_env_set}
- placeholder={
- if(@vereinfacht_api_url_env_set,
- do: gettext("From VEREINFACHT_API_URL"),
- else: "https://api.verein.visuel.dev/api/v1"
- )
- }
- />
-
- <.button
- :if={
- not (@vereinfacht_api_url_env_set and @vereinfacht_api_key_env_set and
- @vereinfacht_club_id_env_set)
- }
- phx-disable-with={gettext("Saving...")}
- variant="primary"
- class="mt-2"
- >
- {gettext("Save Vereinfacht Settings")}
-
-
- <.button
- :if={Mv.Config.vereinfacht_configured?()}
- type="button"
- variant="outline"
- phx-click="test_vereinfacht_connection"
- phx-disable-with={gettext("Testing...")}
- >
- {gettext("Test Integration")}
-
- <.button
- :if={Mv.Config.vereinfacht_configured?()}
- type="button"
- variant="outline"
- phx-click="sync_vereinfacht_contacts"
- phx-disable-with={gettext("Syncing...")}
- >
- {gettext("Sync all members without Vereinfacht contact")}
-
-
- <%= if @vereinfacht_test_result do %>
- <.vereinfacht_test_result result={@vereinfacht_test_result} />
- <% end %>
- <%= if @last_vereinfacht_sync_result do %>
- <.vereinfacht_sync_result result={@last_vereinfacht_sync_result} />
- <% end %>
-
-
- <%!-- OIDC Section --%>
- <.form_section title={gettext("OIDC (Single Sign-On)")}>
- <%= if @oidc_env_configured do %>
-
- {gettext("Some values are set via environment variables. Those fields are read-only.")}
-
- <% end %>
- <.form for={@form} id="oidc-form" phx-change="validate" phx-submit="save">
-
- <.input
- field={@form[:oidc_client_id]}
- type="text"
- label={gettext("Client ID")}
- disabled={@oidc_client_id_env_set}
- placeholder={
- if(@oidc_client_id_env_set, do: gettext("From OIDC_CLIENT_ID"), else: "mv")
- }
- />
- <.input
- field={@form[:oidc_base_url]}
- type="text"
- label={gettext("Base URL")}
- disabled={@oidc_base_url_env_set}
- placeholder={
- if(@oidc_base_url_env_set,
- do: gettext("From OIDC_BASE_URL"),
- else: "http://localhost:8080/auth/v1"
- )
- }
- />
- <.input
- field={@form[:oidc_redirect_uri]}
- type="text"
- label={gettext("Redirect URI")}
- disabled={@oidc_redirect_uri_env_set}
- placeholder={
- if(@oidc_redirect_uri_env_set,
- do: gettext("From OIDC_REDIRECT_URI"),
- else: "http://localhost:4000/auth/user/oidc/callback"
- )
- }
- />
-
-
- {gettext("Client Secret")}
- <%= if @oidc_client_secret_set do %>
-
- <.badge variant="neutral" size="sm">{gettext("(set)")}
-
- <% end %>
-
- <.input
- field={@form[:oidc_client_secret]}
- type="password"
- label=""
- disabled={@oidc_client_secret_env_set}
- placeholder={
- if(@oidc_client_secret_env_set,
- do: gettext("From OIDC_CLIENT_SECRET"),
- else:
- if(@oidc_client_secret_set,
- do: gettext("Leave blank to keep current"),
- else: nil
- )
- )
- }
- />
-
- <.input
- field={@form[:oidc_admin_group_name]}
- type="text"
- label={gettext("Admin group name")}
- disabled={@oidc_admin_group_name_env_set}
- placeholder={
- if(@oidc_admin_group_name_env_set,
- do: gettext("From OIDC_ADMIN_GROUP_NAME"),
- else: gettext("e.g. admin")
- )
- }
- />
- <.input
- field={@form[:oidc_groups_claim]}
- type="text"
- label={gettext("Groups claim")}
- disabled={@oidc_groups_claim_env_set}
- placeholder={
- if(@oidc_groups_claim_env_set,
- do: gettext("From OIDC_GROUPS_CLAIM"),
- else: "groups"
- )
- }
- />
-
- <.button
- :if={
- not (@oidc_client_id_env_set and @oidc_base_url_env_set and
- @oidc_redirect_uri_env_set and @oidc_client_secret_env_set and
- @oidc_admin_group_name_env_set and @oidc_groups_claim_env_set and
- @oidc_only_env_set)
- }
- phx-disable-with={gettext("Saving...")}
- variant="primary"
- class="mt-2"
- >
- {gettext("Save OIDC Settings")}
-
-
-
+
+ <%!-- SMTP / E-Mail Section --%>
+ <.form_section title={gettext("SMTP / E-Mail")}>
+ <%= if @smtp_env_configured do %>
+
+ {gettext("Some values are set via environment variables. Those fields are read-only.")}
+
+ <% end %>
+
+ <%= if @environment == :prod and not @smtp_configured do %>
+
+ <.icon name="hero-exclamation-triangle" class="size-5 shrink-0 mt-0.5" />
+
+ {gettext(
+ "SMTP is not configured. Transactional emails (join confirmation, password reset, etc.) will not be delivered reliably."
+ )}
+
+
+ <% end %>
+
+ <.form for={@form} id="smtp-form" phx-change="validate" phx-submit="save">
+
+
+ <.input
+ field={@form[:smtp_host]}
+ type="text"
+ label={gettext("Host")}
+ disabled={@smtp_host_env_set}
+ placeholder={
+ if(@smtp_host_env_set,
+ do: gettext("From SMTP_HOST"),
+ else: "smtp.example.com"
+ )
+ }
+ />
+ <.input
+ field={@form[:smtp_port]}
+ type="number"
+ label={gettext("Port")}
+ disabled={@smtp_port_env_set}
+ placeholder={if(@smtp_port_env_set, do: gettext("From SMTP_PORT"), else: "587")}
+ />
+ <.input
+ field={@form[:smtp_ssl]}
+ type="select"
+ label={gettext("TLS/SSL")}
+ disabled={@smtp_ssl_env_set}
+ options={[
+ {gettext("TLS (port 587, recommended)"), "tls"},
+ {gettext("SSL (port 465)"), "ssl"},
+ {gettext("None (port 25, insecure)"), "none"}
+ ]}
+ placeholder={if(@smtp_ssl_env_set, do: gettext("From SMTP_SSL"), else: nil)}
+ />
+
+
+
+ <.input
+ field={@form[:smtp_username]}
+ type="text"
+ label={gettext("Username")}
+ disabled={@smtp_username_env_set}
+ placeholder={
+ if(@smtp_username_env_set,
+ do: gettext("From SMTP_USERNAME"),
+ else: "user@example.com"
+ )
+ }
+ />
+ <.input
+ field={@form[:smtp_password]}
+ type="password"
+ label={gettext("Password")}
+ disabled={@smtp_password_env_set}
+ placeholder={
+ if(@smtp_password_env_set,
+ do: gettext("From SMTP_PASSWORD"),
+ else:
+ if(@smtp_password_set,
+ do: gettext("Leave blank to keep current"),
+ else: nil
+ )
+ )
+ }
+ />
+
+
+
+ <.input
+ field={@form[:smtp_from_email]}
+ type="email"
+ label={gettext("Sender email (From)")}
+ disabled={@smtp_from_email_env_set}
+ placeholder={
+ if(@smtp_from_email_env_set,
+ do: gettext("From MAIL_FROM_EMAIL"),
+ else: "noreply@example.com"
+ )
+ }
+ />
+ <.input
+ field={@form[:smtp_from_name]}
+ type="text"
+ label={gettext("Sender name (From)")}
+ disabled={@smtp_from_name_env_set}
+ placeholder={
+ if(@smtp_from_name_env_set, do: gettext("From MAIL_FROM_NAME"), else: "Mila")
+ }
+ />
+
+
+
+ {gettext(
+ "The sender email must be owned by or authorized for the SMTP user on most servers."
+ )}
+
+ <.button
+ :if={
+ not (@smtp_host_env_set and @smtp_port_env_set and @smtp_username_env_set and
+ @smtp_password_env_set and @smtp_ssl_env_set and @smtp_from_email_env_set and
+ @smtp_from_name_env_set)
+ }
+ phx-disable-with={gettext("Saving...")}
+ variant="primary"
+ class="mt-2"
+ >
+ {gettext("Save SMTP Settings")}
+
+
+
+ <%!-- Test email: use form phx-submit so the current input value is always sent (e.g. after paste without blur) --%>
+
+
{gettext("Test email")}
+ <.form
+ for={%{}}
+ id="smtp-test-email-form"
+ data-testid="smtp-test-email-form"
+ phx-submit="send_smtp_test_email"
+ class="space-y-3"
+ >
+
+
+
+ {gettext("Recipient")}
+
+
+
+ <.button
+ type="submit"
+ variant="secondary"
+ class="mb-1"
+ data-testid="smtp-send-test-email"
+ phx-disable-with={gettext("Sending...")}
+ >
+ {gettext("Send test email")}
+
+
+
+ <%= if @smtp_test_result do %>
+
+ <.smtp_test_result result={@smtp_test_result} />
+
+ <% end %>
+
+
+
+ <%!-- Vereinfacht Integration Section --%>
+ <.form_section title={gettext("Accounting-Software (Vereinfacht) Integration")}>
+ <%= if @vereinfacht_env_configured do %>
+
+ {gettext("Some values are set via environment variables. Those fields are read-only.")}
+
+ <% end %>
+ <.form for={@form} id="vereinfacht-form" phx-change="validate" phx-submit="save">
+
+ <.input
+ field={@form[:vereinfacht_api_url]}
+ type="text"
+ label={gettext("API URL")}
+ disabled={@vereinfacht_api_url_env_set}
+ placeholder={
+ if(@vereinfacht_api_url_env_set,
+ do: gettext("From VEREINFACHT_API_URL"),
+ else: "https://api.verein.visuel.dev/api/v1"
+ )
+ }
+ />
+
+
+ {gettext("API Key")}
+ <%= if @vereinfacht_api_key_set do %>
+
+ <.badge variant="neutral" size="sm">{gettext("(set)")}
+
+ <% end %>
+
+
+ <%= for msg <- (
+ if Phoenix.Component.used_input?(@form[:vereinfacht_api_key]) do
+ Enum.map(@form[:vereinfacht_api_key].errors, &MvWeb.CoreComponents.translate_error/1)
+ else
+ []
+ end
+ ) do %>
+
+ <.icon name="hero-exclamation-circle" class="size-5" />
+ {msg}
+
+ <% end %>
+
+ <.input
+ field={@form[:vereinfacht_club_id]}
+ type="text"
+ label={gettext("Club ID")}
+ disabled={@vereinfacht_club_id_env_set}
+ placeholder={
+ if(@vereinfacht_club_id_env_set, do: gettext("From VEREINFACHT_CLUB_ID"), else: "2")
+ }
+ />
+ <.input
+ field={@form[:vereinfacht_app_url]}
+ type="text"
+ label={gettext("App URL (contact view link)")}
+ disabled={@vereinfacht_app_url_env_set}
+ placeholder={
+ if(@vereinfacht_app_url_env_set,
+ do: gettext("From VEREINFACHT_APP_URL"),
+ else: "https://app.verein.visuel.dev"
+ )
+ }
+ />
+
+ <.button
+ :if={
+ not (@vereinfacht_api_url_env_set and @vereinfacht_api_key_env_set and
+ @vereinfacht_club_id_env_set)
+ }
+ phx-disable-with={gettext("Saving...")}
+ variant="primary"
+ class="mt-2"
+ >
+ {gettext("Save Vereinfacht Settings")}
+
+
+ <.button
+ :if={Mv.Config.vereinfacht_configured?()}
+ type="button"
+ variant="secondary"
+ phx-click="test_vereinfacht_connection"
+ phx-disable-with={gettext("Testing...")}
+ >
+ {gettext("Test Integration")}
+
+ <.button
+ :if={Mv.Config.vereinfacht_configured?()}
+ type="button"
+ variant="secondary"
+ phx-click="sync_vereinfacht_contacts"
+ phx-disable-with={gettext("Syncing...")}
+ >
+ {gettext("Sync all members without Vereinfacht contact")}
+
+
+ <%= if @vereinfacht_test_result do %>
+ <.vereinfacht_test_result result={@vereinfacht_test_result} />
+ <% end %>
+ <%= if @last_vereinfacht_sync_result do %>
+ <.vereinfacht_sync_result result={@last_vereinfacht_sync_result} />
+ <% end %>
+
+
+ <%!-- OIDC Section --%>
+ <.form_section title={gettext("OIDC (Single Sign-On)")}>
+ <%= if @oidc_env_configured do %>
+
+ {gettext("Some values are set via environment variables. Those fields are read-only.")}
+
+ <% end %>
+ <.form for={@form} id="oidc-form" phx-change="validate" phx-submit="save">
+
+ <.input
+ field={@form[:oidc_client_id]}
+ type="text"
+ label={gettext("Client ID")}
+ disabled={@oidc_client_id_env_set}
+ placeholder={
+ if(@oidc_client_id_env_set, do: gettext("From OIDC_CLIENT_ID"), else: "mv")
+ }
+ />
+ <.input
+ field={@form[:oidc_base_url]}
+ type="text"
+ label={gettext("Base URL")}
+ disabled={@oidc_base_url_env_set}
+ placeholder={
+ if(@oidc_base_url_env_set,
+ do: gettext("From OIDC_BASE_URL"),
+ else: "http://localhost:8080/auth/v1"
+ )
+ }
+ />
+ <.input
+ field={@form[:oidc_redirect_uri]}
+ type="text"
+ label={gettext("Redirect URI")}
+ disabled={@oidc_redirect_uri_env_set}
+ placeholder={
+ if(@oidc_redirect_uri_env_set,
+ do: gettext("From OIDC_REDIRECT_URI"),
+ else: "http://localhost:4000/auth/user/oidc/callback"
+ )
+ }
+ />
+
+
+ {gettext("Client Secret")}
+ <%= if @oidc_client_secret_set do %>
+
+ <.badge variant="neutral" size="sm">{gettext("(set)")}
+
+ <% end %>
+
+
+ <%= for msg <- (
+ if Phoenix.Component.used_input?(@form[:oidc_client_secret]) do
+ Enum.map(@form[:oidc_client_secret].errors, &MvWeb.CoreComponents.translate_error/1)
+ else
+ []
+ end
+ ) do %>
+
+ <.icon name="hero-exclamation-circle" class="size-5" />
+ {msg}
+
+ <% end %>
+
+ <.input
+ field={@form[:oidc_admin_group_name]}
+ type="text"
+ label={gettext("Admin group name")}
+ disabled={@oidc_admin_group_name_env_set}
+ placeholder={
+ if(@oidc_admin_group_name_env_set,
+ do: gettext("From OIDC_ADMIN_GROUP_NAME"),
+ else: gettext("e.g. admin")
+ )
+ }
+ />
+ <.input
+ field={@form[:oidc_groups_claim]}
+ type="text"
+ label={gettext("Groups claim")}
+ disabled={@oidc_groups_claim_env_set}
+ placeholder={
+ if(@oidc_groups_claim_env_set,
+ do: gettext("From OIDC_GROUPS_CLAIM"),
+ else: "groups"
+ )
+ }
+ />
+
+
+ <.button
+ :if={
+ not (@oidc_client_id_env_set and @oidc_base_url_env_set and
+ @oidc_redirect_uri_env_set and @oidc_client_secret_env_set and
+ @oidc_admin_group_name_env_set and @oidc_groups_claim_env_set and
+ @oidc_only_env_set)
+ }
+ phx-disable-with={gettext("Saving...")}
+ variant="primary"
+ class="mt-2"
+ >
+ {gettext("Save OIDC Settings")}
+
+
+
+
"""
end
diff --git a/priv/gettext/de/LC_MESSAGES/default.po b/priv/gettext/de/LC_MESSAGES/default.po
index a96e6c9..c23799a 100644
--- a/priv/gettext/de/LC_MESSAGES/default.po
+++ b/priv/gettext/de/LC_MESSAGES/default.po
@@ -3306,7 +3306,7 @@ msgstr "Um die Löschung zu bestätigen, gib bitte den Gruppennamen ein:"
msgid "To confirm deletion, please enter this text:"
msgstr "Um die Löschung zu bestätigen, gib bitte folgenden Text ein:"
-#: lib/mv_web/components/layouts/sidebar.ex
+#: lib/mv_web/components/core_components.ex
#, elixir-autogen, elixir-format
msgid "Toggle dark mode"
msgstr "Dunklen Modus umschalten"
diff --git a/priv/gettext/default.pot b/priv/gettext/default.pot
index 6945957..ff61365 100644
--- a/priv/gettext/default.pot
+++ b/priv/gettext/default.pot
@@ -3307,7 +3307,7 @@ msgstr ""
msgid "To confirm deletion, please enter this text:"
msgstr ""
-#: lib/mv_web/components/layouts/sidebar.ex
+#: lib/mv_web/components/core_components.ex
#, elixir-autogen, elixir-format
msgid "Toggle dark mode"
msgstr ""
diff --git a/priv/gettext/en/LC_MESSAGES/default.po b/priv/gettext/en/LC_MESSAGES/default.po
index 827290b..82aed54 100644
--- a/priv/gettext/en/LC_MESSAGES/default.po
+++ b/priv/gettext/en/LC_MESSAGES/default.po
@@ -3307,7 +3307,7 @@ msgstr ""
msgid "To confirm deletion, please enter this text:"
msgstr ""
-#: lib/mv_web/components/layouts/sidebar.ex
+#: lib/mv_web/components/core_components.ex
#, elixir-autogen, elixir-format
msgid "Toggle dark mode"
msgstr ""