fix: ui fixes
This commit is contained in:
@@ -173,10 +173,10 @@ export default function FeedbackPage() {
|
||||
}
|
||||
|
||||
function StatusBadge({ f }: { f: AdminFeedback }) {
|
||||
const label = f.replied_at
|
||||
? "Replied"
|
||||
: f.resolved_at
|
||||
? "Resolved"
|
||||
const label = f.resolved_at
|
||||
? "Resolved"
|
||||
: f.replied_at
|
||||
? "Replied"
|
||||
: f.acknowledged_at
|
||||
? "Acknowledged"
|
||||
: "Open";
|
||||
@@ -240,7 +240,7 @@ function ReplyModal({
|
||||
onChange={(e) => setMessage(e.target.value)}
|
||||
rows={5}
|
||||
maxLength={4000}
|
||||
placeholder="Write your reply… (emailed to the submitter, marks this resolved)"
|
||||
placeholder="Write your reply… (emailed to the submitter; use Resolve separately to close it)"
|
||||
/>
|
||||
</label>
|
||||
<div className="flex justify-end gap-2">
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import { useCallback, useState } from "react";
|
||||
import { Mail } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import { api, AdminError, type AdminUser } from "@/lib/api";
|
||||
import { GoogleIcon, FacebookIcon } from "@/components/ui/provider-icons";
|
||||
import { usePagedList } from "@/lib/use-paged-list";
|
||||
import { ListShell, EmptyRow } from "@/components/list-shell";
|
||||
import { Table, THead, TR, TH, TD } from "@/components/ui/table";
|
||||
@@ -74,6 +76,7 @@ export default function UsersPage() {
|
||||
<TR>
|
||||
<TH>User</TH>
|
||||
<TH>Email</TH>
|
||||
<TH>Auth</TH>
|
||||
<TH>Posts</TH>
|
||||
<TH>Joined</TH>
|
||||
<TH className="text-right">Actions</TH>
|
||||
@@ -81,7 +84,7 @@ export default function UsersPage() {
|
||||
</THead>
|
||||
<tbody>
|
||||
{list.items.length === 0 && !list.loading ? (
|
||||
<EmptyRow cols={5} label="No users found." />
|
||||
<EmptyRow cols={6} label="No users found." />
|
||||
) : (
|
||||
list.items.map((u) => (
|
||||
<TR key={u.id}>
|
||||
@@ -106,6 +109,9 @@ export default function UsersPage() {
|
||||
<TD>
|
||||
{u.email ?? <span className="text-muted-foreground">—</span>}
|
||||
</TD>
|
||||
<TD>
|
||||
<AuthIcons user={u} />
|
||||
</TD>
|
||||
<TD>{u.post_count}</TD>
|
||||
<TD className="whitespace-nowrap">{fmtDate(u.created_at)}</TD>
|
||||
<TD className="text-right">
|
||||
@@ -122,6 +128,38 @@ export default function UsersPage() {
|
||||
);
|
||||
}
|
||||
|
||||
function AuthIcons({ user }: { user: AdminUser }) {
|
||||
const hasGoogle = user.providers.includes("google");
|
||||
const hasFacebook = user.providers.includes("facebook");
|
||||
if (!user.has_password && !hasGoogle && !hasFacebook) {
|
||||
return <span className="text-muted-foreground">—</span>;
|
||||
}
|
||||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
{user.has_password ? (
|
||||
// Tooltip shows the email on hover; clicking copies it to the clipboard.
|
||||
<button
|
||||
type="button"
|
||||
title={user.email ? `Click to copy ${user.email}` : "Email & password"}
|
||||
onClick={() => {
|
||||
if (!user.email) return;
|
||||
// No await before the write — keeps the click's user activation.
|
||||
navigator.clipboard.writeText(user.email).then(
|
||||
() => toast.success("Email copied"),
|
||||
() => toast.error("Could not copy"),
|
||||
);
|
||||
}}
|
||||
className="inline-flex text-muted-foreground outline-none hover:text-foreground focus-visible:text-foreground"
|
||||
>
|
||||
<Mail className="size-4" />
|
||||
</button>
|
||||
) : null}
|
||||
{hasGoogle ? <GoogleIcon className="size-4" /> : null}
|
||||
{hasFacebook ? <FacebookIcon className="size-4" /> : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function NotifyModal({
|
||||
user,
|
||||
onClose,
|
||||
|
||||
Reference in New Issue
Block a user