fix(admin): polish mobile layout and actions
This commit is contained in:
@@ -11,6 +11,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/com
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
import { useToast } from "@/hooks/use-toast";
|
||||
import { formatJalali, resolveErrorMessage } from "@/lib/utils";
|
||||
|
||||
@@ -91,37 +92,41 @@ export default function AdminBlog() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-6" dir="ltr">
|
||||
<div className="space-y-6" dir="rtl">
|
||||
<div className="flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
|
||||
<Button asChild>
|
||||
<Link to="/admin/blog/new/edit">
|
||||
<Plus className="ml-2 h-4 w-4" />
|
||||
نوشته جدید
|
||||
</Link>
|
||||
</Button>
|
||||
<div className="text-right">
|
||||
<h2 className="text-2xl font-bold">مدیریت بلاگ</h2>
|
||||
<p className="mt-1 text-sm text-muted-foreground">
|
||||
پیشنویسها، صف بررسی، انتشار و اصلاح نوشتهها.
|
||||
</p>
|
||||
</div>
|
||||
<Button asChild>
|
||||
<Link to="/admin/blog/new/edit">
|
||||
<Plus className="ml-2 h-4 w-4" />
|
||||
نوشته جدید
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-4 md:grid-cols-4">
|
||||
<Card><CardContent className="flex items-center flex-row-reverse gap-2 p-4"><BookOpenText className="h-5 w-5 text-primary" /><span>کل: {posts.length}</span></CardContent></Card>
|
||||
<Card><CardContent className="flex items-center flex-row-reverse gap-2 p-4"><Clock3 className="h-5 w-5 text-amber-600" /><span>بررسی: {stats.submitted ?? 0}</span></CardContent></Card>
|
||||
<Card><CardContent className="flex items-center flex-row-reverse gap-2 p-4"><CheckCircle2 className="h-5 w-5 text-emerald-600" /><span>منتشر: {stats.published ?? 0}</span></CardContent></Card>
|
||||
<Card><CardContent className="flex items-center flex-row-reverse gap-2 p-4"><XCircle className="h-5 w-5 text-rose-600" /><span>اصلاح: {stats.changes_requested ?? 0}</span></CardContent></Card>
|
||||
<Card><CardContent className="flex items-center flex-row gap-2 p-4"><BookOpenText className="h-5 w-5 text-primary" /><span>کل: {posts.length}</span></CardContent></Card>
|
||||
<Card><CardContent className="flex items-center flex-row gap-2 p-4"><Clock3 className="h-5 w-5 text-amber-600" /><span>بررسی: {stats.submitted ?? 0}</span></CardContent></Card>
|
||||
<Card><CardContent className="flex items-center flex-row gap-2 p-4"><CheckCircle2 className="h-5 w-5 text-emerald-600" /><span>منتشر: {stats.published ?? 0}</span></CardContent></Card>
|
||||
<Card><CardContent className="flex items-center flex-row gap-2 p-4"><XCircle className="h-5 w-5 text-rose-600" /><span>اصلاح: {stats.changes_requested ?? 0}</span></CardContent></Card>
|
||||
</div>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div className="flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
|
||||
<div className="flex gap-2">
|
||||
<div className="text-right">
|
||||
<CardTitle>نوشتهها</CardTitle>
|
||||
<CardDescription>دسترسی نویسندهها به نوشتههای خودشان محدود میشود.</CardDescription>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2 sm:flex-row">
|
||||
<Button variant="outline" onClick={loadPosts}>جستجو</Button>
|
||||
<Input value={search} onChange={(event) => setSearch(event.target.value)} placeholder="جستجو..." className="w-64 text-right" />
|
||||
<Input value={search} onChange={(event) => setSearch(event.target.value)} placeholder="جستجو..." className="w-full text-right sm:w-64" />
|
||||
<Select value={status} onValueChange={setStatus}>
|
||||
<SelectTrigger className="w-48"><SelectValue /></SelectTrigger>
|
||||
<SelectTrigger className="w-full sm:w-48"><SelectValue /></SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">همه وضعیتها</SelectItem>
|
||||
<SelectItem value="draft">پیشنویس</SelectItem>
|
||||
@@ -132,10 +137,6 @@ export default function AdminBlog() {
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<CardTitle>نوشتهها</CardTitle>
|
||||
<CardDescription>دسترسی نویسندهها به نوشتههای خودشان محدود میشود.</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-3">
|
||||
@@ -143,35 +144,87 @@ export default function AdminBlog() {
|
||||
<div className="flex justify-center py-10"><Loader2 className="h-5 w-5 animate-spin" /></div>
|
||||
) : posts.length ? (
|
||||
posts.map((post) => (
|
||||
<div key={post.id} className="flex flex-col gap-3 rounded-2xl border p-4 md:flex-row md:items-center md:justify-between">
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Button variant="outline" size="sm" asChild>
|
||||
<Link to={`/admin/blog/${post.id}/preview`}><Eye className="h-4 w-4" /></Link>
|
||||
</Button>
|
||||
<Button variant="secondary" size="sm" asChild>
|
||||
<Link to={`/admin/blog/${post.id}/edit`}><Edit className="h-4 w-4" /></Link>
|
||||
</Button>
|
||||
{post.status === "draft" || post.status === "changes_requested" ? (
|
||||
<Button size="sm" onClick={() => submitPost(post.id)} disabled={actingId === post.id}>
|
||||
<Send className="h-4 w-4" />
|
||||
</Button>
|
||||
) : null}
|
||||
{canReview && post.status === "submitted" ? (
|
||||
<>
|
||||
<Button size="sm" onClick={() => reviewPost(post.id, "publish")} disabled={actingId === post.id}>انتشار</Button>
|
||||
<Button size="sm" variant="outline" onClick={() => reviewPost(post.id, "request_changes")} disabled={actingId === post.id}>درخواست اصلاح</Button>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
<div key={post.id} className="flex gap-3 rounded-2xl border p-4 flex-row items-center justify-between">
|
||||
<div className="text-right">
|
||||
<div className="flex flex-wrap items-center justify-end gap-2">
|
||||
<Badge variant={post.status === "published" ? "default" : "secondary"}>{statusLabels[post.status] ?? post.status}</Badge>
|
||||
<div className="flex flex-col-reverse md:flex-row flex-wrap items-start gap-2">
|
||||
<h3 className="font-semibold">{post.title}</h3>
|
||||
<Badge variant={post.status === "published" ? "default" : "secondary"}>{statusLabels[post.status] ?? post.status}</Badge>
|
||||
</div>
|
||||
<p className="mt-1 text-xs text-muted-foreground">
|
||||
{post.updated_at ? formatJalali(post.updated_at, false) : ""}
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 grid-flow-col grid-rows-2 gap-2 md:flex md:flex-row md:flex-wrap" dir="ltr">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button variant="outline" size="sm" asChild className="w-full md:w-auto">
|
||||
<Link
|
||||
to={`/admin/blog/${post.id}/preview`}
|
||||
aria-label="پیشنمایش"
|
||||
className="flex justify-center"
|
||||
>
|
||||
<Eye className="h-4 w-4" />
|
||||
</Link>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>پیشنمایش</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button variant="secondary" size="sm" asChild className="w-full md:w-auto">
|
||||
<Link
|
||||
to={`/admin/blog/${post.id}/edit`}
|
||||
aria-label="ویرایش"
|
||||
className="flex justify-center"
|
||||
>
|
||||
<Edit className="h-4 w-4" />
|
||||
</Link>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>ویرایش</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
{post.status === "draft" || post.status === "changes_requested" ? (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={() => submitPost(post.id)}
|
||||
disabled={actingId === post.id}
|
||||
aria-label="ارسال برای بررسی"
|
||||
className="w-full md:w-auto"
|
||||
>
|
||||
<Send className="h-4 w-4" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>ارسال برای بررسی</TooltipContent>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
|
||||
{canReview && post.status === "submitted" ? (
|
||||
<>
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={() => reviewPost(post.id, "publish")}
|
||||
disabled={actingId === post.id}
|
||||
className="w-full md:w-auto"
|
||||
>
|
||||
انتشار
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() => reviewPost(post.id, "request_changes")}
|
||||
disabled={actingId === post.id}
|
||||
className="w-full md:w-auto"
|
||||
>
|
||||
درخواست اصلاح
|
||||
</Button>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
|
||||
Reference in New Issue
Block a user