fix: complete user admin actions - form-based inline actions and API endpoint for bulk operations

This commit is contained in:
remco committed 2026-07-01 19:05:18 +02:00
1 parent c3de7cb576
commit 2efd03de0f
2 files changed
+281 -52

No files matched your search

+114 -52
View File
@@ -63,66 +63,128 @@ export default async function AdminUsers({
<button type="submit" className="btn btn-primary">
Search
</button>
</form>
<section className="admin-section">
<h2>Quick Actions</h2>
<form
action="/api/admin/users/actions"
method="post"
className="card"
style={{ display: "flex", gap: "1rem", alignItems: "center", flexWrap: "wrap", marginBottom: "1.5rem" }}
>
<input type="hidden" name="action" value="alert" />
<input
name="userId"
type="number"
placeholder="User ID"
style={{ width: 120 }}
required
/>
<input
name="username"
type="text"
placeholder="Username"
style={{ width: 150 }}
required
/>
<input
name="message"
type="text"
placeholder="Alert message (max 512 chars)"
maxLength={512}
style={{ flex: 1, minWidth: 300 }}
required
/>
<button type="submit" className="btn btn-primary">
Send Alert
</button>
</form>
</section>
<section className="admin-section">
<h2>Accounts ({total})</h2>
<h2>Accounts ({total})</h2>
{users.length === 0 ? (
<p className="muted">No users match this search.</p>
) : (
<div style={{ overflowX: "auto" }}>
<table>
<thead>
<tr>
<th>ID</th>
<th>Username</th>
<th>Rank</th>
<th>Credits</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{users.map((u) => (
<tr key={u.id}>
<td className="muted">{u.id}</td>
<td>
<Link href={`/admin/users/${u.id}`}>{u.username}</Link>
</td>
<td>{u.rank}</td>
<td>{u.credits}</td>
<td>
<span className={`admin-badge ${u.online === "1" ? "ok" : ""}`}>
{u.online === "1" ? "online" : "offline"}
</span>
</td>
<td>
<div style={{ display: "flex", gap: "0.25rem", flexWrap: "wrap" }}>
<Link href={`/admin/users/${u.id}/edit`} className="btn btn-outline" style={{ fontSize: "0.75rem", padding: "0.25rem 0.5rem" }}>Edit</Link>
<button
type="button"
className="btn btn-outline"
onClick={() => alert(`Set rank for ${u.username}`)}
style={{ fontSize: "0.75rem", padding: "0.25rem 0.5rem" }}
>Set Rank</button>
<button
type="button"
className="btn btn-danger"
onClick={() => alert(`Disconnect ${u.username}`)}
style={{ fontSize: "0.75rem", padding: "0.25rem 0.5rem" }}
>Disconnect</button>
<button
type="button"
className="btn btn-primary"
onClick={() => alert(`Alert ${u.username}`)}
style={{ fontSize: "0.75rem", padding: "0.25rem 0.5rem" }}
>Alert</button>
</div>
</td>
<form action="/api/admin/users/actions" method="post">
<table>
<thead>
<tr>
<th>ID</th>
<th>Username</th>
<th>Rank</th>
<th>Credits</th>
<th>Status</th>
<th style={{ width: "200px" }}>Actions</th>
</tr>
))}
</tbody>
</table>
</thead>
<tbody>
{users.map((u) => (
<tr key={u.id}>
<td className="muted">{u.id}</td>
<td>
<Link href={`/admin/users/${u.id}`}>{u.username}</Link>
</td>
<td>{u.rank}</td>
<td>{u.credits}</td>
<td>
<span className={`admin-badge ${u.online === "1" ? "ok" : ""}`}>
{u.online === "1" ? "online" : "offline"}
</span>
</td>
<td>
<div style={{ display: "flex", gap: "0.25rem", flexWrap: "wrap", justifyContent: "flex-start" }}>
<Link href={`/admin/users/${u.id}/edit`} className="btn btn-outline" style={{ fontSize: "0.75rem", padding: "0.25rem 0.5rem" }}>Edit</Link>
<form style={{ display: "inline-block" }} action="/api/admin/users/actions" method="post">
<input type="hidden" name="userId" value={u.id} />
<input type="hidden" name="username" value={u.username} />
<button
type="submit"
name="action"
value="set_rank"
className="btn btn-outline"
style={{ fontSize: "0.75rem", padding: "0.25rem 0.5rem" }}
onClick={(e) => {
if (!confirm(`Set rank for ${u.username}?`)) e.preventDefault();
}}
>Set Rank</button>
</form>
<form style={{ display: "inline-block" }} action="/api/admin/users/actions" method="post">
<input type="hidden" name="userId" value={u.id} />
<input type="hidden" name="username" value={u.username} />
<button
type="submit"
name="action"
value="disconnect"
className="btn btn-danger"
style={{ fontSize: "0.75rem", padding: "0.25rem 0.5rem" }}
onClick={(e) => {
if (!confirm(`Disconnect ${u.username}?`)) e.preventDefault();
}}
>Disconnect</button>
</form>
<form style={{ display: "inline-block" }} action="/api/admin/users/actions" method="post">
<input type="hidden" name="userId" value={u.id} />
<input type="hidden" name="username" value={u.username} />
<button
type="submit"
name="action"
value="alert"
className="btn btn-primary"
style={{ fontSize: "0.75rem", padding: "0.25rem 0.5rem" }}
onClick={(e) => {
if (!confirm(`Send alert to ${u.username}?`)) e.preventDefault();
}}
>Alert</button>
</form>
</div>
</td>
</tr>
))}
</tbody>
</table>
</form>
</div>
)}
</section>