🐛 fix: announcement manager
This commit is contained in:
parent
22b24041a7
commit
93926d9c99
@ -11,6 +11,12 @@
|
|||||||
"finished": "Finished",
|
"finished": "Finished",
|
||||||
"import": "Import",
|
"import": "Import",
|
||||||
"latestAnnouncement": "Latest Announcement",
|
"latestAnnouncement": "Latest Announcement",
|
||||||
|
"announcements": "Announcements",
|
||||||
|
"all": "All",
|
||||||
|
"pinned": "Pinned",
|
||||||
|
"pinnedOnly": "Pinned Only",
|
||||||
|
"popup": "Popup",
|
||||||
|
"popupOnly": "Popup Only",
|
||||||
"manualImportMessage": "Please import manually",
|
"manualImportMessage": "Please import manually",
|
||||||
"mySubscriptions": "My Subscriptions",
|
"mySubscriptions": "My Subscriptions",
|
||||||
"nextResetDays": "Next Reset Days",
|
"nextResetDays": "Next Reset Days",
|
||||||
|
|||||||
@ -11,6 +11,12 @@
|
|||||||
"finished": "已完成",
|
"finished": "已完成",
|
||||||
"import": "一键导入",
|
"import": "一键导入",
|
||||||
"latestAnnouncement": "最新公告",
|
"latestAnnouncement": "最新公告",
|
||||||
|
"announcements": "公告管理",
|
||||||
|
"all": "全部",
|
||||||
|
"pinned": "置顶",
|
||||||
|
"pinnedOnly": "仅置顶",
|
||||||
|
"popup": "弹窗",
|
||||||
|
"popupOnly": "仅弹窗",
|
||||||
"manualImportMessage": "请手动导入",
|
"manualImportMessage": "请手动导入",
|
||||||
"mySubscriptions": "我的订阅",
|
"mySubscriptions": "我的订阅",
|
||||||
"nextResetDays": "距离下次重置天数",
|
"nextResetDays": "距离下次重置天数",
|
||||||
|
|||||||
@ -32,7 +32,7 @@ export default function Announcement({ type }: { type: "popup" | "pinned" }) {
|
|||||||
skipErrorHandler: true,
|
skipErrorHandler: true,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return result.data.data?.announcements.find((item) => item[type]) || null;
|
return result.data.data?.announcements?.[0] || null;
|
||||||
},
|
},
|
||||||
enabled: !!user,
|
enabled: !!user,
|
||||||
});
|
});
|
||||||
@ -44,13 +44,16 @@ export default function Announcement({ type }: { type: "popup" | "pinned" }) {
|
|||||||
<Dialog defaultOpen={!!data}>
|
<Dialog defaultOpen={!!data}>
|
||||||
<DialogContent className="sm:max-w-[425px]">
|
<DialogContent className="sm:max-w-[425px]">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>{data?.title}</DialogTitle>
|
<DialogTitle>{data.title}</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<Markdown>{data?.content}</Markdown>
|
<div className="prose prose-sm max-w-none dark:prose-invert">
|
||||||
|
<Markdown>{data.content}</Markdown>
|
||||||
|
</div>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === "pinned") {
|
if (type === "pinned") {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -59,9 +62,17 @@ export default function Announcement({ type }: { type: "popup" | "pinned" }) {
|
|||||||
{t("latestAnnouncement", "Latest Announcement")}
|
{t("latestAnnouncement", "Latest Announcement")}
|
||||||
</h2>
|
</h2>
|
||||||
<Card className="p-6">
|
<Card className="p-6">
|
||||||
{data?.content ? <Markdown>{data?.content}</Markdown> : <Empty />}
|
{data.content ? (
|
||||||
|
<div className="prose prose-sm max-w-none dark:prose-invert">
|
||||||
|
<Markdown>{data.content}</Markdown>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<Empty />
|
||||||
|
)}
|
||||||
</Card>
|
</Card>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,34 +1,133 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { Timeline } from "@workspace/ui/components/timeline";
|
import {
|
||||||
import Empty from "@workspace/ui/composed/empty";
|
Card,
|
||||||
|
CardContent,
|
||||||
|
CardDescription,
|
||||||
|
CardHeader,
|
||||||
|
CardTitle,
|
||||||
|
} from "@workspace/ui/components/card";
|
||||||
|
import {
|
||||||
|
Tabs,
|
||||||
|
TabsContent,
|
||||||
|
TabsList,
|
||||||
|
TabsTrigger,
|
||||||
|
} from "@workspace/ui/components/tabs";
|
||||||
|
import {
|
||||||
|
ProList,
|
||||||
|
type ProListActions,
|
||||||
|
} from "@workspace/ui/composed/pro-list/pro-list";
|
||||||
|
import { Icon } from "@workspace/ui/composed/icon";
|
||||||
import { Markdown } from "@workspace/ui/composed/markdown";
|
import { Markdown } from "@workspace/ui/composed/markdown";
|
||||||
import { queryAnnouncement } from "@workspace/ui/services/user/announcement";
|
import { queryAnnouncement } from "@workspace/ui/services/user/announcement";
|
||||||
|
import { formatDate } from "@workspace/ui/utils/formatting";
|
||||||
|
import { useRef, useState } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
export default function Announcement() {
|
export default function Announcement() {
|
||||||
const { data } = useQuery({
|
const { t } = useTranslation("dashboard");
|
||||||
queryKey: ["queryAnnouncement"],
|
const [activeTab, setActiveTab] = useState("all");
|
||||||
queryFn: async () => {
|
const pinnedRef = useRef<ProListActions>(null);
|
||||||
const { data } = await queryAnnouncement({
|
const normalRef = useRef<ProListActions>(null);
|
||||||
page: 1,
|
|
||||||
size: 99,
|
const requestAnnouncements = async (
|
||||||
pinned: false,
|
pagination: { page: number; size: number },
|
||||||
popup: false,
|
filter: { pinned?: boolean; popup?: boolean }
|
||||||
});
|
) => {
|
||||||
return data.data?.announcements || [];
|
const response = await queryAnnouncement({
|
||||||
},
|
...pagination,
|
||||||
});
|
...filter,
|
||||||
return data && data.length > 0 ? (
|
});
|
||||||
<Timeline
|
return {
|
||||||
data={
|
list: response.data.data?.announcements || [],
|
||||||
data.map((item) => ({
|
total: response.data.data?.total || 0,
|
||||||
title: item.title,
|
};
|
||||||
content: <Markdown>{item.content}</Markdown>,
|
};
|
||||||
})) || []
|
|
||||||
}
|
const renderAnnouncement = (item: any) => (
|
||||||
/>
|
<Card className="overflow-hidden">
|
||||||
) : (
|
<CardHeader>
|
||||||
<Empty border />
|
<div className="flex items-start justify-between gap-4">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<CardTitle className="text-lg">{item.title}</CardTitle>
|
||||||
|
{item.pinned && (
|
||||||
|
<span className="flex items-center gap-1 rounded-full bg-primary/10 px-2 py-0.5 text-xs font-medium text-primary">
|
||||||
|
<Icon className="size-3" icon="uil:pin" />
|
||||||
|
{t("pinned", "Pinned")}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{item.popup && (
|
||||||
|
<span className="flex items-center gap-1 rounded-full bg-orange-500/10 px-2 py-0.5 text-xs font-medium text-orange-500">
|
||||||
|
<Icon className="size-3" icon="uil:popcorn" />
|
||||||
|
{t("popup", "Popup")}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<CardDescription className="text-sm">
|
||||||
|
<time dateTime={item.created_at}>
|
||||||
|
{formatDate(item.created_at)}
|
||||||
|
</time>
|
||||||
|
</CardDescription>
|
||||||
|
</div>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="prose prose-sm max-w-none dark:prose-invert">
|
||||||
|
<Markdown>{item.content}</Markdown>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-4">
|
||||||
|
<h2 className="flex items-center gap-1.5 font-semibold">
|
||||||
|
<Icon className="size-5" icon="uil:bell" />
|
||||||
|
{t("announcements", "Announcements")}
|
||||||
|
</h2>
|
||||||
|
<Tabs defaultValue="all" onValueChange={setActiveTab}>
|
||||||
|
<TabsList>
|
||||||
|
<TabsTrigger value="all">
|
||||||
|
{t("all", "All")}
|
||||||
|
</TabsTrigger>
|
||||||
|
<TabsTrigger value="pinned">
|
||||||
|
{t("pinnedOnly", "Pinned Only")}
|
||||||
|
</TabsTrigger>
|
||||||
|
<TabsTrigger value="popup">
|
||||||
|
{t("popupOnly", "Popup Only")}
|
||||||
|
</TabsTrigger>
|
||||||
|
</TabsList>
|
||||||
|
|
||||||
|
<TabsContent value="all">
|
||||||
|
<ProList
|
||||||
|
action={normalRef}
|
||||||
|
renderItem={renderAnnouncement}
|
||||||
|
request={async (pagination) => {
|
||||||
|
return requestAnnouncements(pagination, {});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</TabsContent>
|
||||||
|
|
||||||
|
<TabsContent value="pinned">
|
||||||
|
<ProList
|
||||||
|
action={pinnedRef}
|
||||||
|
renderItem={renderAnnouncement}
|
||||||
|
request={async (pagination) => {
|
||||||
|
return requestAnnouncements(pagination, { pinned: true });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</TabsContent>
|
||||||
|
|
||||||
|
<TabsContent value="popup">
|
||||||
|
<ProList
|
||||||
|
action={normalRef}
|
||||||
|
renderItem={renderAnnouncement}
|
||||||
|
request={async (pagination) => {
|
||||||
|
return requestAnnouncements(pagination, { popup: true });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</TabsContent>
|
||||||
|
</Tabs>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user