Hey is a decentralized and permissionless social media app built with Lens Protocol 馃尶
1import { Regex } from "@hey/data/regex";
2import { useCreateGroupMutation } from "@hey/indexer";
3import type { ApolloClientError } from "@hey/types/errors";
4import { group } from "@lens-protocol/metadata";
5import { useCallback, useState } from "react";
6import { z } from "zod";
7import AvatarUpload from "@/components/Shared/AvatarUpload";
8import {
9 Button,
10 Form,
11 Input,
12 TextArea,
13 useZodForm
14} from "@/components/Shared/UI";
15import errorToast from "@/helpers/errorToast";
16import uploadMetadata from "@/helpers/uploadMetadata";
17import useTransactionLifecycle from "@/hooks/useTransactionLifecycle";
18import { useCreateGroupStore } from "./CreateGroup";
19
20const ValidationSchema = z.object({
21 description: z.string().max(260, {
22 message: "Description should not exceed 260 characters"
23 }),
24 name: z
25 .string()
26 .max(100, { message: "Name should not exceed 100 characters" })
27 .regex(Regex.accountNameValidator, {
28 message: "Account name must not contain restricted symbols"
29 })
30});
31
32const CreateGroupModal = () => {
33 const { setScreen, setTransactionHash } = useCreateGroupStore();
34 const [pfpUrl, setPfpUrl] = useState<string | undefined>();
35 const [isSubmitting, setIsSubmitting] = useState(false);
36 const handleTransactionLifecycle = useTransactionLifecycle();
37
38 const form = useZodForm({
39 schema: ValidationSchema
40 });
41
42 const onCompleted = (hash: string) => {
43 setIsSubmitting(false);
44 setTransactionHash(hash);
45 setScreen("minting");
46 };
47
48 const onError = useCallback((error: ApolloClientError) => {
49 setIsSubmitting(false);
50 errorToast(error);
51 }, []);
52
53 const [createGroup] = useCreateGroupMutation({
54 onCompleted: async ({ createGroup }) => {
55 if (createGroup.__typename === "CreateGroupResponse") {
56 return onCompleted(createGroup.hash);
57 }
58
59 return await handleTransactionLifecycle({
60 onCompleted,
61 onError,
62 transactionData: createGroup
63 });
64 },
65 onError
66 });
67
68 const handleCreateGroup = async (data: z.infer<typeof ValidationSchema>) => {
69 setIsSubmitting(true);
70
71 const metadataUri = await uploadMetadata(
72 group({
73 description: data.description || undefined,
74 icon: pfpUrl,
75 name: data.name
76 })
77 );
78
79 return await createGroup({ variables: { request: { metadataUri } } });
80 };
81
82 return (
83 <Form className="space-y-4 p-5" form={form} onSubmit={handleCreateGroup}>
84 <Input label="Name" placeholder="Name" {...form.register("name")} />
85 <TextArea
86 label="Description"
87 placeholder="Please provide additional details"
88 {...form.register("description")}
89 />
90 <AvatarUpload
91 isSmall
92 setSrc={(src) => setPfpUrl(src)}
93 src={pfpUrl || ""}
94 />
95 <Button
96 className="flex w-full justify-center"
97 disabled={isSubmitting}
98 loading={isSubmitting}
99 type="submit"
100 >
101 Create group
102 </Button>
103 </Form>
104 );
105};
106
107export default CreateGroupModal;