-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Extend frontend to support discussions (#96)
* feat: add copy icon for comment sender address * feat: display comment UI * feat: New comment UI * draft * feat: consume submit api endpoint * feat: inovoke contract to update proposal * feat: implement fetch ipfs file * feat: implement address copy * fix: proposal update * fix: update starknet version * fix: add comment * feat: fetch comments from contract * fix: remove add comments success toast * fix: transaction not activating * fix: format ipfs_hash * to be deployed again * to be deployed again * Update RPC URL as Nethermind Sepolia is buggy * feat: implement balance_of * fix: alignment * fix: padd address from start --------- Co-authored-by: Ondřej Sojka <[email protected]>
- Loading branch information
Showing
14 changed files
with
1,555 additions
and
538 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import axios from "axios"; | ||
import { BASE_API_URL } from "../constants/amm"; | ||
|
||
type CommentPayload = { | ||
address: string; | ||
text: string; | ||
}; | ||
|
||
export const submitCommentApi = async (payload: CommentPayload) => { | ||
const { data } = await axios.post(`${BASE_API_URL}/submit`, payload); | ||
return data; | ||
}; | ||
|
||
|
||
|
||
export const fetchIpfsFile = async (file: string) => { | ||
try { | ||
const response = await axios.get(`https://ipfs.io/ipfs/${file}`); | ||
if (response.status === 200) { | ||
return response.data; | ||
} else { | ||
throw new Error(`Failed to fetch IPFS file with status: ${response.status}`); | ||
} | ||
} catch (error) { | ||
console.error('Error fetching IPFS file:', error); | ||
throw error; // Re-throw the error for further handling if necessary | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import React from "react"; | ||
|
||
export const TickIcon = (props) => ( | ||
<svg | ||
xmlns="http://www.w3.org/2000/svg" | ||
width={24} | ||
height={24} | ||
fill="none" | ||
viewBox="0 -0.5 25 25" | ||
{...props} | ||
> | ||
<path | ||
stroke="#000" | ||
strokeLinecap="round" | ||
strokeLinejoin="round" | ||
strokeWidth={1.5} | ||
d="m5.5 12.5 4.667 4.5L19.5 8" | ||
/> | ||
</svg> | ||
); | ||
|
||
export const CopyIcon = (props) => ( | ||
<svg | ||
xmlns="http://www.w3.org/2000/svg" | ||
width={18} | ||
height={18} | ||
fill="none" | ||
viewBox="0 0 24 24" | ||
{...props} | ||
> | ||
<path | ||
fill="#3B82F6" | ||
d="M15.24 2h-3.894c-1.764 0-3.162 0-4.255.148-1.126.152-2.037.472-2.755 1.193-.719.721-1.038 1.636-1.189 2.766C3 7.205 3 8.608 3 10.379v5.838c0 1.508.92 2.8 2.227 3.342-.067-.91-.067-2.185-.067-3.247v-5.01c0-1.281 0-2.386.118-3.27.127-.948.413-1.856 1.147-2.593.734-.737 1.639-1.024 2.583-1.152.88-.118 1.98-.118 3.257-.118H15.335c1.276 0 2.374 0 3.255.118A3.601 3.601 0 0 0 15.24 2Z" | ||
/> | ||
<path | ||
fill="#3B82F6" | ||
d="M6.6 11.397c0-2.726 0-4.089.844-4.936.843-.847 2.2-.847 4.916-.847h2.88c2.715 0 4.073 0 4.917.847.843.847.843 2.21.843 4.936v4.82c0 2.726 0 4.089-.843 4.936-.844.847-2.202.847-4.917.847h-2.88c-2.715 0-4.073 0-4.916-.847-.844-.847-.844-2.21-.844-4.936v-4.82Z" | ||
/> | ||
</svg> | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { useContractRead } from '@starknet-react/core'; | ||
import React, { } from 'react'; | ||
import { TOKEN_CONTRACT } from '../lib/config'; | ||
import { TokenABI } from '../lib/tokenContractABI'; | ||
|
||
interface CommentCardProps { | ||
address: string; | ||
text: string; | ||
|
||
} | ||
const CommentCard = ({address, text}: CommentCardProps) => { | ||
|
||
const { data, isSuccess } = useContractRead({ | ||
functionName: "balance_of", | ||
args: [address.toString()], | ||
abi:TokenABI, | ||
address: TOKEN_CONTRACT, | ||
watch: false, | ||
retry: false | ||
}); | ||
|
||
return ( | ||
<div > | ||
<div className="grid grid-cols-[1fr_3fr] gap-3 "> | ||
<p className="text-sm font-[400] ">Senders Address:</p> | ||
<div className="flex items-center gap-2"> | ||
<p className="font-[600] text-sm">{address.slice(0, 20)}</p> | ||
|
||
</div> | ||
|
||
<p className="text-sm font-[400] ">Comment:</p> | ||
<p className="font-[600] text-sm">{text}</p> | ||
|
||
<p className="text-sm font-[400]">Token Balance:</p> | ||
<p className="font-[600] text-sm">{isSuccess && parseInt(data?.toString()) / 10**18}</p> | ||
</div> | ||
<div className="border border-b-gray-200 mt-2" /> | ||
</div> | ||
); | ||
} | ||
|
||
export default CommentCard; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import React, { useEffect, useState } from "react"; | ||
import { useContractRead } from "@starknet-react/core"; | ||
import { abi } from "../lib/abi"; | ||
import { fetchIpfsFile } from "../api/apiService"; | ||
import { CONTRACT_ADDR, formatIpfsHash } from "../lib/config"; | ||
import CommentCard from "./CommentCard"; | ||
type CommentProps = { | ||
address: string; | ||
text: string; | ||
starknet_id: string; | ||
}[]; | ||
type Props = { | ||
proposalId: string; | ||
}; | ||
export default function Comments({ proposalId }: Props) { | ||
const [comments, setComments] = useState<CommentProps>([]); | ||
const { data, isLoading } = useContractRead({ | ||
functionName: "get_comments", | ||
args: [proposalId.toString()], | ||
abi, | ||
address: CONTRACT_ADDR, | ||
watch: false, | ||
retry: false | ||
|
||
}); | ||
|
||
|
||
|
||
useEffect(() => { | ||
const fetchData = async () => { | ||
try { | ||
if (Array.isArray(data)) { | ||
const ipfsFetchPromises = data.map((item: { ipfs_hash: string }) => | ||
fetchIpfsFile(formatIpfsHash(item.ipfs_hash)) | ||
); | ||
const ipfsResults = await Promise.all(ipfsFetchPromises); | ||
|
||
setComments(ipfsResults); | ||
} | ||
} catch (e) { | ||
console.error("Error fetching from IPFS:", e); | ||
} | ||
}; | ||
|
||
fetchData(); | ||
}, [data]); | ||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
return isLoading ? ( | ||
<div>loading.... </div> | ||
) : ( | ||
<div className="w-[35rem] pt-5"> | ||
<div className="py-2"> | ||
{comments.length > 0 ? | ||
comments.map(({ address, text }, i) => ( | ||
<div key={i}> | ||
<CommentCard address={address} text={text} /> | ||
</div> | ||
)): <div className="flex justify-center items-center"> <p className="text-sm font-extrabold ">No comments available </p> </div>} | ||
</div> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
import React, { useEffect, useMemo, useState } from "react"; | ||
import toast from "react-hot-toast"; | ||
import { useAccount, useContractWrite } from "@starknet-react/core"; | ||
import { CONTRACT_ADDR, formatAddress, } from "../lib/config"; | ||
import {byteArray} from "starknet" | ||
|
||
import { submitCommentApi } from "../api/apiService"; | ||
export default function NewcommentCommentForm({ | ||
setIsModalOpen, | ||
propId, | ||
}: { | ||
setIsModalOpen: React.Dispatch<React.SetStateAction<boolean>>; | ||
propId: string; | ||
}) { | ||
const { isConnected, address } = useAccount(); | ||
const [comment, setComment] = React.useState<string>(""); | ||
const [ipfsHash, setIpfsHash] = useState<string>(""); | ||
const [isLoading, setIsLoading] = React.useState<boolean>(false); | ||
|
||
const calls = useMemo(() => { | ||
const tx = { | ||
contractAddress: CONTRACT_ADDR, | ||
entrypoint: "add_comment", | ||
calldata: [ | ||
propId.toString(), | ||
byteArray.byteArrayFromString(ipfsHash) | ||
], | ||
}; | ||
return [tx]; | ||
}, [ipfsHash]); | ||
|
||
|
||
|
||
|
||
const { writeAsync } = useContractWrite({ calls }); | ||
async function submitComment(e: React.FormEvent<HTMLFormElement>) { | ||
|
||
e.preventDefault(); | ||
|
||
if (!isConnected) { | ||
toast.error("Please connect your wallet"); | ||
return; | ||
} | ||
|
||
if (!comment) { | ||
toast.error("Please fill out all fields"); | ||
return; | ||
} | ||
|
||
const payload = { | ||
text: comment, | ||
address: formatAddress(address), | ||
}; | ||
|
||
setIsLoading(true); | ||
try { | ||
const result = await submitCommentApi(payload); | ||
if (result) { | ||
setIpfsHash(result?.ipfs_hash); | ||
} | ||
} catch (error) { | ||
toast.error("Something went wrong"); | ||
setIsModalOpen(false); | ||
console.error(error); | ||
} | ||
} | ||
|
||
useEffect(() => { | ||
const updateProposal = async () => { | ||
try { | ||
await writeAsync(); | ||
toast.success("Proposal updated successfully"); | ||
setIsModalOpen(false); | ||
} catch (error) { | ||
toast.error("Unable to update proposal with comment"); | ||
console.error(error); | ||
setIsModalOpen(false); | ||
} | ||
}; | ||
|
||
if (ipfsHash.length > 0) { | ||
updateProposal(); | ||
} | ||
}, [ipfsHash]); | ||
|
||
|
||
|
||
|
||
return ( | ||
<div className="w-[35rem]"> | ||
<form onSubmit={submitComment}> | ||
<label htmlFor="#comment">Comment</label> | ||
<input | ||
id="#comment" | ||
type="text" | ||
placeholder="Leave a comment here" | ||
className="w-full p-2 mb-2 border rounded-lg border-slate-300" | ||
onChange={(e) => setComment(e.target.value)} | ||
/> | ||
|
||
<button | ||
type="submit" | ||
className="w-full p-2 mt-4 text-white bg-blue-500 rounded-lg" | ||
> | ||
{isLoading ? "Loading..." : "Submit"} | ||
</button> | ||
</form> | ||
</div> | ||
); | ||
} |
Oops, something went wrong.