feat: dashboard notifications list

This commit is contained in:
DIYgod 2022-10-31 01:11:18 +00:00
parent 47d489ea56
commit a3425eb9df
No known key found for this signature in database
GPG Key ID: D159328F47A80DCA
6 changed files with 212 additions and 2 deletions

View File

@ -56,5 +56,9 @@
"jingfelix",
"tongyi",
"mayx",
"tcj"
"tcj",
"atlas",
"meow-7218",
"erection",
"vup"
]

View File

@ -64,6 +64,12 @@ export function DashboardLayout({
icon: "i-bi-window-stack",
text: "Pages",
},
{
href: `/dashboard/${subdomain}/notifications`,
isActive: ({ href, pathname }) => href === pathname,
icon: "i-bi:bell",
text: "Notifications",
},
{
href: `/dashboard/${subdomain}/settings/general`,
isActive: ({ pathname }) =>

View File

@ -10,7 +10,7 @@ export const DashboardMain: React.FC<{
className={clsx(
fullWidth
? "relative"
: "max-w-screen-xl relative px-5 py-5 md:px-10",
: "max-w-screen-2xl relative px-5 py-5 md:px-10",
)}
>
{children}

View File

@ -6,6 +6,8 @@ import { toGateway } from "~/lib/ipfs-parser"
import type Unidata from "unidata.js"
import { createClient } from "@urql/core"
import axios from "axios"
import { indexer } from "~/queries/crossbell"
import type { LinkEntity, NoteEntity } from "crossbell.js"
export const checkSubdomain = async ({
subdomain,
@ -341,3 +343,44 @@ export async function unsubscribeFromSite(
},
)
}
export async function getNotifications(input: { siteCId: string }) {
const [subscriptions, notes] = await Promise.all([
indexer.getBacklinksOfCharacter(input.siteCId, {
limit: 100,
}),
indexer.getNotes({
toCharacterId: input.siteCId,
limit: 100,
includeCharacter: true,
}),
])
return [
...(subscriptions.list.map(
(
item: LinkEntity & {
type?: "backlinks"
},
) => {
item.type = "backlinks"
return item
},
) as any),
]
.concat(
notes.list.map(
(
item: NoteEntity & {
type?: "notes"
},
) => {
item.type = "notes"
return item
},
),
)
.sort((a, b) => {
return b.createdAt > a.createdAt ? 1 : -1
})
}

View File

@ -0,0 +1,146 @@
import { useRouter } from "next/router"
import { DashboardLayout } from "~/components/dashboard/DashboardLayout"
import { DashboardMain } from "~/components/dashboard/DashboardMain"
import { UniLink } from "~/components/ui/UniLink"
import { getSiteLink } from "~/lib/helpers"
import { useGetNotifications, useGetSite } from "~/queries/site"
import { CharacterCard } from "~/components/common/CharacterCard"
import { Avatar } from "~/components/ui/Avatar"
import dayjs from "dayjs"
import duration from "dayjs/plugin/duration"
import relativeTime from "dayjs/plugin/relativeTime"
import { BlockchainIcon } from "~/components/icons/BlockchainIcon"
import { CSB_SCAN } from "~/lib/env"
import { PageContent } from "~/components/common/PageContent"
dayjs.extend(duration)
dayjs.extend(relativeTime)
export default function SubdomainIndex() {
const router = useRouter()
const subdomain = router.query.subdomain as string
const site = useGetSite(subdomain)
const notifications = useGetNotifications({
siteCId: site.data?.metadata?.proof,
})
return (
<DashboardLayout title="Dashboard">
<DashboardMain>
<h2 className="text-2xl font-bold">Notifications</h2>
<div className="xlog-comment">
<div className="prose space-y-4 pt-4">
{notifications.data?.map((notification) => {
let key = ""
let character
let message = ""
switch (notification.type) {
case "notes":
if (
!notification.toNote.metadata?.content?.sources?.includes(
"xlog",
)
) {
return null
}
key = notification.characterId + notification.noteId
character = notification?.character
message = "commented on your post"
break
case "backlinks":
key = notification.fromCharacter.handle
character = notification.fromCharacter
message = "follows you"
break
}
return (
<div key={key} className="border-t border-dashed pt-4">
<div className="flex group items-center">
<div>
<CharacterCard siteId={character?.handle}>
<div>
<UniLink
href={
character?.handle &&
getSiteLink({
subdomain: character.handle,
})
}
className="block align-middle mr-3"
>
<Avatar
images={
character?.metadata?.content?.avatars || []
}
name={character?.metadata?.content?.name}
size={35}
/>
</UniLink>
</div>
</CharacterCard>
</div>
<div className="flex-1 flex flex-col rounded-lg">
<div className="mb-1 text-sm">
<UniLink
href={
character?.handle &&
getSiteLink({
subdomain: character.handle,
})
}
className="font-medium text-accent"
>
{character?.metadata?.content?.name ||
character?.handle}
</UniLink>{" "}
{message}{" "}
<UniLink
href={`${getSiteLink({
subdomain: notification.toCharacter?.handle || "",
})}/${
notification.toNote?.metadata?.content?.attributes?.find(
(attribute: any) =>
attribute.trait_type === "xlog_slug",
)?.value ||
notification.toNote?.characterId +
"-" +
notification.toNote?.noteId
}`}
>
{notification.toNote?.metadata?.content?.title}
</UniLink>{" "}
·{" "}
{dayjs
.duration(
dayjs(notification?.createdAt).diff(
dayjs(),
"minute",
),
"minute",
)
.humanize()}{" "}
ago ·{" "}
<UniLink
href={`${CSB_SCAN}/tx/${notification.transactionHash}`}
>
<BlockchainIcon className="w-3 h-3 inline-block" />
</UniLink>
</div>
<PageContent
content={notification.metadata?.content?.content}
></PageContent>
</div>
</div>
</div>
)
})}
</div>
</div>
</DashboardMain>
</DashboardLayout>
)
}

View File

@ -130,3 +130,14 @@ export function useUnsubscribeFromSite() {
},
)
}
export const useGetNotifications = (data: { siteCId?: string }) => {
return useQuery(["getNotifications", data], async () => {
if (!data.siteCId) {
return null
}
return siteModel.getNotifications({
siteCId: data.siteCId,
})
})
}