Brought back newsletter form on admin page

This commit is contained in:
Alphonse Paix
2025-09-18 18:40:03 +02:00
parent 54218f92a9
commit 08d5f611b5
5 changed files with 85 additions and 16 deletions

File diff suppressed because one or more lines are too long

View File

@@ -58,7 +58,8 @@ impl IntoResponse for AdminError {
AdminError::NotAuthenticated => {
let mut headers = HeaderMap::new();
headers.insert("HX-Redirect", "/login".parse().unwrap());
(StatusCode::OK, headers).into_response()
headers.insert("Location", "/login".parse().unwrap());
(StatusCode::SEE_OTHER, headers).into_response()
}
AdminError::ChangePassword(e) => {
let template = ErrorTemplate {

View File

@@ -10,16 +10,19 @@ use uuid::Uuid;
#[template(path = "../templates/dashboard.html")]
struct DashboardTemplate {
username: String,
idempotency_key: String,
idempotency_key_1: String,
idempotency_key_2: String,
}
pub async fn admin_dashboard(
Extension(AuthenticatedUser { username, .. }): Extension<AuthenticatedUser>,
) -> Response {
let idempotency_key = Uuid::new_v4().to_string();
let idempotency_key_1 = Uuid::new_v4().to_string();
let idempotency_key_2 = Uuid::new_v4().to_string();
let template = DashboardTemplate {
username,
idempotency_key,
idempotency_key_1,
idempotency_key_2,
};
Html(template.render().unwrap()).into_response()
}

View File

@@ -10,5 +10,6 @@ pub async fn logout(session: TypedSession) -> Result<Response, AdminError> {
session.clear().await;
let mut headers = HeaderMap::new();
headers.insert("HX-Redirect", "/login".parse().unwrap());
Ok((StatusCode::OK, headers).into_response())
headers.insert("Location", "/login".parse().unwrap());
Ok((StatusCode::SEE_OTHER, headers).into_response())
}

View File

@@ -93,6 +93,56 @@
</div>
</div>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
<div class="bg-white rounded-lg shadow-md border border-gray-200">
<div class="p-6 border-b border-gray-200">
<h2 class="text-xl font-semibold text-gray-900 flex items-center">
<svg class="w-5 h-5 text-purple-600 mr-2"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 20h9M12 4h9M5 4h.01M5 20h.01M5 12h.01M9 16h6M9 8h6" />
</svg>
Write a new post
</h2>
<p class="text-sm text-gray-600 mt-1">Publish a new post online.</p>
</div>
<div class="p-6">
<form hx-post="/admin/posts"
hx-target="#post-messages"
hx-swap="innerHTML"
class="space-y-4">
<input type="hidden" name="idempotency_key" value="{{ idempotency_key_1 }}" />
<div>
<label for="post-title" class="block text-sm font-medium text-gray-700 mb-2">Title</label>
<input type="text"
id="post-title"
name="title"
required
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500" />
</div>
<div>
<label for="post-content"
class="block text-sm font-medium text-gray-700 mb-2">HTML content</label>
<textarea id="post-content"
name="content"
rows="6"
required
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500"></textarea>
</div>
<button type="submit"
class="w-full bg-purple-600 text-white hover:bg-purple-700 font-medium py-3 px-4 rounded-md transition-colors flex items-center justify-center">
<svg class="w-4 h-4 mr-2"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 20h9M12 4h9M5 4h.01M5 20h.01M5 12h.01M9 16h6M9 8h6" />
</svg>
Publish
</button>
<div id="post-messages" class="mt-4"></div>
</form>
</div>
</div>
<div class="bg-white rounded-lg shadow-md border border-gray-200">
<div class="p-6 border-b border-gray-200">
<h2 class="text-xl font-semibold text-gray-900 flex items-center">
@@ -102,29 +152,43 @@
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5.882V19.24a1.76 1.76 0 01-3.417.592l-2.147-6.15M18 13a3 3 0 100-6M5.436 13.683A4.001 4.001 0 017 6h1.832c4.1 0 7.625-1.234 9.168-3v14c-1.543-1.766-5.067-3-9.168-3H7a3.988 3.988 0 01-1.564-.317z" />
</svg>
Write a new post
Contact your subscribers
</h2>
<p class="text-sm text-gray-600 mt-1">Create a new post and notify your subscribers.</p>
<p class="text-sm text-gray-600 mt-1">Contact your subscribers directly.</p>
</div>
<div class="p-6">
<form hx-post="/admin/posts"
<form hx-post="/admin/newsletters"
hx-target="#newsletter-messages"
hx-swap="innerHTML"
class="space-y-4">
<input type="hidden" name="idempotency_key" value="{{ idempotency_key }}" />
<input type="hidden" name="idempotency_key" value="{{ idempotency_key_2 }}" />
<div>
<label for="title" class="block text-sm font-medium text-gray-700 mb-2">Title</label>
<label for="newsletter-title"
class="block text-sm font-medium text-gray-700 mb-2">Subject</label>
<input type="text"
id="title"
id="newsletter-title"
name="title"
placeholder="Subject"
required
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500" />
</div>
<div>
<label for="content" class="block text-sm font-medium text-gray-700 mb-2">HTML content</label>
<textarea id="content"
name="content"
<label for="newsletter-html"
class="block text-sm font-medium text-gray-700 mb-2">HTML content</label>
<textarea id="newsletter-html"
name="html"
rows="6"
placeholder="HTML version"
required
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 font-mono text-sm"></textarea>
</div>
<div>
<label for="newsletter-text"
class="block text-sm font-medium text-gray-700 mb-2">Text content</label>
<textarea id="newsletter-text"
name="text"
rows="6"
placeholder="Plain text version"
required
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 font-mono text-sm"></textarea>
</div>
@@ -136,7 +200,7 @@
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" />
</svg>
Create
Send
</button>
<div id="newsletter-messages" class="mt-4"></div>
</form>