diff --git a/public/locales/zh/common.json b/public/locales/zh/common.json
index 42b49087..57773408 100644
--- a/public/locales/zh/common.json
+++ b/public/locales/zh/common.json
@@ -55,11 +55,14 @@
"Patron": "赞助",
"Become a patron of {{name}}" : "成为 {{name}} 的赞助者",
"Latest patrons": "最近赞助者",
+ "Latest tipper": "最近赞赏者",
"You are here to be the first patron.": "你将是第一个赞助者。",
+ "You are here to be the first tipper.": "你将是第一个赞赏者。",
"Select a tier": "选择一个等级",
"One-time": "一次性",
"Monthly and NFT Rewards": "每月和 NFT 奖励",
"Coming soon": "即将推出",
"What is Mira? Where can I get some?" : "Mira 是什么?我在哪里可以获得?",
- "Tip": "赞赏"
+ "Tip": "赞赏",
+ "Tip the post: {{name}}": "赞赏文章:{{name}}"
}
\ No newline at end of file
diff --git a/src/components/common/PatronModal.tsx b/src/components/common/PatronModal.tsx
index 3b64f5bf..d8235d22 100644
--- a/src/components/common/PatronModal.tsx
+++ b/src/components/common/PatronModal.tsx
@@ -1,5 +1,5 @@
import { Button } from "~/components/ui/Button"
-import { Profile } from "~/lib/types"
+import { Note, Profile } from "~/lib/types"
import { useTranslation } from "next-i18next"
import { HeartIcon } from "@heroicons/react/24/solid"
import { Modal } from "~/components/ui/Modal"
@@ -16,16 +16,19 @@ import { CharacterFloatCard } from "./CharacterFloatCard"
import { UniLink } from "../ui/UniLink"
import { getSiteLink } from "~/lib/helpers"
import { CSB_SCAN } from "~/lib/env"
+import { parsePageId } from "~/models/page.model"
export const PatronModal: React.FC<{
site: Profile | undefined | null
+ page?: Note | null
open: boolean
setOpen: (open: boolean) => void
-}> = ({ site, open, setOpen }) => {
+}> = ({ site, page, open, setOpen }) => {
const { t } = useTranslation("common")
const tipCharacter = useTipCharacter()
const tips = useGetTips({
toCharacterId: site?.metadata?.proof,
+ toNoteId: parsePageId(page?.id || "").noteId,
})
const radios = [
@@ -66,6 +69,7 @@ export const PatronModal: React.FC<{
fromCharacterId: currentCharacterId,
toCharacterId: site?.metadata?.proof,
amount: parseInt(value),
+ noteId: parsePageId(page?.id || "").noteId,
})
}
}
@@ -100,15 +104,20 @@ export const PatronModal: React.FC<{
}
}, [tipCharacter.isError, t])
+ const title =
+ (page
+ ? t("Tip the post: {{name}}", {
+ name: page.title,
+ })
+ : t("Become a patron of {{name}}", {
+ name: site?.name,
+ })) || ""
+
return (
}
size="lg"
>
@@ -131,12 +140,14 @@ export const PatronModal: React.FC<{
)}
-
{t("Latest patrons")}
+
+ {t(page ? "Latest tipper" : "Latest patrons")}
+
- {tips.data?.list?.length ? (
+ {tips.data?.pages?.[0]?.list?.length ? (
<>
-
- {tips.data.list?.map((tip, index) => (
+
+ {tips.data.pages[0].list?.map((tip, index) => (
@@ -167,17 +178,21 @@ export const PatronModal: React.FC<{
))}
- {tips.data.count > 10 && (
+ {tips.data.pages?.[0]?.count > 8 && (
-
- +{tips.data.count - 10}
+
+ +{tips.data.pages?.[0]?.count - 8}
)}
>
) : (
- t("You are here to be the first patron.")
+ t(
+ page
+ ? "You are here to be the first tipper."
+ : "You are here to be the first patron.",
+ )
)}
@@ -219,9 +234,7 @@ export const PatronModal: React.FC<{
isLoading={tipCharacter.isLoading}
ref={submitRef}
>
- {t("Become a patron of {{name}}", {
- name: site?.name,
- })}
+
{title}
diff --git a/src/components/common/Reactions.tsx b/src/components/common/Reactions.tsx
index 961271c0..630699bf 100644
--- a/src/components/common/Reactions.tsx
+++ b/src/components/common/Reactions.tsx
@@ -7,7 +7,7 @@ import {
useToggleLikePage,
useGetLikeCounts,
} from "~/queries/page"
-import { useAccountSites } from "~/queries/site"
+import { useAccountSites, useGetTips } from "~/queries/site"
import { useState, useEffect, useRef } from "react"
import { Button } from "../ui/Button"
import { CSB_SCAN, CSB_XCHAR } from "~/lib/env"
@@ -21,20 +21,24 @@ import { cn } from "~/lib/utils"
import { Tooltip } from "~/components/ui/Tooltip"
import confetti from "canvas-confetti"
import { Trans, useTranslation } from "next-i18next"
-import { Profile } from "~/lib/types"
+import { Note, Profile } from "~/lib/types"
+import { HeartIcon } from "@heroicons/react/24/solid"
+import { useAccountState } from "@crossbell/connect-kit"
+import { PatronModal } from "~/components/common/PatronModal"
export const Reactions: React.FC<{
className?: string
size?: "sm" | "base"
pageId?: string
site?: Profile | null
-}> = ({ className, size, pageId, site }) => {
+ page?: Note | null
+}> = ({ className, size, pageId, site, page }) => {
const toggleLikePage = useToggleLikePage()
const mintPage = useMintPage()
const { t } = useTranslation("common")
// like
- const userSite = useAccountSites()
+ const account = useAccountState((s) => s.computed.account)
const [isLikeOpen, setIsLikeOpen] = useState(false)
const [isLikeListOpen, setIsLikeListOpen] = useState(false)
const likeRef = useRef(null)
@@ -134,6 +138,27 @@ export const Reactions: React.FC<{
}
}, [mintPage.isSuccess])
+ // tip
+ const [isTipOpen, setIsTipOpen] = useState(false)
+ const tipRef = useRef(null)
+
+ const { characterId, noteId } = parsePageId(pageId || "")
+ const tips = useGetTips({
+ toCharacterId: characterId,
+ toNoteId: noteId,
+ })
+ const isTip = useGetTips({
+ toCharacterId: characterId,
+ toNoteId: noteId,
+ characterId: account?.characterId,
+ })
+
+ const tip = () => {
+ if (pageId) {
+ setIsTipOpen(true)
+ }
+ }
+
return (
<>
{(() => {
@@ -260,6 +285,58 @@ export const Reactions: React.FC<{
)}
+ {size !== "sm" && (
+
+
+ {(() => {
+ const inner =
+ return (
+
+ {inner}
+
+ )
+ })()}
+ {tips.data?.pages?.[0]?.count || 0}
+
+ {
+
+ }
+
+ )}
xChar
{" "}
@@ -311,6 +388,12 @@ export const Reactions: React.FC<{
+
= ({ page, site }) => {
return (
<>
-
+
>
)
diff --git a/src/components/ui/Button.tsx b/src/components/ui/Button.tsx
index dfc9f2ff..72da4594 100644
--- a/src/components/ui/Button.tsx
+++ b/src/components/ui/Button.tsx
@@ -15,7 +15,7 @@ export type Variant =
| "collect"
| "crossbell"
| "outline"
- | "patron"
+ | "tip"
export type VariantColor = "green" | "red" | "gray" | "gradient" | "black"
diff --git a/src/components/ui/Modal.tsx b/src/components/ui/Modal.tsx
index 0f0828ac..6f276db4 100644
--- a/src/components/ui/Modal.tsx
+++ b/src/components/ui/Modal.tsx
@@ -40,7 +40,7 @@ export const Modal: React.FC<{
{title && (
{titleIcon && {titleIcon} }
- {title}
+ {title}
)}
{children}
diff --git a/src/css/tailwind.css b/src/css/tailwind.css
index 040b9ec6..0f401675 100644
--- a/src/css/tailwind.css
+++ b/src/css/tailwind.css
@@ -153,15 +153,15 @@ a {
fill: #ffcf55;
}
-.button.is-patron {
+.button.is-tip {
@apply shadow-none p-0;
@apply text-gray-500 fill-gray-500;
}
-.button.is-patron:hover {
+.button.is-tip:hover {
color: #f87171;
fill: #f87171;
}
-.button.is-patron.active {
+.button.is-tip.active {
color: #f87171;
fill: #f87171;
}
diff --git a/src/models/site.model.ts b/src/models/site.model.ts
index 70705ccf..e610ae68 100644
--- a/src/models/site.model.ts
+++ b/src/models/site.model.ts
@@ -520,27 +520,45 @@ export async function tipCharacter(
fromCharacterId: string | number
toCharacterId: string | number
amount: number
+ noteId?: string | number
},
contract: Contract,
) {
const decimals = await contract.getMiraTokenDecimals()
- return await contract?.tipCharacter(
- input.fromCharacterId,
- input.toCharacterId,
- BigInt(input.amount) * BigInt(10) ** BigInt(decimals?.data || 18),
- )
+ if (input.noteId) {
+ return await contract?.tipCharacterForNote(
+ input.fromCharacterId,
+ input.toCharacterId,
+ input.noteId,
+ BigInt(input.amount) * BigInt(10) ** BigInt(decimals?.data || 18),
+ )
+ } else {
+ return await contract?.tipCharacter(
+ input.fromCharacterId,
+ input.toCharacterId,
+ BigInt(input.amount) * BigInt(10) ** BigInt(decimals?.data || 18),
+ )
+ }
}
export async function getTips(
- input: { toCharacterId: string | number },
+ input: {
+ toCharacterId: string | number
+ characterId?: string | number
+ toNoteId?: string | number
+ cursor?: string
+ },
contract: Contract,
) {
const address = await contract.getMiraTokenAddress()
const tips = await indexer?.getTips({
+ characterId: input.characterId,
+ toNoteId: input.toNoteId,
toCharacterId: input.toCharacterId,
tokenAddress: address?.data || "0xAfB95CC0BD320648B3E8Df6223d9CDD05EbeDC64",
includeMetadata: true,
limit: 8,
+ cursor: input.cursor,
})
if (tips?.list?.length) {
diff --git a/src/queries/site.ts b/src/queries/site.ts
index 1b4da9e9..7e165f89 100644
--- a/src/queries/site.ts
+++ b/src/queries/site.ts
@@ -1,4 +1,9 @@
-import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"
+import {
+ useQuery,
+ useMutation,
+ useQueryClient,
+ useInfiniteQuery,
+} from "@tanstack/react-query"
import { useContract } from "@crossbell/contract"
import {
useAccountState,
@@ -324,17 +329,29 @@ export function useTipCharacter() {
return mutation
}
-export const useGetTips = (data: { toCharacterId?: string }) => {
+export const useGetTips = (
+ data: Partial[0]>,
+) => {
const contract = useContract()
- return useQuery(["getTips", data], async () => {
- if (!data.toCharacterId) {
- return null
- }
- return siteModel.getTips(
- {
- toCharacterId: data.toCharacterId,
- },
- contract,
- )
+ return useInfiniteQuery({
+ queryKey: ["getTips", data],
+ queryFn: async ({ pageParam }) => {
+ if (!data.toCharacterId) {
+ return {
+ count: 0,
+ list: [],
+ cursor: undefined,
+ }
+ }
+ return siteModel.getTips(
+ {
+ ...data,
+ toCharacterId: data.toCharacterId,
+ cursor: pageParam,
+ },
+ contract,
+ )
+ },
+ getNextPageParam: (lastPage) => lastPage.cursor || undefined,
})
}