feat: patron contract

This commit is contained in:
DIYgod 2023-03-14 18:05:46 +00:00
parent ed3e0b2e07
commit 1b2aad7d48
No known key found for this signature in database
6 changed files with 160 additions and 42 deletions

View File

@ -46,7 +46,7 @@
"canvas-confetti": "^1.6.0",
"chroma-js": "^2.4.2",
"clsx": "1.2.1",
"crossbell.js": "0.16.7",
"crossbell.js": "0.16.13",
"dayjs": "1.11.7",
"dotenv": "16.0.3",
"emoji-mart": "5.5.2",

View File

@ -58,7 +58,7 @@ specifiers:
chroma-js: ^2.4.2
clsx: 1.2.1
cross-spawn: 7.0.3
crossbell.js: 0.16.7
crossbell.js: 0.16.13
dayjs: 1.11.7
dotenv: 16.0.3
emoji-mart: 5.5.2
@ -163,7 +163,7 @@ dependencies:
canvas-confetti: 1.6.0
chroma-js: 2.4.2
clsx: 1.2.1
crossbell.js: 0.16.7
crossbell.js: 0.16.13
dayjs: 1.11.7
dotenv: 16.0.3
emoji-mart: 5.5.2
@ -1676,7 +1676,7 @@ packages:
canvas-confetti: 1.6.0
check-password-strength: 2.0.7
classnames: 2.3.2
crossbell.js: 0.16.7
crossbell.js: 0.16.13
detect-browser: 5.3.0
embla-carousel-react: 7.1.0_react@18.2.0
immer: 9.0.19
@ -1691,7 +1691,6 @@ packages:
transitivePeerDependencies:
- '@types/react'
- bufferutil
- node-fetch
- react-dom
- react-native
- supports-color
@ -1708,12 +1707,11 @@ packages:
dependencies:
'@crossbell/indexer': 0.0.41_mesmmewwopkmkl7hvhwkhlmhve
'@crossbell/util-hooks': 0.0.41_biqbaboplfbrettd7655fr4n2y
crossbell.js: 0.16.7
crossbell.js: 0.16.13
react: 18.2.0
wagmi: 0.11.7_osprwltll6etshz2owvseumghu
transitivePeerDependencies:
- bufferutil
- node-fetch
- react-dom
- react-native
- supports-color
@ -1727,14 +1725,13 @@ packages:
wagmi: ^0.11
dependencies:
'@tanstack/react-query': 4.24.10_biqbaboplfbrettd7655fr4n2y
crossbell.js: 0.16.7
crossbell.js: 0.16.13
dayjs: 1.11.7
lodash.compact: 3.0.1
lru-cache: 7.18.1
wagmi: 0.11.7_osprwltll6etshz2owvseumghu
transitivePeerDependencies:
- bufferutil
- node-fetch
- react
- react-dom
- react-native
@ -1742,6 +1739,10 @@ packages:
- utf-8-validate
dev: false
/@crossbell/ipfs-fetch/0.0.15:
resolution: {integrity: sha512-AYGDrwiSKqCGNDi0mEPP1k+96loWik+Pd40xH0MzRNM4RtCutPbwm4o+Sj5iWu0tlHoQC2bTs1XcufsLiv+WYw==}
dev: false
/@crossbell/notification/0.0.41_ogut4lnwvlvmg3jumn6qr7hh6u:
resolution: {integrity: sha512-5KjSzUC8SMEx7IHQyeSfLuUEAGI+NBmROxPwx4GAp/hqGIHYtuaz1vDqcINv9OzwnChkmNDuYucz9A1wVe33sg==}
peerDependencies:
@ -1766,7 +1767,6 @@ packages:
- bufferutil
- ethers
- immer
- node-fetch
- react-dom
- react-native
- supports-color
@ -1786,7 +1786,7 @@ packages:
'@crossbell/util-metadata': 0.0.41
'@tanstack/react-query': 4.24.10_biqbaboplfbrettd7655fr4n2y
classnames: 2.3.2
crossbell.js: 0.16.7
crossbell.js: 0.16.13
facepaint: 1.2.1
react: 18.2.0
react-dom: 18.2.0_react@18.2.0
@ -1798,7 +1798,6 @@ packages:
- '@types/react'
- bufferutil
- ethers
- node-fetch
- react-native
- supports-color
- typescript
@ -1816,11 +1815,10 @@ packages:
react: ^18
dependencies:
'@tanstack/react-query': 4.24.10_biqbaboplfbrettd7655fr4n2y
crossbell.js: 0.16.7
crossbell.js: 0.16.13
react: 18.2.0
transitivePeerDependencies:
- bufferutil
- node-fetch
- react-dom
- react-native
- supports-color
@ -1832,10 +1830,9 @@ packages:
dependencies:
'@crossbell/util-ethers': 0.0.41
'@fastify/deepmerge': 1.3.0
crossbell.js: 0.16.7
crossbell.js: 0.16.13
transitivePeerDependencies:
- bufferutil
- node-fetch
- supports-color
- utf-8-validate
dev: false
@ -6351,6 +6348,23 @@ packages:
which: 2.0.2
dev: true
/crossbell.js/0.16.13:
resolution: {integrity: sha512-nX1IBr6XKi0NtgV8SAtQwWhyebUA4zwlpIauFFNRsprScSE1dNbcsSKscwX9AXFB49ai6VhYOvPNpG+k8YjGww==}
dependencies:
'@crossbell/ipfs-fetch': 0.0.15
async-retry: 1.3.3
browser-or-node: 2.1.1
ethers: 5.7.2
fetch-undici: 3.0.1
p-limit: 3.1.0
ts-mixer: 6.0.3
web3-providers-ws: 1.8.2
transitivePeerDependencies:
- bufferutil
- supports-color
- utf-8-validate
dev: false
/crossbell.js/0.16.2:
resolution: {integrity: sha512-Rgy1v6EmXy0ou9JVRezMHfUp3L9OHAub0d8jExoN3iJPQtvd0jopy0QNONL0ShvIJxTsiCwM1rg9SAA5sw6gZQ==}
dependencies:
@ -6368,24 +6382,6 @@ packages:
- utf-8-validate
dev: false
/crossbell.js/0.16.7:
resolution: {integrity: sha512-qr6QRdpPKNVsv7pjazqJGmz2s92MBaH+jaf91u/hgNCYILFKOIAuntnpKGLmP/r3HMccopUUwxxBSH/W9QrAxg==}
dependencies:
async-retry: 1.3.3
browser-or-node: 2.1.1
ethers: 5.7.2
fetch-undici: 3.0.1
is-ipfs: 6.0.2
p-limit: 3.1.0
ts-mixer: 6.0.3
web3-providers-ws: 1.8.2
transitivePeerDependencies:
- bufferutil
- node-fetch
- supports-color
- utf-8-validate
dev: false
/crypto-random-string/2.0.0:
resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==}
engines: {node: '>=8'}
@ -7624,7 +7620,7 @@ packages:
resolution: {integrity: sha512-UHHu1HqW22ZhK6C/1Zmjf7mQpOwPwLYZ+xcsOgpzistONU8QqvCop6Od29p/kw1GUVoq2Ihu6ItpKLtlojx4FQ==}
engines: {node: '>=16'}
dependencies:
undici: 5.20.0
undici: 5.21.0
dev: false
/file-entry-cache/6.0.1:
@ -8065,7 +8061,7 @@ packages:
engines: {node: '>=4'}
dependencies:
inherits: 2.0.4
readable-stream: 3.6.1
readable-stream: 3.6.2
safe-buffer: 5.2.1
dev: false
@ -11385,6 +11381,15 @@ packages:
util-deprecate: 1.0.2
dev: false
/readable-stream/3.6.2:
resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
engines: {node: '>= 6'}
dependencies:
inherits: 2.0.4
string_decoder: 1.3.0
util-deprecate: 1.0.2
dev: false
/readdirp/3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
@ -12859,8 +12864,8 @@ packages:
jiti: 1.17.1
dev: true
/undici/5.20.0:
resolution: {integrity: sha512-J3j60dYzuo6Eevbawwp1sdg16k5Tf768bxYK4TUJRH7cBM4kFCbf3mOnM/0E3vQYXvpxITbbWmBafaDbxLDz3g==}
/undici/5.21.0:
resolution: {integrity: sha512-HOjK8l6a57b2ZGXOcUsI5NLfoTrfmbOl90ixJDl0AEFG4wgHNDQxtZy15/ZQp7HhjkpaGlp/eneMgtsu1dIlUA==}
engines: {node: '>=12.18'}
dependencies:
busboy: 1.6.0

View File

@ -4,11 +4,15 @@ import { useTranslation } from "next-i18next"
import { HeartIcon } from "@heroicons/react/24/solid"
import { cn } from "~/lib/utils"
import { Modal } from "~/components/ui/Modal"
import { useState } from "react"
import { useEffect, useRef, useState } from "react"
import { BoxRadio } from "~/components/ui/BoxRadio"
import { CharacterCard } from "~/components/common/CharacterCard"
import { QuestionMarkCircleIcon } from "@heroicons/react/24/outline"
import { Tabs } from "../ui/Tabs"
import { useTipCharacter, useGetTips } from "~/queries/site"
import { useAccountState } from "@crossbell/connect-kit"
import { toast } from "react-hot-toast"
import confetti from "canvas-confetti"
export const PatronModal: React.FC<{
site: Profile | undefined | null
@ -16,6 +20,11 @@ export const PatronModal: React.FC<{
setOpen: (open: boolean) => void
}> = ({ site, open, setOpen }) => {
const { t } = useTranslation("common")
const tipCharacter = useTipCharacter()
// const tips = useGetTips({
// toCharacterId: site?.metadata?.proof,
// })
// console.log(tips.data)
const radios = [
{
@ -45,10 +54,48 @@ export const PatronModal: React.FC<{
const [value, setValue] = useState(radios[1].value!)
const currentCharacterId = useAccountState(
(s) => s.computed.account?.characterId,
)
const submit = () => {
console.log(value)
if (currentCharacterId && site?.metadata?.proof && parseInt(value)) {
tipCharacter.mutate({
fromCharacterId: currentCharacterId,
toCharacterId: site?.metadata?.proof,
amount: parseInt(value),
})
}
}
const submitRef = useRef<HTMLButtonElement>(null)
useEffect(() => {
if (!tipCharacter.isSuccess) {
if (submitRef.current?.getBoundingClientRect()) {
confetti({
particleCount: 150,
spread: 70,
origin: {
x:
(submitRef.current.getBoundingClientRect().left +
submitRef.current.getBoundingClientRect().width / 2 || 0.5) /
window.innerWidth,
y:
(submitRef.current.getBoundingClientRect().top || 0.5) /
window.innerHeight,
},
})
}
}
}, [tipCharacter.isSuccess, t, site?.name])
useEffect(() => {
if (tipCharacter.isError) {
toast.error(t("Failed to become a patron"))
}
}, [tipCharacter.isError, t])
return (
<Modal
open={open}
@ -99,7 +146,16 @@ export const PatronModal: React.FC<{
</p>
</div>
<div>
<Button variant="primary" className="w-full" onClick={submit}>
<Button
variant="primary"
className="w-full"
onClick={submit}
style={{
height: "2.5rem",
}}
isLoading={tipCharacter.isLoading}
ref={submitRef}
>
{t("Become a patron to {{name}}", {
name: site?.name,
})}

View File

@ -43,7 +43,10 @@ export const BoxRadio: React.FC<{
<div className="grid gap-4 grid-cols-3">
{items.map((item) => {
return (
<div key={item.value} className="relative w-full min-h-[80px]">
<div
key={item.value || item.text}
className="relative w-full min-h-[80px]"
>
{item.value ? (
<>
<input

View File

@ -511,3 +511,25 @@ export async function getStat({ characterId }: { characterId: string }) {
}
}
}
export async function tipCharacter(
input: {
fromCharacterId: string | number
toCharacterId: string | number
amount: number
},
contract: Contract,
) {
return await contract?.tipCharacter(
input.fromCharacterId,
input.toCharacterId,
input.amount,
)
}
export async function getTips(input: { toCharacterId: string | number }) {
return await indexer?.getTips({
toCharacterId: input.toCharacterId,
tokenAddress: "0xAfB95CC0BD320648B3E8Df6223d9CDD05EbeDC64",
})
}

View File

@ -302,3 +302,35 @@ export const useGetStat = (
})
})
}
export function useTipCharacter() {
const queryClient = useQueryClient()
const contract = useContract()
const mutation = useMutation(
async (payload: Parameters<typeof siteModel.tipCharacter>[0]) => {
return siteModel.tipCharacter(payload, contract)
},
{
onSuccess: (data, variables) => {
queryClient.invalidateQueries([
"getTips",
{
toCharacterId: variables.toCharacterId,
},
])
},
},
)
return mutation
}
export const useGetTips = (data: { toCharacterId?: string }) => {
return useQuery(["getTips", data], async () => {
if (!data.toCharacterId) {
return null
}
return siteModel.getTips({
toCharacterId: data.toCharacterId,
})
})
}