fix: complete user admin actions - form-based inline actions and API endpoint for bulk operations
This commit is contained in:
1 parent
c3de7cb576
commit
2efd03de0f
2 files changed
+281
-52
No files matched your search
+114
-52
@@ -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>
|
||||
|
||||
Reference in new issue
Block a user