diff --git a/frontend/app/page.tsx b/frontend/app/page.tsx index d9a0847..6e48d48 100644 --- a/frontend/app/page.tsx +++ b/frontend/app/page.tsx @@ -28,7 +28,7 @@ export default function Home() { - + diff --git a/frontend/components/post/NewPost.tsx b/frontend/components/post/NewPost.tsx index 0f3f7c9..ccda9fd 100644 --- a/frontend/components/post/NewPost.tsx +++ b/frontend/components/post/NewPost.tsx @@ -29,7 +29,7 @@ export default function NewPost({ const selectType = (selected: PostType) => { setType(selected); - if (selected !== 'post' && (isVerified as number) < 2) { + if ((isVerified as number) < 2) { setNeedVerify(true) } } @@ -60,7 +60,7 @@ export default function NewPost({ } const userProps = { ...props, contract: userContract, refetch }; - const postProps = { ...props, contract: postContract, type: type ?? 'post', refetch: refetchPosts }; + const postProps = { ...props, contract: postContract, type: type ?? 'announcement', refetch: refetchPosts }; const modalBody = () => { if (needVerify && isVerified == 0) { diff --git a/frontend/components/post/RandomAvatar.tsx b/frontend/components/post/RandomAvatar.tsx index 1b37937..39bea2d 100644 --- a/frontend/components/post/RandomAvatar.tsx +++ b/frontend/components/post/RandomAvatar.tsx @@ -1,10 +1,11 @@ import { useUserInfo } from "@/hooks/useUserInfo"; import getPostContent from "@/utils/getPostContent"; -import { PostContent, PostItem } from "@/utils/types"; +import { PostItem, UserInfo } from "@/utils/types"; import { useEffect, useState } from "react"; import UserModal from "../user/UserModal"; import { sendTx } from "@/utils/sendTx"; import { toast } from "react-hot-toast"; +import Skeleton from "./Skeleton"; export default function RandomAvatar({ author, @@ -20,7 +21,7 @@ export default function RandomAvatar({ const index = Math.floor(Math.random() * 6); const { data: cid } = useUserInfo(author); const [showUserModal, setShowUserModal] = useState(false); - const [authorInfo, setAuthorInfo] = useState(null); + const [authorInfo, setAuthorInfo] = useState(null); useEffect(() => { if (cid) { @@ -57,6 +58,12 @@ export default function RandomAvatar({ } + if (!authorInfo) { + return + } + + const { description, token, chatId, website } = authorInfo; + return ( <>
{authorInfo.description}
)} -
- { authorInfo?.type } -
{showUserModal && ( -
-
- Project Owner -
- {POST_TYPES.map((pt) => ( - - ))} +
+
+ Project Owner
-
-
-
- Web3er -
+ {POST_TYPES.map((pt) => ( -
+ ))}
) } diff --git a/frontend/components/push/ChatList.tsx b/frontend/components/push/ChatList.tsx index 5438d46..26eff8c 100644 --- a/frontend/components/push/ChatList.tsx +++ b/frontend/components/push/ChatList.tsx @@ -1,3 +1,4 @@ +/* eslint-disable @next/next/no-img-element */ 'use client' import { IFeeds, PushAPI, viemSignerType } from "@pushprotocol/restapi"; @@ -6,16 +7,15 @@ import { useEffect, useState } from "react"; import { useWalletClient } from "wagmi"; import MainButton from "../button/MainButton"; import EmptyText from "../EmptyText"; -import { useUserInfo } from "@/hooks/useUserInfo"; -import { AccessTokenProps, PostContent } from "@/utils/types"; -import getPostContent from "@/utils/getPostContent"; +import ChatModal from "./ChatModal"; -export default function ChatList({web3StorageAccessToken} : AccessTokenProps) { +export default function ChatList() { const { data: walletClient } = useWalletClient(); const [chats, setChats] = useState([]); const [showChat, setShowChat] = useState(false); const [loading, setLoading] = useState(false); + const [chatId, setChatId] = useState('') useEffect(() => { async function getChats() { @@ -34,15 +34,22 @@ export default function ChatList({web3StorageAccessToken} : AccessTokenProps) { return } - return ( - <> - { showChat ? ( + return <> + { showChat && !loading ? (
- {chats.map((c) =>
{c.chatId}
)} +
My Messages
+ {chats.map((c) => ( +
{ setChatId(c.chatId ?? '') }} key={c.chatId}> + +
+ ))}
) : ( { setShowChat(true) }} @@ -50,34 +57,29 @@ export default function ChatList({web3StorageAccessToken} : AccessTokenProps) { Show My Chats )} - - ) + { chatId && { setChatId('') }} walletClient={walletClient!} />} + } function Chat({ chat, - myAddress, - web3StorageAccessToken }: { chat: any, - myAddress: string, - web3StorageAccessToken: string }) { - const from = chat.fromDID; - const to = chat.toDID; - const target = (myAddress === from ? to : from).replace('eip155:', ''); - const { data: cid } = useUserInfo(target); - const [loading, setLoading] = useState(false); - const [authorInfo, setAuthorInfo] = useState(null); - useEffect(() => { - async function getUserInfo() { - const res = await getPostContent(web3StorageAccessToken, cid as string); - setAuthorInfo(res) - } - if (cid) { - getUserInfo() - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [cid]) + return ( +
+ logo +
+
{chat.groupName}
+
{chat.msg.messageContent}
+
+
+ ) } \ No newline at end of file diff --git a/frontend/components/push/ChatModal.tsx b/frontend/components/push/ChatModal.tsx new file mode 100644 index 0000000..2d3b822 --- /dev/null +++ b/frontend/components/push/ChatModal.tsx @@ -0,0 +1,32 @@ +import Image from "next/image"; +import { ChatUIProvider, ChatViewComponent } from "@pushprotocol/uiweb"; +import closeIcon from "@/public/close.png"; +import { WalletClient } from "viem"; +import { viemSignerType } from "@pushprotocol/restapi"; + +export default function ChatModal({ + chatId, + walletClient, + close, +} : { + chatId: string, + walletClient: WalletClient + close: () => void, +}) { + return ( + +
+ +
+ close +
+
+
+ ) +} \ No newline at end of file diff --git a/frontend/components/push/sendNewChat.ts b/frontend/components/push/sendNewChat.ts deleted file mode 100644 index 42ae8bb..0000000 --- a/frontend/components/push/sendNewChat.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Address, WalletClient } from "viem"; -import { PushAPI, viemSignerType } from '@pushprotocol/restapi'; -import { ENV } from "@pushprotocol/restapi/src/lib/constants"; - -export default async function sendNewChat( - walletClient: WalletClient, - recipient: Address, - msg: string, -) { - try { - const me = await PushAPI.initialize(walletClient as viemSignerType, { env: ENV.STAGING }); - const msgObj = await me.chat.send(recipient, { - content: msg - }); - return msgObj; - } catch(e) { - console.log('Send msg error', e) - return null; - } -} \ No newline at end of file diff --git a/frontend/components/user/UserInfo.tsx b/frontend/components/user/UserInfo.tsx index 0a0d125..ed1202c 100644 --- a/frontend/components/user/UserInfo.tsx +++ b/frontend/components/user/UserInfo.tsx @@ -3,8 +3,11 @@ import MainButton from "../button/MainButton"; import { toast } from "react-hot-toast"; import Image from "next/image"; import { storePost } from "@/utils/storePost"; +import { ConditionType, PushAPI, viemSignerType } from '@pushprotocol/restapi'; import { TxProps } from "@/utils/types"; import { sendTx } from "@/utils/sendTx"; +import { ENV } from "@pushprotocol/restapi/src/lib/constants"; +import toBase64 from "@/utils/fileToBase64"; export default function UserInfo({ @@ -18,6 +21,9 @@ export default function UserInfo({ } : TxProps) { const [name, setName] = useState(''); + const [website, setWebsite] = useState(''); + const [token, setToken] = useState(''); + const [contact, setContact] = useState(''); const [desc, setDesc] = useState(''); const [loading, setLoading] = useState(false); const [file, setFile] = useState(); @@ -26,8 +32,18 @@ export default function UserInfo({ const fileSelect = (e: ChangeEvent) => { setFile(e.target.files![0]) } - const updateName = (e: ChangeEvent) => { - setName(e.target.value); + // 0 for name, 1 for website, 2 for token address, 3 for contact info + const updateField = (e: ChangeEvent, field: number) => { + const val = e.target.value; + if (field == 0) { + setName(val); + } else if (field == 1) { + setWebsite(val); + } else if (field == 2) { + setToken(val); + } else { + setContact(val); + } } const updateDesc = (e: ChangeEvent) => { setDesc(e.target.value); @@ -44,8 +60,23 @@ export default function UserInfo({ return; } + if (!website) { + toast.error('Please provide your project\'s website url', { position: 'top-center' }) + return; + } + + if (!token) { + toast.error('Please provide your project\'s ERC20 token address', { position: 'top-center' }) + return; + } + + if (!contact) { + toast.error('Please provide your project\'s contact info', { position: 'top-center' }) + return; + } + if (!desc) { - toast.error('Please provide your project\'s description and contact info', { position: 'top-center' }) + toast.error('Please provide your project\'s description ', { position: 'top-center' }) return; } @@ -54,17 +85,72 @@ export default function UserInfo({ return; } - const info = { name, description: desc }; - const blob = new Blob([JSON.stringify(info)], { type: 'application/json' }) - const files = [ - file, - new File([blob], 'content.json') - ] - setLoading(true); try { + + const projectOwner = await PushAPI.initialize(walletClient as viemSignerType, {env: ENV.STAGING}); + const base64File = await toBase64(file); + const tokenContract = `eip155:${publicClient.chain?.id}:${token}`; + const createdGroup = await projectOwner.chat.group.create(name, { + description: desc, + image: base64File as string, + admins: [account], + rules: { + "entry": { + conditions: { + all: [ + { + "type": ConditionType.PUSH, // define type that rules engine should go for + "category": "ERC20", // define it's ERC20 token that you want to check, supports ERC721 as well + "subcategory": "holder", // define if you are checking 'holder' or 'owner' + "data": { + "contract": tokenContract, + "comparison": ">=", // what comparison needs to pass + "amount": 1, // amount that needs to passed + "decimals": 18, // the decimals for the token + } + } + ] + } + }, + "chat": { + conditions: { + all: [ + { + "type": ConditionType.PUSH, // define type that rules engine should go for + "category": "ERC20", // define it's ERC20 token that you want to check, supports ERC721 as well + "subcategory": "holder", // define if you are checking 'holder' or 'owner' + "data": { + "contract": tokenContract, + "comparison": ">=", // what comparison needs to pass + "amount": 100, // amount that needs to passed + "decimals": 18, // the decimals for the token + } + } + ] + } + }, + } + }); + + const chatId = createdGroup.chatId; + + const info = { + name, + description: desc, + website, + token, + contact, + chatId + }; + const blob = new Blob([JSON.stringify(info)], { type: 'application/json' }) + const files = [ + file, + new File([blob], 'content.json') + ] + const cid = await storePost(web3StorageAccessToken, files); - console.log('CID: ', cid); + console.log('Group Chat Id: ', chatId); const success = await sendTx( "Store Project Info", account, @@ -100,11 +186,32 @@ export default function UserInfo({ { updateField(e, 0) }} value={name} /> + { updateField(e, 1) }} + value={website} + /> + { updateField(e, 2) }} + value={token} + /> + { updateField(e, 3) }} + value={contact} + />