fix(email): Add SMTP configuration and fix invitation link routing
- Add SMTP email backend support to production settings (EMAIL_HOST, EMAIL_PORT, etc.) - Falls back to console backend if SMTP not configured - Fix AcceptInvitePage to support both path parameter (/accept-invite/:token) and query parameter (?token=...) formats for invitation tokens - Add route for /accept-invite/:token in App.tsx 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -279,6 +279,7 @@ const AppContent: React.FC = () => {
|
|||||||
<Route path="/oauth/callback/:provider" element={<OAuthCallback />} />
|
<Route path="/oauth/callback/:provider" element={<OAuthCallback />} />
|
||||||
<Route path="/verify-email" element={<VerifyEmail />} />
|
<Route path="/verify-email" element={<VerifyEmail />} />
|
||||||
<Route path="/accept-invite" element={<AcceptInvitePage />} />
|
<Route path="/accept-invite" element={<AcceptInvitePage />} />
|
||||||
|
<Route path="/accept-invite/:token" element={<AcceptInvitePage />} />
|
||||||
<Route path="/tenant-onboard" element={<TenantOnboardPage />} />
|
<Route path="/tenant-onboard" element={<TenantOnboardPage />} />
|
||||||
<Route path="*" element={<Navigate to="/" replace />} />
|
<Route path="*" element={<Navigate to="/" replace />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
@@ -322,6 +323,7 @@ const AppContent: React.FC = () => {
|
|||||||
<Route path="/oauth/callback/:provider" element={<OAuthCallback />} />
|
<Route path="/oauth/callback/:provider" element={<OAuthCallback />} />
|
||||||
<Route path="/verify-email" element={<VerifyEmail />} />
|
<Route path="/verify-email" element={<VerifyEmail />} />
|
||||||
<Route path="/accept-invite" element={<AcceptInvitePage />} />
|
<Route path="/accept-invite" element={<AcceptInvitePage />} />
|
||||||
|
<Route path="/accept-invite/:token" element={<AcceptInvitePage />} />
|
||||||
<Route path="/tenant-onboard" element={<TenantOnboardPage />} />
|
<Route path="/tenant-onboard" element={<TenantOnboardPage />} />
|
||||||
<Route path="*" element={<Navigate to="/" replace />} />
|
<Route path="*" element={<Navigate to="/" replace />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { useSearchParams, useNavigate } from 'react-router-dom';
|
import { useSearchParams, useNavigate, useParams } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import {
|
import {
|
||||||
useInvitationDetails,
|
useInvitationDetails,
|
||||||
@@ -23,8 +23,10 @@ import {
|
|||||||
const AcceptInvitePage: React.FC = () => {
|
const AcceptInvitePage: React.FC = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
|
const { token: pathToken } = useParams<{ token: string }>();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const token = searchParams.get('token');
|
// Support both path parameter (/accept-invite/:token) and query parameter (?token=...)
|
||||||
|
const token = pathToken || searchParams.get('token');
|
||||||
|
|
||||||
const { data: invitation, isLoading, error } = useInvitationDetails(token);
|
const { data: invitation, isLoading, error } = useInvitationDetails(token);
|
||||||
const acceptInvitationMutation = useAcceptInvitation();
|
const acceptInvitationMutation = useAcceptInvitation();
|
||||||
|
|||||||
@@ -168,10 +168,19 @@ if MAILGUN_API_KEY and MAILGUN_DOMAIN:
|
|||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
# Fall back to SMTP or console email
|
# Fall back to SMTP or console email
|
||||||
EMAIL_BACKEND = env(
|
EMAIL_HOST = env("EMAIL_HOST", default="")
|
||||||
"DJANGO_EMAIL_BACKEND",
|
EMAIL_PORT = env.int("EMAIL_PORT", default=587)
|
||||||
default="django.core.mail.backends.console.EmailBackend"
|
EMAIL_HOST_USER = env("EMAIL_HOST_USER", default="")
|
||||||
)
|
EMAIL_HOST_PASSWORD = env("EMAIL_HOST_PASSWORD", default="")
|
||||||
|
EMAIL_USE_TLS = env.bool("EMAIL_USE_TLS", default=True)
|
||||||
|
|
||||||
|
if EMAIL_HOST and EMAIL_HOST_USER and EMAIL_HOST_PASSWORD:
|
||||||
|
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
|
||||||
|
else:
|
||||||
|
EMAIL_BACKEND = env(
|
||||||
|
"DJANGO_EMAIL_BACKEND",
|
||||||
|
default="django.core.mail.backends.console.EmailBackend"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# LOGGING
|
# LOGGING
|
||||||
|
|||||||
Reference in New Issue
Block a user