From 20ae6a2091d419726cde36dcb1071558d510512e Mon Sep 17 00:00:00 2001 From: DIYgod Date: Wed, 8 Mar 2023 01:09:34 +0000 Subject: [PATCH] feat: events page in dashboard --- public/locales/zh/dashboard.json | 10 +- showcase.json | 4 +- src/components/dashboard/DashboardLayout.tsx | 33 +++- src/models/page.model.ts | 1 + src/pages/dashboard/[subdomain]/events.tsx | 194 +++++++++++++++++++ 5 files changed, 239 insertions(+), 3 deletions(-) create mode 100644 src/pages/dashboard/[subdomain]/events.tsx diff --git a/public/locales/zh/dashboard.json b/public/locales/zh/dashboard.json index d79e1536..bfa17a61 100644 --- a/public/locales/zh/dashboard.json +++ b/public/locales/zh/dashboard.json @@ -6,6 +6,7 @@ "Unread notifications": "未读通知", "Settings": "设置", "Events": "活动", + "New Events": "新活动", "Site Stats": "站点统计", "Total Posts": "文章总数", "Total Comments": "评论总数", @@ -131,5 +132,12 @@ "Published!" : "已发布!", "Title goes here...": "标题在这里...", "Start writing...": "开始写作...", - "Slug can only contain letters, numbers, hyphens, and underscores." : "短链接只能包含字母、数字、连字符和下划线。" + "Slug can only contain letters, numbers, hyphens, and underscores." : "短链接只能包含字母、数字、连字符和下划线。", + "Date": "日期", + "Prize": "奖金", + "Winners": "获奖者", + "Learn more": "了解更多", + "Ended": "已结束", + "Upcoming": "即将开始", + "Ongoing": "进行中" } \ No newline at end of file diff --git a/showcase.json b/showcase.json index 3bf495d2..22e428f2 100644 --- a/showcase.json +++ b/showcase.json @@ -98,5 +98,7 @@ "0xcavin", "shuxinfeng", "tea-24", - "revery" + "revery", + "hsinyau", + "rootless" ] diff --git a/src/components/dashboard/DashboardLayout.tsx b/src/components/dashboard/DashboardLayout.tsx index d721498c..1acfc4d4 100644 --- a/src/components/dashboard/DashboardLayout.tsx +++ b/src/components/dashboard/DashboardLayout.tsx @@ -21,6 +21,8 @@ import { useAccountState, useConnectModal } from "@crossbell/connect-kit" import { useTranslation } from "react-i18next" import { Logo } from "~/components/common/Logo" import { QuestionMarkCircleIcon } from "@heroicons/react/24/outline" +import { getStorage } from "~/lib/storage" +import { useGetPagesBySite } from "~/queries/page" export function DashboardLayout({ children, @@ -64,6 +66,26 @@ export function DashboardLayout({ const showNotificationModal = useShowNotificationModal() const { isAllRead } = useNotifications() + const pages = useGetPagesBySite({ + type: "post", + site: "xlog-events", + take: 1, + }) + const [isEventsAllRead, setIsEventsAllRead] = React.useState(true) + const latestEventRead = getStorage("latestEventRead")?.value || 0 + useEffect(() => { + if (pages.isSuccess) { + if ( + new Date(pages.data.pages[0].list?.[0].date_created) > + new Date(latestEventRead) + ) { + setIsEventsAllRead(false) + } else { + setIsEventsAllRead(true) + } + } + }, [pages.isSuccess, pages.data?.pages, latestEventRead]) + const links: { href?: string onClick?: () => void @@ -95,6 +117,12 @@ export function DashboardLayout({ icon: isAllRead ? "i-bi:bell" : "i-bi:bell-fill", text: isAllRead ? "Notifications" : "Unread notifications", }, + { + href: `/dashboard/${subdomain}/events`, + isActive: ({ href, pathname }) => href === pathname, + icon: isEventsAllRead ? "i-bi-gift" : "i-bi-gift-fill", + text: isEventsAllRead ? "Events" : "New Events", + }, { href: `/dashboard/${subdomain}/settings/general`, isActive: ({ pathname }) => @@ -195,7 +223,7 @@ export function DashboardLayout({
{isOpen && {t("Need help?")}} @@ -225,6 +253,9 @@ export function DashboardLayout({
Please switch account or request the owner to set you as the operator.
+ + Take me to my own dashboard +
) ) : ( diff --git a/src/models/page.model.ts b/src/models/page.model.ts index c4b07f83..8746ea9c 100644 --- a/src/models/page.model.ts +++ b/src/models/page.model.ts @@ -141,6 +141,7 @@ const expandPage = async (page: Note, useStat?: boolean) => { } } page.cover = rendered.cover + page.metadata!.frontMatter = rendered.frontMatter } page.slug = encodeURIComponent( page.attributes?.find((a) => a.trait_type === "xlog_slug")?.value || diff --git a/src/pages/dashboard/[subdomain]/events.tsx b/src/pages/dashboard/[subdomain]/events.tsx new file mode 100644 index 00000000..93cdc6c4 --- /dev/null +++ b/src/pages/dashboard/[subdomain]/events.tsx @@ -0,0 +1,194 @@ +import { DashboardLayout } from "~/components/dashboard/DashboardLayout" +import { DashboardMain } from "~/components/dashboard/DashboardMain" +import { UniLink } from "~/components/ui/UniLink" +import { Image } from "~/components/ui/Image" +import type { ReactElement } from "react" +import { useGetSite } from "~/queries/site" +import { useDate } from "~/hooks/useDate" +import { useTranslation } from "next-i18next" +import { getServerSideProps as getLayoutServerSideProps } from "~/components/dashboard/DashboardLayout.server" +import { GetServerSideProps } from "next" +import { serverSidePropsHandler } from "~/lib/server-side-props" +import { useGetPagesBySite } from "~/queries/page" +import { CharacterFloatCard } from "~/components/common/CharacterFloatCard" +import { useEffect, useState } from "react" +import { Avatar } from "~/components/ui/Avatar" +import { cn } from "~/lib/utils" +import { ChevronRightIcon } from "@heroicons/react/20/solid" +import { getSiteLink } from "~/lib/helpers" +import { getStorage, setStorage } from "~/lib/storage" + +export const getServerSideProps: GetServerSideProps = serverSidePropsHandler( + async (ctx) => { + const { props: layoutProps } = await getLayoutServerSideProps(ctx) + + return { + props: { + ...layoutProps, + }, + } + }, +) + +function SiteAvatar({ siteId }: { siteId: string }) { + const site = useGetSite(siteId) + return ( +
+ + + + + +
+ ) +} + +export default function EventsPage() { + const date = useDate() + const { t } = useTranslation("dashboard") + const pages = useGetPagesBySite({ + type: "post", + site: "xlog-events", + take: 100, + }) + + const [latestEventRead, setLatestEventRead] = useState() + + const [isMounted, setIsMounted] = useState(false) + + useEffect(() => { + setIsMounted(true) + setLatestEventRead(new Date(getStorage("latestEventRead")?.value || 0)) + setStorage("latestEventRead", { + value: new Date().toISOString(), + }) + }, []) + + pages.data?.pages[0]?.list.forEach((item) => { + item.metadata?.frontMatter?.Winners + }) + + return ( + +
+
+ {pages.data?.pages[0]?.list.map((item) => { + let status + if (item.metadata?.frontMatter?.EndTime < new Date()) { + status = "Ended" + } else if (item.metadata?.frontMatter?.StartTime > new Date()) { + status = "Upcoming" + } else { + status = "Ongoing" + } + + let isUnread = false + if ( + latestEventRead && + new Date(item.date_created) > latestEventRead + ) { + isUnread = true + } + return ( +
+ {isUnread && ( +
+ +
+ )} +
+
+
+ + {t(status)} + +
+ {item.cover && ( +
+ cover +
+ )} +
+ {item.title} +
+
+
+
+ {t("Date")}:{" "} + {date.formatDate( + item.metadata?.frontMatter?.StartTime, + "lll", + isMounted ? undefined : "America/Los_Angeles", + )}{" "} + -{" "} + {date.formatDate( + item.metadata?.frontMatter?.EndTime, + "lll", + isMounted ? undefined : "America/Los_Angeles", + )} +
+
+ {t("Prize")}:{" "} + {item.metadata?.frontMatter?.Prize} +
+
+ {t("Winners")}: +
+ {item.metadata?.frontMatter?.Winners.map( + (winner: string) => ( + + ), + )} +
+
+
+ + {t("Learn more")}{" "} + + +
+
+ ) + })} +
+
+
+ ) +} + +EventsPage.getLayout = (page: ReactElement) => { + return {page} +}