feat: can add contributor

This commit is contained in:
0xzio
2024-08-24 13:17:02 +08:00
parent ebbad33a18
commit 70be5589fa
5 changed files with 55 additions and 47 deletions

View File

@@ -17,7 +17,9 @@ export function AddContributorDialog() {
return (
<Dialog open={isOpen} onOpenChange={(v) => setIsOpen(v)}>
<DialogTrigger asChild>
<Button onClick={() => setIsOpen(true)}>Add Contributor</Button>
<Button className="rounded-xl" onClick={() => setIsOpen(true)}>
Add Contributor
</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>

View File

@@ -1,5 +1,6 @@
'use client'
import { useState } from 'react'
import { useForm } from 'react-hook-form'
import LoadingDots from '@/components/icons/loading-dots'
import { Button } from '@/components/ui/button'
@@ -12,13 +13,13 @@ import {
FormMessage,
} from '@/components/ui/form'
import { Input } from '@/components/ui/input'
import { channelsAtom } from '@/hooks/useChannels'
import { useContributors } from '@/hooks/useContributors'
import { useSpace } from '@/hooks/useSpace'
import { spaceAbi } from '@/lib/abi'
import { checkChain } from '@/lib/checkChain'
import { extractErrorMessage } from '@/lib/extractErrorMessage'
import { api, trpc } from '@/lib/trpc'
import { wagmiConfig } from '@/lib/wagmi'
import { store } from '@/store'
import { zodResolver } from '@hookform/resolvers/zod'
import { readContract, writeContract } from '@wagmi/core'
import { toast } from 'sonner'
@@ -33,53 +34,53 @@ const FormSchema = z.object({
.string()
.min(1, { message: 'Address is required' })
.regex(ethAddressRegex, { message: 'Invalid Ethereum address' }),
share: z
.string()
.min(1, { message: 'Share cannot be empty' })
.regex(/^\d+$/, { message: 'Share must be a numeric string' }),
})
export function AddContributorForm() {
const [isLoading, setLoading] = useState(false)
const { isPending, mutateAsync } = trpc.contributor.create.useMutation()
const { setIsOpen } = useAddContributorDialog()
const { space } = useSpace()
const { contributors = [], refetch } = useContributors()
const form = useForm<z.infer<typeof FormSchema>>({
resolver: zodResolver(FormSchema),
defaultValues: {
address: '',
share: '',
},
})
async function onSubmit(data: z.infer<typeof FormSchema>) {
try {
setLoading(true)
await checkChain()
const some = contributors.find((c) => c.user.address === data.address)
if (some) {
setLoading(false)
return toast.error('This address has already been added.')
}
await writeContract(wagmiConfig, {
address: space.spaceAddress as Address,
abi: spaceAbi,
functionName: 'addContributor',
args: [data.address as Address],
})
await mutateAsync({
spaceId: space.id,
address: data.address,
share: data.share,
})
refetch()
// await writeContract(wagmiConfig, {
// address: space.spaceAddress as Address,
// abi: spaceAbi,
// functionName: 'addContributor',
// args: [
// {
// account: data.address as Address,
// shares: BigInt(data.share),
// },
// ],
// })
// const channels = await api.channel.listBySpaceId.query(space.id)
// store.set(channelsAtom, channels)
setIsOpen(false)
toast.success('Add Contributor successfully!')
} catch (error) {
const msg = extractErrorMessage(error)
toast.error(msg || 'Failed to add Contributor. Please try again.')
}
setLoading(false)
}
return (
@@ -99,22 +100,12 @@ export function AddContributorForm() {
)}
/>
<FormField
control={form.control}
name="share"
render={({ field }) => (
<FormItem className="w-full">
<FormLabel>Share</FormLabel>
<FormControl>
<Input placeholder="" {...field} className="w-full" />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit" className="w-full">
{isPending ? <LoadingDots color="#808080" /> : <p>Add</p>}
<Button
type="submit"
className="w-full"
disabled={isLoading || !form.formState.isValid}
>
{isLoading ? <LoadingDots color="#808080" /> : <p>Add</p>}
</Button>
</form>
</Form>

View File

@@ -1,20 +1,20 @@
'use client'
import { Badge } from '@/components/ui/badge'
import { Skeleton } from '@/components/ui/skeleton'
import { UserAvatar } from '@/components/UserAvatar'
import { useContributors } from '@/hooks/useContributors'
import { useSpace } from '@/hooks/useSpace'
import { trpc } from '@/lib/trpc'
import { cn, shortenAddress } from '@/lib/utils'
export function ContributorList() {
const { space } = useSpace()
const { data = [], isLoading } = trpc.contributor.listBySpaceId.useQuery(
space.id,
)
const { contributors = [], isLoading } = useContributors()
if (isLoading) {
return (
<div className="grid gap-4 mx-auto w-[800x] md:w-[800px] sm:w-full mt-6">
<div className="grid gap-4 mt-6">
{Array(5)
.fill('')
.map((_, i) => (
@@ -24,7 +24,7 @@ export function ContributorList() {
)
}
if (!data.length) {
if (!contributors.length) {
return (
<div className="grid gap-4 mx-auto sm:w-full mt-6 text-neutral-400">
No contributors yet.
@@ -34,7 +34,7 @@ export function ContributorList() {
return (
<div className="space-y-3 mt-8">
{data.map((item) => (
{contributors.map((item) => (
<div key={item.id} className="flex justify-between">
<div className="flex gap-2 items-center">
<UserAvatar user={item.user} />
@@ -44,9 +44,13 @@ export function ContributorList() {
? item.user.ensName
: shortenAddress(item.user.address)}
</div>
{space.userId === item.user.id && <Badge>Founder</Badge>}
{space.userId !== item.user.id && (
<Badge variant="outline">Shareholder</Badge>
)}
</div>
<div>
<span className="font-bold">{item.shares}</span> share
<span className="font-bold">{item.shares}</span> shares
</div>
</div>
))}

11
hooks/useContributors.ts Normal file
View File

@@ -0,0 +1,11 @@
import { trpc } from '@/lib/trpc'
import { useSpace } from './useSpace'
export function useContributors() {
const { space } = useSpace()
const { data: contributors = [], ...rest } =
trpc.contributor.listBySpaceId.useQuery(space.id, {
enabled: !!space?.id,
})
return { contributors, ...rest }
}

View File

@@ -8,6 +8,7 @@ export const contributorRouter = router({
.query(async ({ input }) => {
return [] as (Contributor & {
user: {
id: string
name: string | null
ensName: string | null
email: string | null
@@ -25,7 +26,6 @@ export const contributorRouter = router({
z.object({
spaceId: z.string(),
address: z.string(),
share: z.string(),
}),
)
.mutation(async ({ ctx, input }) => {