feat: dashboard notifications list
This commit is contained in:
parent
47d489ea56
commit
a3425eb9df
|
|
@ -56,5 +56,9 @@
|
|||
"jingfelix",
|
||||
"tongyi",
|
||||
"mayx",
|
||||
"tcj"
|
||||
"tcj",
|
||||
"atlas",
|
||||
"meow-7218",
|
||||
"erection",
|
||||
"vup"
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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 }) =>
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
|
@ -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,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue