diff --git a/contracts/deployments/base-sepolia.json b/contracts/deployments/base-sepolia.json new file mode 100644 index 000000000..dbb4aee3f --- /dev/null +++ b/contracts/deployments/base-sepolia.json @@ -0,0 +1,4 @@ +{ + "MOONEYToken": "0x3B3024e49261866a420F2444Fa1f248902C8D143", + "vMOONEYToken": "0xa83aceC4e6784a0c9C4Ba6fa414665Ba15F6F3b6" +} \ No newline at end of file diff --git a/contracts/deployments/base.json b/contracts/deployments/base.json new file mode 100644 index 000000000..e23833aff --- /dev/null +++ b/contracts/deployments/base.json @@ -0,0 +1,4 @@ +{ + "MOONEYToken": "0x6585a54A98fADA893904EB8A9E9CDFb927bddf39", + "vMOONEYToken": "0x7f8f1B45c3FD6Be4F467520Fc1Cf030d5CaBAcF5" +} \ No newline at end of file diff --git a/ui/.env.testnet b/ui/.env.testnet index 614fd4185..2b2103bc6 100644 --- a/ui/.env.testnet +++ b/ui/.env.testnet @@ -1,3 +1,4 @@ NEXT_PUBLIC_CHAIN=mumbai NEXT_PUBLIC_VMOONEY_REQUIRED_STAKE=1 NEXT_PUBLIC_SNAPSHOT_API_KEY=placeholder +COORDINAPE_API_KEY=placeholder diff --git a/ui/components/contribution/ContributionEditor.tsx b/ui/components/contribution/ContributionEditor.tsx new file mode 100644 index 000000000..6d66abd2f --- /dev/null +++ b/ui/components/contribution/ContributionEditor.tsx @@ -0,0 +1,146 @@ +import React, { useEffect, useState } from 'react'; +import dynamic from "next/dynamic"; +import { usePrivy, getAccessToken } from "@privy-io/react-auth"; +import { GetMarkdown, SetMarkdown } from "@nance/nance-editor"; +import { LoadingSpinner } from "@/components/layout/LoadingSpinner"; +import { pinBlobOrFile } from "@/lib/ipfs/pinBlobOrFile"; +import { createSession, destroySession } from "@/lib/iron-session/iron-session"; +import useAccount from "@/lib/nance/useAccountAddress"; +import { toast } from "react-hot-toast"; +import "@nance/nance-editor/lib/css/dark.css"; +import "@nance/nance-editor/lib/css/editor.css"; + +let getMarkdown: GetMarkdown; +let setMarkdown: SetMarkdown; + +const NanceEditor = dynamic( + async () => { + const editorModule = await import("@nance/nance-editor"); + getMarkdown = editorModule.getMarkdown; + setMarkdown = editorModule.setMarkdown; + return editorModule.NanceEditor; + }, + { + ssr: false, + loading: () => , + } +); + +const CONTRIBUTION_TEMPLATE = ` +## Contribution Summary +When documenting contributions, please ensure they meet the following criteria: + 1. Completed Work Only: Contributions should reflect completed efforts, not ongoing or planned work. + 2. Specific and Measurable Results: Describe the tangible outcomes of the contribution. Include metrics, timelines, or other objective measures wherever possible. +Clear, detailed, and results-focused contributions help us understand and value the impact of your work. + +*Example:* +*Good Contribution:* + • *"Improved search performance by optimizing database queries, reducing response times by 30% within one month."* + +*Poor Contribution:* + • *"Worked on improving search performance."* + +`; + +const ContributionEditor: React.FC = () => { + const { authenticated } = usePrivy(); + const [submitting, setSubmitting] = useState(false); + const [coordinapeLink, setCoordinapeLink] = useState(null); + const { address } = useAccount(); + + useEffect(() => { + if (setMarkdown) { + setMarkdown(CONTRIBUTION_TEMPLATE); + } + }, []); + + const handleSubmit = async () => { + if (!authenticated) { + toast.error("Please sign in to submit a contribution!"); + return; + } + + setSubmitting(true); + const accessToken = await getAccessToken(); + await createSession(accessToken); + const loadingToast = toast.loading("Submitting contribution..."); + + try { + const body = JSON.stringify({ + description: getMarkdown(), + address, + }); + + const res = await fetch("/api/coordinape/createContribution", { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${accessToken}` + }, + body + }); + await destroySession(accessToken); + const data = await res.json(); + + if (!res.ok) { + throw new Error(data.error); + } + + setCoordinapeLink(`https://app.coordinape.com/circles/${data.insert_contributions_one.circle_id}`); + toast.success("Contribution submitted successfully!"); + } catch (err) { + toast.error("Failed to submit contribution"); + } finally { + toast.dismiss(loadingToast); + setSubmitting(false); + } + }; + + if (!authenticated) { + return

Please sign in to submit a contribution!

; + } + + if (coordinapeLink) { + return ( +
+

Contribution submitted!

+

+ View and edit your contribution {" "} + + here + +

+
+ ); + } + + return ( +
+
+ { + const accessToken = await getAccessToken() + await createSession(accessToken) + const res = await pinBlobOrFile(val) + await destroySession(accessToken) + return res.url; + }} + darkMode={true} + /> +
+
+ +
+
+ ); +}; + +export default ContributionEditor; diff --git a/ui/components/dashboard/analytics/AnalyticsChainSelector.tsx b/ui/components/dashboard/analytics/AnalyticsChainSelector.tsx index bb41803cf..2b65dc411 100644 --- a/ui/components/dashboard/analytics/AnalyticsChainSelector.tsx +++ b/ui/components/dashboard/analytics/AnalyticsChainSelector.tsx @@ -1,11 +1,32 @@ import { ChartBarSquareIcon, ChevronDownIcon, - SignalIcon, } from '@heroicons/react/24/outline' import Image from 'next/image' import { useEffect, useState } from 'react' +function AnalyticsChain({ chain, selectChain }: any) { + return ( + + ) +} + export default function AnalyticsChainSelector({ analyticsChain, setAnalyticsChain, @@ -60,50 +81,11 @@ export default function AnalyticsChainSelector({ id="network-selector-dropdown" className="w-[250px] absolute flex flex-col items-start gap-2 text-black z-10" > - - - - + + + + + )} diff --git a/ui/components/hats/Hat.tsx b/ui/components/hats/Hat.tsx index e59264280..074af174d 100644 --- a/ui/components/hats/Hat.tsx +++ b/ui/components/hats/Hat.tsx @@ -1,6 +1,6 @@ import { ArrowUpRightIcon } from '@heroicons/react/24/outline' import { Chain } from '@thirdweb-dev/chains' -import { NFT, ThirdwebNftMedia } from '@thirdweb-dev/react' +import { MediaRenderer, NFT } from '@thirdweb-dev/react' import { useRouter } from 'next/router' import { useEffect, useState } from 'react' import { useHatData } from '@/lib/hats/useHatData' @@ -48,8 +48,8 @@ export function Hat({
{teamNFT && (
- diff --git a/ui/components/jobs/Job.tsx b/ui/components/jobs/Job.tsx index 222fb1dbd..919067fea 100644 --- a/ui/components/jobs/Job.tsx +++ b/ui/components/jobs/Job.tsx @@ -22,6 +22,7 @@ export type Job = { } type JobProps = { + id?: string job: Job jobTableContract?: any refreshJobs?: any @@ -31,6 +32,7 @@ type JobProps = { } export default function Job({ + id, job, jobTableContract, refreshJobs, @@ -71,6 +73,8 @@ export default function Job({ <> {isActive && (
diff --git a/ui/components/layout/Footer.tsx b/ui/components/layout/Footer.tsx index d013a2ea9..7e1e8b0ff 100644 --- a/ui/components/layout/Footer.tsx +++ b/ui/components/layout/Footer.tsx @@ -1,79 +1,114 @@ // footer.tsx - -import Link from 'next/link'; +import Link from 'next/link' interface FooterProps { - darkBackground?: boolean; + darkBackground?: boolean +} + +type FooterTokenLinkProps = { + href: string + label: string +} + +function FooterTokenLink({ href, label }: FooterTokenLinkProps) { + return ( + + + + {label} + + + + ) } export default function Footer({ darkBackground = false }: FooterProps) { - return ( -